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