// Copyright (c) 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include "source/spirv_stats.h" #include "source/table.h" #include "spirv-tools/libspirv.h" #include "stats_analyzer.h" #include "tools/io.h" using libspirv::SpirvStats; namespace { struct ScopedContext { ScopedContext(spv_target_env env) : context(spvContextCreate(env)) {} ~ScopedContext() { spvContextDestroy(context); } spv_context context; }; void PrintUsage(char* argv0) { printf( R"(%s - Collect statistics from one or more SPIR-V binary file(s). USAGE: %s [options] [] TIP: In order to collect statistics from all .spv files under current dir use find . -name "*.spv" -print0 | xargs -0 -s 2000000 %s Options: -h, --help Print this help. -v, --verbose Print additional info to stderr. )", argv0, argv0, argv0); } void DiagnosticsMessageHandler(spv_message_level_t level, const char*, const spv_position_t& position, const char* message) { switch (level) { case SPV_MSG_FATAL: case SPV_MSG_INTERNAL_ERROR: case SPV_MSG_ERROR: std::cerr << "error: " << position.index << ": " << message << std::endl; break; case SPV_MSG_WARNING: std::cout << "warning: " << position.index << ": " << message << std::endl; break; case SPV_MSG_INFO: std::cout << "info: " << position.index << ": " << message << std::endl; break; default: break; } } } // namespace int main(int argc, char** argv) { bool continue_processing = true; int return_code = 0; bool verbose = false; std::vector paths; for (int argi = 1; continue_processing && argi < argc; ++argi) { const char* cur_arg = argv[argi]; if ('-' == cur_arg[0]) { if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { PrintUsage(argv[0]); continue_processing = false; return_code = 0; } else if (0 == strcmp(cur_arg, "--verbose") || 0 == strcmp(cur_arg, "-v")) { verbose = true; } else { PrintUsage(argv[0]); continue_processing = false; return_code = 1; } } else { paths.push_back(cur_arg); } } // Exit if command line parsing was not successful. if (!continue_processing) { return return_code; } std::cerr << "Processing " << paths.size() << " files..." << std::endl; ScopedContext ctx(SPV_ENV_UNIVERSAL_1_1); SetContextMessageConsumer(ctx.context, DiagnosticsMessageHandler); libspirv::SpirvStats stats; stats.opcode_markov_hist.resize(1); for (size_t index = 0; index < paths.size(); ++index) { const size_t kMilestonePeriod = 1000; if (verbose) { if (index % kMilestonePeriod == kMilestonePeriod - 1) std::cerr << "Processed " << index + 1 << " files..." << std::endl; } const char* path = paths[index]; std::vector contents; if (!ReadFile(path, "rb", &contents)) return 1; if (SPV_SUCCESS != libspirv::AggregateStats( *ctx.context, contents.data(), contents.size(), nullptr, &stats)) { std::cerr << "error: Failed to aggregate stats for " << path << std::endl; return 1; } } StatsAnalyzer analyzer(stats); std::ostream& out = std::cout; out << std::endl; analyzer.WriteVersion(out); analyzer.WriteGenerator(out); out << std::endl; analyzer.WriteCapability(out); out << std::endl; analyzer.WriteExtension(out); out << std::endl; analyzer.WriteOpcode(out); out << std::endl; analyzer.WriteOpcodeMarkov(out); out << std::endl; analyzer.WriteConstantLiterals(out); return 0; }