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 #include <sstream>
18
19 #include "android-base/file.h"
20 #include "android-base/logging.h"
21 #include "base/macros.h"
22 #include "base/scoped_flock.h"
23 #include "metrics.h"
24
25 #pragma clang diagnostic push
26 #pragma clang diagnostic error "-Wconversion"
27
28 namespace art {
29 namespace metrics {
30
DatumName(DatumId datum)31 std::string DatumName(DatumId datum) {
32 switch (datum) {
33 #define ART_METRIC(name, Kind, ...) \
34 case DatumId::k##name: \
35 return #name;
36 ART_METRICS(ART_METRIC)
37 #undef ART_METRIC
38
39 default:
40 LOG(FATAL) << "Unknown datum id: " << static_cast<unsigned>(datum);
41 UNREACHABLE();
42 }
43 }
44
CreateDefault()45 SessionData SessionData::CreateDefault() {
46 #ifdef _WIN32
47 int32_t uid = kInvalidUserId; // Windows does not support getuid();
48 #else
49 int32_t uid = static_cast<int32_t>(getuid());
50 #endif
51
52 return SessionData{
53 .session_id = kInvalidSessionId,
54 .uid = uid,
55 .compilation_reason = CompilationReason::kUnknown,
56 .compiler_filter = CompilerFilterReporting::kUnknown,
57 };
58 }
59
ArtMetrics()60 ArtMetrics::ArtMetrics()
61 : beginning_timestamp_{MilliTime()},
62 last_report_timestamp_{beginning_timestamp_}
63 #define ART_METRIC(name, Kind, ...) \
64 , name##_ {}
65 ART_METRICS(ART_METRIC)
66 #undef ART_METRIC
67 {
68 }
69
ReportAllMetricsAndResetValueMetrics(const std::vector<MetricsBackend * > & backends)70 void ArtMetrics::ReportAllMetricsAndResetValueMetrics(
71 const std::vector<MetricsBackend*>& backends) {
72 uint64_t current_timestamp_ = MilliTime();
73 for (auto& backend : backends) {
74 backend->BeginReport(current_timestamp_ - beginning_timestamp_);
75 }
76
77 #define REPORT_METRIC(name, Kind, ...) name()->Report(backends);
78 ART_EVENT_METRICS(REPORT_METRIC)
79 #undef REPORT_METRIC
80
81 // Update ART_DATUM_DELTA_TIME_ELAPSED_MS before ART Value Metrics are reported.
82 TimeElapsedDelta()->Add(current_timestamp_ - last_report_timestamp_);
83
84 #define REPORT_METRIC(name, Kind, ...) name()->ReportAndReset(backends);
85 ART_VALUE_METRICS(REPORT_METRIC)
86 #undef REPORT_METRIC
87
88 for (auto& backend : backends) {
89 backend->EndReport();
90 }
91
92 // Save the current timestamp to be able to calculate the elapsed time for the next report cycle.
93 last_report_timestamp_ = current_timestamp_;
94 }
95
DumpForSigQuit(std::ostream & os)96 void ArtMetrics::DumpForSigQuit(std::ostream& os) {
97 StringBackend backend(std::make_unique<TextFormatter>());
98 ReportAllMetricsAndResetValueMetrics({&backend});
99 os << backend.GetAndResetBuffer();
100 }
101
Reset()102 void ArtMetrics::Reset() {
103 beginning_timestamp_ = MilliTime();
104 #define RESET_METRIC(name, ...) name##_.Reset();
105 ART_METRICS(RESET_METRIC)
106 #undef RESET_METRIC
107 }
108
StringBackend(std::unique_ptr<MetricsFormatter> formatter)109 StringBackend::StringBackend(std::unique_ptr<MetricsFormatter> formatter)
110 : formatter_(std::move(formatter)) {}
111
GetAndResetBuffer()112 std::string StringBackend::GetAndResetBuffer() {
113 return formatter_->GetAndResetBuffer();
114 }
115
BeginOrUpdateSession(const SessionData & session_data)116 void StringBackend::BeginOrUpdateSession(const SessionData& session_data) {
117 session_data_ = session_data;
118 }
119
BeginReport(uint64_t timestamp_since_start_ms)120 void StringBackend::BeginReport(uint64_t timestamp_since_start_ms) {
121 formatter_->FormatBeginReport(timestamp_since_start_ms, session_data_);
122 }
123
EndReport()124 void StringBackend::EndReport() {
125 formatter_->FormatEndReport();
126 }
127
ReportCounter(DatumId counter_type,uint64_t value)128 void StringBackend::ReportCounter(DatumId counter_type, uint64_t value) {
129 formatter_->FormatReportCounter(counter_type, value);
130 }
131
ReportHistogram(DatumId histogram_type,int64_t minimum_value_,int64_t maximum_value_,const std::vector<uint32_t> & buckets)132 void StringBackend::ReportHistogram(DatumId histogram_type,
133 int64_t minimum_value_,
134 int64_t maximum_value_,
135 const std::vector<uint32_t>& buckets) {
136 formatter_->FormatReportHistogram(histogram_type, minimum_value_, maximum_value_, buckets);
137 }
138
FormatBeginReport(uint64_t timestamp_since_start_ms,const std::optional<SessionData> & session_data)139 void TextFormatter::FormatBeginReport(uint64_t timestamp_since_start_ms,
140 const std::optional<SessionData>& session_data) {
141 os_ << "\n*** ART internal metrics ***\n";
142 os_ << " Metadata:\n";
143 os_ << " timestamp_since_start_ms: " << timestamp_since_start_ms << "\n";
144 if (session_data.has_value()) {
145 os_ << " session_id: " << session_data->session_id << "\n";
146 os_ << " uid: " << session_data->uid << "\n";
147 os_ << " compilation_reason: " << CompilationReasonName(session_data->compilation_reason)
148 << "\n";
149 os_ << " compiler_filter: " << CompilerFilterReportingName(session_data->compiler_filter)
150 << "\n";
151 }
152 os_ << " Metrics:\n";
153 }
154
FormatReportCounter(DatumId counter_type,uint64_t value)155 void TextFormatter::FormatReportCounter(DatumId counter_type, uint64_t value) {
156 os_ << " " << DatumName(counter_type) << ": count = " << value << "\n";
157 }
158
FormatReportHistogram(DatumId histogram_type,int64_t minimum_value_,int64_t maximum_value_,const std::vector<uint32_t> & buckets)159 void TextFormatter::FormatReportHistogram(DatumId histogram_type,
160 int64_t minimum_value_,
161 int64_t maximum_value_,
162 const std::vector<uint32_t>& buckets) {
163 os_ << " " << DatumName(histogram_type) << ": range = "
164 << minimum_value_ << "..." << maximum_value_;
165 if (!buckets.empty()) {
166 os_ << ", buckets: ";
167 bool first = true;
168 for (const auto& count : buckets) {
169 if (!first) {
170 os_ << ",";
171 }
172 first = false;
173 os_ << count;
174 }
175 os_ << "\n";
176 } else {
177 os_ << ", no buckets\n";
178 }
179 }
180
FormatEndReport()181 void TextFormatter::FormatEndReport() {
182 os_ << "*** Done dumping ART internal metrics ***\n";
183 }
184
GetAndResetBuffer()185 std::string TextFormatter::GetAndResetBuffer() {
186 std::string result = os_.str();
187 os_.clear();
188 os_.str("");
189 return result;
190 }
191
FormatBeginReport(uint64_t timestamp_millis,const std::optional<SessionData> & session_data)192 void XmlFormatter::FormatBeginReport(uint64_t timestamp_millis,
193 const std::optional<SessionData>& session_data) {
194 tinyxml2::XMLElement* art_runtime_metrics = document_.NewElement("art_runtime_metrics");
195 document_.InsertEndChild(art_runtime_metrics);
196
197 art_runtime_metrics->InsertNewChildElement("version")->SetText(version.data());
198
199 tinyxml2::XMLElement* metadata = art_runtime_metrics->InsertNewChildElement("metadata");
200 metadata->InsertNewChildElement("timestamp_since_start_ms")->SetText(timestamp_millis);
201
202 if (session_data.has_value()) {
203 metadata->InsertNewChildElement("session_id")->SetText(session_data->session_id);
204 metadata->InsertNewChildElement("uid")->SetText(session_data->uid);
205 metadata
206 ->InsertNewChildElement("compilation_reason")
207 ->SetText(CompilationReasonName(session_data->compilation_reason));
208 metadata
209 ->InsertNewChildElement("compiler_filter")
210 ->SetText(CompilerFilterReportingName(session_data->compiler_filter));
211 }
212
213 art_runtime_metrics->InsertNewChildElement("metrics");
214 }
215
FormatReportCounter(DatumId counter_type,uint64_t value)216 void XmlFormatter::FormatReportCounter(DatumId counter_type, uint64_t value) {
217 tinyxml2::XMLElement* metrics = document_.RootElement()->FirstChildElement("metrics");
218
219 tinyxml2::XMLElement* counter = metrics->InsertNewChildElement(DatumName(counter_type).data());
220 counter->InsertNewChildElement("counter_type")->SetText("count");
221 counter->InsertNewChildElement("value")->SetText(value);
222 }
223
FormatReportHistogram(DatumId histogram_type,int64_t low_value,int64_t high_value,const std::vector<uint32_t> & buckets)224 void XmlFormatter::FormatReportHistogram(DatumId histogram_type,
225 int64_t low_value,
226 int64_t high_value,
227 const std::vector<uint32_t>& buckets) {
228 tinyxml2::XMLElement* metrics = document_.RootElement()->FirstChildElement("metrics");
229
230 tinyxml2::XMLElement* histogram =
231 metrics->InsertNewChildElement(DatumName(histogram_type).data());
232 histogram->InsertNewChildElement("counter_type")->SetText("histogram");
233 histogram->InsertNewChildElement("minimum_value")->SetText(low_value);
234 histogram->InsertNewChildElement("maximum_value")->SetText(high_value);
235
236 tinyxml2::XMLElement* buckets_element = histogram->InsertNewChildElement("buckets");
237 for (const auto& count : buckets) {
238 buckets_element->InsertNewChildElement("bucket")->SetText(count);
239 }
240 }
241
FormatEndReport()242 void XmlFormatter::FormatEndReport() {}
243
GetAndResetBuffer()244 std::string XmlFormatter::GetAndResetBuffer() {
245 tinyxml2::XMLPrinter printer(/*file=*/nullptr, /*compact=*/true);
246 document_.Print(&printer);
247 std::string result = printer.CStr();
248 document_.Clear();
249
250 return result;
251 }
252
LogBackend(std::unique_ptr<MetricsFormatter> formatter,android::base::LogSeverity level)253 LogBackend::LogBackend(std::unique_ptr<MetricsFormatter> formatter,
254 android::base::LogSeverity level)
255 : StringBackend{std::move(formatter)}, level_{level}
256 {}
257
BeginReport(uint64_t timestamp_since_start_ms)258 void LogBackend::BeginReport(uint64_t timestamp_since_start_ms) {
259 StringBackend::GetAndResetBuffer();
260 StringBackend::BeginReport(timestamp_since_start_ms);
261 }
262
EndReport()263 void LogBackend::EndReport() {
264 StringBackend::EndReport();
265 LOG_STREAM(level_) << StringBackend::GetAndResetBuffer();
266 }
267
FileBackend(std::unique_ptr<MetricsFormatter> formatter,const std::string & filename)268 FileBackend::FileBackend(std::unique_ptr<MetricsFormatter> formatter,
269 const std::string& filename)
270 : StringBackend{std::move(formatter)}, filename_{filename}
271 {}
272
BeginReport(uint64_t timestamp_since_start_ms)273 void FileBackend::BeginReport(uint64_t timestamp_since_start_ms) {
274 StringBackend::GetAndResetBuffer();
275 StringBackend::BeginReport(timestamp_since_start_ms);
276 }
277
EndReport()278 void FileBackend::EndReport() {
279 StringBackend::EndReport();
280 std::string error_message;
281 auto file{
282 LockedFile::Open(filename_.c_str(), O_CREAT | O_WRONLY | O_APPEND, true, &error_message)};
283 if (file.get() == nullptr) {
284 LOG(WARNING) << "Could open metrics file '" << filename_ << "': " << error_message;
285 } else {
286 if (!android::base::WriteStringToFd(StringBackend::GetAndResetBuffer(), file.get()->Fd())) {
287 PLOG(WARNING) << "Error writing metrics to file";
288 }
289 }
290 }
291
292 // Make sure CompilationReasonName and CompilationReasonForName are inverses.
293 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kError)) ==
294 CompilationReason::kError);
295 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kUnknown)) ==
296 CompilationReason::kUnknown);
297 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kFirstBoot)) ==
298 CompilationReason::kFirstBoot);
299 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBootAfterOTA)) ==
300 CompilationReason::kBootAfterOTA);
301 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPostBoot)) ==
302 CompilationReason::kPostBoot);
303 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstall)) ==
304 CompilationReason::kInstall);
305 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallFast)) ==
306 CompilationReason::kInstallFast);
307 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulk)) ==
308 CompilationReason::kInstallBulk);
309 static_assert(
310 CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkSecondary)) ==
311 CompilationReason::kInstallBulkSecondary);
312 static_assert(
313 CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkDowngraded)) ==
314 CompilationReason::kInstallBulkDowngraded);
315 static_assert(CompilationReasonFromName(
316 CompilationReasonName(CompilationReason::kInstallBulkSecondaryDowngraded)) ==
317 CompilationReason::kInstallBulkSecondaryDowngraded);
318 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBgDexopt)) ==
319 CompilationReason::kBgDexopt);
320 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kABOTA)) ==
321 CompilationReason::kABOTA);
322 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInactive)) ==
323 CompilationReason::kInactive);
324 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kShared)) ==
325 CompilationReason::kShared);
326 static_assert(
327 CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallWithDexMetadata)) ==
328 CompilationReason::kInstallWithDexMetadata);
329 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPrebuilt)) ==
330 CompilationReason::kPrebuilt);
331 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kCmdLine)) ==
332 CompilationReason::kCmdLine);
333 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kVdex)) ==
334 CompilationReason::kVdex);
335 static_assert(
336 CompilationReasonFromName(CompilationReasonName(CompilationReason::kBootAfterMainlineUpdate)) ==
337 CompilationReason::kBootAfterMainlineUpdate);
338
339 } // namespace metrics
340 } // namespace art
341
342 #pragma clang diagnostic pop // -Wconversion
343