xref: /aosp_15_r20/art/libartbase/base/metrics/metrics.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_LIBARTBASE_BASE_METRICS_METRICS_H_
18 #define ART_LIBARTBASE_BASE_METRICS_METRICS_H_
19 
20 #include <stdint.h>
21 
22 #include <array>
23 #include <atomic>
24 #include <optional>
25 #include <sstream>
26 #include <string_view>
27 #include <thread>
28 #include <vector>
29 
30 #include "android-base/logging.h"
31 #include "base/bit_utils.h"
32 #include "base/macros.h"
33 #include "base/time_utils.h"
34 #include "jni.h"
35 #include "tinyxml2.h"
36 
37 #pragma clang diagnostic push
38 #pragma clang diagnostic error "-Wconversion"
39 
40 // See README.md in this directory for how to define metrics.
41 
42 // Metrics reported as Event Metrics.
43 #define ART_EVENT_METRICS(METRIC)                                   \
44   METRIC(ClassLoadingTotalTime, MetricsCounter)                     \
45   METRIC(ClassVerificationTotalTime, MetricsCounter)                \
46   METRIC(ClassVerificationCount, MetricsCounter)                    \
47   METRIC(WorldStopTimeDuringGCAvg, MetricsAverage)                  \
48   METRIC(YoungGcCount, MetricsCounter)                              \
49   METRIC(FullGcCount, MetricsCounter)                               \
50   METRIC(TotalBytesAllocated, MetricsCounter)                       \
51   METRIC(TotalGcCollectionTime, MetricsCounter)                     \
52   METRIC(YoungGcThroughputAvg, MetricsAverage)                      \
53   METRIC(FullGcThroughputAvg, MetricsAverage)                       \
54   METRIC(YoungGcTracingThroughputAvg, MetricsAverage)               \
55   METRIC(FullGcTracingThroughputAvg, MetricsAverage)                \
56   METRIC(JitMethodCompileTotalTime, MetricsCounter)                 \
57   METRIC(JitMethodCompileCount, MetricsCounter)                     \
58   METRIC(YoungGcCollectionTime, MetricsHistogram, 15, 0, 60'000)    \
59   METRIC(FullGcCollectionTime, MetricsHistogram, 15, 0, 60'000)     \
60   METRIC(YoungGcThroughput, MetricsHistogram, 15, 0, 10'000)        \
61   METRIC(FullGcThroughput, MetricsHistogram, 15, 0, 10'000)         \
62   METRIC(YoungGcTracingThroughput, MetricsHistogram, 15, 0, 10'000) \
63   METRIC(FullGcTracingThroughput, MetricsHistogram, 15, 0, 10'000)  \
64   METRIC(GcWorldStopTime, MetricsCounter)                           \
65   METRIC(GcWorldStopCount, MetricsCounter)                          \
66   METRIC(YoungGcScannedBytes, MetricsCounter)                       \
67   METRIC(YoungGcFreedBytes, MetricsCounter)                         \
68   METRIC(YoungGcDuration, MetricsCounter)                           \
69   METRIC(FullGcScannedBytes, MetricsCounter)                        \
70   METRIC(FullGcFreedBytes, MetricsCounter)                          \
71   METRIC(FullGcDuration, MetricsCounter)
72 
73 // Increasing counter metrics, reported as Value Metrics in delta increments.
74 #define ART_VALUE_METRICS(METRIC)                              \
75   METRIC(GcWorldStopTimeDelta, MetricsDeltaCounter)            \
76   METRIC(GcWorldStopCountDelta, MetricsDeltaCounter)           \
77   METRIC(YoungGcScannedBytesDelta, MetricsDeltaCounter)        \
78   METRIC(YoungGcFreedBytesDelta, MetricsDeltaCounter)          \
79   METRIC(YoungGcDurationDelta, MetricsDeltaCounter)            \
80   METRIC(FullGcScannedBytesDelta, MetricsDeltaCounter)         \
81   METRIC(FullGcFreedBytesDelta, MetricsDeltaCounter)           \
82   METRIC(FullGcDurationDelta, MetricsDeltaCounter)             \
83   METRIC(JitMethodCompileTotalTimeDelta, MetricsDeltaCounter)  \
84   METRIC(JitMethodCompileCountDelta, MetricsDeltaCounter)      \
85   METRIC(ClassVerificationTotalTimeDelta, MetricsDeltaCounter) \
86   METRIC(ClassVerificationCountDelta, MetricsDeltaCounter)     \
87   METRIC(ClassLoadingTotalTimeDelta, MetricsDeltaCounter)      \
88   METRIC(TotalBytesAllocatedDelta, MetricsDeltaCounter)        \
89   METRIC(TotalGcCollectionTimeDelta, MetricsDeltaCounter)      \
90   METRIC(YoungGcCountDelta, MetricsDeltaCounter)               \
91   METRIC(FullGcCountDelta, MetricsDeltaCounter)                \
92   METRIC(TimeElapsedDelta, MetricsDeltaCounter)
93 
94 #define ART_METRICS(METRIC) \
95   ART_EVENT_METRICS(METRIC) \
96   ART_VALUE_METRICS(METRIC)
97 
98 // A lot of the metrics implementation code is generated by passing one-off macros into ART_COUNTERS
99 // and ART_HISTOGRAMS. This means metrics.h and metrics.cc are very #define-heavy, which can be
100 // challenging to read. The alternative was to require a lot of boilerplate code for each new metric
101 // added, all of which would need to be rewritten if the metrics implementation changed. Using
102 // macros lets us add new metrics by adding a single line to either ART_COUNTERS or ART_HISTOGRAMS,
103 // and modifying the implementation only requires changing the implementation once, instead of once
104 // per metric.
105 
106 namespace art {
107 
108 class Runtime;
109 struct RuntimeArgumentMap;
110 
111 [[maybe_unused]] static jlong VMRuntime_getFullGcCount(JNIEnv* env, jclass klass);
112 
113 namespace metrics {
114 template <typename value_t>
115 class MetricsBase;
116 }  // namespace metrics
117 
118 namespace gc {
119 class HeapTest_GCMetrics_Test;
120 }  // namespace gc
121 
122 namespace metrics {
123 
124 /**
125  * An enumeration of all ART counters and histograms.
126  */
127 enum class DatumId {
128 #define METRIC(name, type, ...) k##name,
129   ART_METRICS(METRIC)
130 #undef METRIC
131 };
132 
133 // Names come from PackageManagerServiceCompilerMapping.java
134 #define REASON_NAME_LIST(V)                                               \
135   V(kError, "error")                                                      \
136   V(kUnknown, "unknown")                                                  \
137   V(kFirstBoot, "first-boot")                                             \
138   V(kBootAfterOTA, "boot-after-ota")                                      \
139   V(kPostBoot, "post-boot")                                               \
140   V(kInstall, "install")                                                  \
141   V(kInstallFast, "install-fast")                                         \
142   V(kInstallBulk, "install-bulk")                                         \
143   V(kInstallBulkSecondary, "install-bulk-secondary")                      \
144   V(kInstallBulkDowngraded, "install-bulk-downgraded")                    \
145   V(kInstallBulkSecondaryDowngraded, "install-bulk-secondary-downgraded") \
146   V(kBgDexopt, "bg-dexopt")                                               \
147   V(kABOTA, "ab-ota")                                                     \
148   V(kInactive, "inactive")                                                \
149   V(kShared, "shared")                                                    \
150   V(kInstallWithDexMetadata, "install-with-dex-metadata")                 \
151   V(kPrebuilt, "prebuilt")                                                \
152   V(kCmdLine, "cmdline")                                                  \
153   V(kVdex, "vdex")                                                        \
154   V(kBootAfterMainlineUpdate, "boot-after-mainline-update")
155 
156 // We log compilation reasons as part of the metadata we report. Since elsewhere compilation reasons
157 // are specified as a string, we define them as an enum here which indicates the reasons that we
158 // support.
159 enum class CompilationReason {
160 #define REASON(kind, name) kind,
161   REASON_NAME_LIST(REASON)
162 #undef REASON
163 };
164 
165 #define REASON_NAME(kind, kind_name) \
166     case CompilationReason::kind: return kind_name;
167 #define REASON_FROM_NAME(kind, kind_name) \
168     if (name == (kind_name)) { return CompilationReason::kind; }
169 
CompilationReasonName(CompilationReason reason)170 constexpr const char* CompilationReasonName(CompilationReason reason) {
171   switch (reason) {
172     REASON_NAME_LIST(REASON_NAME)
173   }
174 }
175 
CompilationReasonFromName(std::string_view name)176 constexpr CompilationReason CompilationReasonFromName(std::string_view name) {
177   REASON_NAME_LIST(REASON_FROM_NAME)
178   return CompilationReason::kError;
179 }
180 
181 #undef REASON_NAME
182 #undef REASON_FROM_NAME
183 
184 #define COMPILER_FILTER_REPORTING_LIST(V) \
185   V(kError, "error") /* Error (invalid value) condition */ \
186   V(kUnknown, "unknown") /* Unknown (not set) condition */ \
187   V(kAssumeVerified, "assume-verified") /* Standard compiler filters */ \
188   V(kExtract, "extract") \
189   V(kVerify, "verify") \
190   V(kSpaceProfile, "space-profile") \
191   V(kSpace, "space") \
192   V(kSpeedProfile, "speed-profile") \
193   V(kSpeed, "speed") \
194   V(kEverythingProfile, "everything-profile") \
195   V(kEverything, "everything") \
196   V(kRunFromApk, "run-from-apk") /* Augmented compiler filters as produces by OatFileAssistant#GetOptimizationStatus */ \
197   V(kRunFromApkFallback, "run-from-apk-fallback")
198 
199 // Augmented compiler filter enum, used in the reporting infra.
200 enum class CompilerFilterReporting {
201 #define FILTER(kind, name) kind,
202   COMPILER_FILTER_REPORTING_LIST(FILTER)
203 #undef FILTER
204 };
205 
206 #define FILTER_NAME(kind, kind_name) \
207     case CompilerFilterReporting::kind: return kind_name;
208 #define FILTER_FROM_NAME(kind, kind_name) \
209     if (name == (kind_name)) { return CompilerFilterReporting::kind; }
210 
CompilerFilterReportingName(CompilerFilterReporting filter)211 constexpr const char* CompilerFilterReportingName(CompilerFilterReporting filter) {
212   switch (filter) {
213     COMPILER_FILTER_REPORTING_LIST(FILTER_NAME)
214   }
215 }
216 
CompilerFilterReportingFromName(std::string_view name)217 constexpr CompilerFilterReporting CompilerFilterReportingFromName(std::string_view name) {
218   COMPILER_FILTER_REPORTING_LIST(FILTER_FROM_NAME)
219   return CompilerFilterReporting::kError;
220 }
221 
222 #undef FILTER_NAME
223 #undef FILTER_FROM_NAME
224 
225 // SessionData contains metadata about a metrics session (basically the lifetime of an ART process).
226 // This information should not change for the lifetime of the session.
227 struct SessionData {
228   static SessionData CreateDefault();
229 
230   static constexpr int64_t kInvalidSessionId = -1;
231   static constexpr int32_t kInvalidUserId = -1;
232 
233   int64_t session_id;
234   int32_t uid;
235   CompilationReason compilation_reason;
236   CompilerFilterReporting compiler_filter;
237 };
238 
239 // MetricsBackends are used by a metrics reporter to write metrics to some external location. For
240 // example, a backend might write to logcat, or to a file, or to statsd.
241 class MetricsBackend {
242  public:
~MetricsBackend()243   virtual ~MetricsBackend() {}
244 
245   // Begins an ART metrics session.
246   //
247   // This is called by the metrics reporter when the runtime is starting up. The session_data
248   // includes a session id which is used to correlate any metric reports with the same instance of
249   // the ART runtime. Additionally, session_data includes useful metadata such as the package name
250   // for this process.
251   //
252   // It may also be called whenever there is an update to the session metadata (e.g. optimization
253   // state).
254   virtual void BeginOrUpdateSession(const SessionData& session_data) = 0;
255 
256  protected:
257   // Called by the metrics reporter to indicate that a new metrics report is starting.
258   virtual void BeginReport(uint64_t timestamp_since_start_ms) = 0;
259 
260   // Called by the metrics reporter to give the current value of the counter with id counter_type.
261   //
262   // This will be called multiple times for each counter based on when the metrics reporter chooses
263   // to report metrics. For example, the metrics reporter may call this at shutdown or every N
264   // minutes. Counters are not reset in between invocations, so the value should represent the
265   // total count at the point this method is called.
266   virtual void ReportCounter(DatumId counter_type, uint64_t value) = 0;
267 
268   // Called by the metrics reporter to report a histogram.
269   //
270   // This is called similarly to ReportCounter, but instead of receiving a single value, it receives
271   // a vector of the value in each bucket. Additionally, the function receives the lower and upper
272   // limit for the histogram. Note that these limits are the allowed limits, and not the observed
273   // range. Values below the lower limit will be counted in the first bucket, and values above the
274   // upper limit will be counted in the last bucket. Backends should store the minimum and maximum
275   // values to allow comparisons across module versions, since the minimum and maximum values may
276   // change over time.
277   virtual void ReportHistogram(DatumId histogram_type,
278                                int64_t minimum_value,
279                                int64_t maximum_value,
280                                const std::vector<uint32_t>& buckets) = 0;
281 
282   // Called by the metrics reporter to indicate that the current metrics report is complete.
283   virtual void EndReport() = 0;
284 
285   template <DatumId counter_type, typename T>
286   friend class MetricsCounter;
287   template <DatumId counter_type, typename T>
288   friend class MetricsDeltaCounter;
289   template <DatumId histogram_type, size_t num_buckets, int64_t low_value, int64_t high_value>
290   friend class MetricsHistogram;
291   template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
292   friend class MetricsAccumulator;
293   template <DatumId datum_id, typename T>
294   friend class MetricsAverage;
295   friend class ArtMetrics;
296 };
297 
298 template <typename value_t>
299 class MetricsBase {
300  public:
301   virtual void Add(value_t value) = 0;
~MetricsBase()302   virtual ~MetricsBase() { }
303 
304  private:
305   // Is the metric "null", i.e. never updated or freshly reset?
306   // Used for testing purpose only.
307   virtual bool IsNull() const = 0;
308 
309   ART_FRIEND_TEST(gc::HeapTest, GCMetrics);
310 };
311 
312 template <DatumId counter_type, typename T = uint64_t>
313 class MetricsCounter : public MetricsBase<T> {
314  public:
315   using value_t = T;
316   explicit constexpr MetricsCounter(uint64_t value = 0) : value_{value} {
317     // Ensure we do not have any unnecessary data in this class.
318     // Adding intptr_t to accommodate vtable, and rounding up to incorporate
319     // padding.
320     static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
321                   == RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
322   }
323 
AddOne()324   void AddOne() { Add(1u); }
Add(value_t value)325   void Add(value_t value) override {
326     value_.fetch_add(value, std::memory_order_relaxed);
327   }
328 
Report(const std::vector<MetricsBackend * > & backends)329   void Report(const std::vector<MetricsBackend*>& backends) const {
330     for (MetricsBackend* backend : backends) {
331       backend->ReportCounter(counter_type, Value());
332     }
333   }
334 
335  protected:
Reset()336   void Reset() { value_ = 0; }
Value()337   value_t Value() const { return value_.load(std::memory_order_relaxed); }
338 
339  private:
IsNull()340   bool IsNull() const override { return Value() == 0; }
341 
342   std::atomic<value_t> value_;
343   static_assert(std::atomic<value_t>::is_always_lock_free);
344 
345   friend class ArtMetrics;
346   friend jlong art::VMRuntime_getFullGcCount(JNIEnv* env, jclass klass);
347 };
348 
349 template <DatumId datum_id, typename T = uint64_t>
350 class MetricsAverage final : public MetricsCounter<datum_id, T> {
351  public:
352   using value_t = T;
353   using count_t = T;
354   explicit constexpr MetricsAverage(uint64_t value = 0, uint64_t count = 0) :
355       MetricsCounter<datum_id, value_t>(value), count_(count) {
356     // Ensure we do not have any unnecessary data in this class.
357     // Adding intptr_t to accommodate vtable, and rounding up to incorporate
358     // padding.
359     static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
360                   == RoundUp(sizeof(intptr_t) + sizeof(value_t) + sizeof(count_t),
361                              sizeof(uint64_t)));
362   }
363 
364   // We use release memory-order here and then acquire in Report() to ensure
365   // that at least the non-racy reads/writes to this metric are consistent. This
366   // doesn't guarantee the atomicity of the change to both fields, but that
367   // may not be desired because:
368   // 1. The metric eventually becomes consistent.
369   // 2. For sufficiently large count_, a few data points which are off shouldn't
370   // make a huge difference to the reporter.
Add(value_t value)371   void Add(value_t value) override {
372     MetricsCounter<datum_id, value_t>::Add(value);
373     count_.fetch_add(1, std::memory_order_release);
374   }
375 
Report(const std::vector<MetricsBackend * > & backends)376   void Report(const std::vector<MetricsBackend*>& backends) const {
377     count_t value = MetricsCounter<datum_id, value_t>::Value();
378     count_t count = count_.load(std::memory_order_acquire);
379     // Avoid divide-by-0.
380     count_t average_value = count != 0 ? value / count : 0;
381     for (MetricsBackend* backend : backends) {
382       backend->ReportCounter(datum_id, average_value);
383     }
384   }
385 
386  protected:
Reset()387   void Reset() {
388     count_ = 0;
389     MetricsCounter<datum_id, value_t>::Reset();
390   }
391 
392  private:
Count()393   count_t Count() const { return count_.load(std::memory_order_relaxed); }
394 
IsNull()395   bool IsNull() const override { return Count() == 0; }
396 
397   std::atomic<count_t> count_;
398   static_assert(std::atomic<count_t>::is_always_lock_free);
399 
400   friend class ArtMetrics;
401 };
402 
403 template <DatumId datum_id, typename T = uint64_t>
404 class MetricsDeltaCounter : public MetricsBase<T> {
405  public:
406   using value_t = T;
407 
408   explicit constexpr MetricsDeltaCounter(uint64_t value = 0) : value_{value} {
409     // Ensure we do not have any unnecessary data in this class.
410     // Adding intptr_t to accommodate vtable, and rounding up to incorporate
411     // padding.
412     static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
413                   RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
414   }
415 
Add(value_t value)416   void Add(value_t value) override {
417     value_.fetch_add(value, std::memory_order_relaxed);
418   }
AddOne()419   void AddOne() { Add(1u); }
420 
ReportAndReset(const std::vector<MetricsBackend * > & backends)421   void ReportAndReset(const std::vector<MetricsBackend*>& backends) {
422     value_t value = value_.exchange(0, std::memory_order_relaxed);
423     for (MetricsBackend* backend : backends) {
424       backend->ReportCounter(datum_id, value);
425     }
426   }
427 
Reset()428   void Reset() { value_ = 0; }
429 
430  private:
Value()431   value_t Value() const { return value_.load(std::memory_order_relaxed); }
432 
IsNull()433   bool IsNull() const override { return Value() == 0; }
434 
435   std::atomic<value_t> value_;
436   static_assert(std::atomic<value_t>::is_always_lock_free);
437 
438   friend class ArtMetrics;
439 };
440 
441 template <DatumId histogram_type_,
442           size_t num_buckets_,
443           int64_t minimum_value_,
444           int64_t maximum_value_>
445 class MetricsHistogram final : public MetricsBase<int64_t> {
446   static_assert(num_buckets_ >= 1);
447   static_assert(minimum_value_ < maximum_value_);
448 
449  public:
450   using value_t = uint32_t;
451 
MetricsHistogram()452   constexpr MetricsHistogram() : buckets_{} {
453     // Ensure we do not have any unnecessary data in this class.
454     // Adding intptr_t to accommodate vtable, and rounding up to incorporate
455     // padding.
456     static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
457                   == RoundUp(sizeof(intptr_t) + sizeof(value_t) * num_buckets_, sizeof(uint64_t)));
458   }
459 
Add(int64_t value)460   void Add(int64_t value) override {
461     const size_t i = FindBucketId(value);
462     buckets_[i].fetch_add(1u, std::memory_order_relaxed);
463   }
464 
Report(const std::vector<MetricsBackend * > & backends)465   void Report(const std::vector<MetricsBackend*>& backends) const {
466     for (MetricsBackend* backend : backends) {
467       backend->ReportHistogram(histogram_type_, minimum_value_, maximum_value_, GetBuckets());
468     }
469   }
470 
471  protected:
Reset()472   void Reset() {
473     for (auto& bucket : buckets_) {
474       bucket = 0;
475     }
476   }
477 
478  private:
FindBucketId(int64_t value)479   inline constexpr size_t FindBucketId(int64_t value) const {
480     // Values below the minimum are clamped into the first bucket.
481     if (value <= minimum_value_) {
482       return 0;
483     }
484     // Values above the maximum are clamped into the last bucket.
485     if (value >= maximum_value_) {
486       return num_buckets_ - 1;
487     }
488     // Otherise, linearly interpolate the value into the right bucket
489     constexpr size_t bucket_width = maximum_value_ - minimum_value_;
490     return static_cast<size_t>(value - minimum_value_) * num_buckets_ / bucket_width;
491   }
492 
GetBuckets()493   std::vector<value_t> GetBuckets() const {
494     // The loads from buckets_ will all be memory_order_seq_cst, which means they will be acquire
495     // loads. This is a stricter memory order than is needed, but this should not be a
496     // performance-critical section of code.
497     return std::vector<value_t>{buckets_.begin(), buckets_.end()};
498   }
499 
IsNull()500   bool IsNull() const override {
501     std::vector<value_t> buckets = GetBuckets();
502     return std::all_of(buckets.cbegin(), buckets.cend(), [](value_t i) { return i == 0; });
503   }
504 
505   std::array<std::atomic<value_t>, num_buckets_> buckets_;
506   static_assert(std::atomic<value_t>::is_always_lock_free);
507 
508   friend class ArtMetrics;
509 };
510 
511 template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
512 class MetricsAccumulator final : MetricsBase<T> {
513  public:
514   explicit constexpr MetricsAccumulator(T value = 0) : value_{value} {
515     // Ensure we do not have any unnecessary data in this class.
516     // Adding intptr_t to accommodate vtable, and rounding up to incorporate
517     // padding.
518     static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
519                   RoundUp(sizeof(intptr_t) + sizeof(T), sizeof(uint64_t)));
520   }
521 
Add(T value)522   void Add(T value) override {
523     T current = value_.load(std::memory_order_relaxed);
524     T new_value;
525     do {
526       new_value = AccumulatorFunction(current, value);
527       // If the value didn't change, don't bother storing it.
528       if (current == new_value) {
529         break;
530       }
531     } while (!value_.compare_exchange_weak(
532         current, new_value, std::memory_order_relaxed));
533   }
534 
535   // Report the metric as a counter, since this has only a single value.
Report(MetricsBackend * backend)536   void Report(MetricsBackend* backend) const {
537     backend->ReportCounter(datum_id, static_cast<uint64_t>(Value()));
538   }
539 
540  protected:
Reset()541   void Reset() {
542     value_ = 0;
543   }
544 
545  private:
Value()546   T Value() const { return value_.load(std::memory_order_relaxed); }
547 
IsNull()548   bool IsNull() const override { return Value() == 0; }
549 
550   std::atomic<T> value_;
551 
552   friend class ArtMetrics;
553 };
554 
555 // Base class for formatting metrics into different formats
556 // (human-readable text, JSON, etc.)
557 class MetricsFormatter {
558  public:
559   virtual ~MetricsFormatter() = default;
560 
561   virtual void FormatBeginReport(uint64_t timestamp_since_start_ms,
562                                  const std::optional<SessionData>& session_data) = 0;
563   virtual void FormatEndReport() = 0;
564   virtual void FormatReportCounter(DatumId counter_type, uint64_t value) = 0;
565   virtual void FormatReportHistogram(DatumId histogram_type,
566                                      int64_t low_value,
567                                      int64_t high_value,
568                                      const std::vector<uint32_t>& buckets) = 0;
569   virtual std::string GetAndResetBuffer() = 0;
570 
571  protected:
572   const std::string version = "1.0";
573 };
574 
575 // Formatter outputting metrics in human-readable text format
576 class TextFormatter : public MetricsFormatter {
577  public:
578   TextFormatter() = default;
579 
580   void FormatBeginReport(uint64_t timestamp_millis,
581                          const std::optional<SessionData>& session_data) override;
582 
583   void FormatReportCounter(DatumId counter_type, uint64_t value) override;
584 
585   void FormatReportHistogram(DatumId histogram_type,
586                              int64_t low_value,
587                              int64_t high_value,
588                              const std::vector<uint32_t>& buckets) override;
589 
590   void FormatEndReport() override;
591 
592   std::string GetAndResetBuffer() override;
593 
594  private:
595   std::ostringstream os_;
596 };
597 
598 // Formatter outputting metrics in XML format
599 class XmlFormatter : public MetricsFormatter {
600  public:
601   XmlFormatter() = default;
602 
603   void FormatBeginReport(uint64_t timestamp_millis,
604                          const std::optional<SessionData>& session_data) override;
605 
606   void FormatReportCounter(DatumId counter_type, uint64_t value) override;
607 
608   void FormatReportHistogram(DatumId histogram_type,
609                              int64_t low_value,
610                              int64_t high_value,
611                              const std::vector<uint32_t>& buckets) override;
612 
613   void FormatEndReport() override;
614 
615   std::string GetAndResetBuffer() override;
616 
617  private:
618   tinyxml2::XMLDocument document_;
619 };
620 
621 // A backend that writes metrics to a string.
622 // The format of the metrics' output is delegated
623 // to the MetricsFormatter class.
624 //
625 // This is used as a base for LogBackend and FileBackend.
626 class StringBackend : public MetricsBackend {
627  public:
628   explicit StringBackend(std::unique_ptr<MetricsFormatter> formatter);
629 
630   void BeginOrUpdateSession(const SessionData& session_data) override;
631 
632   void BeginReport(uint64_t timestamp_millis) override;
633 
634   void ReportCounter(DatumId counter_type, uint64_t value) override;
635 
636   void ReportHistogram(DatumId histogram_type,
637                        int64_t low_value,
638                        int64_t high_value,
639                        const std::vector<uint32_t>& buckets) override;
640 
641   void EndReport() override;
642 
643   std::string GetAndResetBuffer();
644 
645  private:
646   std::unique_ptr<MetricsFormatter> formatter_;
647   std::optional<SessionData> session_data_;
648 };
649 
650 // A backend that writes metrics in human-readable format to the log (i.e. logcat).
651 class LogBackend : public StringBackend {
652  public:
653   explicit LogBackend(std::unique_ptr<MetricsFormatter> formatter,
654                       android::base::LogSeverity level);
655 
656   void BeginReport(uint64_t timestamp_millis) override;
657   void EndReport() override;
658 
659  private:
660   android::base::LogSeverity level_;
661 };
662 
663 // A backend that writes metrics to a file.
664 class FileBackend : public StringBackend {
665  public:
666   explicit FileBackend(std::unique_ptr<MetricsFormatter> formatter,
667                        const std::string& filename);
668 
669   void BeginReport(uint64_t timestamp_millis) override;
670   void EndReport() override;
671 
672  private:
673   std::string filename_;
674 };
675 
676 /**
677  * AutoTimer simplifies time-based metrics collection.
678  *
679  * Several modes are supported. In the default case, the timer starts immediately and stops when it
680  * goes out of scope. Example:
681  *
682  *     {
683  *       AutoTimer timer{metric};
684  *       DoStuff();
685  *       // timer stops and updates metric automatically here.
686  *     }
687  *
688  * You can also stop the timer early:
689  *
690  *     timer.Stop();
691  *
692  * Finally, you can choose to not automatically start the timer at the beginning by passing false as
693  * the second argument to the constructor:
694  *
695  *     AutoTimer timer{metric, false};
696  *     DoNotTimeThis();
697  *     timer.Start();
698  *     TimeThis();
699  *
700  * Manually started timers will still automatically stop in the destructor, but they can be manually
701  * stopped as well.
702  *
703  * Note that AutoTimer makes calls to MicroTime(), so this may not be suitable on critical paths, or
704  * in cases where the counter needs to be started and stopped on different threads.
705  */
706 template <typename Metric>
707 class AutoTimer {
708  public:
709   explicit AutoTimer(Metric* metric, bool autostart = true)
710       : running_{false}, start_time_microseconds_{}, metric_{metric} {
711     if (autostart) {
712       Start();
713     }
714   }
715 
~AutoTimer()716   ~AutoTimer() {
717     if (running_) {
718       Stop();
719     }
720   }
721 
Start()722   void Start() {
723     DCHECK(!running_);
724     running_ = true;
725     start_time_microseconds_ = MicroTime();
726   }
727 
728   // Stops a running timer. Returns the time elapsed since starting the timer in microseconds.
Stop()729   uint64_t Stop() {
730     DCHECK(running_);
731     uint64_t stop_time_microseconds = MicroTime();
732     running_ = false;
733 
734     uint64_t elapsed_time = stop_time_microseconds - start_time_microseconds_;
735     metric_->Add(static_cast<typename Metric::value_t>(elapsed_time));
736     return elapsed_time;
737   }
738 
739  private:
740   bool running_;
741   uint64_t start_time_microseconds_;
742   Metric* metric_;
743 };
744 
745 /**
746  * This struct contains all of the metrics that ART reports.
747  */
748 class ArtMetrics {
749  public:
750   ArtMetrics();
751 
752   void ReportAllMetricsAndResetValueMetrics(const std::vector<MetricsBackend*>& backends);
753   void DumpForSigQuit(std::ostream& os);
754 
755   // Resets all metrics to their initial value. This is intended to be used after forking from the
756   // zygote so we don't attribute parent values to the child process.
757   void Reset();
758 
759 #define METRIC_ACCESSORS(name, Kind, ...)                                        \
760   Kind<DatumId::k##name, ##__VA_ARGS__>* name() { return &name##_; } \
761   const Kind<DatumId::k##name, ##__VA_ARGS__>* name() const { return &name##_; }
762   ART_METRICS(METRIC_ACCESSORS)
763 #undef METRIC_ACCESSORS
764 
765  private:
766   uint64_t beginning_timestamp_;
767   uint64_t last_report_timestamp_;
768 
769 #define METRIC(name, Kind, ...) Kind<DatumId::k##name, ##__VA_ARGS__> name##_;
770   ART_METRICS(METRIC)
771 #undef METRIC
772 };
773 
774 // Returns a human readable name for the given DatumId.
775 std::string DatumName(DatumId datum);
776 
777 // We also log the thread type for metrics so we can distinguish things that block the UI thread
778 // from things that happen on the background thread. This enum keeps track of what thread types we
779 // support.
780 enum class ThreadType {
781   kMain,
782   kBackground,
783 };
784 
785 }  // namespace metrics
786 }  // namespace art
787 
788 #pragma clang diagnostic pop  // -Wconversion
789 
790 #endif  // ART_LIBARTBASE_BASE_METRICS_METRICS_H_
791