• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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