[metrics] Dump ArtMetrics on SIGQUIT
ART now writes a current snapshot of its internal metrics in response to
a SIGQUIT.
Example output:
```
*** ART internal metrics ***
ClassVerificationTotalTime: count = 863833
JitMethodCompileTime: range = 0...1000000, buckets: 244,5,1,0,1,0,0,0,0,1,0,0,0,0,0
*** Done dumping ART internal metrics ***
```
This includes a new StreamBackend, which is used to write ART metrics to
an output stream in a human readable format.
Bug: 170149255
Test: m test-art-host-gtest-art_libartbase_tests
Change-Id: Iaf8bcee5a4993e70ac4e36940591a734fe1a6697
diff --git a/libartbase/base/metrics.cc b/libartbase/base/metrics.cc
index e146856..6c79b47 100644
--- a/libartbase/base/metrics.cc
+++ b/libartbase/base/metrics.cc
@@ -69,6 +69,48 @@
#undef ART_HISTOGRAM
}
+void ArtMetrics::DumpForSigQuit(std::ostream& os) const {
+ os << "\n*** ART internal metrics ***\n\n";
+ StreamBackend backend{os};
+ ReportAllMetrics(&backend);
+ os << "\n*** Done dumping ART internal metrics ***\n";
+}
+
+StreamBackend::StreamBackend(std::ostream& os) : os_{os} {}
+
+void StreamBackend::BeginSession([[maybe_unused]] const SessionData& session_data) {
+ // Not needed for now.
+}
+
+void StreamBackend::EndSession() {
+ // Not needed for now.
+}
+
+void StreamBackend::ReportCounter(DatumId counter_type, uint64_t value) {
+ os_ << DatumName(counter_type) << ": count = " << value << "\n";
+}
+
+void StreamBackend::ReportHistogram(DatumId histogram_type,
+ int64_t minimum_value_,
+ int64_t maximum_value_,
+ const std::vector<uint32_t>& buckets) {
+ os_ << DatumName(histogram_type) << ": range = " << minimum_value_ << "..." << maximum_value_;
+ if (buckets.size() > 0) {
+ os_ << ", buckets: ";
+ bool first = true;
+ for (const auto& count : buckets) {
+ if (!first) {
+ os_ << ",";
+ }
+ first = false;
+ os_ << count;
+ }
+ os_ << "\n";
+ } else {
+ os_ << ", no buckets\n";
+ }
+}
+
} // namespace metrics
} // namespace art
diff --git a/libartbase/base/metrics.h b/libartbase/base/metrics.h
index d5a4873..0c0227a 100644
--- a/libartbase/base/metrics.h
+++ b/libartbase/base/metrics.h
@@ -202,6 +202,25 @@
static_assert(std::atomic<value_t>::is_always_lock_free);
};
+// A backend that writes metrics in a human-readable format to an std::ostream.
+class StreamBackend : public MetricsBackend {
+ public:
+ explicit StreamBackend(std::ostream& os);
+
+ void BeginSession(const SessionData& session_data) override;
+ void EndSession() override;
+
+ void ReportCounter(DatumId counter_type, uint64_t value) override;
+
+ void ReportHistogram(DatumId histogram_type,
+ int64_t low_value,
+ int64_t high_value,
+ const std::vector<uint32_t>& buckets) override;
+
+ private:
+ std::ostream& os_;
+};
+
/**
* AutoTimer simplifies time-based metrics collection.
*
@@ -279,6 +298,7 @@
ArtMetrics();
void ReportAllMetrics(MetricsBackend* backend) const;
+ void DumpForSigQuit(std::ostream& os) const;
#define ART_COUNTER(name) \
MetricsCounter<DatumId::k##name>* name() { return &name##_; } \
diff --git a/libartbase/base/metrics_test.cc b/libartbase/base/metrics_test.cc
index 20ac92c..f568ea0 100644
--- a/libartbase/base/metrics_test.cc
+++ b/libartbase/base/metrics_test.cc
@@ -205,6 +205,27 @@
EXPECT_GT(GetBuckets(test_histogram)[0], 0u);
}
+// Makes sure all defined metrics are included when dumping through StreamBackend.
+TEST_F(MetricsTest, StreamBackendDumpAllMetrics) {
+ ArtMetrics metrics;
+ std::stringstream os;
+ StreamBackend backend(os);
+
+ metrics.ReportAllMetrics(&backend);
+
+ // Make sure the resulting string lists all the counters.
+#define COUNTER(name) \
+ EXPECT_NE(os.str().find(DatumName(DatumId::k##name)), std::string::npos)
+ ART_COUNTERS(COUNTER);
+#undef COUNTER
+
+ // Make sure the resulting string lists all the histograms.
+#define HISTOGRAM(name, num_buckets, minimum_value, maximum_value) \
+ EXPECT_NE(os.str().find(DatumName(DatumId::k##name)), std::string::npos)
+ ART_HISTOGRAMS(HISTOGRAM);
+#undef HISTOGRAM
+}
+
} // namespace metrics
} // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 70e3ae3..9c0b4df 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2020,6 +2020,7 @@
}
DumpDeoptimizations(os);
TrackedAllocators::Dump(os);
+ GetMetrics()->DumpForSigQuit(os);
os << "\n";
thread_list_->DumpForSigQuit(os);