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