diff options
| -rw-r--r-- | tools/dexanalyze/Android.bp | 5 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze.cc | 142 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.cc | 133 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.h | 68 |
4 files changed, 206 insertions, 142 deletions
diff --git a/tools/dexanalyze/Android.bp b/tools/dexanalyze/Android.bp index 34aaaac451..2754e6445e 100644 --- a/tools/dexanalyze/Android.bp +++ b/tools/dexanalyze/Android.bp @@ -18,7 +18,10 @@ cc_defaults { name: "dexanalyze-defaults", defaults: ["art_defaults"], host_supported: true, - srcs: ["dexanalyze.cc"], + srcs: [ + "dexanalyze.cc", + "dexanalyze_experiments.cc", + ], target: { android: { shared_libs: ["libcutils"], diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc index 75fa13cc03..a5f647cc56 100644 --- a/tools/dexanalyze/dexanalyze.cc +++ b/tools/dexanalyze/dexanalyze.cc @@ -20,6 +20,7 @@ #include <android-base/file.h> +#include "dexanalyze_experiments.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" @@ -27,147 +28,6 @@ namespace art { -// An experiment a stateful visitor that runs on dex files. Results are cumulative. -class Experiment { - public: - virtual ~Experiment() {} - virtual void ProcessDexFile(const DexFile& dex_file) = 0; - virtual void Dump(std::ostream& os) const = 0; -}; - -class CountDexIndices : public Experiment { - public: - void ProcessDexFile(const DexFile& dex_file) { - num_string_ids_ += dex_file.NumStringIds(); - num_method_ids_ += dex_file.NumMethodIds(); - num_field_ids_ += dex_file.NumFieldIds(); - num_type_ids_ += dex_file.NumTypeIds(); - num_class_defs_ += dex_file.NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - continue; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - std::set<size_t> unique_method_ids; - std::set<size_t> unique_string_ids; - while (it.HasNextMethod()) { - const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); - if (code_item != nullptr) { - CodeItemInstructionAccessor instructions(dex_file, code_item); - const uint16_t* code_ptr = instructions.Insns(); - dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]); - for (const DexInstructionPcPair& inst : instructions) { - switch (inst->Opcode()) { - case Instruction::CONST_STRING: { - const dex::StringIndex string_index(inst->VRegB_21c()); - unique_string_ids.insert(string_index.index_); - ++num_string_ids_from_code_; - break; - } - case Instruction::CONST_STRING_JUMBO: { - const dex::StringIndex string_index(inst->VRegB_31c()); - unique_string_ids.insert(string_index.index_); - ++num_string_ids_from_code_; - break; - } - // Invoke cases. - case Instruction::INVOKE_VIRTUAL: - case Instruction::INVOKE_VIRTUAL_RANGE: { - bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); - uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { - ++same_class_virtual_; - } else { - ++other_class_virtual_; - unique_method_ids.insert(method_idx); - } - break; - } - case Instruction::INVOKE_DIRECT: - case Instruction::INVOKE_DIRECT_RANGE: { - bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE); - uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { - ++same_class_direct_; - } else { - ++other_class_direct_; - unique_method_ids.insert(method_idx); - } - break; - } - case Instruction::INVOKE_STATIC: - case Instruction::INVOKE_STATIC_RANGE: { - bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); - uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { - ++same_class_static_; - } else { - ++other_class_static_; - unique_method_ids.insert(method_idx); - } - break; - } - default: - break; - } - } - } - it.Next(); - } - DCHECK(!it.HasNext()); - total_unique_method_idx_ += unique_method_ids.size(); - total_unique_string_ids_ += unique_string_ids.size(); - } - } - - void Dump(std::ostream& os) const { - os << "Num string ids: " << num_string_ids_ << "\n"; - os << "Num method ids: " << num_method_ids_ << "\n"; - os << "Num field ids: " << num_field_ids_ << "\n"; - os << "Num type ids: " << num_type_ids_ << "\n"; - os << "Num class defs: " << num_class_defs_ << "\n"; - os << "Same class direct: " << same_class_direct_ << "\n"; - os << "Other class direct: " << other_class_direct_ << "\n"; - os << "Same class virtual: " << same_class_virtual_ << "\n"; - os << "Other class virtual: " << other_class_virtual_ << "\n"; - os << "Same class static: " << same_class_static_ << "\n"; - os << "Other class static: " << other_class_static_ << "\n"; - os << "Num strings accessed from code: " << num_string_ids_from_code_ << "\n"; - os << "Unique(per class) method ids accessed from code: " << total_unique_method_idx_ << "\n"; - os << "Unique(per class) string ids accessed from code: " << total_unique_string_ids_ << "\n"; - size_t same_class_total = same_class_direct_ + same_class_virtual_ + same_class_static_; - size_t other_class_total = other_class_direct_ + other_class_virtual_ + other_class_static_; - os << "Same class invoke: " << same_class_total << "\n"; - os << "Other class invoke: " << other_class_total << "\n"; - os << "Invokes from code: " << (same_class_total + other_class_total) << "\n"; - } - - private: - // Total string ids loaded from dex code. - size_t num_string_ids_from_code_ = 0; - size_t total_unique_method_idx_ = 0; - size_t total_unique_string_ids_ = 0; - - // Other dex ids. - size_t dex_code_bytes_ = 0; - size_t num_string_ids_ = 0; - size_t num_method_ids_ = 0; - size_t num_field_ids_ = 0; - size_t num_type_ids_ = 0; - size_t num_class_defs_ = 0; - - // Invokes - size_t same_class_direct_ = 0; - size_t other_class_direct_ = 0; - size_t same_class_virtual_ = 0; - size_t other_class_virtual_ = 0; - size_t same_class_static_ = 0; - size_t other_class_static_ = 0; -}; - class DexAnalyze { static const int kExitCodeUsageError = 1; diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc new file mode 100644 index 0000000000..e1f119df59 --- /dev/null +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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 "dexanalyze_experiments.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_instruction-inl.h" +#include "dex/standard_dex_file.h" + +namespace art { + +void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { + num_string_ids_ += dex_file.NumStringIds(); + num_method_ids_ += dex_file.NumMethodIds(); + num_field_ids_ += dex_file.NumFieldIds(); + num_type_ids_ += dex_file.NumTypeIds(); + num_class_defs_ += dex_file.NumClassDefs(); + for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); ++class_def_index) { + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); + const uint8_t* class_data = dex_file.GetClassData(class_def); + if (class_data == nullptr) { + continue; + } + ClassDataItemIterator it(dex_file, class_data); + it.SkipAllFields(); + std::set<size_t> unique_method_ids; + std::set<size_t> unique_string_ids; + while (it.HasNextMethod()) { + const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); + if (code_item != nullptr) { + CodeItemInstructionAccessor instructions(dex_file, code_item); + const uint16_t* code_ptr = instructions.Insns(); + dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]); + for (const DexInstructionPcPair& inst : instructions) { + switch (inst->Opcode()) { + case Instruction::CONST_STRING: { + const dex::StringIndex string_index(inst->VRegB_21c()); + unique_string_ids.insert(string_index.index_); + ++num_string_ids_from_code_; + break; + } + case Instruction::CONST_STRING_JUMBO: { + const dex::StringIndex string_index(inst->VRegB_31c()); + unique_string_ids.insert(string_index.index_); + ++num_string_ids_from_code_; + break; + } + // Invoke cases. + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_VIRTUAL_RANGE: { + bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); + uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); + if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + ++same_class_virtual_; + } else { + ++other_class_virtual_; + unique_method_ids.insert(method_idx); + } + break; + } + case Instruction::INVOKE_DIRECT: + case Instruction::INVOKE_DIRECT_RANGE: { + bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE); + uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + ++same_class_direct_; + } else { + ++other_class_direct_; + unique_method_ids.insert(method_idx); + } + break; + } + case Instruction::INVOKE_STATIC: + case Instruction::INVOKE_STATIC_RANGE: { + bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); + uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + ++same_class_static_; + } else { + ++other_class_static_; + unique_method_ids.insert(method_idx); + } + break; + } + default: + break; + } + } + } + it.Next(); + } + DCHECK(!it.HasNext()); + total_unique_method_idx_ += unique_method_ids.size(); + total_unique_string_ids_ += unique_string_ids.size(); + } +} + +void CountDexIndices::Dump(std::ostream& os) const { + os << "Num string ids: " << num_string_ids_ << "\n"; + os << "Num method ids: " << num_method_ids_ << "\n"; + os << "Num field ids: " << num_field_ids_ << "\n"; + os << "Num type ids: " << num_type_ids_ << "\n"; + os << "Num class defs: " << num_class_defs_ << "\n"; + os << "Same class direct: " << same_class_direct_ << "\n"; + os << "Other class direct: " << other_class_direct_ << "\n"; + os << "Same class virtual: " << same_class_virtual_ << "\n"; + os << "Other class virtual: " << other_class_virtual_ << "\n"; + os << "Same class static: " << same_class_static_ << "\n"; + os << "Other class static: " << other_class_static_ << "\n"; + os << "Num strings accessed from code: " << num_string_ids_from_code_ << "\n"; + os << "Unique(per class) method ids accessed from code: " << total_unique_method_idx_ << "\n"; + os << "Unique(per class) string ids accessed from code: " << total_unique_string_ids_ << "\n"; + size_t same_class_total = same_class_direct_ + same_class_virtual_ + same_class_static_; + size_t other_class_total = other_class_direct_ + other_class_virtual_ + other_class_static_; + os << "Same class invoke: " << same_class_total << "\n"; + os << "Other class invoke: " << other_class_total << "\n"; + os << "Invokes from code: " << (same_class_total + other_class_total) << "\n"; +} + +} // namespace art + diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h new file mode 100644 index 0000000000..5d0f51b821 --- /dev/null +++ b/tools/dexanalyze/dexanalyze_experiments.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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. + */ + +#ifndef ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ +#define ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ + +#include <iosfwd> +#include <set> + +namespace art { + +class DexFile; + +// An experiment a stateful visitor that runs on dex files. Results are cumulative. +class Experiment { + public: + virtual ~Experiment() {} + virtual void ProcessDexFile(const DexFile& dex_file) = 0; + virtual void Dump(std::ostream& os) const = 0; +}; + +// Count numbers of dex indices. +class CountDexIndices : public Experiment { + public: + void ProcessDexFile(const DexFile& dex_file); + + void Dump(std::ostream& os) const; + + private: + // Total string ids loaded from dex code. + size_t num_string_ids_from_code_ = 0; + size_t total_unique_method_idx_ = 0; + size_t total_unique_string_ids_ = 0; + + // Other dex ids. + size_t dex_code_bytes_ = 0; + size_t num_string_ids_ = 0; + size_t num_method_ids_ = 0; + size_t num_field_ids_ = 0; + size_t num_type_ids_ = 0; + size_t num_class_defs_ = 0; + + // Invokes + size_t same_class_direct_ = 0; + size_t other_class_direct_ = 0; + size_t same_class_virtual_ = 0; + size_t other_class_virtual_ = 0; + size_t same_class_static_ = 0; + size_t other_class_static_ = 0; +}; + +} // namespace art + +#endif // ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ + |