diff options
-rw-r--r-- | libartbase/base/stats-inl.h | 64 | ||||
-rw-r--r-- | libartbase/base/stats.h | 13 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 43 | ||||
-rw-r--r-- | runtime/stack_map.cc | 18 | ||||
-rw-r--r-- | runtime/stack_map.h | 2 |
5 files changed, 91 insertions, 49 deletions
diff --git a/libartbase/base/stats-inl.h b/libartbase/base/stats-inl.h new file mode 100644 index 0000000000..5fa1372432 --- /dev/null +++ b/libartbase/base/stats-inl.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 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_LIBARTBASE_BASE_STATS_INL_H_ +#define ART_LIBARTBASE_BASE_STATS_INL_H_ + +#include <iomanip> +#include <map> + +#include "base/stats.h" +#include "base/indenter.h" + +namespace art { + void Stats::DumpSizes(VariableIndentationOutputStream& os, std::string_view name) const { + Dump(os, name, Value(), 1000.0, "KB"); + } + + void Stats::Dump(VariableIndentationOutputStream& os, + std::string_view name, + double total, + double unit_size, + const char* unit) const { + double percent = total > 0 ? 100.0 * Value() / total : 0; + os.Stream() + << std::setw(40 - os.GetIndentation()) << std::left << name << std::right << " " + << std::setw(8) << Count() << " " + << std::setw(12) << std::fixed << std::setprecision(3) << Value() / unit_size << unit + << std::setw(8) << std::fixed << std::setprecision(1) << percent << "%\n"; + + // Sort all children by largest value first, than by name. + std::map<std::pair<double, std::string_view>, const Stats&> sorted_children; + for (const auto& it : Children()) { + sorted_children.emplace(std::make_pair(-it.second.Value(), it.first), it.second); + } + + // Add "other" row to represent any amount not account for by the children. + Stats other; + other.AddBytes(Value() - SumChildrenValues(), Count()); + if (other.Value() != 0.0 && !Children().empty()) { + sorted_children.emplace(std::make_pair(-other.Value(), "(other)"), other); + } + + // Print the data. + ScopedIndentation indent1(&os); + for (const auto& it : sorted_children) { + it.second.Dump(os, it.first.second, total, unit_size, unit); + } + } +} // namespace art + +#endif // ART_LIBARTBASE_BASE_STATS_INL_H_ diff --git a/libartbase/base/stats.h b/libartbase/base/stats.h index 4dcbfe81c6..c5680358a1 100644 --- a/libartbase/base/stats.h +++ b/libartbase/base/stats.h @@ -18,17 +18,20 @@ #define ART_LIBARTBASE_BASE_STATS_H_ #include <unordered_map> +#include <string> #include "globals.h" namespace art { +class VariableIndentationOutputStream; + // Simple structure to record tree of statistical values. class Stats { public: double Value() const { return value_; } size_t Count() const { return count_; } - Stats* Child(const char* name) { return &children_[name]; } + Stats& operator[](const char* name) { return children_[name]; } const std::unordered_map<const char*, Stats>& Children() const { return children_; } void AddBytes(double bytes, size_t count = 1) { Add(bytes, count); } @@ -44,12 +47,20 @@ class Stats { return sum; } + inline void DumpSizes(VariableIndentationOutputStream& os, std::string_view name) const; + private: void Add(double value, size_t count = 1) { value_ += value; count_ += count; } + inline void Dump(VariableIndentationOutputStream& os, + std::string_view name, + double total, + double unit_size, + const char* unit) const; + double value_ = 0.0; // Commutative sum of the collected statistic in basic units. size_t count_ = 0; // The number of samples for this node. std::unordered_map<const char*, Stats> children_; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 6c7f6102d8..7e6a85ec1b 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -39,7 +39,7 @@ #include "base/indenter.h" #include "base/os.h" #include "base/safe_map.h" -#include "base/stats.h" +#include "base/stats-inl.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" @@ -696,7 +696,7 @@ class OatDumper { os << "OAT FILE STATS:\n"; VariableIndentationOutputStream vios(&os); stats_.AddBytes(oat_file_.Size()); - DumpStats(vios, "OatFile", stats_, stats_.Value()); + stats_.DumpSizes(vios, "OatFile"); } os << std::flush; @@ -817,39 +817,6 @@ class OatDumper { return seen_stats_objects_.insert(address).second; // Inserted new entry. } - void DumpStats(VariableIndentationOutputStream& os, - const std::string& name, - const Stats& stats, - double total) { - if (std::fabs(stats.Value()) > 0 || !stats.Children().empty()) { - double percent = 100.0 * stats.Value() / total; - os.Stream() - << std::setw(40 - os.GetIndentation()) << std::left << name << std::right << " " - << std::setw(8) << stats.Count() << " " - << std::setw(12) << std::fixed << std::setprecision(3) << stats.Value() / KB << "KB " - << std::setw(8) << std::fixed << std::setprecision(1) << percent << "%\n"; - - // Sort all children by largest value first, than by name. - std::map<std::pair<double, std::string>, const Stats&> sorted_children; - for (const auto& it : stats.Children()) { - sorted_children.emplace(std::make_pair(-it.second.Value(), it.first), it.second); - } - - // Add "other" row to represent any amount not account for by the children. - Stats other; - other.AddBytes(stats.Value() - stats.SumChildrenValues(), stats.Count()); - if (std::fabs(other.Value()) > 0 && !stats.Children().empty()) { - sorted_children.emplace(std::make_pair(-other.Value(), "(other)"), other); - } - - // Print the data. - ScopedIndentation indent1(&os); - for (const auto& it : sorted_children) { - DumpStats(os, it.first.second, it.second, total); - } - } - } - private: void AddAllOffsets() { // We don't know the length of the code for each method, but we need to know where to stop @@ -1215,7 +1182,7 @@ class OatDumper { uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset(); const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader(); if (AddStatsObject(method_header)) { - stats_.Child("QuickMethodHeader")->AddBytes(sizeof(*method_header)); + stats_["QuickMethodHeader"].AddBytes(sizeof(*method_header)); } if (options_.absolute_addresses_) { vios->Stream() << StringPrintf("%p ", method_header); @@ -1289,7 +1256,7 @@ class OatDumper { uint32_t aligned_code_begin = AlignCodeOffset(code_offset); uint64_t aligned_code_end = aligned_code_begin + code_size; if (AddStatsObject(code)) { - stats_.Child("Code")->AddBytes(code_size); + stats_["Code"].AddBytes(code_size); } if (options_.absolute_addresses_) { @@ -1639,7 +1606,7 @@ class OatDumper { // The optimizing compiler outputs its CodeInfo data in the vmap table. StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_); if (AddStatsObject(oat_method.GetVmapTable())) { - helper.GetCodeInfo().CollectSizeStats(oat_method.GetVmapTable(), &stats_); + helper.GetCodeInfo().CollectSizeStats(oat_method.GetVmapTable(), stats_["CodeInfo"]); } const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code); size_t offset = 0; diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 5086f922b0..276a67c109 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -21,7 +21,7 @@ #include "art_method.h" #include "base/indenter.h" -#include "base/stats.h" +#include "base/stats-inl.h" #include "oat_quick_method_header.h" #include "scoped_thread_state_change-inl.h" @@ -227,26 +227,26 @@ void CodeInfo::DecodeDexRegisterMap(uint32_t stack_map_index, } // Decode the CodeInfo while collecting size statistics. -void CodeInfo::CollectSizeStats(const uint8_t* code_info_data, /*out*/ Stats* parent) { - Stats* codeinfo_stats = parent->Child("CodeInfo"); +void CodeInfo::CollectSizeStats(const uint8_t* code_info_data, /*out*/ Stats& stats) { BitMemoryReader reader(code_info_data); reader.ReadInterleavedVarints<kNumHeaders>(); - codeinfo_stats->Child("Header")->AddBits(reader.NumberOfReadBits()); + stats["Header"].AddBits(reader.NumberOfReadBits()); size_t num_bits; CodeInfo code_info(code_info_data, &num_bits, [&](size_t i, auto* table, BitMemoryRegion region) { if (!code_info.IsBitTableDeduped(i)) { - Stats* table_stats = codeinfo_stats->Child(table->GetName()); - table_stats->AddBits(region.size_in_bits()); + Stats& table_stats = stats[table->GetName()]; + table_stats.AddBits(region.size_in_bits()); + table_stats["Header"].AddBits(region.size_in_bits() - table->DataBitSize()); const char* const* column_names = table->GetColumnNames(); for (size_t c = 0; c < table->NumColumns(); c++) { if (table->NumColumnBits(c) > 0) { - Stats* column_stats = table_stats->Child(column_names[c]); - column_stats->AddBits(table->NumRows() * table->NumColumnBits(c), table->NumRows()); + Stats& column_stats = table_stats[column_names[c]]; + column_stats.AddBits(table->NumRows() * table->NumColumnBits(c), table->NumRows()); } } } }); - codeinfo_stats->AddBytes(BitsToBytesRoundUp(num_bits)); + stats.AddBytes(BitsToBytesRoundUp(num_bits)); } void DexRegisterMap::Dump(VariableIndentationOutputStream* vios) const { diff --git a/runtime/stack_map.h b/runtime/stack_map.h index e8e57aa2e5..ce577c0661 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -424,7 +424,7 @@ class CodeInfo { InstructionSet instruction_set) const; // Accumulate code info size statistics into the given Stats tree. - static void CollectSizeStats(const uint8_t* code_info, /*out*/ Stats* parent); + static void CollectSizeStats(const uint8_t* code_info, /*out*/ Stats& parent); ALWAYS_INLINE static bool HasInlineInfo(const uint8_t* code_info_data) { return (*code_info_data & kHasInlineInfo) != 0; |