[metrics] Add MetricsAccumulator
MetricsAccumulator metrics are a generalization of counters that allow
a custom function to be supplied that specifies how to combine
incoming values. This allows for the definition of things like minimum
and maximum metrics.
Test: libartbase_gtests
Bug: 170149255
Change-Id: Ibc928a5d0e5cad3036e5829be9a535bc4a685ae1
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index e61e982..acfd20c 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -177,6 +177,8 @@
friend class MetricsCounter;
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&)>
+ friend class MetricsAccumulator;
friend class ArtMetrics;
};
@@ -281,6 +283,48 @@
friend class ArtMetrics;
};
+template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
+class MetricsAccumulator final : MetricsBase<T> {
+ public:
+ explicit constexpr MetricsAccumulator(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(T), sizeof(uint64_t)));
+ }
+
+ void Add(T value) {
+ T current = value_.load(std::memory_order::memory_order_relaxed);
+ T new_value;
+ do {
+ new_value = AccumulatorFunction(current, value);
+ // If the value didn't change, don't bother storing it.
+ if (current == new_value) {
+ break;
+ }
+ } while (!value_.compare_exchange_weak(
+ current, new_value, std::memory_order::memory_order_relaxed));
+ }
+
+ // Report the metric as a counter, since this has only a single value.
+ void Report(MetricsBackend* backend) const {
+ backend->ReportCounter(datum_id, static_cast<uint64_t>(Value()));
+ }
+
+ protected:
+ void Reset() {
+ value_ = 0;
+ }
+
+ private:
+ T Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
+
+ std::atomic<T> value_;
+
+ friend class ArtMetrics;
+};
+
// A backend that writes metrics in a human-readable format to a string.
//
// This is used as a base for LogBackend and FileBackend.