blob: 72d8365c39b599742734aba7eec7dc566c9cc958 [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 Holkc7ac91b2021-02-04 21:44:01 +000032#include "base/compiler_filter.h"
Eric Holkf1a2c0e2020-09-29 11:13:55 -070033#include "base/time_utils.h"
34
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.
39#define ART_METRICS(METRIC) \
40 METRIC(ClassLoadingTotalTime, MetricsCounter) \
41 METRIC(ClassVerificationTotalTime, MetricsCounter) \
Eric Holke7ff7ef2021-03-17 16:42:24 -070042 METRIC(ClassVerificationCount, MetricsCounter) \
Eric Holka4c87952021-03-05 17:58:17 -080043 METRIC(MutatorPauseTimeDuringGC, MetricsCounter) \
44 METRIC(YoungGcCount, MetricsCounter) \
45 METRIC(FullGcCount, MetricsCounter) \
46 METRIC(TotalBytesAllocated, MetricsCounter) \
47 METRIC(TotalGcMetaDataSize, MetricsCounter) \
48 METRIC(JitMethodCompileTime, MetricsHistogram, 15, 0, 1'000'000) \
Eric Holkb2a14162021-03-30 16:54:13 -070049 METRIC(JitMethodCompileCount, MetricsCounter) \
Eric Holka4c87952021-03-05 17:58:17 -080050 METRIC(YoungGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
51 METRIC(FullGcCollectionTime, MetricsHistogram, 15, 0, 60'000) \
52 METRIC(YoungGcThroughput, MetricsHistogram, 15, 0, 1'000) \
53 METRIC(FullGcThroughput, MetricsHistogram, 15, 0, 1'000)
Eric Holkd02435d2020-09-29 11:16:24 -070054
55// A lot of the metrics implementation code is generated by passing one-off macros into ART_COUNTERS
56// and ART_HISTOGRAMS. This means metrics.h and metrics.cc are very #define-heavy, which can be
57// challenging to read. The alternative was to require a lot of boilerplate code for each new metric
58// added, all of which would need to be rewritten if the metrics implementation changed. Using
59// macros lets us add new metrics by adding a single line to either ART_COUNTERS or ART_HISTOGRAMS,
60// and modifying the implementation only requires changing the implementation once, instead of once
61// per metric.
62
Eric Holkf1a2c0e2020-09-29 11:13:55 -070063namespace art {
Eric Holk5bb354f2021-01-13 20:38:34 +000064
65class Runtime;
66struct RuntimeArgumentMap;
67
Eric Holkf1a2c0e2020-09-29 11:13:55 -070068namespace metrics {
69
70/**
71 * An enumeration of all ART counters and histograms.
72 */
73enum class DatumId {
Eric Holka4c87952021-03-05 17:58:17 -080074#define METRIC(name, type, ...) k##name,
75 ART_METRICS(METRIC)
76#undef METRIC
Eric Holkf1a2c0e2020-09-29 11:13:55 -070077};
78
Eric Holkc7ac91b2021-02-04 21:44:01 +000079// We log compilation reasons as part of the metadata we report. Since elsewhere compilation reasons
80// are specified as a string, we define them as an enum here which indicates the reasons that we
81// support.
82enum class CompilationReason {
83 kError,
84 kUnknown,
85 kFirstBoot,
Eric Holk722992f2021-04-06 23:12:17 +000086 kBootAfterOTA,
87 kPostBoot,
Eric Holkc7ac91b2021-02-04 21:44:01 +000088 kInstall,
Eric Holk722992f2021-04-06 23:12:17 +000089 kInstallFast,
90 kInstallBulk,
91 kInstallBulkSecondary,
92 kInstallBulkDowngraded,
93 kInstallBulkSecondaryDowngraded,
Eric Holkc7ac91b2021-02-04 21:44:01 +000094 kBgDexopt,
95 kABOTA,
96 kInactive,
97 kShared,
98 kInstallWithDexMetadata,
Eric Holkb772ec82021-05-13 17:18:34 -070099 kPrebuilt,
100 kCmdLine
Eric Holkc7ac91b2021-02-04 21:44:01 +0000101};
102
103constexpr const char* CompilationReasonName(CompilationReason reason) {
104 switch (reason) {
105 case CompilationReason::kError:
Eric Holk722992f2021-04-06 23:12:17 +0000106 return "error";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000107 case CompilationReason::kUnknown:
Eric Holk722992f2021-04-06 23:12:17 +0000108 return "unknown";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000109 case CompilationReason::kFirstBoot:
Eric Holk722992f2021-04-06 23:12:17 +0000110 return "first-boot";
111 case CompilationReason::kBootAfterOTA:
112 return "boot-after-ota";
113 case CompilationReason::kPostBoot:
114 return "post-boot";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000115 case CompilationReason::kInstall:
Eric Holk722992f2021-04-06 23:12:17 +0000116 return "install";
117 case CompilationReason::kInstallFast:
118 return "install-fast";
119 case CompilationReason::kInstallBulk:
120 return "install-bulk";
121 case CompilationReason::kInstallBulkSecondary:
122 return "install-bulk-secondary";
123 case CompilationReason::kInstallBulkDowngraded:
124 return "install-bulk-downgraded";
125 case CompilationReason::kInstallBulkSecondaryDowngraded:
126 return "install-bulk-secondary-downgraded";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000127 case CompilationReason::kBgDexopt:
Eric Holk722992f2021-04-06 23:12:17 +0000128 return "bg-dexopt";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000129 case CompilationReason::kABOTA:
Eric Holk722992f2021-04-06 23:12:17 +0000130 return "ab-ota";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000131 case CompilationReason::kInactive:
Eric Holk722992f2021-04-06 23:12:17 +0000132 return "inactive";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000133 case CompilationReason::kShared:
Eric Holk722992f2021-04-06 23:12:17 +0000134 return "shared";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000135 case CompilationReason::kInstallWithDexMetadata:
Eric Holk722992f2021-04-06 23:12:17 +0000136 return "install-with-dex-metadata";
Eric Holkb772ec82021-05-13 17:18:34 -0700137 case CompilationReason::kPrebuilt:
138 return "prebuilt";
139 case CompilationReason::kCmdLine:
140 return "cmdline";
Eric Holkc7ac91b2021-02-04 21:44:01 +0000141 }
142}
143
Eric Holk722992f2021-04-06 23:12:17 +0000144constexpr CompilationReason CompilationReasonFromName(std::string_view name) {
145 // Names come from PackageManagerServiceCompilerMapping.java
146 if (name == "unknown") {
147 return CompilationReason::kUnknown;
148 }
149 if (name == "first-boot") {
150 return CompilationReason::kFirstBoot;
151 }
152 if (name == "boot-after-ota") {
153 return CompilationReason::kBootAfterOTA;
154 }
155 if (name == "post-boot") {
156 return CompilationReason::kPostBoot;
157 }
158 if (name == "install") {
159 return CompilationReason::kInstall;
160 }
161 if (name == "install-fast") {
162 return CompilationReason::kInstallFast;
163 }
164 if (name == "install-bulk") {
165 return CompilationReason::kInstallBulk;
166 }
167 if (name == "install-bulk-secondary") {
168 return CompilationReason::kInstallBulkSecondary;
169 }
170 if (name == "install-bulk-downgraded") {
171 return CompilationReason::kInstallBulkDowngraded;
172 }
173 if (name == "install-bulk-secondary-downgraded") {
174 return CompilationReason::kInstallBulkSecondaryDowngraded;
175 }
176 if (name == "bg-dexopt") {
177 return CompilationReason::kBgDexopt;
178 }
179 if (name == "ab-ota") {
180 return CompilationReason::kABOTA;
181 }
182 if (name == "inactive") {
183 return CompilationReason::kInactive;
184 }
185 if (name == "shared") {
186 return CompilationReason::kShared;
187 }
188 if (name == "install-with-dex-metadata") {
189 return CompilationReason::kInstallWithDexMetadata;
190 }
Eric Holkb772ec82021-05-13 17:18:34 -0700191 if (name == "prebuilt") {
192 return CompilationReason::kPrebuilt;
193 }
194 if (name == "cmdline") {
195 return CompilationReason::kCmdLine;
196 }
Eric Holk722992f2021-04-06 23:12:17 +0000197 return CompilationReason::kError;
198}
199
Eric Holkc7ac91b2021-02-04 21:44:01 +0000200// SessionData contains metadata about a metrics session (basically the lifetime of an ART process).
201// This information should not change for the lifetime of the session.
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700202struct SessionData {
Eric Holkc7ac91b2021-02-04 21:44:01 +0000203 static SessionData CreateDefault();
204
205 static constexpr int64_t kInvalidSessionId = -1;
206 static constexpr int32_t kInvalidUserId = -1;
207
208 int64_t session_id;
209 int32_t uid;
210 CompilationReason compilation_reason;
211 std::optional<CompilerFilter::Filter> compiler_filter;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700212};
213
214// MetricsBackends are used by a metrics reporter to write metrics to some external location. For
215// example, a backend might write to logcat, or to a file, or to statsd.
216class MetricsBackend {
217 public:
218 virtual ~MetricsBackend() {}
219
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700220 // Begins an ART metrics session.
221 //
222 // This is called by the metrics reporter when the runtime is starting up. The session_data
223 // includes a session id which is used to correlate any metric reports with the same instance of
224 // the ART runtime. Additionally, session_data includes useful metadata such as the package name
225 // for this process.
226 virtual void BeginSession(const SessionData& session_data) = 0;
227
Eric Holkc7ac91b2021-02-04 21:44:01 +0000228 protected:
229 // Called by the metrics reporter to indicate that a new metrics report is starting.
Eric Holk39d529f2021-02-17 12:48:53 -0800230 virtual void BeginReport(uint64_t timestamp_since_start_ms) = 0;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700231
232 // Called by the metrics reporter to give the current value of the counter with id counter_type.
233 //
234 // This will be called multiple times for each counter based on when the metrics reporter chooses
235 // to report metrics. For example, the metrics reporter may call this at shutdown or every N
236 // minutes. Counters are not reset in between invocations, so the value should represent the
237 // total count at the point this method is called.
238 virtual void ReportCounter(DatumId counter_type, uint64_t value) = 0;
239
Eric Holkd02435d2020-09-29 11:16:24 -0700240 // Called by the metrics reporter to report a histogram.
241 //
242 // This is called similarly to ReportCounter, but instead of receiving a single value, it receives
243 // a vector of the value in each bucket. Additionally, the function receives the lower and upper
244 // limit for the histogram. Note that these limits are the allowed limits, and not the observed
245 // range. Values below the lower limit will be counted in the first bucket, and values above the
246 // upper limit will be counted in the last bucket. Backends should store the minimum and maximum
247 // values to allow comparisons across module versions, since the minimum and maximum values may
248 // change over time.
249 virtual void ReportHistogram(DatumId histogram_type,
250 int64_t minimum_value,
251 int64_t maximum_value,
252 const std::vector<uint32_t>& buckets) = 0;
253
Eric Holkc7ac91b2021-02-04 21:44:01 +0000254 // Called by the metrics reporter to indicate that the current metrics report is complete.
255 virtual void EndReport() = 0;
256
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800257 template <DatumId counter_type, typename T>
Eric Holk096bef82020-10-19 12:04:39 -0700258 friend class MetricsCounter;
259 template <DatumId histogram_type, size_t num_buckets, int64_t low_value, int64_t high_value>
Eric Holkd02435d2020-09-29 11:16:24 -0700260 friend class MetricsHistogram;
Eric Holk1043aa22021-03-09 15:41:11 -0800261 template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
262 friend class MetricsAccumulator;
Eric Holkc7ac91b2021-02-04 21:44:01 +0000263 friend class ArtMetrics;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700264};
265
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800266template <typename value_t>
267class MetricsBase {
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700268 public:
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800269 virtual void Add(value_t value) = 0;
270 virtual ~MetricsBase() { }
271};
Eric Holk1cd030f2020-09-30 11:42:34 -0700272
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800273template <DatumId counter_type, typename T = uint64_t>
274class MetricsCounter final : public MetricsBase<T> {
275 public:
276 using value_t = T;
Eric Holkd02435d2020-09-29 11:16:24 -0700277 explicit constexpr MetricsCounter(uint64_t value = 0) : value_{value} {
278 // Ensure we do not have any unnecessary data in this class.
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800279 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
280 // padding.
281 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
282 == RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
Eric Holkd02435d2020-09-29 11:16:24 -0700283 }
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700284
Eric Holkc4adf542020-10-02 13:46:28 -0700285 void AddOne() { Add(1u); }
Eric Holk1cd030f2020-09-30 11:42:34 -0700286 void Add(value_t value) { value_.fetch_add(value, std::memory_order::memory_order_relaxed); }
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700287
Eric Holk096bef82020-10-19 12:04:39 -0700288 void Report(MetricsBackend* backend) const { backend->ReportCounter(counter_type, Value()); }
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700289
Eric Holkd91328f2021-03-17 16:21:51 -0700290 protected:
291 void Reset() {
292 value_ = 0;
293 }
294
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700295 private:
Eric Holk096bef82020-10-19 12:04:39 -0700296 value_t Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
297
Eric Holk1cd030f2020-09-30 11:42:34 -0700298 std::atomic<value_t> value_;
299 static_assert(std::atomic<value_t>::is_always_lock_free);
Eric Holkd91328f2021-03-17 16:21:51 -0700300
301 friend class ArtMetrics;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700302};
303
Eric Holk096bef82020-10-19 12:04:39 -0700304template <DatumId histogram_type_,
305 size_t num_buckets_,
306 int64_t minimum_value_,
307 int64_t maximum_value_>
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800308class MetricsHistogram final : public MetricsBase<int64_t> {
Eric Holkd02435d2020-09-29 11:16:24 -0700309 static_assert(num_buckets_ >= 1);
310 static_assert(minimum_value_ < maximum_value_);
311
312 public:
Eric Holk096bef82020-10-19 12:04:39 -0700313 using value_t = uint32_t;
Eric Holk1cd030f2020-09-30 11:42:34 -0700314
Eric Holkd02435d2020-09-29 11:16:24 -0700315 constexpr MetricsHistogram() : buckets_{} {
316 // Ensure we do not have any unnecessary data in this class.
Lokesh Gidrae99a8582021-02-23 19:07:39 -0800317 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
318 // padding.
319 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
320 == RoundUp(sizeof(intptr_t) + sizeof(value_t) * num_buckets_, sizeof(uint64_t)));
Eric Holkd02435d2020-09-29 11:16:24 -0700321 }
322
323 void Add(int64_t value) {
324 const size_t i = FindBucketId(value);
Eric Holkc4adf542020-10-02 13:46:28 -0700325 buckets_[i].fetch_add(1u, std::memory_order::memory_order_relaxed);
Eric Holkd02435d2020-09-29 11:16:24 -0700326 }
327
Eric Holk096bef82020-10-19 12:04:39 -0700328 void Report(MetricsBackend* backend) const {
329 backend->ReportHistogram(histogram_type_, minimum_value_, maximum_value_, GetBuckets());
Eric Holkd02435d2020-09-29 11:16:24 -0700330 }
331
Eric Holkd91328f2021-03-17 16:21:51 -0700332 protected:
333 void Reset() {
334 for (auto& bucket : buckets_) {
335 bucket = 0;
336 }
337 }
338
Eric Holkd02435d2020-09-29 11:16:24 -0700339 private:
340 inline constexpr size_t FindBucketId(int64_t value) const {
341 // Values below the minimum are clamped into the first bucket.
342 if (value <= minimum_value_) {
343 return 0;
344 }
345 // Values above the maximum are clamped into the last bucket.
346 if (value >= maximum_value_) {
347 return num_buckets_ - 1;
348 }
349 // Otherise, linearly interpolate the value into the right bucket
350 constexpr size_t bucket_width = maximum_value_ - minimum_value_;
351 return static_cast<size_t>(value - minimum_value_) * num_buckets_ / bucket_width;
352 }
353
Eric Holk096bef82020-10-19 12:04:39 -0700354 std::vector<value_t> GetBuckets() const {
355 // The loads from buckets_ will all be memory_order_seq_cst, which means they will be acquire
356 // loads. This is a stricter memory order than is needed, but this should not be a
357 // performance-critical section of code.
358 return std::vector<value_t>{buckets_.begin(), buckets_.end()};
359 }
Eric Holkd02435d2020-09-29 11:16:24 -0700360
Eric Holk096bef82020-10-19 12:04:39 -0700361 std::array<std::atomic<value_t>, num_buckets_> buckets_;
362 static_assert(std::atomic<value_t>::is_always_lock_free);
Eric Holkd91328f2021-03-17 16:21:51 -0700363
364 friend class ArtMetrics;
Eric Holkd02435d2020-09-29 11:16:24 -0700365};
366
Eric Holk1043aa22021-03-09 15:41:11 -0800367template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)>
368class MetricsAccumulator final : MetricsBase<T> {
369 public:
370 explicit constexpr MetricsAccumulator(T value = 0) : value_{value} {
371 // Ensure we do not have any unnecessary data in this class.
372 // Adding intptr_t to accommodate vtable, and rounding up to incorporate
373 // padding.
374 static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
375 RoundUp(sizeof(intptr_t) + sizeof(T), sizeof(uint64_t)));
376 }
377
378 void Add(T value) {
379 T current = value_.load(std::memory_order::memory_order_relaxed);
380 T new_value;
381 do {
382 new_value = AccumulatorFunction(current, value);
383 // If the value didn't change, don't bother storing it.
384 if (current == new_value) {
385 break;
386 }
387 } while (!value_.compare_exchange_weak(
388 current, new_value, std::memory_order::memory_order_relaxed));
389 }
390
391 // Report the metric as a counter, since this has only a single value.
392 void Report(MetricsBackend* backend) const {
393 backend->ReportCounter(datum_id, static_cast<uint64_t>(Value()));
394 }
395
396 protected:
397 void Reset() {
398 value_ = 0;
399 }
400
401 private:
402 T Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
403
404 std::atomic<T> value_;
405
406 friend class ArtMetrics;
407};
408
Eric Holkc7ac91b2021-02-04 21:44:01 +0000409// A backend that writes metrics in a human-readable format to a string.
410//
411// This is used as a base for LogBackend and FileBackend.
412class StringBackend : public MetricsBackend {
Eric Holk61c71ef2020-10-19 12:04:39 -0700413 public:
Eric Holkc7ac91b2021-02-04 21:44:01 +0000414 StringBackend();
Eric Holk61c71ef2020-10-19 12:04:39 -0700415
416 void BeginSession(const SessionData& session_data) override;
Eric Holkc7ac91b2021-02-04 21:44:01 +0000417
418 void BeginReport(uint64_t timestamp_millis) override;
Eric Holk61c71ef2020-10-19 12:04:39 -0700419
420 void ReportCounter(DatumId counter_type, uint64_t value) override;
421
422 void ReportHistogram(DatumId histogram_type,
423 int64_t low_value,
424 int64_t high_value,
425 const std::vector<uint32_t>& buckets) override;
426
Eric Holkc7ac91b2021-02-04 21:44:01 +0000427 void EndReport() override;
428
429 std::string GetAndResetBuffer();
430
Eric Holk61c71ef2020-10-19 12:04:39 -0700431 private:
Eric Holkc7ac91b2021-02-04 21:44:01 +0000432 std::ostringstream os_;
433 std::optional<SessionData> session_data_;
434};
435
436// A backend that writes metrics in human-readable format to the log (i.e. logcat).
437class LogBackend : public StringBackend {
438 public:
439 explicit LogBackend(android::base::LogSeverity level);
440
441 void BeginReport(uint64_t timestamp_millis) override;
442 void EndReport() override;
443
444 private:
445 android::base::LogSeverity level_;
446};
447
448// A backend that writes metrics to a file.
449//
450// These are currently written in the same human-readable format used by StringBackend and
451// LogBackend, but we will probably want a more machine-readable format in the future.
452class FileBackend : public StringBackend {
453 public:
Greg Kaiser271662c2021-02-10 06:44:08 -0800454 explicit FileBackend(const std::string& filename);
Eric Holkc7ac91b2021-02-04 21:44:01 +0000455
456 void BeginReport(uint64_t timestamp_millis) override;
457 void EndReport() override;
458
459 private:
460 std::string filename_;
Eric Holk61c71ef2020-10-19 12:04:39 -0700461};
462
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700463/**
Eric Holk1cd030f2020-09-30 11:42:34 -0700464 * AutoTimer simplifies time-based metrics collection.
465 *
466 * Several modes are supported. In the default case, the timer starts immediately and stops when it
467 * goes out of scope. Example:
468 *
469 * {
470 * AutoTimer timer{metric};
471 * DoStuff();
472 * // timer stops and updates metric automatically here.
473 * }
474 *
475 * You can also stop the timer early:
476 *
477 * timer.Stop();
478 *
479 * Finally, you can choose to not automatically start the timer at the beginning by passing false as
480 * the second argument to the constructor:
481 *
482 * AutoTimer timer{metric, false};
483 * DoNotTimeThis();
484 * timer.Start();
485 * TimeThis();
486 *
487 * Manually started timers will still automatically stop in the destructor, but they can be manually
488 * stopped as well.
489 *
490 * Note that AutoTimer makes calls to MicroTime(), so this may not be suitable on critical paths, or
491 * in cases where the counter needs to be started and stopped on different threads.
492 */
493template <typename Metric>
494class AutoTimer {
495 public:
496 explicit AutoTimer(Metric* metric, bool autostart = true)
497 : running_{false}, start_time_microseconds_{}, metric_{metric} {
498 if (autostart) {
499 Start();
500 }
501 }
502
503 ~AutoTimer() {
504 if (running_) {
505 Stop();
506 }
507 }
508
509 void Start() {
510 DCHECK(!running_);
511 running_ = true;
512 start_time_microseconds_ = MicroTime();
513 }
514
Eric Holka79872b2020-10-01 13:09:53 -0700515 // Stops a running timer. Returns the time elapsed since starting the timer in microseconds.
516 uint64_t Stop() {
Eric Holk1cd030f2020-09-30 11:42:34 -0700517 DCHECK(running_);
518 uint64_t stop_time_microseconds = MicroTime();
519 running_ = false;
520
Eric Holka79872b2020-10-01 13:09:53 -0700521 uint64_t elapsed_time = stop_time_microseconds - start_time_microseconds_;
522 metric_->Add(static_cast<typename Metric::value_t>(elapsed_time));
523 return elapsed_time;
Eric Holk1cd030f2020-09-30 11:42:34 -0700524 }
525
526 private:
527 bool running_;
528 uint64_t start_time_microseconds_;
529 Metric* metric_;
530};
531
532/**
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700533 * This struct contains all of the metrics that ART reports.
534 */
535class ArtMetrics {
536 public:
537 ArtMetrics();
538
539 void ReportAllMetrics(MetricsBackend* backend) const;
Eric Holk61c71ef2020-10-19 12:04:39 -0700540 void DumpForSigQuit(std::ostream& os) const;
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700541
Eric Holkd91328f2021-03-17 16:21:51 -0700542 // Resets all metrics to their initial value. This is intended to be used after forking from the
543 // zygote so we don't attribute parent values to the child process.
544 void Reset();
545
Eric Holka4c87952021-03-05 17:58:17 -0800546#define METRIC_ACCESSORS(name, Kind, ...) \
547 Kind<DatumId::k##name, ##__VA_ARGS__>* name() { return &name##_; } \
548 const Kind<DatumId::k##name, ##__VA_ARGS__>* name() const { return &name##_; }
549 ART_METRICS(METRIC_ACCESSORS)
550#undef METRIC_ACCESSORS
Eric Holkd02435d2020-09-29 11:16:24 -0700551
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700552 private:
Eric Holkc7ac91b2021-02-04 21:44:01 +0000553 uint64_t beginning_timestamp_;
Eric Holkd02435d2020-09-29 11:16:24 -0700554
Eric Holka4c87952021-03-05 17:58:17 -0800555#define METRIC(name, Kind, ...) Kind<DatumId::k##name, ##__VA_ARGS__> name##_;
556 ART_METRICS(METRIC)
557#undef METRIC
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700558};
559
560// Returns a human readable name for the given DatumId.
561std::string DatumName(DatumId datum);
562
Eric Holk39d529f2021-02-17 12:48:53 -0800563// We also log the thread type for metrics so we can distinguish things that block the UI thread
564// from things that happen on the background thread. This enum keeps track of what thread types we
565// support.
566enum class ThreadType {
567 kMain,
568 kBackground,
569};
570
Eric Holkf1a2c0e2020-09-29 11:13:55 -0700571} // namespace metrics
572} // namespace art
573
574#pragma clang diagnostic pop // -Wconversion
575
Eric Holk480d9812021-01-27 23:41:45 +0000576#endif // ART_LIBARTBASE_BASE_METRICS_METRICS_H_