Refactor experiments to allow multidex analysis
Analyze multidex deduplication for debug infos when excluding the
header fields.
Bug: 77721545
Test: test-art-host
Change-Id: I247399aaecaf072cce1b3e035256db0f5e91e8c3
diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc
index 7d7e5f2..7a9b8fb 100644
--- a/tools/dexanalyze/dexanalyze.cc
+++ b/tools/dexanalyze/dexanalyze.cc
@@ -116,12 +116,14 @@
}
}
- bool ProcessDexFile(const DexFile& dex_file) {
+ bool ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
for (std::unique_ptr<Experiment>& experiment : experiments_) {
- experiment->ProcessDexFile(dex_file);
+ experiment->ProcessDexFiles(dex_files);
}
- total_size_ += dex_file.Size();
- ++dex_count_;
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ total_size_ += dex_file->Size();
+ }
+ dex_count_ += dex_files.size();
return true;
}
@@ -169,18 +171,16 @@
LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl;
return kExitCodeFailedToOpenDex;
}
- for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
- if (options.dump_per_input_dex_) {
- Analysis current(&options);
- if (!current.ProcessDexFile(*dex_file)) {
- LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
- return kExitCodeFailedToProcessDex;
- }
- LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl;
- current.Dump(LOG_STREAM(INFO));
+ if (options.dump_per_input_dex_) {
+ Analysis current(&options);
+ if (!current.ProcessDexFiles(dex_files)) {
+ LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
+ return kExitCodeFailedToProcessDex;
}
- cumulative.ProcessDexFile(*dex_file);
+ LOG(INFO) << "Analysis for " << filename << std::endl;
+ current.Dump(LOG_STREAM(INFO));
}
+ cumulative.ProcessDexFiles(dex_files);
}
LOG(INFO) << "Cumulative analysis for " << cumulative.dex_count_ << " DEX files" << std::endl;
cumulative.Dump(LOG_STREAM(INFO));
diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc
index 1a3b89c..244f45b 100644
--- a/tools/dexanalyze/dexanalyze_experiments.cc
+++ b/tools/dexanalyze/dexanalyze_experiments.cc
@@ -75,86 +75,95 @@
return len;
}
-void AnalyzeDebugInfo::ProcessDexFile(const DexFile& dex_file) {
+void Experiment::ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ProcessDexFile(*dex_file);
+ }
+}
+
+void AnalyzeDebugInfo::ProcessDexFiles(
+ const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
std::set<const uint8_t*> seen;
std::vector<size_t> counts(256, 0u);
std::vector<size_t> opcode_counts(256, 0u);
std::set<std::vector<uint8_t>> unique_non_header;
- for (ClassAccessor accessor : dex_file.GetClasses()) {
- for (const ClassAccessor::Method& method : accessor.GetMethods()) {
- CodeItemDebugInfoAccessor code_item(dex_file, method.GetCodeItem(), method.GetIndex());
- const uint8_t* debug_info = dex_file.GetDebugInfoStream(code_item.DebugInfoOffset());
- if (debug_info != nullptr && seen.insert(debug_info).second) {
- const uint8_t* stream = debug_info;
- DecodeUnsignedLeb128(&stream); // line_start
- uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
- for (uint32_t i = 0; i < parameters_size; ++i) {
- DecodeUnsignedLeb128P1(&stream); // Parameter name.
- }
- bool done = false;
- const uint8_t* after_header_start = stream;
- while (!done) {
- const uint8_t* const op_start = stream;
- uint8_t opcode = *stream++;
- ++opcode_counts[opcode];
- ++total_opcode_bytes_;
- switch (opcode) {
- case DexFile::DBG_END_SEQUENCE:
- ++total_end_seq_bytes_;
- done = true;
- break;
- case DexFile::DBG_ADVANCE_PC:
- DecodeUnsignedLeb128(&stream); // addr_diff
- total_advance_pc_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_ADVANCE_LINE:
- DecodeSignedLeb128(&stream); // line_diff
- total_advance_line_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_START_LOCAL:
- DecodeUnsignedLeb128(&stream); // register_num
- DecodeUnsignedLeb128P1(&stream); // name_idx
- DecodeUnsignedLeb128P1(&stream); // type_idx
- total_start_local_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_START_LOCAL_EXTENDED:
- DecodeUnsignedLeb128(&stream); // register_num
- DecodeUnsignedLeb128P1(&stream); // name_idx
- DecodeUnsignedLeb128P1(&stream); // type_idx
- DecodeUnsignedLeb128P1(&stream); // sig_idx
- total_start_local_extended_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_END_LOCAL:
- DecodeUnsignedLeb128(&stream); // register_num
- total_end_local_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_RESTART_LOCAL:
- DecodeUnsignedLeb128(&stream); // register_num
- total_restart_local_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_SET_PROLOGUE_END:
- case DexFile::DBG_SET_EPILOGUE_BEGIN:
- total_epilogue_bytes_ += stream - op_start;
- break;
- case DexFile::DBG_SET_FILE: {
- DecodeUnsignedLeb128P1(&stream); // name_idx
- total_set_file_bytes_ += stream - op_start;
- break;
- }
- default: {
- total_other_bytes_ += stream - op_start;
- break;
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ for (ClassAccessor accessor : dex_file->GetClasses()) {
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ CodeItemDebugInfoAccessor code_item(*dex_file, method.GetCodeItem(), method.GetIndex());
+ const uint8_t* debug_info = dex_file->GetDebugInfoStream(code_item.DebugInfoOffset());
+ if (debug_info != nullptr && seen.insert(debug_info).second) {
+ const uint8_t* stream = debug_info;
+ DecodeUnsignedLeb128(&stream); // line_start
+ uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+ for (uint32_t i = 0; i < parameters_size; ++i) {
+ DecodeUnsignedLeb128P1(&stream); // Parameter name.
+ }
+ bool done = false;
+ const uint8_t* after_header_start = stream;
+ while (!done) {
+ const uint8_t* const op_start = stream;
+ uint8_t opcode = *stream++;
+ ++opcode_counts[opcode];
+ ++total_opcode_bytes_;
+ switch (opcode) {
+ case DexFile::DBG_END_SEQUENCE:
+ ++total_end_seq_bytes_;
+ done = true;
+ break;
+ case DexFile::DBG_ADVANCE_PC:
+ DecodeUnsignedLeb128(&stream); // addr_diff
+ total_advance_pc_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_ADVANCE_LINE:
+ DecodeSignedLeb128(&stream); // line_diff
+ total_advance_line_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_START_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ DecodeUnsignedLeb128P1(&stream); // type_idx
+ total_start_local_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_START_LOCAL_EXTENDED:
+ DecodeUnsignedLeb128(&stream); // register_num
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ DecodeUnsignedLeb128P1(&stream); // type_idx
+ DecodeUnsignedLeb128P1(&stream); // sig_idx
+ total_start_local_extended_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_END_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ total_end_local_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_RESTART_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ total_restart_local_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_SET_PROLOGUE_END:
+ case DexFile::DBG_SET_EPILOGUE_BEGIN:
+ total_epilogue_bytes_ += stream - op_start;
+ break;
+ case DexFile::DBG_SET_FILE: {
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ total_set_file_bytes_ += stream - op_start;
+ break;
+ }
+ default: {
+ total_other_bytes_ += stream - op_start;
+ break;
+ }
}
}
- }
- const size_t bytes = stream - debug_info;
- total_bytes_ += bytes;
- total_non_header_bytes_ += stream - after_header_start;
- if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) {
- total_unique_non_header_bytes_ += stream - after_header_start;
- }
- for (size_t i = 0; i < bytes; ++i) {
- ++counts[debug_info[i]];
+ const size_t bytes = stream - debug_info;
+ total_bytes_ += bytes;
+ total_non_header_bytes_ += stream - after_header_start;
+ if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) {
+ total_unique_non_header_bytes_ += stream - after_header_start;
+ }
+ for (size_t i = 0; i < bytes; ++i) {
+ ++counts[debug_info[i]];
+ }
}
}
}
diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h
index a2621c8..2be53d6 100644
--- a/tools/dexanalyze/dexanalyze_experiments.h
+++ b/tools/dexanalyze/dexanalyze_experiments.h
@@ -18,7 +18,9 @@
#define ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_
#include <iosfwd>
+#include <memory>
#include <set>
+#include <vector>
namespace art {
@@ -30,7 +32,8 @@
class Experiment {
public:
virtual ~Experiment() {}
- virtual void ProcessDexFile(const DexFile& dex_file) = 0;
+ virtual void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
+ virtual void ProcessDexFile(const DexFile&) {}
virtual void Dump(std::ostream& os, uint64_t total_size) const = 0;
};
@@ -54,7 +57,7 @@
// Analyze debug info sizes.
class AnalyzeDebugInfo : public Experiment {
public:
- void ProcessDexFile(const DexFile& dex_file);
+ void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
void Dump(std::ostream& os, uint64_t total_size) const;
private:
@@ -112,7 +115,7 @@
size_t total_super_ = 0;
};
-// Measure various code metrics including args per invoke-virtual, fill/spill move paterns.
+// Measure various code metrics including args per invoke-virtual, fill/spill move patterns.
class CodeMetrics : public Experiment {
public:
void ProcessDexFile(const DexFile& dex_file);