mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-30 15:00:06 +00:00
78cf86150e
Id descriptors are computed as a recursive hash of all instructions used to define an id. Descriptors are invarint of actual id values and the similar code in different files would produce the same descriptors. Multiple ids can have the same descriptor. For example %1 = OpConstant %u32 1 %2 = OpConstant %u32 1 would produce two ids with the same descriptor. But %3 = OpConstant %s32 1 %4 = OpConstant %u32 2 would have descriptors different from %1 and %2. Descriptors will be used as handles of move-to-front sequences in SPIR-V compression.
275 lines
8.2 KiB
C++
275 lines
8.2 KiB
C++
// 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 "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] [<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.
|
|
|
|
--codegen_opcode_hist
|
|
Output generated C++ code for opcode histogram.
|
|
This flag disables non-C++ output.
|
|
|
|
--codegen_opcode_and_num_operands_hist
|
|
Output generated C++ code for opcode_and_num_operands
|
|
histogram.
|
|
This flag disables non-C++ output.
|
|
|
|
--codegen_opcode_and_num_operands_markov_huffman_codecs
|
|
Output generated C++ code for Huffman codecs of
|
|
opcode_and_num_operands Markov chain.
|
|
This flag disables non-C++ output.
|
|
|
|
--codegen_literal_string_huffman_codecs
|
|
Output generated C++ code for Huffman codecs for
|
|
literal strings.
|
|
This flag disables non-C++ output.
|
|
|
|
--codegen_non_id_word_huffman_codecs
|
|
Output generated C++ code for Huffman codecs for
|
|
single-word non-id slots.
|
|
This flag disables non-C++ output.
|
|
|
|
--codegen_id_descriptor_huffman_codecs
|
|
Output generated C++ code for Huffman codecs for
|
|
common id descriptors.
|
|
This flag disables non-C++ output.
|
|
)",
|
|
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;
|
|
bool export_text = true;
|
|
bool codegen_opcode_hist = false;
|
|
bool codegen_opcode_and_num_operands_hist = false;
|
|
bool codegen_opcode_and_num_operands_markov_huffman_codecs = false;
|
|
bool codegen_literal_string_huffman_codecs = false;
|
|
bool codegen_non_id_word_huffman_codecs = false;
|
|
bool codegen_id_descriptor_huffman_codecs = 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, "--codegen_opcode_hist")) {
|
|
codegen_opcode_hist = true;
|
|
export_text = false;
|
|
} else if (0 == strcmp(cur_arg,
|
|
"--codegen_opcode_and_num_operands_hist")) {
|
|
codegen_opcode_and_num_operands_hist = true;
|
|
export_text = false;
|
|
} else if (strcmp(
|
|
"--codegen_opcode_and_num_operands_markov_huffman_codecs",
|
|
cur_arg) == 0) {
|
|
codegen_opcode_and_num_operands_markov_huffman_codecs = true;
|
|
export_text = false;
|
|
} else if (0 == strcmp(cur_arg,
|
|
"--codegen_literal_string_huffman_codecs")) {
|
|
codegen_literal_string_huffman_codecs = true;
|
|
export_text = false;
|
|
} else if (0 == strcmp(cur_arg,
|
|
"--codegen_non_id_word_huffman_codecs")) {
|
|
codegen_non_id_word_huffman_codecs = true;
|
|
export_text = false;
|
|
} else if (0 == strcmp(cur_arg,
|
|
"--codegen_id_descriptor_huffman_codecs")) {
|
|
codegen_id_descriptor_huffman_codecs = true;
|
|
export_text = false;
|
|
} 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;
|
|
|
|
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<uint32_t> contents;
|
|
if (!ReadFile<uint32_t>(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::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;
|
|
|
|
if (export_text) {
|
|
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);
|
|
}
|
|
|
|
if (codegen_opcode_hist) {
|
|
out << std::endl;
|
|
analyzer.WriteCodegenOpcodeHist(out);
|
|
}
|
|
|
|
if (codegen_opcode_and_num_operands_hist) {
|
|
out << std::endl;
|
|
analyzer.WriteCodegenOpcodeAndNumOperandsHist(out);
|
|
}
|
|
|
|
if (codegen_opcode_and_num_operands_markov_huffman_codecs) {
|
|
out << std::endl;
|
|
analyzer.WriteCodegenOpcodeAndNumOperandsMarkovHuffmanCodecs(out);
|
|
}
|
|
|
|
if (codegen_literal_string_huffman_codecs) {
|
|
out << std::endl;
|
|
analyzer.WriteCodegenLiteralStringHuffmanCodecs(out);
|
|
}
|
|
|
|
if (codegen_non_id_word_huffman_codecs) {
|
|
out << std::endl;
|
|
analyzer.WriteCodegenNonIdWordHuffmanCodecs(out);
|
|
}
|
|
|
|
if (codegen_id_descriptor_huffman_codecs) {
|
|
out << std::endl;
|
|
analyzer.WriteCodegenIdDescriptorHuffmanCodecs(out);
|
|
}
|
|
|
|
return 0;
|
|
}
|