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