1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ 18 #define ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ 19 20 #include <cstdint> 21 #include <iosfwd> 22 #include <memory> 23 #include <set> 24 #include <unordered_map> 25 #include <vector> 26 27 #include "base/macros.h" 28 #include "dex/dex_instruction.h" 29 30 namespace art { 31 32 class DexFile; 33 34 namespace dexanalyze { 35 36 enum class VerboseLevel : size_t { 37 kQuiet, 38 kNormal, 39 kEverything, 40 }; 41 42 bool IsRange(Instruction::Code code); 43 44 uint16_t NumberOfArgs(const Instruction& inst); 45 46 uint16_t DexMethodIndex(const Instruction& inst); 47 48 std::string PercentDivide(uint64_t value, uint64_t max); 49 50 size_t PrefixLen(const std::string& a, const std::string& b); 51 52 std::string Percent(uint64_t value, uint64_t max); 53 54 // An experiment a stateful visitor that runs on dex files. Results are cumulative. 55 class Experiment { 56 public: ~Experiment()57 virtual ~Experiment() {} 58 virtual void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files); ProcessDexFile(const DexFile &)59 virtual void ProcessDexFile(const DexFile&) {} 60 virtual void Dump(std::ostream& os, uint64_t total_size) const = 0; 61 62 VerboseLevel verbose_level_ = VerboseLevel::kNormal; 63 }; 64 65 // Analyze debug info sizes. 66 class AnalyzeDebugInfo : public Experiment { 67 public: 68 void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) override; 69 void Dump(std::ostream& os, uint64_t total_size) const override; 70 71 private: 72 int64_t total_bytes_ = 0u; 73 int64_t total_entropy_ = 0u; 74 int64_t total_opcode_bytes_ = 0u; 75 int64_t total_opcode_entropy_ = 0u; 76 int64_t total_non_header_bytes_ = 0u; 77 int64_t total_unique_non_header_bytes_ = 0u; 78 // Opcode and related data. 79 int64_t total_end_seq_bytes_ = 0u; 80 int64_t total_advance_pc_bytes_ = 0u; 81 int64_t total_advance_line_bytes_ = 0u; 82 int64_t total_start_local_bytes_ = 0u; 83 int64_t total_start_local_extended_bytes_ = 0u; 84 int64_t total_end_local_bytes_ = 0u; 85 int64_t total_restart_local_bytes_ = 0u; 86 int64_t total_epilogue_bytes_ = 0u; 87 int64_t total_set_file_bytes_ = 0u; 88 int64_t total_other_bytes_ = 0u; 89 }; 90 91 // Count numbers of dex indices. 92 class CountDexIndices : public Experiment { 93 public: 94 void ProcessDexFile(const DexFile& dex_file) override; 95 void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) override; 96 97 void Dump(std::ostream& os, uint64_t total_size) const override; 98 99 private: 100 // Total string ids loaded from dex code. 101 size_t num_string_ids_from_code_ = 0; 102 size_t total_unique_method_ids_ = 0; 103 size_t total_unique_string_ids_ = 0; 104 uint64_t total_unique_code_items_ = 0u; 105 106 struct FieldAccessStats { 107 static constexpr size_t kMaxFieldIndex = 32; 108 uint64_t field_index_[kMaxFieldIndex] = {}; 109 uint64_t field_index_other_ = 0u; 110 uint64_t field_index_other_class_ = 0u; // Includes superclass fields referenced with 111 // type index pointing to this class. 112 113 static constexpr size_t kShortBytecodeFieldIndexOutCutOff = 16u; 114 static constexpr size_t kShortBytecodeInOutCutOff = 16u; 115 uint64_t short_bytecode_ = 0u; 116 117 uint64_t inout_[16] = {}; // Input for IPUT/SPUT, output for IGET/SGET. 118 }; 119 struct InstanceFieldAccessStats : FieldAccessStats { 120 uint64_t receiver_[16] = {}; 121 }; 122 struct StaticFieldAccessStats : FieldAccessStats { 123 uint64_t inout_other_ = 0u; // Input for SPUT, output for SGET. 124 }; 125 InstanceFieldAccessStats iget_stats_; 126 InstanceFieldAccessStats iput_stats_; 127 StaticFieldAccessStats sget_stats_; 128 StaticFieldAccessStats sput_stats_; 129 130 // Unique names. 131 uint64_t total_unique_method_names_ = 0u; 132 uint64_t total_unique_field_names_ = 0u; 133 uint64_t total_unique_type_names_ = 0u; 134 uint64_t total_unique_mf_names_ = 0u; 135 136 // Other dex ids. 137 size_t dex_code_bytes_ = 0; 138 size_t num_string_ids_ = 0; 139 size_t num_method_ids_ = 0; 140 size_t num_field_ids_ = 0; 141 size_t num_type_ids_ = 0; 142 size_t num_class_defs_ = 0; 143 144 // Invokes 145 size_t same_class_direct_ = 0; 146 size_t total_direct_ = 0; 147 size_t same_class_virtual_ = 0; 148 size_t total_virtual_ = 0; 149 size_t same_class_static_ = 0; 150 size_t total_static_ = 0; 151 size_t same_class_interface_ = 0; 152 size_t total_interface_ = 0; 153 size_t same_class_super_ = 0; 154 size_t total_super_ = 0; 155 156 // Type usage. 157 uint64_t uses_top_types_ = 0u; 158 uint64_t uses_all_types_ = 0u; 159 uint64_t total_unique_types_ = 0u; 160 }; 161 162 // Measure various code metrics including args per invoke-virtual, fill/spill move patterns. 163 class CodeMetrics : public Experiment { 164 public: 165 void ProcessDexFile(const DexFile& dex_file) override; 166 167 void Dump(std::ostream& os, uint64_t total_size) const override; 168 169 private: 170 static constexpr size_t kMaxArgCount = 6; 171 uint64_t arg_counts_[kMaxArgCount] = {}; 172 uint64_t move_result_savings_ = 0u; 173 }; 174 175 } // namespace dexanalyze 176 } // namespace art 177 178 #endif // ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ 179