in opt/instrument/BlockInstrument.cpp [1141:1405]
void print_stats(ScopedMetrics& sm,
const std::vector<MethodInfo>& instrumented_methods,
const size_t max_num_blocks) {
MethodInfo total{};
for (const auto& i : instrumented_methods) {
total += i;
}
const size_t total_instrumented = instrumented_methods.size();
const size_t only_method_instrumented = total.num_too_many_blocks;
const size_t total_block_instrumented =
total_instrumented - only_method_instrumented;
auto print = [](size_t num, size_t total, size_t& accumulate) {
std::stringstream ss;
accumulate += num;
ss << std::fixed << std::setprecision(3) << std::setw(6) << num << " ("
<< std::setw(6) << (num * 100. / total) << "%, " << std::setw(6)
<< (accumulate * 100. / total) << "%)";
return ss.str();
};
auto divide = [](size_t a, size_t b) {
if (b == 0) {
return std::string("N/A");
}
std::stringstream ss;
ss << std::fixed << std::setprecision(4) << double(a) / double(b);
return ss.str();
};
// ----- Print summary
{
auto summary_scope = sm.scope("summary");
TRACE(INSTRUMENT, 4, "Maximum blocks for block instrumentation: %zu",
max_num_blocks);
sm.set_metric("max_num_blocks", max_num_blocks);
TRACE(INSTRUMENT, 4, "Total instrumented methods: %zu", total_instrumented);
sm.set_metric("total_instrumented", total_instrumented);
TRACE(INSTRUMENT, 4, "- Block + method instrumented: %zu",
total_block_instrumented);
sm.set_metric("block_and_method_instrumented", total_block_instrumented);
TRACE(INSTRUMENT, 4, "- Only method instrumented: %zu",
only_method_instrumented);
sm.set_metric("method_instrumented_only", only_method_instrumented);
}
auto scope_total_avg = [&](const std::string& key, size_t num, size_t denom) {
auto scope = sm.scope(key);
sm.set_metric("total", num);
if (denom != 0) {
sm.set_metric("average100", 100 * num / denom);
}
return scope;
};
// ----- Bit-vector stats
TRACE(INSTRUMENT, 4, "Bit-vector stats for block instrumented methods:");
{
size_t acc = 0;
size_t total_bit_vectors = 0;
std::map<int /*num_vectors*/, size_t /*num_methods*/> dist;
for (const auto& i : instrumented_methods) {
if (i.too_many_blocks) {
++dist[-1];
} else {
++dist[i.num_vectors];
total_bit_vectors += i.num_vectors;
}
}
for (const auto& p : dist) {
TRACE(INSTRUMENT, 4, " %3d vectors: %s", p.first,
SHOW(print(p.second, total_instrumented, acc)));
}
TRACE(INSTRUMENT, 4, "Total/average bit vectors: %zu, %s",
total_bit_vectors,
SHOW(divide(total_bit_vectors, total_block_instrumented)));
scope_total_avg("bit_vectors", total_bit_vectors, total_block_instrumented);
}
// ----- Instrumented block stats
TRACE(INSTRUMENT, 4, "Instrumented / actual non-entry block stats:");
{
std::map<int, std::pair<size_t /*instrumented*/, size_t /*block*/>> dist;
for (const auto& i : instrumented_methods) {
if (i.too_many_blocks) {
++dist[-1].first;
} else {
++dist[i.num_instrumented_blocks].first;
}
++dist[i.num_non_entry_blocks].second;
}
std::array<size_t, 2> accs = {0, 0};
for (const auto& p : dist) {
TRACE(INSTRUMENT, 4, " %5d blocks: %s | %s", p.first,
SHOW(print(p.second.first, total_instrumented, accs[0])),
SHOW(print(p.second.second, total_instrumented, accs[1])));
}
TRACE(
INSTRUMENT, 4, "Total/average instrumented blocks: %zu, %s",
total.num_instrumented_blocks,
SHOW(divide(total.num_instrumented_blocks, total_block_instrumented)));
scope_total_avg("instrumented_blocks", total.num_instrumented_blocks,
total_block_instrumented);
TRACE(INSTRUMENT, 4, "Total/average non-entry blocks: %zu, %s",
total.num_non_entry_blocks,
SHOW(divide(total.num_non_entry_blocks, total_instrumented)));
scope_total_avg("non_entry_blocks", total.num_non_entry_blocks,
total_block_instrumented);
}
const size_t total_catches = std::accumulate(
instrumented_methods.begin(), instrumented_methods.end(), size_t(0),
[](int a, auto&& i) { return a + i.num_catches; });
const size_t total_instrumented_catches = std::accumulate(
instrumented_methods.begin(), instrumented_methods.end(), size_t(0),
[](int a, auto&& i) { return a + i.num_instrumented_catches; });
// ----- Instrumented/skipped block stats
auto print_ratio = [&total](size_t num) {
std::stringstream ss;
ss << num << std::fixed << std::setprecision(2) << " ("
<< (num * 100. / total.num_non_entry_blocks) << "%)";
return ss.str();
};
auto metric_ratio = [&sm, &total](const std::string& sub_key, size_t num) {
if (total.num_non_entry_blocks == 0) {
return;
}
sm.set_metric(sub_key, num);
sm.set_metric(sub_key + ".ratio100.00",
10000 * num / total.num_non_entry_blocks);
};
{
auto non_entry_scope = sm.scope("non_entry_blocks_stats");
TRACE(INSTRUMENT, 4, "Total non-entry blocks: %zu",
total.num_non_entry_blocks);
sm.set_metric("total", total.num_non_entry_blocks);
TRACE(INSTRUMENT, 4, "- Instrumented blocks: %s",
SHOW(print_ratio(total.num_instrumented_blocks)));
metric_ratio("total_instrumented_blocks", total.num_instrumented_blocks);
TRACE(INSTRUMENT, 4, "- Merged blocks: %s",
print_ratio(total.num_merged).c_str());
sm.set_metric("merged", total.num_merged);
TRACE(INSTRUMENT, 4, "- Merged blocks (into non-instrumentable): %s",
print_ratio(total.num_merged_not_instrumented).c_str());
sm.set_metric("merged_not_instrumentable",
total.num_merged_not_instrumented);
TRACE(INSTRUMENT, 4, "- Skipped catch blocks: %s",
SHOW(print_ratio(total_catches - total_instrumented_catches)));
{
auto skipped_scope = sm.scope("skipped");
metric_ratio("catch_blocks", total_catches - total_instrumented_catches);
auto no_sb = std::accumulate(
instrumented_methods.begin(), instrumented_methods.end(), size_t(0),
[](size_t a, auto&& i) { return a + i.num_no_source_blocks; });
TRACE(INSTRUMENT, 4, "- Skipped due to no source block: %s",
SHOW(print_ratio(no_sb)));
metric_ratio("no_source_blocks", no_sb);
auto too_large_methods = std::accumulate(
instrumented_methods.begin(), instrumented_methods.end(), size_t(0),
[](size_t a, auto&& i) { return a + i.num_blocks_too_large; });
TRACE(INSTRUMENT, 4, "- Skipped due to too large methods: %s",
SHOW(print_ratio(too_large_methods)));
metric_ratio("too_large_methods", too_large_methods);
auto empty_blocks = std::accumulate(
instrumented_methods.begin(), instrumented_methods.end(), size_t(0),
[](size_t a, auto&& i) { return a + i.num_empty_blocks; });
TRACE(INSTRUMENT, 4, "- Skipped empty blocks: %s",
SHOW(print_ratio(empty_blocks)));
metric_ratio("empty_blocks", empty_blocks);
auto useless_blocks = std::accumulate(
instrumented_methods.begin(), instrumented_methods.end(), size_t(0),
[](size_t a, auto&& i) { return a + i.num_useless_blocks; });
TRACE(INSTRUMENT, 4, "- Skipped useless blocks: %s",
SHOW(print_ratio(useless_blocks)));
metric_ratio("useless_blocks", useless_blocks);
}
}
// ----- Instrumented exit block stats
TRACE(INSTRUMENT, 4, "Instrumented exit block stats:");
{
size_t acc = 0;
size_t total_exits = 0;
size_t no_exit = 0;
std::map<int /*num_vectors*/, size_t /*num_methods*/> dist;
TRACE(INSTRUMENT, 4, "No onMethodExit but 1+ non-entry blocks:");
int k = 0;
for (const auto& i : instrumented_methods) {
if (!i.too_many_blocks && i.num_exit_calls == 0 &&
i.num_non_entry_blocks != 0) {
TRACE(INSTRUMENT, 4, "- %d: %zu, %s", ++k, i.num_non_entry_blocks,
show_deobfuscated(i.method).c_str());
++no_exit;
}
++dist[i.num_exit_calls];
total_exits += i.num_exit_calls;
}
for (const auto& p : dist) {
TRACE(INSTRUMENT, 4, " %4d exits: %s", p.first,
SHOW(print(p.second, total_instrumented, acc)));
}
TRACE(INSTRUMENT, 4, "Total/average instrumented exits: %zu, %s",
total_exits, SHOW(divide(total_exits, total_instrumented)));
auto exit_scope =
scope_total_avg("instrumented_exits", total_exits, total_instrumented);
sm.set_metric("methods_without_exit_calls", no_exit);
}
// ----- Catch block stats
TRACE(INSTRUMENT, 4, "Catch block stats:");
{
size_t acc = 0;
std::map<int, size_t> dist;
for (const auto& i : instrumented_methods) {
++dist[i.num_catches];
}
for (const auto& p : dist) {
TRACE(INSTRUMENT, 4, " %4d catches: %s", p.first,
SHOW(print(p.second, total_instrumented, acc)));
}
TRACE(INSTRUMENT, 4, "Total/average catch blocks: %zu, %s",
total.num_catches,
SHOW(divide(total.num_catches, total_instrumented)));
scope_total_avg("catch_blocks", total.num_catches, total_instrumented);
}
auto print_two_dists = [÷, &print, &instrumented_methods,
total_instrumented, total_block_instrumented](
const char* name1, const char* name2,
auto&& accessor1, auto&& accessor2) {
std::map<int, std::pair<size_t, size_t>> dist;
size_t total1 = 0;
size_t total2 = 0;
for (const auto& i : instrumented_methods) {
if (i.too_many_blocks) {
++dist[-1].first;
++dist[-1].second;
} else {
++dist[accessor1(i)].first;
++dist[accessor2(i)].second;
total1 += accessor1(i);
total2 += accessor2(i);
}
}
std::array<size_t, 2> accs = {0, 0};
for (const auto& p : dist) {
TRACE(INSTRUMENT, 4, " %5d blocks: %s | %s", p.first,
SHOW(print(p.second.first, total_instrumented, accs[0])),
SHOW(print(p.second.second, total_instrumented, accs[1])));
}
TRACE(INSTRUMENT, 4, "Total/average %s blocks: %zu, %s", name1, total1,
SHOW(divide(total1, total_block_instrumented)));
TRACE(INSTRUMENT, 4, "Total/average %s blocks: %zu, %s", name2, total2,
SHOW(divide(total2, total_block_instrumented)));
};
TRACE(INSTRUMENT, 4, "Empty / useless block stats:");
print_two_dists(
"empty", "useless", [](auto&& v) { return v.num_empty_blocks; },
[](auto&& v) { return v.num_useless_blocks; });
}