| // 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 <cassert> | |
| #include <cstring> | |
| #include <fstream> | |
| #include <iostream> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include "spirv-tools/libspirv.h" | |
| #include "tools/io.h" | |
| #include "tools/stats/spirv_stats.h" | |
| #include "tools/stats/stats_analyzer.h" | |
| namespace { | |
| void PrintUsage(char* argv0) { | |
| printf( | |
| R"(%s - Collect statistics from one or more SPIR-V binary file(s). | |
| USAGE: %s [options] [<filepaths>] | |
| 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 expect_output_path = false; | |
| bool verbose = false; | |
| std::vector<const char*> paths; | |
| const char* output_path = nullptr; | |
| 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 if (0 == strcmp(cur_arg, "--output") || | |
| 0 == strcmp(cur_arg, "-o")) { | |
| expect_output_path = true; | |
| } else { | |
| PrintUsage(argv[0]); | |
| continue_processing = false; | |
| return_code = 1; | |
| } | |
| } else { | |
| if (expect_output_path) { | |
| output_path = cur_arg; | |
| expect_output_path = false; | |
| } 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; | |
| spvtools::Context ctx(SPV_ENV_UNIVERSAL_1_1); | |
| ctx.SetMessageConsumer(DiagnosticsMessageHandler); | |
| spvtools::stats::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<uint32_t> contents; | |
| if (!ReadFile<uint32_t>(path, "rb", &contents)) return 1; | |
| if (SPV_SUCCESS != | |
| spvtools::stats::AggregateStats(ctx.CContext(), contents.data(), | |
| contents.size(), nullptr, &stats)) { | |
| std::cerr << "error: Failed to aggregate stats for " << path << std::endl; | |
| return 1; | |
| } | |
| } | |
| spvtools::stats::StatsAnalyzer analyzer(stats); | |
| std::ofstream fout; | |
| if (output_path) { | |
| fout.open(output_path); | |
| if (!fout.is_open()) { | |
| std::cerr << "error: Failed to open " << output_path << std::endl; | |
| return 1; | |
| } | |
| } | |
| std::ostream& out = fout.is_open() ? fout : 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; | |
| } |