summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Stefano Cianciulli <scianciulli@google.com> 2022-10-07 14:27:34 +0000
committer Stefano Cianciulli <scianciulli@google.com> 2023-01-09 15:23:11 +0000
commitf6f5ada7b8231d19898726b37fa7db674a006065 (patch)
tree52a05d1c4f2885a5e7b397265b408068b0900c00
parente175b35f009451b3c0a218d6057aa4829206da55 (diff)
Report value metrics as increments / deltas
This CL changes value metrics to be represented as increment / deltas rather than absolute values, which will be aggregated on device by summing them instead of taking the maximum value produced. This should make the value metrics representative of all processes across restarts, rather than reporting only the process producing the maximum value (for which numerator and denominator could have been produced by different processes). Bug: 246330418 Test: atest ArtGtestsTargetChroot (in particular art_standalone_libartbase_tests) Merged-In: I9b6e67143fbbf4e93748746491ac23b02543cd28 Merged-In: I660d3b4b3bd4a3cbcfb3a69263956b96cb248f3e Change-Id: Ibc69f68b52b792f8844cab36c6a340efdfbfa380
-rw-r--r--compiler/jit/jit_compiler.cc2
-rw-r--r--libartbase/base/metrics/metrics.h150
-rw-r--r--libartbase/base/metrics/metrics_common.cc34
-rw-r--r--libartbase/base/metrics/metrics_test.cc94
-rw-r--r--libartbase/base/metrics/metrics_test.h4
-rw-r--r--libartbase/base/utils.h13
-rw-r--r--runtime/class_linker.cc1
-rw-r--r--runtime/gc/collector/concurrent_copying.cc8
-rw-r--r--runtime/gc/collector/garbage_collector.cc11
-rw-r--r--runtime/gc/collector/garbage_collector.h4
-rw-r--r--runtime/gc/heap-inl.h1
-rw-r--r--runtime/metrics/reporter.cc10
-rw-r--r--runtime/metrics/reporter.h2
-rw-r--r--runtime/metrics/reporter_test.cc9
-rw-r--r--runtime/metrics/statsd.cc105
-rw-r--r--runtime/verifier/class_verifier.cc3
-rw-r--r--test/2232-write-metrics-to-log/expected-stderr.txt2
-rw-r--r--test/2232-write-metrics-to-log/run.py2
18 files changed, 360 insertions, 95 deletions
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index d2f5aa6799..e67236769e 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -203,6 +203,8 @@ bool JitCompiler::CompileMethod(
VLOG(jit) << "Compilation of " << method->PrettyMethod() << " took "
<< PrettyDuration(UsToNs(duration_us));
runtime->GetMetrics()->JitMethodCompileCount()->AddOne();
+ runtime->GetMetrics()->JitMethodCompileTotalTimeDelta()->Add(duration_us);
+ runtime->GetMetrics()->JitMethodCompileCountDelta()->AddOne();
}
// Trim maps to reduce memory usage.
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index 6d856da410..8432be50a4 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -36,36 +36,62 @@
#pragma clang diagnostic error "-Wconversion"
// See README.md in this directory for how to define metrics.
-#define ART_METRICS(METRIC) \
- METRIC(ClassLoadingTotalTime, MetricsCounter) \
- METRIC(ClassVerificationTotalTime, MetricsCounter) \
- METRIC(ClassVerificationCount, MetricsCounter) \
- METRIC(WorldStopTimeDuringGCAvg, MetricsAverage) \
- METRIC(YoungGcCount, MetricsCounter) \
- METRIC(FullGcCount, MetricsCounter) \
- METRIC(TotalBytesAllocated, MetricsCounter) \
- METRIC(TotalGcCollectionTime, MetricsCounter) \
- METRIC(YoungGcThroughputAvg, MetricsAverage) \
- METRIC(FullGcThroughputAvg, MetricsAverage) \
- METRIC(YoungGcTracingThroughputAvg, MetricsAverage) \
- METRIC(FullGcTracingThroughputAvg, MetricsAverage) \
- METRIC(JitMethodCompileTotalTime, MetricsCounter) \
- METRIC(JitMethodCompileCount, MetricsCounter) \
- METRIC(YoungGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
- METRIC(FullGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
- METRIC(YoungGcThroughput, MetricsHistogram, 15, 0, 10'000) \
- METRIC(FullGcThroughput, MetricsHistogram, 15, 0, 10'000) \
- METRIC(YoungGcTracingThroughput, MetricsHistogram, 15, 0, 10'000) \
- METRIC(FullGcTracingThroughput, MetricsHistogram, 15, 0, 10'000) \
- METRIC(GcWorldStopTime, MetricsCounter) \
- METRIC(GcWorldStopCount, MetricsCounter) \
- METRIC(YoungGcScannedBytes, MetricsCounter) \
- METRIC(YoungGcFreedBytes, MetricsCounter) \
- METRIC(YoungGcDuration, MetricsCounter) \
- METRIC(FullGcScannedBytes, MetricsCounter) \
- METRIC(FullGcFreedBytes, MetricsCounter) \
+
+// Metrics reported as Event Metrics.
+#define ART_EVENT_METRICS(METRIC) \
+ METRIC(ClassLoadingTotalTime, MetricsCounter) \
+ METRIC(ClassVerificationTotalTime, MetricsCounter) \
+ METRIC(ClassVerificationCount, MetricsCounter) \
+ METRIC(WorldStopTimeDuringGCAvg, MetricsAverage) \
+ METRIC(YoungGcCount, MetricsCounter) \
+ METRIC(FullGcCount, MetricsCounter) \
+ METRIC(TotalBytesAllocated, MetricsCounter) \
+ METRIC(TotalGcCollectionTime, MetricsCounter) \
+ METRIC(YoungGcThroughputAvg, MetricsAverage) \
+ METRIC(FullGcThroughputAvg, MetricsAverage) \
+ METRIC(YoungGcTracingThroughputAvg, MetricsAverage) \
+ METRIC(FullGcTracingThroughputAvg, MetricsAverage) \
+ METRIC(JitMethodCompileTotalTime, MetricsCounter) \
+ METRIC(JitMethodCompileCount, MetricsCounter) \
+ METRIC(YoungGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
+ METRIC(FullGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
+ METRIC(YoungGcThroughput, MetricsHistogram, 15, 0, 10'000) \
+ METRIC(FullGcThroughput, MetricsHistogram, 15, 0, 10'000) \
+ METRIC(YoungGcTracingThroughput, MetricsHistogram, 15, 0, 10'000) \
+ METRIC(FullGcTracingThroughput, MetricsHistogram, 15, 0, 10'000) \
+ METRIC(GcWorldStopTime, MetricsCounter) \
+ METRIC(GcWorldStopCount, MetricsCounter) \
+ METRIC(YoungGcScannedBytes, MetricsCounter) \
+ METRIC(YoungGcFreedBytes, MetricsCounter) \
+ METRIC(YoungGcDuration, MetricsCounter) \
+ METRIC(FullGcScannedBytes, MetricsCounter) \
+ METRIC(FullGcFreedBytes, MetricsCounter) \
METRIC(FullGcDuration, MetricsCounter)
+// Increasing counter metrics, reported as Value Metrics in delta increments.
+#define ART_VALUE_METRICS(METRIC) \
+ METRIC(GcWorldStopTimeDelta, MetricsDeltaCounter) \
+ METRIC(GcWorldStopCountDelta, MetricsDeltaCounter) \
+ METRIC(YoungGcScannedBytesDelta, MetricsDeltaCounter) \
+ METRIC(YoungGcFreedBytesDelta, MetricsDeltaCounter) \
+ METRIC(YoungGcDurationDelta, MetricsDeltaCounter) \
+ METRIC(FullGcScannedBytesDelta, MetricsDeltaCounter) \
+ METRIC(FullGcFreedBytesDelta, MetricsDeltaCounter) \
+ METRIC(FullGcDurationDelta, MetricsDeltaCounter) \
+ METRIC(JitMethodCompileTotalTimeDelta, MetricsDeltaCounter) \
+ METRIC(JitMethodCompileCountDelta, MetricsDeltaCounter) \
+ METRIC(ClassVerificationTotalTimeDelta, MetricsDeltaCounter) \
+ METRIC(ClassVerificationCountDelta, MetricsDeltaCounter) \
+ METRIC(ClassLoadingTotalTimeDelta, MetricsDeltaCounter) \
+ METRIC(TotalBytesAllocatedDelta, MetricsDeltaCounter) \
+ METRIC(TotalGcCollectionTimeDelta, MetricsDeltaCounter) \
+ METRIC(YoungGcCountDelta, MetricsDeltaCounter) \
+ METRIC(FullGcCountDelta, MetricsDeltaCounter)
+
+#define ART_METRICS(METRIC) \
+ ART_EVENT_METRICS(METRIC) \
+ ART_VALUE_METRICS(METRIC)
+
// A lot of the metrics implementation code is generated by passing one-off macros into ART_COUNTERS
// and ART_HISTOGRAMS. This means metrics.h and metrics.cc are very #define-heavy, which can be
// challenging to read. The alternative was to require a lot of boilerplate code for each new metric
@@ -243,6 +269,8 @@ class MetricsBackend {
template <DatumId counter_type, typename T>
friend class MetricsCounter;
+ template <DatumId counter_type, typename T>
+ friend class MetricsDeltaCounter;
template <DatumId histogram_type, size_t num_buckets, int64_t low_value, int64_t high_value>
friend class MetricsHistogram;
template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
@@ -274,13 +302,14 @@ class MetricsCounter : public MetricsBase<T> {
void AddOne() { Add(1u); }
void Add(value_t value) { value_.fetch_add(value, std::memory_order::memory_order_relaxed); }
- void Report(MetricsBackend* backend) const { backend->ReportCounter(counter_type, Value()); }
-
- protected:
- void Reset() {
- value_ = 0;
+ void Report(const std::vector<MetricsBackend*>& backends) const {
+ for (MetricsBackend* backend : backends) {
+ backend->ReportCounter(counter_type, Value());
+ }
}
+ protected:
+ void Reset() { value_ = 0; }
value_t Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
private:
@@ -317,11 +346,14 @@ class MetricsAverage final : public MetricsCounter<datum_id, T> {
count_.fetch_add(1, std::memory_order::memory_order_release);
}
- void Report(MetricsBackend* backend) const {
+ void Report(const std::vector<MetricsBackend*>& backends) const {
+ count_t value = MetricsCounter<datum_id, value_t>::Value();
count_t count = count_.load(std::memory_order::memory_order_acquire);
- backend->ReportCounter(datum_id,
- // Avoid divide-by-0.
- count != 0 ? MetricsCounter<datum_id, value_t>::Value() / count : 0);
+ // Avoid divide-by-0.
+ count_t average_value = count != 0 ? value / count : 0;
+ for (MetricsBackend* backend : backends) {
+ backend->ReportCounter(datum_id, average_value);
+ }
}
protected:
@@ -337,6 +369,40 @@ class MetricsAverage final : public MetricsCounter<datum_id, T> {
friend class ArtMetrics;
};
+template <DatumId datum_id, typename T = uint64_t>
+class MetricsDeltaCounter : public MetricsBase<T> {
+ public:
+ using value_t = T;
+
+ explicit constexpr MetricsDeltaCounter(uint64_t value = 0) : value_{value} {
+ // Ensure we do not have any unnecessary data in this class.
+ // Adding intptr_t to accommodate vtable, and rounding up to incorporate
+ // padding.
+ static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
+ RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
+ }
+
+ void Add(value_t value) override {
+ value_.fetch_add(value, std::memory_order::memory_order_relaxed);
+ }
+ void AddOne() { Add(1u); }
+
+ void ReportAndReset(const std::vector<MetricsBackend*>& backends) {
+ value_t value = value_.exchange(0, std::memory_order::memory_order_relaxed);
+ for (MetricsBackend* backend : backends) {
+ backend->ReportCounter(datum_id, value);
+ }
+ }
+
+ void Reset() { value_ = 0; }
+
+ private:
+ std::atomic<value_t> value_;
+ static_assert(std::atomic<value_t>::is_always_lock_free);
+
+ friend class ArtMetrics;
+};
+
template <DatumId histogram_type_,
size_t num_buckets_,
int64_t minimum_value_,
@@ -361,8 +427,10 @@ class MetricsHistogram final : public MetricsBase<int64_t> {
buckets_[i].fetch_add(1u, std::memory_order::memory_order_relaxed);
}
- void Report(MetricsBackend* backend) const {
- backend->ReportHistogram(histogram_type_, minimum_value_, maximum_value_, GetBuckets());
+ void Report(const std::vector<MetricsBackend*>& backends) const {
+ for (MetricsBackend* backend : backends) {
+ backend->ReportHistogram(histogram_type_, minimum_value_, maximum_value_, GetBuckets());
+ }
}
protected:
@@ -639,8 +707,8 @@ class ArtMetrics {
public:
ArtMetrics();
- void ReportAllMetrics(MetricsBackend* backend) const;
- void DumpForSigQuit(std::ostream& os) const;
+ void ReportAllMetricsAndResetValueMetrics(const std::vector<MetricsBackend*>& backends);
+ void DumpForSigQuit(std::ostream& os);
// Resets all metrics to their initial value. This is intended to be used after forking from the
// zygote so we don't attribute parent values to the child process.
diff --git a/libartbase/base/metrics/metrics_common.cc b/libartbase/base/metrics/metrics_common.cc
index 025f5eb79e..2732088e85 100644
--- a/libartbase/base/metrics/metrics_common.cc
+++ b/libartbase/base/metrics/metrics_common.cc
@@ -65,32 +65,40 @@ ART_METRICS(ART_METRIC)
{
}
-void ArtMetrics::ReportAllMetrics(MetricsBackend* backend) const {
- backend->BeginReport(MilliTime() - beginning_timestamp_);
+void ArtMetrics::ReportAllMetricsAndResetValueMetrics(
+ const std::vector<MetricsBackend*>& backends) {
+ for (auto& backend : backends) {
+ backend->BeginReport(MilliTime() - beginning_timestamp_);
+ }
-#define ART_METRIC(name, Kind, ...) name()->Report(backend);
- ART_METRICS(ART_METRIC)
-#undef ART_METRIC
+#define REPORT_METRIC(name, Kind, ...) name()->Report(backends);
+ ART_EVENT_METRICS(REPORT_METRIC)
+#undef REPORT_METRIC
+
+#define REPORT_METRIC(name, Kind, ...) name()->ReportAndReset(backends);
+ ART_VALUE_METRICS(REPORT_METRIC)
+#undef REPORT_METRIC
- backend->EndReport();
+ for (auto& backend : backends) {
+ backend->EndReport();
+ }
}
-void ArtMetrics::DumpForSigQuit(std::ostream& os) const {
+void ArtMetrics::DumpForSigQuit(std::ostream& os) {
StringBackend backend(std::make_unique<TextFormatter>());
- ReportAllMetrics(&backend);
+ ReportAllMetricsAndResetValueMetrics({&backend});
os << backend.GetAndResetBuffer();
}
void ArtMetrics::Reset() {
beginning_timestamp_ = MilliTime();
-#define ART_METRIC(name, kind, ...) name##_.Reset();
- ART_METRICS(ART_METRIC);
-#undef ART_METRIC
+#define RESET_METRIC(name, ...) name##_.Reset();
+ ART_METRICS(RESET_METRIC)
+#undef RESET_METRIC
}
StringBackend::StringBackend(std::unique_ptr<MetricsFormatter> formatter)
- : formatter_(std::move(formatter))
-{}
+ : formatter_(std::move(formatter)) {}
std::string StringBackend::GetAndResetBuffer() {
return formatter_->GetAndResetBuffer();
diff --git a/libartbase/base/metrics/metrics_test.cc b/libartbase/base/metrics/metrics_test.cc
index fd7124be8b..6c2e0451f4 100644
--- a/libartbase/base/metrics/metrics_test.cc
+++ b/libartbase/base/metrics/metrics_test.cc
@@ -16,6 +16,7 @@
#include "metrics.h"
+#include "base/macros.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "metrics_test.h"
@@ -232,7 +233,7 @@ TEST_F(MetricsTest, ArtMetricsReport) {
bool found_histogram_{false};
} backend;
- metrics.ReportAllMetrics(&backend);
+ metrics.ReportAllMetricsAndResetValueMetrics({&backend});
}
TEST_F(MetricsTest, HistogramTimer) {
@@ -251,7 +252,7 @@ TEST_F(MetricsTest, StreamBackendDumpAllMetrics) {
ArtMetrics metrics;
StringBackend backend(std::make_unique<TextFormatter>());
- metrics.ReportAllMetrics(&backend);
+ metrics.ReportAllMetricsAndResetValueMetrics({&backend});
// Make sure the resulting string lists all the metrics.
const std::string result = backend.GetAndResetBuffer();
@@ -271,11 +272,14 @@ TEST_F(MetricsTest, ResetMetrics) {
class NonZeroBackend : public TestBackendBase {
public:
- void ReportCounter(DatumId, uint64_t value) override {
+ void ReportCounter(DatumId counter_type [[gnu::unused]], uint64_t value) override {
EXPECT_NE(value, 0u);
}
- void ReportHistogram(DatumId, int64_t, int64_t, const std::vector<uint32_t>& buckets) override {
+ void ReportHistogram(DatumId histogram_type [[gnu::unused]],
+ int64_t minimum_value [[gnu::unused]],
+ int64_t maximum_value [[gnu::unused]],
+ const std::vector<uint32_t>& buckets) override {
bool nonzero = false;
for (const auto value : buckets) {
nonzero |= (value != 0u);
@@ -285,25 +289,99 @@ TEST_F(MetricsTest, ResetMetrics) {
} non_zero_backend;
// Make sure the metrics all have a nonzero value.
- metrics.ReportAllMetrics(&non_zero_backend);
+ metrics.ReportAllMetricsAndResetValueMetrics({&non_zero_backend});
// Reset the metrics and make sure they are all zero again
metrics.Reset();
class ZeroBackend : public TestBackendBase {
public:
- void ReportCounter(DatumId, uint64_t value) override {
+ void ReportCounter(DatumId counter_type [[gnu::unused]], uint64_t value) override {
EXPECT_EQ(value, 0u);
}
- void ReportHistogram(DatumId, int64_t, int64_t, const std::vector<uint32_t>& buckets) override {
+ void ReportHistogram(DatumId histogram_type [[gnu::unused]],
+ int64_t minimum_value [[gnu::unused]],
+ int64_t maximum_value [[gnu::unused]],
+ const std::vector<uint32_t>& buckets) override {
for (const auto value : buckets) {
EXPECT_EQ(value, 0u);
}
}
} zero_backend;
- metrics.ReportAllMetrics(&zero_backend);
+ metrics.ReportAllMetricsAndResetValueMetrics({&zero_backend});
+}
+
+TEST_F(MetricsTest, KeepEventMetricsResetValueMetricsAfterReporting) {
+ ArtMetrics metrics;
+
+ // Add something to each of the metrics.
+#define METRIC(name, type, ...) metrics.name()->Add(42);
+ ART_METRICS(METRIC)
+#undef METRIC
+
+ class FirstBackend : public TestBackendBase {
+ public:
+ void ReportCounter(DatumId counter_type [[gnu::unused]], uint64_t value) override {
+ EXPECT_NE(value, 0u);
+ }
+
+ void ReportHistogram(DatumId histogram_type [[gnu::unused]],
+ int64_t minimum_value [[gnu::unused]],
+ int64_t maximum_value [[gnu::unused]],
+ const std::vector<uint32_t>& buckets) override {
+ bool nonzero = false;
+ for (const auto value : buckets) {
+ nonzero |= (value != 0u);
+ }
+ EXPECT_TRUE(nonzero);
+ }
+ } first_backend;
+
+ // Make sure the metrics all have a nonzero value, and they are not reset between backends.
+ metrics.ReportAllMetricsAndResetValueMetrics({&first_backend, &first_backend});
+
+ // After reporting, the Value Metrics should have been reset.
+ class SecondBackend : public TestBackendBase {
+ public:
+ void ReportCounter(DatumId datum_id, uint64_t value) override {
+ switch (datum_id) {
+ // Value metrics - expected to have been reset
+#define CHECK_METRIC(name, ...) case DatumId::k##name:
+ ART_VALUE_METRICS(CHECK_METRIC)
+#undef CHECK_METRIC
+ EXPECT_EQ(value, 0u);
+ return;
+
+ // Event metrics - expected to have retained their previous value
+#define CHECK_METRIC(name, ...) case DatumId::k##name:
+ ART_EVENT_METRICS(CHECK_METRIC)
+#undef CHECK_METRIC
+ EXPECT_NE(value, 0u);
+ return;
+
+ default:
+ // unknown metric - it should not be possible to reach this path
+ FAIL();
+ UNREACHABLE();
+ }
+ }
+
+ // All histograms are event metrics.
+ void ReportHistogram(DatumId histogram_type [[gnu::unused]],
+ int64_t minimum_value [[gnu::unused]],
+ int64_t maximum_value [[gnu::unused]],
+ const std::vector<uint32_t>& buckets) override {
+ bool nonzero = false;
+ for (const auto value : buckets) {
+ nonzero |= (value != 0u);
+ }
+ EXPECT_TRUE(nonzero);
+ }
+ } second_backend;
+
+ metrics.ReportAllMetricsAndResetValueMetrics({&second_backend});
}
TEST(TextFormatterTest, ReportMetrics_WithBuckets) {
diff --git a/libartbase/base/metrics/metrics_test.h b/libartbase/base/metrics/metrics_test.h
index 3e8b42a5cc..07b4e9dfcd 100644
--- a/libartbase/base/metrics/metrics_test.h
+++ b/libartbase/base/metrics/metrics_test.h
@@ -58,7 +58,7 @@ uint64_t CounterValue(const MetricType& counter) {
uint64_t* counter_value_;
} backend{&counter_value};
- counter.Report(&backend);
+ counter.Report({&backend});
return counter_value;
}
@@ -75,7 +75,7 @@ std::vector<uint32_t> GetBuckets(
std::vector<uint32_t>* buckets_;
} backend{&buckets};
- histogram.Report(&backend);
+ histogram.Report({&backend});
return buckets;
}
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index f311f09975..b32dcec665 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -186,6 +186,19 @@ bool IsAddressKnownBackedByFileOrShared(const void* addr);
// Returns the number of threads running.
int GetTaskCount();
+// Returns a vector holding the raw pointer targets of the elements of "unique_pointers", a vector
+// of smart pointers. This does not affect the target objects e.g. by incrementing ref-counts; it's
+// a raw pointer read.
+template <typename T>
+static std::vector<T*> ToRawPointers(const std::vector<std::unique_ptr<T>>& unique_pointers) {
+ std::vector<T*> raw_pointers;
+ raw_pointers.reserve(unique_pointers.size());
+ for (const std::unique_ptr<T>& p : unique_pointers) {
+ raw_pointers.push_back(p.get());
+ }
+ return raw_pointers;
+}
+
} // namespace art
#endif // ART_LIBARTBASE_BASE_UTILS_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b98f704af3..f5a4ce689c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3234,6 +3234,7 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
ScopedDefiningClass sdc(self);
StackHandleScope<3> hs(self);
metrics::AutoTimer timer{GetMetrics()->ClassLoadingTotalTime()};
+ metrics::AutoTimer timeDelta{GetMetrics()->ClassLoadingTotalTimeDelta()};
auto klass = hs.NewHandle<mirror::Class>(nullptr);
// Load the class from the dex file.
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index d540873e77..5118523a95 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -160,23 +160,31 @@ ConcurrentCopying::ConcurrentCopying(Heap* heap,
if (young_gen_) {
gc_time_histogram_ = metrics->YoungGcCollectionTime();
metrics_gc_count_ = metrics->YoungGcCount();
+ metrics_gc_count_delta_ = metrics->YoungGcCountDelta();
gc_throughput_histogram_ = metrics->YoungGcThroughput();
gc_tracing_throughput_hist_ = metrics->YoungGcTracingThroughput();
gc_throughput_avg_ = metrics->YoungGcThroughputAvg();
gc_tracing_throughput_avg_ = metrics->YoungGcTracingThroughputAvg();
gc_scanned_bytes_ = metrics->YoungGcScannedBytes();
+ gc_scanned_bytes_delta_ = metrics->YoungGcScannedBytesDelta();
gc_freed_bytes_ = metrics->YoungGcFreedBytes();
+ gc_freed_bytes_delta_ = metrics->YoungGcFreedBytesDelta();
gc_duration_ = metrics->YoungGcDuration();
+ gc_duration_delta_ = metrics->YoungGcDurationDelta();
} else {
gc_time_histogram_ = metrics->FullGcCollectionTime();
metrics_gc_count_ = metrics->FullGcCount();
+ metrics_gc_count_delta_ = metrics->FullGcCountDelta();
gc_throughput_histogram_ = metrics->FullGcThroughput();
gc_tracing_throughput_hist_ = metrics->FullGcTracingThroughput();
gc_throughput_avg_ = metrics->FullGcThroughputAvg();
gc_tracing_throughput_avg_ = metrics->FullGcTracingThroughputAvg();
gc_scanned_bytes_ = metrics->FullGcScannedBytes();
+ gc_scanned_bytes_delta_ = metrics->FullGcScannedBytesDelta();
gc_freed_bytes_ = metrics->FullGcFreedBytes();
+ gc_freed_bytes_delta_ = metrics->FullGcFreedBytesDelta();
gc_duration_ = metrics->FullGcDuration();
+ gc_duration_delta_ = metrics->FullGcDurationDelta();
}
}
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 4efe48c318..03a432dbf4 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -72,13 +72,17 @@ GarbageCollector::GarbageCollector(Heap* heap, const std::string& name)
freed_bytes_histogram_((name_ + " freed-bytes").c_str(), kMemBucketSize, kMemBucketCount),
gc_time_histogram_(nullptr),
metrics_gc_count_(nullptr),
+ metrics_gc_count_delta_(nullptr),
gc_throughput_histogram_(nullptr),
gc_tracing_throughput_hist_(nullptr),
gc_throughput_avg_(nullptr),
gc_tracing_throughput_avg_(nullptr),
gc_scanned_bytes_(nullptr),
+ gc_scanned_bytes_delta_(nullptr),
gc_freed_bytes_(nullptr),
+ gc_freed_bytes_delta_(nullptr),
gc_duration_(nullptr),
+ gc_duration_delta_(nullptr),
cumulative_timings_(name),
pause_histogram_lock_("pause histogram lock", kDefaultMutexLevel, true),
is_transaction_active_(false),
@@ -203,11 +207,15 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
const uint64_t total_pause_time_us = total_pause_time_ns / 1'000;
metrics->WorldStopTimeDuringGCAvg()->Add(total_pause_time_us);
metrics->GcWorldStopTime()->Add(total_pause_time_us);
+ metrics->GcWorldStopTimeDelta()->Add(total_pause_time_us);
metrics->GcWorldStopCount()->AddOne();
+ metrics->GcWorldStopCountDelta()->AddOne();
// Report total collection time of all GCs put together.
metrics->TotalGcCollectionTime()->Add(NsToMs(duration_ns));
+ metrics->TotalGcCollectionTimeDelta()->Add(NsToMs(duration_ns));
if (are_metrics_initialized_) {
metrics_gc_count_->Add(1);
+ metrics_gc_count_delta_->Add(1);
// Report GC time in milliseconds.
gc_time_histogram_->Add(NsToMs(duration_ns));
// Throughput in bytes/s. Add 1us to prevent possible division by 0.
@@ -224,8 +232,11 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
gc_throughput_avg_->Add(throughput);
gc_scanned_bytes_->Add(current_iteration->GetScannedBytes());
+ gc_scanned_bytes_delta_->Add(current_iteration->GetScannedBytes());
gc_freed_bytes_->Add(current_iteration->GetFreedBytes());
+ gc_freed_bytes_delta_->Add(current_iteration->GetFreedBytes());
gc_duration_->Add(NsToMs(current_iteration->GetDurationNs()));
+ gc_duration_delta_->Add(NsToMs(current_iteration->GetDurationNs()));
}
is_transaction_active_ = false;
}
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index d11aea36c9..948a868bd2 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -162,13 +162,17 @@ class GarbageCollector : public RootVisitor, public IsMarkedVisitor, public Mark
Histogram<size_t> freed_bytes_histogram_;
metrics::MetricsBase<int64_t>* gc_time_histogram_;
metrics::MetricsBase<uint64_t>* metrics_gc_count_;
+ metrics::MetricsBase<uint64_t>* metrics_gc_count_delta_;
metrics::MetricsBase<int64_t>* gc_throughput_histogram_;
metrics::MetricsBase<int64_t>* gc_tracing_throughput_hist_;
metrics::MetricsBase<uint64_t>* gc_throughput_avg_;
metrics::MetricsBase<uint64_t>* gc_tracing_throughput_avg_;
metrics::MetricsBase<uint64_t>* gc_scanned_bytes_;
+ metrics::MetricsBase<uint64_t>* gc_scanned_bytes_delta_;
metrics::MetricsBase<uint64_t>* gc_freed_bytes_;
+ metrics::MetricsBase<uint64_t>* gc_freed_bytes_delta_;
metrics::MetricsBase<uint64_t>* gc_duration_;
+ metrics::MetricsBase<uint64_t>* gc_duration_delta_;
uint64_t total_thread_cpu_time_ns_;
uint64_t total_time_ns_;
uint64_t total_freed_objects_;
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 9c76060062..922b58870d 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -214,6 +214,7 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self,
need_gc = true;
}
GetMetrics()->TotalBytesAllocated()->Add(bytes_tl_bulk_allocated);
+ GetMetrics()->TotalBytesAllocatedDelta()->Add(bytes_tl_bulk_allocated);
}
}
if (kIsDebugBuild && Runtime::Current()->IsStarted()) {
diff --git a/runtime/metrics/reporter.cc b/runtime/metrics/reporter.cc
index 28ca997cec..736ef7f879 100644
--- a/runtime/metrics/reporter.cc
+++ b/runtime/metrics/reporter.cc
@@ -196,12 +196,10 @@ void MetricsReporter::MaybeResetTimeout() {
}
}
-const ArtMetrics* MetricsReporter::GetMetrics() {
- return runtime_->GetMetrics();
-}
+ArtMetrics* MetricsReporter::GetMetrics() { return runtime_->GetMetrics(); }
void MetricsReporter::ReportMetrics() {
- const ArtMetrics* metrics = GetMetrics();
+ ArtMetrics* metrics = GetMetrics();
if (!session_started_) {
for (auto& backend : backends_) {
@@ -210,9 +208,7 @@ void MetricsReporter::ReportMetrics() {
session_started_ = true;
}
- for (auto& backend : backends_) {
- metrics->ReportAllMetrics(backend.get());
- }
+ metrics->ReportAllMetricsAndResetValueMetrics(ToRawPointers(backends_));
}
void MetricsReporter::UpdateSessionInBackends() {
diff --git a/runtime/metrics/reporter.h b/runtime/metrics/reporter.h
index af9e0ca151..865815e0bf 100644
--- a/runtime/metrics/reporter.h
+++ b/runtime/metrics/reporter.h
@@ -136,7 +136,7 @@ class MetricsReporter {
// Returns the metrics to be reported.
// This exists only for testing purposes so that we can verify reporting with minimum
// runtime interference.
- virtual const ArtMetrics* GetMetrics();
+ virtual ArtMetrics* GetMetrics();
MetricsReporter(const ReportingConfig& config, Runtime* runtime);
diff --git a/runtime/metrics/reporter_test.cc b/runtime/metrics/reporter_test.cc
index 62131d8e87..848a74ee61 100644
--- a/runtime/metrics/reporter_test.cc
+++ b/runtime/metrics/reporter_test.cc
@@ -34,13 +34,10 @@ namespace metrics {
// other runtime setup logic.
class MockMetricsReporter : public MetricsReporter {
protected:
- MockMetricsReporter(const ReportingConfig& config, Runtime* runtime) :
- MetricsReporter(config, runtime),
- art_metrics_(new ArtMetrics()) {}
+ MockMetricsReporter(const ReportingConfig& config, Runtime* runtime)
+ : MetricsReporter(config, runtime), art_metrics_(std::make_unique<ArtMetrics>()) {}
- const ArtMetrics* GetMetrics() override {
- return art_metrics_.get();
- }
+ ArtMetrics* GetMetrics() override { return art_metrics_.get(); }
std::unique_ptr<ArtMetrics> art_metrics_;
diff --git a/runtime/metrics/statsd.cc b/runtime/metrics/statsd.cc
index 036f667171..3b498db414 100644
--- a/runtime/metrics/statsd.cc
+++ b/runtime/metrics/statsd.cc
@@ -47,27 +47,49 @@ constexpr std::optional<int32_t> EncodeDatumId(DatumId datum_id) {
case DatumId::kClassVerificationTotalTime:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_VERIFICATION_TIME_COUNTER_MICROS);
+ case DatumId::kClassVerificationTotalTimeDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_CLASS_VERIFICATION_TIME_MICROS);
case DatumId::kJitMethodCompileTotalTime:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_JIT_METHOD_COMPILE_TIME_MICROS);
+ case DatumId::kJitMethodCompileTotalTimeDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_JIT_METHOD_COMPILE_TIME_MICROS);
case DatumId::kClassLoadingTotalTime:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_LOADING_TIME_COUNTER_MICROS);
+ case DatumId::kClassLoadingTotalTimeDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_CLASS_LOADING_TIME_MICROS);
case DatumId::kClassVerificationCount:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_VERIFICATION_COUNT);
+ case DatumId::kClassVerificationCountDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_CLASS_VERIFICATION_COUNT);
case DatumId::kWorldStopTimeDuringGCAvg:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_WORLD_STOP_TIME_AVG_MICROS);
case DatumId::kYoungGcCount:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_COUNT);
+ case DatumId::kYoungGcCountDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_YOUNG_GENERATION_COLLECTION_COUNT);
case DatumId::kFullGcCount:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_COUNT);
+ case DatumId::kFullGcCountDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_FULL_HEAP_COLLECTION_COUNT);
case DatumId::kTotalBytesAllocated:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_TOTAL_BYTES_ALLOCATED);
+ case DatumId::kTotalBytesAllocatedDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_TOTAL_BYTES_ALLOCATED);
case DatumId::kYoungGcCollectionTime:
return std::make_optional(
statsd::
@@ -86,6 +108,9 @@ constexpr std::optional<int32_t> EncodeDatumId(DatumId datum_id) {
case DatumId::kJitMethodCompileCount:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_JIT_METHOD_COMPILE_COUNT);
+ case DatumId::kJitMethodCompileCountDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_JIT_METHOD_COMPILE_COUNT);
case DatumId::kYoungGcTracingThroughput:
return std::make_optional(
statsd::
@@ -97,6 +122,9 @@ constexpr std::optional<int32_t> EncodeDatumId(DatumId datum_id) {
case DatumId::kTotalGcCollectionTime:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_TOTAL_COLLECTION_TIME_MS);
+ case DatumId::kTotalGcCollectionTimeDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_TOTAL_COLLECTION_TIME_MS);
case DatumId::kYoungGcThroughputAvg:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_THROUGHPUT_AVG_MB_PER_SEC);
@@ -112,27 +140,57 @@ constexpr std::optional<int32_t> EncodeDatumId(DatumId datum_id) {
case DatumId::kGcWorldStopTime:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_WORLD_STOP_TIME_US);
+ case DatumId::kGcWorldStopTimeDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_WORLD_STOP_TIME_US);
case DatumId::kGcWorldStopCount:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_WORLD_STOP_COUNT);
+ case DatumId::kGcWorldStopCountDelta:
+ return std::make_optional(
+ statsd::ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_WORLD_STOP_COUNT);
case DatumId::kYoungGcScannedBytes:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_SCANNED_BYTES);
+ case DatumId::kYoungGcScannedBytesDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_YOUNG_GENERATION_COLLECTION_SCANNED_BYTES);
case DatumId::kYoungGcFreedBytes:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_FREED_BYTES);
+ case DatumId::kYoungGcFreedBytesDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_YOUNG_GENERATION_COLLECTION_FREED_BYTES);
case DatumId::kYoungGcDuration:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_DURATION_MS);
+ case DatumId::kYoungGcDurationDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_YOUNG_GENERATION_COLLECTION_DURATION_MS);
case DatumId::kFullGcScannedBytes:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_SCANNED_BYTES);
+ case DatumId::kFullGcScannedBytesDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_FULL_HEAP_COLLECTION_SCANNED_BYTES);
case DatumId::kFullGcFreedBytes:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_FREED_BYTES);
+ case DatumId::kFullGcFreedBytesDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_FULL_HEAP_COLLECTION_FREED_BYTES);
case DatumId::kFullGcDuration:
return std::make_optional(
statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_DURATION_MS);
+ case DatumId::kFullGcDurationDelta:
+ return std::make_optional(
+ statsd::
+ ART_DATUM_DELTA_REPORTED__KIND__ART_DATUM_DELTA_GC_FULL_HEAP_COLLECTION_DURATION_MS);
}
}
@@ -247,22 +305,39 @@ class StatsdBackend : public MetricsBackend {
void ReportCounter(DatumId counter_type, uint64_t value) override {
std::optional<int32_t> datum_id = EncodeDatumId(counter_type);
- if (datum_id.has_value()) {
- statsd::stats_write(
- statsd::ART_DATUM_REPORTED,
- session_data_.session_id,
- session_data_.uid,
- EncodeCompileFilter(session_data_.compiler_filter),
- EncodeCompilationReason(session_data_.compilation_reason),
- current_timestamp_,
- 0, // TODO: collect and report thread type (0 means UNKNOWN, but that
- // constant is not present in all branches)
- datum_id.value(),
- static_cast<int64_t>(value),
- statsd::ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN,
- statsd::ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_UNKNOWN,
- EncodeInstructionSet(kRuntimeISA));
+ if (!datum_id.has_value()) {
+ return;
}
+
+ int32_t atom;
+ switch (counter_type) {
+#define EVENT_METRIC_CASE(name, ...) case DatumId::k##name:
+ ART_EVENT_METRICS(EVENT_METRIC_CASE)
+#undef EVENT_METRIC_CASE
+ atom = statsd::ART_DATUM_REPORTED;
+ break;
+
+#define VALUE_METRIC_CASE(name, type, ...) case DatumId::k##name:
+ ART_VALUE_METRICS(VALUE_METRIC_CASE)
+#undef VALUE_METRIC_CASE
+ atom = statsd::ART_DATUM_DELTA_REPORTED;
+ break;
+ }
+
+ statsd::stats_write(
+ atom,
+ session_data_.session_id,
+ session_data_.uid,
+ EncodeCompileFilter(session_data_.compiler_filter),
+ EncodeCompilationReason(session_data_.compilation_reason),
+ current_timestamp_,
+ 0, // TODO: collect and report thread type (0 means UNKNOWN, but that
+ // constant is not present in all branches)
+ datum_id.value(),
+ static_cast<int64_t>(value),
+ statsd::ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN,
+ statsd::ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_UNKNOWN,
+ EncodeInstructionSet(kRuntimeISA));
}
void ReportHistogram(DatumId /*histogram_type*/,
diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc
index 8c541f877e..8946bb2081 100644
--- a/runtime/verifier/class_verifier.cc
+++ b/runtime/verifier/class_verifier.cc
@@ -176,6 +176,9 @@ FailureKind ClassVerifier::VerifyClass(Thread* self,
GetMetrics()->ClassVerificationCount()->AddOne();
+ GetMetrics()->ClassVerificationTotalTimeDelta()->Add(elapsed_time_microseconds);
+ GetMetrics()->ClassVerificationCountDelta()->AddOne();
+
if (failure_data.kind == verifier::FailureKind::kHardFailure && callbacks != nullptr) {
ClassReference ref(dex_file, dex_file->GetIndexForClassDef(class_def));
callbacks->ClassRejected(ref);
diff --git a/test/2232-write-metrics-to-log/expected-stderr.txt b/test/2232-write-metrics-to-log/expected-stderr.txt
index 9546999d34..5bc27fe98f 100644
--- a/test/2232-write-metrics-to-log/expected-stderr.txt
+++ b/test/2232-write-metrics-to-log/expected-stderr.txt
@@ -1 +1 @@
-ClassVerificationTotalTime
+ClassVerificationTotalTimeDelta
diff --git a/test/2232-write-metrics-to-log/run.py b/test/2232-write-metrics-to-log/run.py
index 980da22824..89fe040087 100644
--- a/test/2232-write-metrics-to-log/run.py
+++ b/test/2232-write-metrics-to-log/run.py
@@ -26,5 +26,5 @@ def run(ctx, args):
# Check that one of the metrics appears in stderr.
ctx.run(
- fr"sed -i -n 's/.*\(ClassVerificationTotalTime\).*/\1/p' '{args.stderr_file}'"
+ fr"sed -i -n 's/.*\(ClassVerificationTotalTimeDelta\).*/\1/p' '{args.stderr_file}'"
)