Add analysis for move-result target
Added analysis for target of move-result. Removed useless counters.
Added verbosity options to reduce spam:
-0: Print only summary
-1: Print summary and distribution
-2: Print all the things
Test: test-art-host
Bug: 77721545
Change-Id: Ib002754d4f50fdf4a3d2e57c83d565dc8d64a054
diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc
index c90bb9c..e1989d0 100644
--- a/tools/dexanalyze/dexanalyze.cc
+++ b/tools/dexanalyze/dexanalyze.cc
@@ -58,7 +58,7 @@
<< " -a (Run all experiments)\n"
<< " -n <int> (run experiment with 1 .. n as argument)\n"
<< " -d (Dump on per Dex basis)\n"
- << " -v (Verbose dumping)\n";
+ << " -v (quiet(0) to everything(2))\n";
return kExitCodeUsageError;
}
@@ -71,7 +71,17 @@
verify_checksum_ = false;
run_dex_file_verifier_ = false;
} else if (arg == "-v") {
- verbose_ = true;
+ if (i + 1 >= argc) {
+ return Usage(argv);
+ }
+ std::istringstream iss(argv[i + 1]);
+ size_t verbose_level = 0u;
+ iss >> verbose_level;
+ if (verbose_level > static_cast<size_t>(VerboseLevel::kEverything)) {
+ return Usage(argv);
+ }
+ ++i;
+ verbose_level_ = static_cast<VerboseLevel>(verbose_level);
} else if (arg == "-a") {
run_all_experiments_ = true;
} else if (arg == "-n") {
@@ -104,7 +114,7 @@
return 0;
}
- bool verbose_ = false;
+ VerboseLevel verbose_level_ = VerboseLevel::kNormal;
bool verify_checksum_ = true;
bool run_dex_file_verifier_ = true;
bool dump_per_input_dex_ = false;
@@ -147,7 +157,7 @@
}
}
for (const std::unique_ptr<Experiment>& experiment : experiments_) {
- experiment->dump_ = options->verbose_;
+ experiment->verbose_level_ = options->verbose_level_;
}
}
diff --git a/tools/dexanalyze/dexanalyze_bytecode.cc b/tools/dexanalyze/dexanalyze_bytecode.cc
index d18b0df..1c5a5d5 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.cc
+++ b/tools/dexanalyze/dexanalyze_bytecode.cc
@@ -88,7 +88,7 @@
if (method.GetCodeItem() == nullptr || !visited.insert(method.GetCodeItem()).second) {
continue;
}
- if (dump_) {
+ if (verbose_level_ >= VerboseLevel::kEverything) {
std::cout << std::endl
<< "Processing " << dex_file->PrettyMethod(method.GetIndex(), true);
}
@@ -122,8 +122,6 @@
os << "Total Dex code bytes: " << Percent(dex_code_bytes_, total_size) << "\n";
os << "Total output code bytes: " << Percent(output_size_, total_size) << "\n";
os << "Total deduped code bytes: " << Percent(deduped_size_, total_size) << "\n";
- os << "Missing field idx count: " << missing_field_idx_count_ << "\n";
- os << "Missing method idx count: " << missing_method_idx_count_ << "\n";
std::vector<std::pair<size_t, std::vector<uint8_t>>> pairs;
for (auto&& pair : instruction_freq_) {
if (pair.second > 0 && !pair.first.empty()) {
@@ -133,11 +131,14 @@
}
}
std::sort(pairs.rbegin(), pairs.rend());
- os << "Top instruction bytecode sizes and hex dump" << "\n";
+ static constexpr size_t kMaxMacros = 128;
uint64_t top_instructions_savings = 0u;
- for (size_t i = 0; i < 128 && i < pairs.size(); ++i) {
+ for (size_t i = 0; i < kMaxMacros && i < pairs.size(); ++i) {
top_instructions_savings += pairs[i].first;
- if (dump_ || (true)) {
+ }
+ if (verbose_level_ >= VerboseLevel::kNormal) {
+ os << "Top " << kMaxMacros << " instruction bytecode sizes and hex dump" << "\n";
+ for (size_t i = 0; i < kMaxMacros && i < pairs.size(); ++i) {
auto bytes = pairs[i].second;
// Remove opcode bytes.
bytes.erase(bytes.begin());
@@ -145,6 +146,12 @@
<< Instruction::Name(static_cast<Instruction::Code>(pairs[i].second[0]))
<< "(" << bytes << ")\n";
}
+ os << "Move result register distribution" << "\n";
+ const size_t move_result_total =
+ std::accumulate(move_result_reg_.begin(), move_result_reg_.end(), 0u);
+ for (size_t i = 0; i < move_result_reg_.size(); ++i) {
+ os << i << ": " << Percent(move_result_reg_[i], move_result_total) << "\n";
+ }
}
os << "Top instructions 1b macro savings "
<< Percent(top_instructions_savings, total_size) << "\n";
@@ -167,7 +174,7 @@
if (inst == code_item.end()) {
break;
}
- if (dump_) {
+ if (verbose_level_ >= VerboseLevel::kEverything) {
std::cout << std::endl;
std::cout << inst->DumpString(nullptr);
if (skip_next) {
@@ -323,6 +330,7 @@
next->Opcode() == Instruction::MOVE_RESULT_OBJECT;
if (next_move_result) {
dest_reg = next->VRegA_11x();
+ ++move_result_reg_[dest_reg];
}
}
@@ -406,9 +414,9 @@
++current_type.types_.FindOrAdd(type_idx)->second;
} else {
bool next_is_init = false;
- if (opcode == Instruction::NEW_INSTANCE && inst != code_item.end()) {
+ if (opcode == Instruction::NEW_INSTANCE) {
auto next = std::next(inst);
- if (next->Opcode() == Instruction::INVOKE_DIRECT) {
+ if (next != code_item.end() && next->Opcode() == Instruction::INVOKE_DIRECT) {
uint32_t args[6] = {};
uint32_t arg_count = next->GetVarArgs(args);
uint32_t method_idx = DexMethodIndex(next.Inst());
@@ -449,7 +457,7 @@
Add(new_opcode, inst.Inst());
}
}
- if (dump_) {
+ if (verbose_level_ >= VerboseLevel::kEverything) {
std::cout << std::endl
<< "Bytecode size " << code_item.InsnsSizeInBytes() << " -> " << buffer_.size();
std::cout << std::endl;
@@ -504,7 +512,7 @@
}
bool NewRegisterInstructions::InstNibbles(uint8_t opcode, const std::vector<uint32_t>& args) {
- if (dump_) {
+ if (verbose_level_ >= VerboseLevel::kEverything) {
std::cout << " ==> " << Instruction::Name(static_cast<Instruction::Code>(opcode)) << " ";
for (int v : args) {
std::cout << v << ", ";
@@ -512,7 +520,7 @@
}
for (int v : args) {
if (v >= 16) {
- if (dump_) {
+ if (verbose_level_ >= VerboseLevel::kEverything) {
std::cout << "(OUT_OF_RANGE)";
}
return false;
diff --git a/tools/dexanalyze/dexanalyze_bytecode.h b/tools/dexanalyze/dexanalyze_bytecode.h
index 9ea819b..ed40ba7 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.h
+++ b/tools/dexanalyze/dexanalyze_bytecode.h
@@ -17,6 +17,7 @@
#ifndef ART_TOOLS_DEXANALYZE_DEXANALYZE_BYTECODE_H_
#define ART_TOOLS_DEXANALYZE_DEXANALYZE_BYTECODE_H_
+#include <array>
#include <vector>
#include <map>
@@ -75,9 +76,8 @@
uint64_t output_size_ = 0u;
uint64_t deduped_size_ = 0u;
uint64_t dex_code_bytes_ = 0u;
- uint64_t missing_field_idx_count_ = 0u;
- uint64_t missing_method_idx_count_ = 0u;
uint64_t experiments_ = std::numeric_limits<uint64_t>::max();
+ std::array<size_t, 256> move_result_reg_;
std::map<std::vector<uint8_t>, size_t> instruction_freq_;
// Output instruction buffer.
std::vector<uint8_t> buffer_;
diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h
index 468b74b..312330b 100644
--- a/tools/dexanalyze/dexanalyze_experiments.h
+++ b/tools/dexanalyze/dexanalyze_experiments.h
@@ -32,6 +32,12 @@
namespace dexanalyze {
+enum class VerboseLevel : size_t {
+ kQuiet,
+ kNormal,
+ kEverything,
+};
+
bool IsRange(Instruction::Code code);
uint16_t NumberOfArgs(const Instruction& inst);
@@ -52,7 +58,7 @@
virtual void ProcessDexFile(const DexFile&) {}
virtual void Dump(std::ostream& os, uint64_t total_size) const = 0;
- bool dump_ = false;
+ VerboseLevel verbose_level_ = VerboseLevel::kNormal;
};
// Analyze string data and strings accessed from code.