Slightly refactor stack map stats printing.
Take advantage of the "operator" overload and move
the pretty print method so it can be better reused.
Test: m dump-oat
Change-Id: I46b169e044f2c4481bb2bc277601d61f873c9950
diff --git a/libartbase/base/stats-inl.h b/libartbase/base/stats-inl.h
new file mode 100644
index 0000000..5fa1372
--- /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 4dcbfe8..c568035 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 @@
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 6c7f610..7e6a85e 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 5086f92..276a67c 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 @@
}
// 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 e8e57aa..ce577c0 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -424,7 +424,7 @@
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;