// A lot of the metrics implementation code is generated by passing one-off macros into ART_COUNTERS // and ART_HISTOGRAMS. This means metrics.h and metrics.cc are very #define-heavy, which can be // challenging to read. The alternative was to require a lot of boilerplate code for each new metric // added, all of which would need to be rewritten if the metrics implementation changed. Using // macros lets us add new metrics by adding a single line to either ART_COUNTERS or ART_HISTOGRAMS, // and modifying the implementation only requires changing the implementation once, instead of once // per metric.
// NOLINTBEGIN(readability/multiline_comment) - multi-line /*...*/-style comment needed in macro. #define REASON_NAME_LIST(V) \ /* A special value indicating that the compilation reason is not successfully obtained from ART \
* due to some expected internal error. */ \
V(kAbsent, "absent") \ /* A catch-all value for compilation reasons that are not explicitly listed. Usually this means \
* the reason is a custom reason defined by an OEM. */ \
V(kOther, "other") \ /* A value representing the string literal "unknown" obtained from ART. Usually this means no \
* OAT file or no dex code. */ \
V(kUnknown, "unknown") \
V(kFirstBoot, "first-boot") \
V(kBootAfterOTA, "boot-after-ota") \
V(kPostBoot, "post-boot") \
V(kInstall, "install") \
V(kInstallFast, "install-fast") \
V(kInstallBulk, "install-bulk") \
V(kInstallBulkSecondary, "install-bulk-secondary") \
V(kInstallBulkDowngraded, "install-bulk-downgraded") \
V(kInstallBulkSecondaryDowngraded, "install-bulk-secondary-downgraded") \
V(kBgDexopt, "bg-dexopt") \
V(kABOTA, "ab-ota") \
V(kInactive, "inactive") \
V(kShared, "shared") \
V(kInstallWithDexMetadata, "install-with-dex-metadata") \
V(kPrebuilt, "prebuilt") \
V(kCmdLine, "cmdline") \
V(kVdex, "vdex") \
V(kBootAfterMainlineUpdate, "boot-after-mainline-update") \
V(kCloud, "cloud") \
V(kVdexDm, "vdex-dm") \
V(kDefDexopt, "def-dexopt") \
V(kPostUr, "post-ur") // NOLINTEND(readability/multiline_comment)
// We log compilation reasons as part of the metadata we report. Since elsewhere compilation reasons // are specified as a string, we define them as an enum here which indicates the reasons that we // support. enumclass CompilationReason { #define REASON(kind, name) kind,
REASON_NAME_LIST(REASON) #undef REASON
};
#define REASON_NAME(kind, kind_name) \ case CompilationReason::kind: return kind_name; #define REASON_FROM_NAME(kind, kind_name) \ if (name == (kind_name)) { return CompilationReason::kind; }
// NOLINTBEGIN(readability/multiline_comment) - multi-line /*...*/-style comment needed in macro. #define COMPILER_FILTER_REPORTING_LIST(V) \ /* A special value indicating that the compiler filter is not successfully obtained from ART \
* due to some expected internal error. */ \
V(kAbsent, "absent") \ /* A catch-all value for compiler filters that are not explicitly listed. Usually this is \
* unexecpted. */ \
V(kOther, "other") \ /* A value representing the string literal "unknown" obtained from ART. Usually this means no \
* dex code. */ \
V(kUnknown, "unknown") \ /* Standard compiler filters start from here. */ \
V(kAssumeVerified, "assume-verified") \
V(kExtract, "extract") \
V(kVerify, "verify") \
V(kSpaceProfile, "space-profile") \
V(kSpace, "space") \
V(kSpeedProfile, "speed-profile") \
V(kSpeed, "speed") \
V(kEverythingProfile, "everything-profile") \
V(kEverything, "everything") \ /* Augmented compiler filters produced by OatFileAssistant#GetOptimizationStatus start from \
* here. */ \
V(kRunFromApk, "run-from-apk") \
V(kRunFromApkFallback, "run-from-apk-fallback") // NOLINTEND(readability/multiline_comment)
// Augmented compiler filter enum, used in the reporting infra. enumclass CompilerFilterReporting { #define FILTER(kind, name) kind,
COMPILER_FILTER_REPORTING_LIST(FILTER) #undef FILTER
};
#define FILTER_NAME(kind, kind_name) \ case CompilerFilterReporting::kind: return kind_name; #define FILTER_FROM_NAME(kind, kind_name) \ if (name == (kind_name)) { return CompilerFilterReporting::kind; }
// SessionData contains metadata about a metrics session (basically the lifetime of an ART process). // This information should not change for the lifetime of the session. struct SessionData { static SessionData CreateDefault();
// MetricsBackends are used by a metrics reporter to write metrics to some external location. For // example, a backend might write to logcat, or to a file, or to statsd. class MetricsBackend { public: virtual ~MetricsBackend() {}
// Begins an ART metrics session. // // This is called by the metrics reporter when the runtime is starting up. The session_data // includes a session id which is used to correlate any metric reports with the same instance of // the ART runtime. Additionally, session_data includes useful metadata such as the package name // for this process. // // It may also be called whenever there is an update to the session metadata (e.g. optimization // state). virtualvoid BeginOrUpdateSession(const SessionData& session_data) = 0;
protected: // Called by the metrics reporter to indicate that a new metrics report is starting. virtualvoid BeginReport(uint64_t timestamp_since_start_ms) = 0;
// Called by the metrics reporter to give the current value of the counter with id counter_type. // // This will be called multiple times for each counter based on when the metrics reporter chooses // to report metrics. For example, the metrics reporter may call this at shutdown or every N // minutes. Counters are not reset in between invocations, so the value should represent the // total count at the point this method is called. virtualvoid ReportCounter(DatumId counter_type, uint64_t value) = 0;
// Called by the metrics reporter to report a histogram. // // This is called similarly to ReportCounter, but instead of receiving a single value, it receives // a vector of the value in each bucket. Additionally, the function receives the lower and upper // limit for the histogram. Note that these limits are the allowed limits, and not the observed // range. Values below the lower limit will be counted in the first bucket, and values above the // upper limit will be counted in the last bucket. Backends should store the minimum and maximum // values to allow comparisons across module versions, since the minimum and maximum values may // change over time. virtualvoid ReportHistogram(DatumId histogram_type,
int64_t minimum_value,
int64_t maximum_value, const std::vector<uint32_t>& buckets) = 0;
// Called by the metrics reporter to indicate that the current metrics report is complete. virtualvoid EndReport() = 0;
private: // Is the metric "null", i.e. never updated or freshly reset? // Used for testing purpose only. virtualbool IsNull() const = 0;
ART_FRIEND_TEST(gc::HeapTest, GCMetrics);
};
template <DatumId counter_type, typename T = uint64_t> class MetricsCounter : public MetricsBase<T> { public: using value_t = T; explicit constexpr MetricsCounter(uint64_t value = 0) : value_{value} { // Ensure we do not have any unnecessary data in this class. // Adding intptr_t to accommodate vtable, and rounding up to incorporate // padding.
static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
== RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
}
template <DatumId datum_id, typename T = uint64_t> class MetricsAverage final : public MetricsCounter<datum_id, T> { public: using value_t = T; using count_t = T; explicit constexpr MetricsAverage(uint64_t value = 0, uint64_t count = 0) :
MetricsCounter<datum_id, value_t>(value), count_(count) { // Ensure we do not have any unnecessary data in this class. // Adding intptr_t to accommodate vtable, and rounding up to incorporate // padding.
static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
== RoundUp(sizeof(intptr_t) + sizeof(value_t) + sizeof(count_t), sizeof(uint64_t)));
}
// We use release memory-order here and then acquire in Report() to ensure // that at least the non-racy reads/writes to this metric are consistent. This // doesn't guarantee the atomicity of the change to both fields, but that // may not be desired because: // 1. The metric eventually becomes consistent. // 2. For sufficiently large count_, a few data points which are off shouldn't // make a huge difference to the reporter. void Add(value_t value) override {
MetricsCounter<datum_id, value_t>::Add(value);
count_.fetch_add(1, std::memory_order_release);
}
template <DatumId datum_id, typename T = uint64_t> class MetricsDeltaCounter : public MetricsBase<T> { public: using value_t = T;
explicit constexpr MetricsDeltaCounter(uint64_t value = 0) : value_{value} { // Ensure we do not have any unnecessary data in this class. // Adding intptr_t to accommodate vtable, and rounding up to incorporate // padding.
static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
RoundUp(sizeof(intptr_t) + sizeof(value_t), sizeof(uint64_t)));
}
template <DatumId histogram_type_,
size_t num_buckets_,
int64_t minimum_value_,
int64_t maximum_value_> class MetricsHistogram final : public MetricsBase<int64_t> {
static_assert(num_buckets_ >= 1);
static_assert(minimum_value_ < maximum_value_);
public: using value_t = uint32_t;
constexpr MetricsHistogram() : buckets_{} { // Ensure we do not have any unnecessary data in this class. // Adding intptr_t to accommodate vtable, and rounding up to incorporate // padding.
static_assert(RoundUp(sizeof(*this), sizeof(uint64_t))
== RoundUp(sizeof(intptr_t) + sizeof(value_t) * num_buckets_, sizeof(uint64_t)));
}
private: inline constexpr size_t FindBucketId(int64_t value) const { // Values below the minimum are clamped into the first bucket. if (value <= minimum_value_) { return0;
} // Values above the maximum are clamped into the last bucket. if (value >= maximum_value_) { return num_buckets_ - 1;
} // Otherise, linearly interpolate the value into the right bucket
constexpr size_t bucket_width = maximum_value_ - minimum_value_; returnstatic_cast<size_t>(value - minimum_value_) * num_buckets_ / bucket_width;
}
std::vector<value_t> GetBuckets() const { // The loads from buckets_ will all be memory_order_seq_cst, which means they will be acquire // loads. This is a stricter memory order than is needed, but this should not be a // performance-critical section of code. return std::vector<value_t>{buckets_.begin(), buckets_.end()};
}
template <DatumId datum_id, typename T, const T& AccumulatorFunction(const T&, const T&)> class MetricsAccumulator final : MetricsBase<T> { public: explicit constexpr MetricsAccumulator(T value = 0) : value_{value} { // Ensure we do not have any unnecessary data in this class. // Adding intptr_t to accommodate vtable, and rounding up to incorporate // padding.
static_assert(RoundUp(sizeof(*this), sizeof(uint64_t)) ==
RoundUp(sizeof(intptr_t) + sizeof(T), sizeof(uint64_t)));
}
void Add(T value) override {
T current = value_.load(std::memory_order_relaxed);
T new_value; do {
new_value = AccumulatorFunction(current, value); // If the value didn't change, don't bother storing it. if (current == new_value) { break;
}
} while (!value_.compare_exchange_weak(
current, new_value, std::memory_order_relaxed));
}
// Report the metric as a counter, since this has only a single value. void Report(MetricsBackend* backend) const {
backend->ReportCounter(datum_id, static_cast<uint64_t>(Value()));
}
protected: void Reset() {
value_ = 0;
}
private:
T Value() const { return value_.load(std::memory_order_relaxed); }
// Base class for formatting metrics into different formats // (human-readable text, JSON, etc.) class MetricsFormatter { public: virtual ~MetricsFormatter() = default;
// A backend that writes metrics to a string. // The format of the metrics' output is delegated // to the MetricsFormatter class. // // This is used as a base for LogBackend and FileBackend. class StringBackend : public MetricsBackend { public: explicit StringBackend(std::unique_ptr<MetricsFormatter> formatter);
// A backend that writes metrics in human-readable format to the log (i.e. logcat). class LogBackend : public StringBackend { public: explicit LogBackend(std::unique_ptr<MetricsFormatter> formatter,
android::base::LogSeverity level);
// A backend that writes metrics to a file. class FileBackend : public StringBackend { public: explicit FileBackend(std::unique_ptr<MetricsFormatter> formatter, const std::string& filename);
// Stops a running timer. Returns the time elapsed since starting the timer in microseconds.
uint64_t Stop() {
DCHECK(running_);
uint64_t stop_time_microseconds = MicroTime();
running_ = false;
// Resets all metrics to their initial value. This is intended to be used after forking from the // zygote so we don't attribute parent values to the child process. void Reset();
// Returns a human readable name for the given DatumId.
std::string DatumName(DatumId datum);
// We also log the thread type for metrics so we can distinguish things that block the UI thread // from things that happen on the background thread. This enum keeps track of what thread types we // support. enumclass ThreadType {
kMain,
kBackground,
};
} // namespace metrics
} // namespace art
#pragma clang diagnostic pop // -Wconversion
#endif// ART_LIBARTBASE_BASE_METRICS_METRICS_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.