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