| // 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; |
| } |