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 
ReportAllMetrics(MetricsBackend * backend) const68 void ArtMetrics::ReportAllMetrics(MetricsBackend* backend) const {
69   backend->BeginReport(MilliTime() - beginning_timestamp_);
70 
71 #define ART_METRIC(name, Kind, ...) name()->Report(backend);
72   ART_METRICS(ART_METRIC)
73 #undef ART_METRIC
74 
75   backend->EndReport();
76 }
77 
DumpForSigQuit(std::ostream & os) const78 void ArtMetrics::DumpForSigQuit(std::ostream& os) const {
79   StringBackend backend;
80   ReportAllMetrics(&backend);
81   os << backend.GetAndResetBuffer();
82 }
83 
Reset()84 void ArtMetrics::Reset() {
85   beginning_timestamp_ = MilliTime();
86 #define ART_METRIC(name, kind, ...) name##_.Reset();
87   ART_METRICS(ART_METRIC);
88 #undef ART_METRIC
89 }
90 
StringBackend()91 StringBackend::StringBackend() {}
92 
GetAndResetBuffer()93 std::string StringBackend::GetAndResetBuffer() {
94   std::string result = os_.str();
95   os_.clear();
96   os_.str("");
97   return result;
98 }
99 
BeginOrUpdateSession(const SessionData & session_data)100 void StringBackend::BeginOrUpdateSession(const SessionData& session_data) {
101   session_data_ = session_data;
102 }
103 
BeginReport(uint64_t timestamp_since_start_ms)104 void StringBackend::BeginReport(uint64_t timestamp_since_start_ms) {
105   os_ << "\n*** ART internal metrics ***\n";
106   os_ << "  Metadata:\n";
107   os_ << "    timestamp_since_start_ms: " << timestamp_since_start_ms << "\n";
108   if (session_data_.has_value()) {
109     os_ << "    session_id: " << session_data_->session_id << "\n";
110     os_ << "    uid: " << session_data_->uid << "\n";
111     os_ << "    compilation_reason: " << CompilationReasonName(session_data_->compilation_reason)
112         << "\n";
113     os_ << "    compiler_filter: " << CompilerFilterReportingName(session_data_->compiler_filter)
114         << "\n";
115   }
116   os_ << "  Metrics:\n";
117 }
118 
EndReport()119 void StringBackend::EndReport() { os_ << "*** Done dumping ART internal metrics ***\n"; }
120 
ReportCounter(DatumId counter_type,uint64_t value)121 void StringBackend::ReportCounter(DatumId counter_type, uint64_t value) {
122   os_ << "    " << DatumName(counter_type) << ": count = " << value << "\n";
123 }
124 
ReportHistogram(DatumId histogram_type,int64_t minimum_value_,int64_t maximum_value_,const std::vector<uint32_t> & buckets)125 void StringBackend::ReportHistogram(DatumId histogram_type,
126                                     int64_t minimum_value_,
127                                     int64_t maximum_value_,
128                                     const std::vector<uint32_t>& buckets) {
129   os_ << "    " << DatumName(histogram_type) << ": range = " << minimum_value_ << "..." << maximum_value_;
130   if (buckets.size() > 0) {
131     os_ << ", buckets: ";
132     bool first = true;
133     for (const auto& count : buckets) {
134       if (!first) {
135         os_ << ",";
136       }
137       first = false;
138       os_ << count;
139     }
140     os_ << "\n";
141   } else {
142     os_ << ", no buckets\n";
143   }
144 }
145 
LogBackend(android::base::LogSeverity level)146 LogBackend::LogBackend(android::base::LogSeverity level) : level_{level} {}
147 
BeginReport(uint64_t timestamp_since_start_ms)148 void LogBackend::BeginReport(uint64_t timestamp_since_start_ms) {
149   GetAndResetBuffer();
150   StringBackend::BeginReport(timestamp_since_start_ms);
151 }
152 
EndReport()153 void LogBackend::EndReport() {
154   StringBackend::EndReport();
155   LOG_STREAM(level_) << GetAndResetBuffer();
156 }
157 
FileBackend(const std::string & filename)158 FileBackend::FileBackend(const std::string& filename) : filename_{filename} {}
159 
BeginReport(uint64_t timestamp_since_start_ms)160 void FileBackend::BeginReport(uint64_t timestamp_since_start_ms) {
161   GetAndResetBuffer();
162   StringBackend::BeginReport(timestamp_since_start_ms);
163 }
164 
EndReport()165 void FileBackend::EndReport() {
166   StringBackend::EndReport();
167   std::string error_message;
168   auto file{
169       LockedFile::Open(filename_.c_str(), O_CREAT | O_WRONLY | O_APPEND, true, &error_message)};
170   if (file.get() == nullptr) {
171     LOG(WARNING) << "Could open metrics file '" << filename_ << "': " << error_message;
172   } else {
173     if (!android::base::WriteStringToFd(GetAndResetBuffer(), file.get()->Fd())) {
174       PLOG(WARNING) << "Error writing metrics to file";
175     }
176   }
177 }
178 
179 // Make sure CompilationReasonName and CompilationReasonForName are inverses.
180 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kError)) ==
181               CompilationReason::kError);
182 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kUnknown)) ==
183               CompilationReason::kUnknown);
184 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kFirstBoot)) ==
185               CompilationReason::kFirstBoot);
186 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBootAfterOTA)) ==
187               CompilationReason::kBootAfterOTA);
188 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPostBoot)) ==
189               CompilationReason::kPostBoot);
190 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstall)) ==
191               CompilationReason::kInstall);
192 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallFast)) ==
193               CompilationReason::kInstallFast);
194 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulk)) ==
195               CompilationReason::kInstallBulk);
196 static_assert(
197     CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkSecondary)) ==
198     CompilationReason::kInstallBulkSecondary);
199 static_assert(
200     CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkDowngraded)) ==
201     CompilationReason::kInstallBulkDowngraded);
202 static_assert(CompilationReasonFromName(
203                   CompilationReasonName(CompilationReason::kInstallBulkSecondaryDowngraded)) ==
204               CompilationReason::kInstallBulkSecondaryDowngraded);
205 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBgDexopt)) ==
206               CompilationReason::kBgDexopt);
207 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kABOTA)) ==
208               CompilationReason::kABOTA);
209 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInactive)) ==
210               CompilationReason::kInactive);
211 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kShared)) ==
212               CompilationReason::kShared);
213 static_assert(
214     CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallWithDexMetadata)) ==
215     CompilationReason::kInstallWithDexMetadata);
216 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPrebuilt)) ==
217               CompilationReason::kPrebuilt);
218 static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kCmdLine)) ==
219               CompilationReason::kCmdLine);
220 
221 }  // namespace metrics
222 }  // namespace art
223 
224 #pragma clang diagnostic pop  // -Wconversion
225