blob: 2004c7d9184b06af4e1e6a44fd3a9b0493d61bfa [file] [log] [blame]
Eric Holk480d9812021-01-27 23:41:45 +00001/*
2 * Copyright (C) 2021 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
Ulyana Trafimovichdbad1ef2021-02-17 13:46:00 +000017#include "metrics_reporter.h"
Eric Holk480d9812021-01-27 23:41:45 +000018
Eric Holk480d9812021-01-27 23:41:45 +000019#include "runtime.h"
20#include "runtime_options.h"
21#include "thread-current-inl.h"
22
23#pragma clang diagnostic push
24#pragma clang diagnostic error "-Wconversion"
25
26namespace art {
27namespace metrics {
28
Eric Holk480d9812021-01-27 23:41:45 +000029std::unique_ptr<MetricsReporter> MetricsReporter::Create(ReportingConfig config, Runtime* runtime) {
30 // We can't use std::make_unique here because the MetricsReporter constructor is private.
31 return std::unique_ptr<MetricsReporter>{new MetricsReporter{std::move(config), runtime}};
32}
33
34MetricsReporter::MetricsReporter(ReportingConfig config, Runtime* runtime)
35 : config_{std::move(config)}, runtime_{runtime} {}
36
37MetricsReporter::~MetricsReporter() { MaybeStopBackgroundThread(); }
38
Eric Holkc7ac91b2021-02-04 21:44:01 +000039void MetricsReporter::MaybeStartBackgroundThread(SessionData session_data) {
40 CHECK(!thread_.has_value());
Eric Holk480d9812021-01-27 23:41:45 +000041
Eric Holkc7ac91b2021-02-04 21:44:01 +000042 thread_.emplace(&MetricsReporter::BackgroundThreadRun, this);
43
44 messages_.SendMessage(BeginSessionMessage{session_data});
Eric Holk480d9812021-01-27 23:41:45 +000045}
46
47void MetricsReporter::MaybeStopBackgroundThread() {
48 if (thread_.has_value()) {
49 messages_.SendMessage(ShutdownRequestedMessage{});
50 thread_->join();
51 }
Eric Holk480d9812021-01-27 23:41:45 +000052}
53
Eric Holkb6dda5a2021-02-04 01:09:58 +000054void MetricsReporter::NotifyStartupCompleted() {
55 if (thread_.has_value()) {
56 messages_.SendMessage(StartupCompletedMessage{});
57 }
58}
59
Eric Holk480d9812021-01-27 23:41:45 +000060void MetricsReporter::BackgroundThreadRun() {
61 LOG_STREAM(DEBUG) << "Metrics reporting thread started";
62
63 // AttachCurrentThread is needed so we can safely use the ART concurrency primitives within the
64 // messages_ MessageQueue.
Eric Holkb6dda5a2021-02-04 01:09:58 +000065 const bool attached = runtime_->AttachCurrentThread(kBackgroundThreadName,
66 /*as_daemon=*/true,
67 runtime_->GetSystemThreadGroup(),
68 /*create_peer=*/true);
Eric Holk480d9812021-01-27 23:41:45 +000069 bool running = true;
70
Eric Holkc7ac91b2021-02-04 21:44:01 +000071 // Configure the backends
72 if (config_.dump_to_logcat) {
73 backends_.emplace_back(new LogBackend(LogSeverity::INFO));
74 }
75 if (config_.dump_to_file.has_value()) {
76 backends_.emplace_back(new FileBackend(config_.dump_to_file.value()));
77 }
78
Eric Holk480d9812021-01-27 23:41:45 +000079 MaybeResetTimeout();
80
81 while (running) {
82 messages_.SwitchReceive(
Eric Holkc7ac91b2021-02-04 21:44:01 +000083 [&](BeginSessionMessage message) {
84 LOG_STREAM(DEBUG) << "Received session metadata";
85
86 for (auto& backend : backends_) {
87 backend->BeginSession(message.session_data);
88 }
89 },
Eric Holk480d9812021-01-27 23:41:45 +000090 [&]([[maybe_unused]] ShutdownRequestedMessage message) {
91 LOG_STREAM(DEBUG) << "Shutdown request received";
92 running = false;
Eric Holkc7ac91b2021-02-04 21:44:01 +000093
94 // Do one final metrics report, if enabled.
95 if (config_.report_metrics_on_shutdown) {
96 ReportMetrics();
97 }
Eric Holk480d9812021-01-27 23:41:45 +000098 },
99 [&]([[maybe_unused]] TimeoutExpiredMessage message) {
100 LOG_STREAM(DEBUG) << "Timer expired, reporting metrics";
101
102 ReportMetrics();
103
104 MaybeResetTimeout();
Eric Holkb6dda5a2021-02-04 01:09:58 +0000105 },
106 [&]([[maybe_unused]] StartupCompletedMessage message) {
107 LOG_STREAM(DEBUG) << "App startup completed, reporting metrics";
108 ReportMetrics();
Eric Holk480d9812021-01-27 23:41:45 +0000109 });
110 }
111
Eric Holkb6dda5a2021-02-04 01:09:58 +0000112 if (attached) {
113 runtime_->DetachCurrentThread();
114 }
Eric Holk480d9812021-01-27 23:41:45 +0000115 LOG_STREAM(DEBUG) << "Metrics reporting thread terminating";
116}
117
118void MetricsReporter::MaybeResetTimeout() {
119 if (config_.periodic_report_seconds.has_value()) {
120 messages_.SetTimeout(SecondsToMs(config_.periodic_report_seconds.value()));
121 }
122}
123
124void MetricsReporter::ReportMetrics() const {
Eric Holkc7ac91b2021-02-04 21:44:01 +0000125 ArtMetrics* metrics{runtime_->GetMetrics()};
Eric Holk480d9812021-01-27 23:41:45 +0000126
Eric Holkc7ac91b2021-02-04 21:44:01 +0000127 for (auto& backend : backends_) {
128 metrics->ReportAllMetrics(backend.get());
Eric Holk480d9812021-01-27 23:41:45 +0000129 }
130}
131
Eric Holkdf69bd72021-02-23 11:36:21 -0800132ReportingConfig ReportingConfig::FromRuntimeArguments(const RuntimeArgumentMap& args) {
133 using M = RuntimeArgumentMap;
Eric Holk480d9812021-01-27 23:41:45 +0000134 return {
Eric Holkdf69bd72021-02-23 11:36:21 -0800135 .dump_to_logcat = args.Exists(M::WriteMetricsToLog),
136 .dump_to_file = args.GetOptional(M::WriteMetricsToFile),
137 .report_metrics_on_shutdown = !args.Exists(M::DisableFinalMetricsReport),
138 .periodic_report_seconds = args.GetOptional(M::MetricsReportingPeriod),
Eric Holk480d9812021-01-27 23:41:45 +0000139 };
140}
141
142} // namespace metrics
143} // namespace art
144
145#pragma clang diagnostic pop // -Wconversion