blob: 4a1664ad24b64b04b7a765a6f13e5cc571c0a604 [file] [log] [blame]
Eric Holkf1a2c0e2020-09-29 11:13:55 -07001/*
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
Eric Holk480d9812021-01-27 23:41:45 +000017#ifndef ART_LIBARTBASE_BASE_METRICS_METRICS_H_
18#define ART_LIBARTBASE_BASE_METRICS_METRICS_H_
Eric Holkf1a2c0e2020-09-29 11:13:55 -070019
20#include <stdint.h>
21
22#include <array>
Eric Holkc4adf542020-10-02 13:46:28 -070023#include <atomic>
Eric Holk5bb354f2021-01-13 20:38:34 +000024#include <optional>
Eric Holkc7ac91b2021-02-04 21:44:01 +000025#include <sstream>
Eric Holkf1a2c0e2020-09-29 11:13:55 -070026#include <string_view>
Eric Holk0b986f72021-01-20 22:24:06 +000027#include <thread>
Eric Holkd02435d2020-09-29 11:16:24 -070028#include <vector>
Eric Holkf1a2c0e2020-09-29 11:13:55 -070029
Eric Holk1cd030f2020-09-30 11:42:34 -070030#include "android-base/logging.h"
Lokesh Gidrae99a8582021-02-23 19:07:39 -080031#include "base/bit_utils.h"
Eric Holkf1a2c0e2020-09-29 11:13:55 -070032#include "base/time_utils.h"
Stefano Cianciullie22579c2022-05-11 09:46:58 +000033#include "tinyxml2.h"
Eric Holkf1a2c0e2020-09-29 11:13:55 -070034
35#pragma clang diagnostic push
36#pragma clang diagnostic error "-Wconversion"
37
Eric Holka4c87952021-03-05 17:58:17 -080038// See README.md in this directory for how to define metrics.
Lokesh Gidraf3686412021-06-25 21:30:30 -070039#define ART_METRICS(METRIC) \
40 METRIC(ClassLoadingTotalTime, MetricsCounter) \
41 METRIC(ClassVerificationTotalTime, MetricsCounter) \
42 METRIC(ClassVerificationCount, MetricsCounter) \
43 METRIC(WorldStopTimeDuringGCAvg, MetricsAverage) \
44 METRIC(YoungGcCount, MetricsCounter) \
45 METRIC(FullGcCount, MetricsCounter) \
46 METRIC(TotalBytesAllocated, MetricsCounter) \
47 METRIC(TotalGcCollectionTime, MetricsCounter) \
48 METRIC(YoungGcThroughputAvg, MetricsAverage) \
49 METRIC(FullGcThroughputAvg, MetricsAverage) \
50 METRIC(YoungGcTracingThroughputAvg, MetricsAverage) \
51 METRIC(FullGcTracingThroughputAvg, MetricsAverage) \
Calin Juravle9b996ce2021-06-29 16:05:38 -070052 METRIC(JitMethodCompileTotalTime, MetricsCounter) \
Lokesh Gidraf3686412021-06-25 21:30:30 -070053 METRIC(JitMethodCompileCount, MetricsCounter) \
54 METRIC(YoungGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
55 METRIC(FullGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
56 METRIC(YoungGcThroughput, MetricsHistogram, 15, 0, 10'000) \
57 METRIC(FullGcThroughput, MetricsHistogram, 15, 0, 10'000) \
58 METRIC(YoungGcTracingThroughput, MetricsHistogram, 15, 0, 10'000) \
Lokesh Gidra7f047382021-06-17 16:28:46 -070059 METRIC(FullGcTracingThroughput, MetricsHistogram, 15, 0, 10'000)
Eric Holkd02435d2020-09-29 11:16:24 -070060
61// A lot of the metrics implementation code is generated by passing one-off macros into ART_COUNTERS
62// and ART_HISTOGRAMS. This means metrics.h and metrics.cc are very #define-heavy, which can be
63// challenging to read. The alternative was to require a lot of boilerplate code for each new metric
64// added, all of which would need to be rewritten if the metrics implementation changed. Using
65// macros lets us add new metrics by adding a single line to either ART_COUNTERS or ART_HISTOGRAMS,
66// and modifying the implementation only requires changing the implementation once, instead of once
67// per metric.
68
Eric Holkf1a2c0e2020-09-29 11:13:55 -070069namespace art {
Eric Holk5bb354f2021-01-13 20:38:34 +000070
71class Runtime;
72struct RuntimeArgumentMap;
73
Eric Holkf1a2c0e2020-09-29 11:13:55 -070074namespace metrics {
75
76/**
77 * An enumeration of all ART counters and histograms.
78 */
79enum class DatumId {
Eric Holka4c87952021-03-05 17:58:17 -080080#define METRIC(name, type, ...) k##name,
81 ART_METRICS(METRIC)
82#undef METRIC
Eric Holkf1a2c0e2020-09-29 11:13:55 -070083};
84
Calin Juravlec2753e62021-06-25 15:34:09 -070085// Names come from PackageManagerServiceCompilerMapping.java
86#define REASON_NAME_LIST(V) \
87 V(kError, "error") \
88 V(kUnknown, "unknown") \
89 V(kFirstBoot, "first-boot") \
90 V(kBootAfterOTA, "boot-after-ota") \
91 V(kPostBoot, "post-boot") \
92 V(kInstall, "install") \
93 V(kInstallFast, "install-fast") \
94 V(kInstallBulk, "install-bulk") \
95 V(kInstallBulkSecondary, "install-bulk-secondary") \
96 V(kInstallBulkDowngraded, "install-bulk-downgraded") \
97 V(kInstallBulkSecondaryDowngraded, "install-bulk-secondary-downgraded") \
98 V(kBgDexopt, "bg-dexopt") \
99 V(kABOTA, "ab-ota") \
100 V(kInactive, "inactive") \
101 V(kShared, "shared") \
102 V(kInstallWithDexMetadata, "install-with-dex-metadata") \
103 V(kPrebuilt, "prebuilt") \
Nicolas Geoffraye431d132021-07-06 08:16:34 +0100104 V(kCmdLine, "cmdline") \
105 V(kVdex, "vdex")
Calin Juravlec2753e62021-06-25 15:34:09 -0700106
Eric Holkc7ac91b2021-02-04 21:44:01 +0000107// We log compilation reasons as part of the metadata we report. Since elsewhere compilation reasons
108// are specified as a string, we define them as an enum here which indicates the reasons that we
109// support.
110enum class CompilationReason {
Calin Juravlec2753e62021-06-25 15:34:09 -0700111#define REASON(kind, name) kind,
112 REASON_NAME_LIST(REASON)
113#undef REASON
Eric Holkc7ac91b2021-02-04 21:44:01 +0000114};
115
Calin Juravlec2753e62021-06-25 15:34:09 -0700116#define REASON_NAME(kind, kind_name) \
117 case CompilationReason::kind: return kind_name;
118#define REASON_FROM_NAME(kind, kind_name) \
119 if (name == kind_name) { return CompilationReason::kind; }
120
Eric Holkc7ac91b2021-02-04 21:44:01 +0000121constexpr const char* CompilationReasonName(CompilationReason reason) {
122 switch (reason) {
Calin Juravlec2753e62021-06-25 15:34:09 -0700123 REASON_NAME_LIST(REASON_NAME)
Eric Holkc7ac91b2021-02-04 21:44:01 +0000124 }
125}
126
Eric Holk722992f2021-04-06 23:12:17 +0000127constexpr CompilationReason CompilationReasonFromName(std::string_view name) {
Calin Juravlec2753e62021-06-25 15:34:09 -0700128 REASON_NAME_LIST(REASON_FROM_NAME)
Eric Holk722992f2021-04-06 23:12:17 +0000129 return CompilationReason::kError;
130}
131
Calin Juravlec2753e62021-06-25 15:34:09 -0700132#undef REASON_NAME
Stefano Cianciulli5a0eb392022-04-26 15:28:36 +0000133#undef REASON_FROM_NAME
Calin Juravlec2753e62021-06-25 15:34:09 -0700134
135#define COMPILER_FILTER_REPORTING_LIST(V) \
136 V(kError, "error") /* Error (invalid value) condition */ \
137 V(kUnknown, "unknown") /* Unknown (not set) condition */ \
138 V(kAssumeVerified, "assume-verified") /* Standard compiler filters */ \
139 V(kExtract, "extract") \
140 V(kVerify, "verify") \
141 V(kSpaceProfile, "space-profile") \
142 V(kSpace, "space") \
143 V(kSpeedProfile, "speed-profile") \
144 V(kSpeed, "speed") \
145 V(kEverythingProfile, "everything-profile") \
146 V(kEverything, "everything") \
147 V(kRunFromApk, "run-from-apk") /* Augmented compiler filters as produces by OatFileAssistant#GetOptimizationStatus */ \
148 V(kRunFromApkFallback, "run-from-apk-fallback")
149
150// Augmented compiler filter enum, used in the reporting infra.
151enum class CompilerFilterReporting {
152#define FILTER(kind, name) kind,
153 COMPILER_FILTER_REPORTING_LIST(FILTER)
154#undef FILTER
155};
156
157#define FILTER_NAME(kind, kind_name) \
158 case CompilerFilterReporting::kind: return kind_name;
159#define FILTER_FROM_NAME(kind, kind_name) \
160 if (name == kind_name) { return CompilerFilterReporting::kind; }
161
162constexpr const char* CompilerFilterReportingName(CompilerFilterReporting filter) {
163 switch (filter) {
164 COMPILER_FILTER_REPORTING_LIST(FILTER_NAME)
165 }
166}
167
168constexpr CompilerFilterReporting CompilerFilterReportingFromName(std::string_view name) {
169 COMPILER_FILTER_REPORTING_LIST(FILTER_FROM_NAME)
170 return CompilerFilterReporting::kError;
171}
172
173#undef FILTER_NAME
174#undef FILTER_FROM_NAME
175
Eric Holkc7ac91b2021-02-04 21:44:01 +0000176// SessionData contains metadata about a metrics session (basically the lifetime of an ART process).
177// This information should not change for the lifetime of the session.
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700178struct SessionData {
Eric Holkc7ac91b2021-02-04 21:44:01 +0000179 static SessionData CreateDefault();
180
181 static constexpr int64_t kInvalidSessionId = -1;
182 static constexpr int32_t kInvalidUserId = -1;
183
184 int64_t session_id;
185 int32_t uid;
186 CompilationReason compilation_reason;
Calin Juravlec2753e62021-06-25 15:34:09 -0700187 CompilerFilterReporting compiler_filter;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700188};
189
190// MetricsBackends are used by a metrics reporter to write metrics to some external location. For
191// example, a backend might write to logcat, or to a file, or to statsd.
192class MetricsBackend {
193 public:
194 virtual ~MetricsBackend() {}
195
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700196 // Begins an ART metrics session.
197 //
198 // This is called by the metrics reporter when the runtime is starting up. The session_data
199 // includes a session id which is used to correlate any metric reports with the same instance of
200 // the ART runtime. Additionally, session_data includes useful metadata such as the package name
201 // for this process.
Calin Juravlec2753e62021-06-25 15:34:09 -0700202 //
203 // It may also be called whenever there is an update to the session metadata (e.g. optimization
204 // state).
205 virtual void BeginOrUpdateSession(const SessionData& session_data) = 0;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700206
Eric Holkc7ac91b2021-02-04 21:44:01 +0000207 protected:
208 // Called by the metrics reporter to indicate that a new metrics report is starting.
Eric Holk39d529f2021-02-17 12:48:53 -0800209 virtual void BeginReport(uint64_t timestamp_since_start_ms) = 0;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700210
211 // Called by the metrics reporter to give the current value of the counter with id counter_type.
212 //
213 // This will be called multiple times for each counter based on when the metrics reporter chooses
214 // to report metrics. For example, the metrics reporter may call this at shutdown or every N
215 // minutes. Counters are not reset in between invocations, so the value should represent the
216 // total count at the point this method is called.
217 virtual void ReportCounter(DatumId counter_type, uint64_t value) = 0;
218
Eric Holkd02435d2020-09-29 11:16:24 -0700219 // Called by the metrics reporter to report a histogram.
220 //
221 // This is called similarly to ReportCounter, but instead of receiving a single value, it receives
222 // a vector of the value in each bucket. Additionally, the function receives the lower and upper
223 // limit for the histogram. Note that these limits are the allowed limits, and not the observed
224 // range. Values below the lower limit will be counted in the first bucket, and values above the
225 // upper limit will be counted in the last bucket. Backends should store the minimum and maximum
226 // values to allow comparisons across module versions, since the minimum and maximum values may
227 // change over time.
228 virtual void ReportHistogram(DatumId histogram_type,
229 int64_t minimum_value,
230 int64_t maximum_value,
231 const std::vector<uint32_t>& buckets) = 0;
232
Eric Holkc7ac91b2021-02-04 21:44:01 +0000233 // Called by the metrics reporter to indicate that the current metrics report is complete.
234 virtual void EndReport() = 0;
235
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800236 template <DatumId counter_type, typename T>
Eric Holk096bef82020-10-19 12:04:39 -0700237 friend class MetricsCounter;
238 template <DatumId histogram_type, size_t num_buckets, int64_t low_value, int64_t high_value>
Eric Holkd02435d2020-09-29 11:16:24 -0700239 friend class MetricsHistogram;
Eric Holk1043aa22021-03-09 15:41:11 -0800240 template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
241 friend class MetricsAccumulator;
Lokesh Gidraf3686412021-06-25 21:30:30 -0700242 template <DatumId datum_id, typename T>
243 friend class MetricsAverage;
Eric Holkc7ac91b2021-02-04 21:44:01 +0000244 friend class ArtMetrics;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700245};
246
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800247template <typename value_t>
248class MetricsBase {
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700249 public:
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800250 virtual void Add(value_t value) = 0;
251 virtual ~MetricsBase() { }
252};
Eric Holk1cd030f2020-09-30 11:42:34 -0700253
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800254template <DatumId counter_type, typename T = uint64_t>
Lokesh Gidraf3686412021-06-25 21:30:30 -0700255class MetricsCounter : public MetricsBase<T> {
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800256 public:
257 using value_t = T;
Eric Holkd02435d2020-09-29 11:16:24 -0700258 explicit constexpr MetricsCounter(uint64_t value = 0) : value_{value} {
259 // Ensure we do not have any unnecessary data in this class.
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800260 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
261 // padding.
262 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
263 == RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
Eric Holkd02435d2020-09-29 11:16:24 -0700264 }
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700265
Eric Holkc4adf542020-10-02 13:46:28 -0700266 void AddOne() { Add(1u); }
Eric Holk1cd030f2020-09-30 11:42:34 -0700267 void Add(value_t value) { value_.fetch_add(value, std::memory_order::memory_order_relaxed); }
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700268
Eric Holk096bef82020-10-19 12:04:39 -0700269 void Report(MetricsBackend* backend) const { backend->ReportCounter(counter_type, Value()); }
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700270
Eric Holkd91328f2021-03-17 16:21:51 -0700271 protected:
272 void Reset() {
273 value_ = 0;
274 }
275
Eric Holk096bef82020-10-19 12:04:39 -0700276 value_t Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
277
Lokesh Gidraf3686412021-06-25 21:30:30 -0700278 private:
Eric Holk1cd030f2020-09-30 11:42:34 -0700279 std::atomic<value_t> value_;
280 static_assert(std::atomic<value_t>::is_always_lock_free);
Eric Holkd91328f2021-03-17 16:21:51 -0700281
282 friend class ArtMetrics;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700283};
284
Lokesh Gidraf3686412021-06-25 21:30:30 -0700285template <DatumId datum_id, typename T = uint64_t>
286class MetricsAverage final : public MetricsCounter<datum_id, T> {
287 public:
288 using value_t = T;
289 using count_t = T;
290 explicit constexpr MetricsAverage(uint64_t value = 0, uint64_t count = 0) :
291 MetricsCounter<datum_id, value_t>(value), count_(count) {
292 // Ensure we do not have any unnecessary data in this class.
293 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
294 // padding.
295 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
296 == RoundUp(sizeof(intptr_t) + sizeof(value_t) + sizeof(count_t),
297 sizeof(uint64_t)));
298 }
299
300 // We use release memory-order here and then acquire in Report() to ensure
301 // that at least the non-racy reads/writes to this metric are consistent. This
302 // doesn't guarantee the atomicity of the change to both fields, but that
303 // may not be desired because:
304 // 1. The metric eventually becomes consistent.
305 // 2. For sufficiently large count_, a few data points which are off shouldn't
306 // make a huge difference to the reporter.
307 void Add(value_t value) {
308 MetricsCounter<datum_id, value_t>::Add(value);
309 count_.fetch_add(1, std::memory_order::memory_order_release);
310 }
311
312 void Report(MetricsBackend* backend) const {
313 count_t count = count_.load(std::memory_order::memory_order_acquire);
314 backend->ReportCounter(datum_id,
315 // Avoid divide-by-0.
316 count != 0 ? MetricsCounter<datum_id, value_t>::Value() / count : 0);
317 }
318
319 protected:
320 void Reset() {
321 count_ = 0;
322 MetricsCounter<datum_id, value_t>::Reset();
323 }
324
325 private:
326 std::atomic<count_t> count_;
327 static_assert(std::atomic<count_t>::is_always_lock_free);
328
329 friend class ArtMetrics;
330};
331
Eric Holk096bef82020-10-19 12:04:39 -0700332template <DatumId histogram_type_,
333 size_t num_buckets_,
334 int64_t minimum_value_,
335 int64_t maximum_value_>
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800336class MetricsHistogram final : public MetricsBase<int64_t> {
Eric Holkd02435d2020-09-29 11:16:24 -0700337 static_assert(num_buckets_ >= 1);
338 static_assert(minimum_value_ < maximum_value_);
339
340 public:
Eric Holk096bef82020-10-19 12:04:39 -0700341 using value_t = uint32_t;
Eric Holk1cd030f2020-09-30 11:42:34 -0700342
Eric Holkd02435d2020-09-29 11:16:24 -0700343 constexpr MetricsHistogram() : buckets_{} {
344 // Ensure we do not have any unnecessary data in this class.
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800345 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
346 // padding.
347 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
348 == RoundUp(sizeof(intptr_t) + sizeof(value_t) * num_buckets_, sizeof(uint64_t)));
Eric Holkd02435d2020-09-29 11:16:24 -0700349 }
350
351 void Add(int64_t value) {
352 const size_t i = FindBucketId(value);
Eric Holkc4adf542020-10-02 13:46:28 -0700353 buckets_[i].fetch_add(1u, std::memory_order::memory_order_relaxed);
Eric Holkd02435d2020-09-29 11:16:24 -0700354 }
355
Eric Holk096bef82020-10-19 12:04:39 -0700356 void Report(MetricsBackend* backend) const {
357 backend->ReportHistogram(histogram_type_, minimum_value_, maximum_value_, GetBuckets());
Eric Holkd02435d2020-09-29 11:16:24 -0700358 }
359
Eric Holkd91328f2021-03-17 16:21:51 -0700360 protected:
361 void Reset() {
362 for (auto& bucket : buckets_) {
363 bucket = 0;
364 }
365 }
366
Eric Holkd02435d2020-09-29 11:16:24 -0700367 private:
368 inline constexpr size_t FindBucketId(int64_t value) const {
369 // Values below the minimum are clamped into the first bucket.
370 if (value <= minimum_value_) {
371 return 0;
372 }
373 // Values above the maximum are clamped into the last bucket.
374 if (value >= maximum_value_) {
375 return num_buckets_ - 1;
376 }
377 // Otherise, linearly interpolate the value into the right bucket
378 constexpr size_t bucket_width = maximum_value_ - minimum_value_;
379 return static_cast<size_t>(value - minimum_value_) * num_buckets_ / bucket_width;
380 }
381
Eric Holk096bef82020-10-19 12:04:39 -0700382 std::vector<value_t> GetBuckets() const {
383 // The loads from buckets_ will all be memory_order_seq_cst, which means they will be acquire
384 // loads. This is a stricter memory order than is needed, but this should not be a
385 // performance-critical section of code.
386 return std::vector<value_t>{buckets_.begin(), buckets_.end()};
387 }
Eric Holkd02435d2020-09-29 11:16:24 -0700388
Eric Holk096bef82020-10-19 12:04:39 -0700389 std::array<std::atomic<value_t>, num_buckets_> buckets_;
390 static_assert(std::atomic<value_t>::is_always_lock_free);
Eric Holkd91328f2021-03-17 16:21:51 -0700391
392 friend class ArtMetrics;
Eric Holkd02435d2020-09-29 11:16:24 -0700393};
394
Eric Holk1043aa22021-03-09 15:41:11 -0800395template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
396class MetricsAccumulator final : MetricsBase<T> {
397 public:
398 explicit constexpr MetricsAccumulator(T value = 0) : value_{value} {
399 // Ensure we do not have any unnecessary data in this class.
400 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
401 // padding.
402 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
403 RoundUp(sizeof(intptr_t) + sizeof(T), sizeof(uint64_t)));
404 }
405
406 void Add(T value) {
407 T current = value_.load(std::memory_order::memory_order_relaxed);
408 T new_value;
409 do {
410 new_value = AccumulatorFunction(current, value);
411 // If the value didn't change, don't bother storing it.
412 if (current == new_value) {
413 break;
414 }
415 } while (!value_.compare_exchange_weak(
416 current, new_value, std::memory_order::memory_order_relaxed));
417 }
418
419 // Report the metric as a counter, since this has only a single value.
420 void Report(MetricsBackend* backend) const {
421 backend->ReportCounter(datum_id, static_cast<uint64_t>(Value()));
422 }
423
424 protected:
425 void Reset() {
426 value_ = 0;
427 }
428
429 private:
430 T Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
431
432 std::atomic<T> value_;
433
434 friend class ArtMetrics;
435};
436
Stefano Cianciullie22579c2022-05-11 09:46:58 +0000437// Base class for formatting metrics into different formats
438// (human-readable text, JSON, etc.)
439class MetricsFormatter {
440 public:
441 virtual ~MetricsFormatter() = default;
442
443 virtual void FormatBeginReport(uint64_t timestamp_since_start_ms,
444 const std::optional<SessionData>& session_data) = 0;
445 virtual void FormatEndReport() = 0;
446 virtual void FormatReportCounter(DatumId counter_type, uint64_t value) = 0;
447 virtual void FormatReportHistogram(DatumId histogram_type,
448 int64_t low_value,
449 int64_t high_value,
450 const std::vector<uint32_t>& buckets) = 0;
451 virtual std::string GetAndResetBuffer() = 0;
452
453 protected:
454 const std::string version = "1.0";
455};
456
457// Formatter outputting metrics in human-readable text format
458class TextFormatter : public MetricsFormatter {
459 public:
460 TextFormatter() = default;
461
462 void FormatBeginReport(uint64_t timestamp_millis,
463 const std::optional<SessionData>& session_data) override;
464
465 void FormatReportCounter(DatumId counter_type, uint64_t value) override;
466
467 void FormatReportHistogram(DatumId histogram_type,
468 int64_t low_value,
469 int64_t high_value,
470 const std::vector<uint32_t>& buckets) override;
471
472 void FormatEndReport() override;
473
474 std::string GetAndResetBuffer() override;
475
476 private:
477 std::ostringstream os_;
478};
479
480// Formatter outputting metrics in XML format
481class XmlFormatter : public MetricsFormatter {
482 public:
483 XmlFormatter() = default;
484
485 void FormatBeginReport(uint64_t timestamp_millis,
486 const std::optional<SessionData>& session_data) override;
487
488 void FormatReportCounter(DatumId counter_type, uint64_t value) override;
489
490 void FormatReportHistogram(DatumId histogram_type,
491 int64_t low_value,
492 int64_t high_value,
493 const std::vector<uint32_t>& buckets) override;
494
495 void FormatEndReport() override;
496
497 std::string GetAndResetBuffer() override;
498
499 private:
500 tinyxml2::XMLDocument document_;
501};
502
503// A backend that writes metrics to a string.
504// The format of the metrics' output is delegated
505// to the MetricsFormatter class.
Eric Holkc7ac91b2021-02-04 21:44:01 +0000506//
507// This is used as a base for LogBackend and FileBackend.
508class StringBackend : public MetricsBackend {
Eric Holk61c71ef2020-10-19 12:04:39 -0700509 public:
Stefano Cianciullie22579c2022-05-11 09:46:58 +0000510 explicit StringBackend(std::unique_ptr<MetricsFormatter> formatter);
Eric Holk61c71ef2020-10-19 12:04:39 -0700511
Calin Juravlec2753e62021-06-25 15:34:09 -0700512 void BeginOrUpdateSession(const SessionData& session_data) override;
Eric Holkc7ac91b2021-02-04 21:44:01 +0000513
514 void BeginReport(uint64_t timestamp_millis) override;
Eric Holk61c71ef2020-10-19 12:04:39 -0700515
516 void ReportCounter(DatumId counter_type, uint64_t value) override;
517
518 void ReportHistogram(DatumId histogram_type,
519 int64_t low_value,
520 int64_t high_value,
521 const std::vector<uint32_t>& buckets) override;
522
Eric Holkc7ac91b2021-02-04 21:44:01 +0000523 void EndReport() override;
524
525 std::string GetAndResetBuffer();
526
Eric Holk61c71ef2020-10-19 12:04:39 -0700527 private:
Stefano Cianciullie22579c2022-05-11 09:46:58 +0000528 std::unique_ptr<MetricsFormatter> formatter_;
Eric Holkc7ac91b2021-02-04 21:44:01 +0000529 std::optional<SessionData> session_data_;
530};
531
532// A backend that writes metrics in human-readable format to the log (i.e. logcat).
533class LogBackend : public StringBackend {
534 public:
Stefano Cianciullie22579c2022-05-11 09:46:58 +0000535 explicit LogBackend(std::unique_ptr<MetricsFormatter> formatter,
536 android::base::LogSeverity level);
Eric Holkc7ac91b2021-02-04 21:44:01 +0000537
538 void BeginReport(uint64_t timestamp_millis) override;
539 void EndReport() override;
540
541 private:
542 android::base::LogSeverity level_;
543};
544
545// A backend that writes metrics to a file.
Eric Holkc7ac91b2021-02-04 21:44:01 +0000546class FileBackend : public StringBackend {
547 public:
Stefano Cianciullie22579c2022-05-11 09:46:58 +0000548 explicit FileBackend(std::unique_ptr<MetricsFormatter> formatter,
549 const std::string& filename);
Eric Holkc7ac91b2021-02-04 21:44:01 +0000550
551 void BeginReport(uint64_t timestamp_millis) override;
552 void EndReport() override;
553
554 private:
555 std::string filename_;
Eric Holk61c71ef2020-10-19 12:04:39 -0700556};
557
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700558/**
Eric Holk1cd030f2020-09-30 11:42:34 -0700559 * AutoTimer simplifies time-based metrics collection.
560 *
561 * Several modes are supported. In the default case, the timer starts immediately and stops when it
562 * goes out of scope. Example:
563 *
564 * {
565 * AutoTimer timer{metric};
566 * DoStuff();
567 * // timer stops and updates metric automatically here.
568 * }
569 *
570 * You can also stop the timer early:
571 *
572 * timer.Stop();
573 *
574 * Finally, you can choose to not automatically start the timer at the beginning by passing false as
575 * the second argument to the constructor:
576 *
577 * AutoTimer timer{metric, false};
578 * DoNotTimeThis();
579 * timer.Start();
580 * TimeThis();
581 *
582 * Manually started timers will still automatically stop in the destructor, but they can be manually
583 * stopped as well.
584 *
585 * Note that AutoTimer makes calls to MicroTime(), so this may not be suitable on critical paths, or
586 * in cases where the counter needs to be started and stopped on different threads.
587 */
588template <typename Metric>
589class AutoTimer {
590 public:
591 explicit AutoTimer(Metric* metric, bool autostart = true)
592 : running_{false}, start_time_microseconds_{}, metric_{metric} {
593 if (autostart) {
594 Start();
595 }
596 }
597
598 ~AutoTimer() {
599 if (running_) {
600 Stop();
601 }
602 }
603
604 void Start() {
605 DCHECK(!running_);
606 running_ = true;
607 start_time_microseconds_ = MicroTime();
608 }
609
Eric Holka79872b2020-10-01 13:09:53 -0700610 // Stops a running timer. Returns the time elapsed since starting the timer in microseconds.
611 uint64_t Stop() {
Eric Holk1cd030f2020-09-30 11:42:34 -0700612 DCHECK(running_);
613 uint64_t stop_time_microseconds = MicroTime();
614 running_ = false;
615
Eric Holka79872b2020-10-01 13:09:53 -0700616 uint64_t elapsed_time = stop_time_microseconds - start_time_microseconds_;
617 metric_->Add(static_cast<typename Metric::value_t>(elapsed_time));
618 return elapsed_time;
Eric Holk1cd030f2020-09-30 11:42:34 -0700619 }
620
621 private:
622 bool running_;
623 uint64_t start_time_microseconds_;
624 Metric* metric_;
625};
626
627/**
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700628 * This struct contains all of the metrics that ART reports.
629 */
630class ArtMetrics {
631 public:
632 ArtMetrics();
633
634 void ReportAllMetrics(MetricsBackend* backend) const;
Eric Holk61c71ef2020-10-19 12:04:39 -0700635 void DumpForSigQuit(std::ostream& os) const;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700636
Eric Holkd91328f2021-03-17 16:21:51 -0700637 // Resets all metrics to their initial value. This is intended to be used after forking from the
638 // zygote so we don't attribute parent values to the child process.
639 void Reset();
640
Eric Holka4c87952021-03-05 17:58:17 -0800641#define METRIC_ACCESSORS(name, Kind, ...) \
642 Kind<DatumId::k##name, ##__VA_ARGS__>* name() { return &name##_; } \
643 const Kind<DatumId::k##name, ##__VA_ARGS__>* name() const { return &name##_; }
644 ART_METRICS(METRIC_ACCESSORS)
645#undef METRIC_ACCESSORS
Eric Holkd02435d2020-09-29 11:16:24 -0700646
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700647 private:
Eric Holkc7ac91b2021-02-04 21:44:01 +0000648 uint64_t beginning_timestamp_;
Eric Holkd02435d2020-09-29 11:16:24 -0700649
Eric Holka4c87952021-03-05 17:58:17 -0800650#define METRIC(name, Kind, ...) Kind<DatumId::k##name, ##__VA_ARGS__> name##_;
651 ART_METRICS(METRIC)
652#undef METRIC
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700653};
654
655// Returns a human readable name for the given DatumId.
656std::string DatumName(DatumId datum);
657
Eric Holk39d529f2021-02-17 12:48:53 -0800658// We also log the thread type for metrics so we can distinguish things that block the UI thread
659// from things that happen on the background thread. This enum keeps track of what thread types we
660// support.
661enum class ThreadType {
662 kMain,
663 kBackground,
664};
665
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700666} // namespace metrics
667} // namespace art
668
669#pragma clang diagnostic pop // -Wconversion
670
Eric Holk480d9812021-01-27 23:41:45 +0000671#endif // ART_LIBARTBASE_BASE_METRICS_METRICS_H_