1 /*
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 
17 #include "statsd.h"
18 
19 #include "arch/instruction_set.h"
20 #include "base/compiler_filter.h"
21 #include "base/metrics/metrics.h"
22 #include "statslog_art.h"
23 
24 #pragma clang diagnostic push
25 #pragma clang diagnostic error "-Wconversion"
26 
27 namespace art {
28 namespace metrics {
29 
30 namespace {
31 
32 // EncodeDatumId returns a std::optional that provides a enum value from atoms.proto if the datum is
33 // one that we support logging to statsd. The list of datums that ART collects is a superset of what
34 // we report to statsd. Therefore, we only have mappings for the DatumIds that statsd recognizes.
35 // Also it must be noted that histograms are not handled yet by statsd yet.
36 //
37 // Other code can use whether the result of this function has a value to decide whether to report
38 // the atom to statsd.
39 //
40 // To report additional measurements to statsd, first add an entry in atoms.proto and then add an
41 // entry to this function as well.
EncodeDatumId(DatumId datum_id)42 constexpr std::optional<int32_t> EncodeDatumId(DatumId datum_id) {
43   switch (datum_id) {
44     case DatumId::kClassVerificationTotalTime:
45       return std::make_optional(
46           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_VERIFICATION_TIME_COUNTER_MICROS);
47     case DatumId::kJitMethodCompileTotalTime:
48       return std::make_optional(
49           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_JIT_METHOD_COMPILE_TIME_MICROS);
50     case DatumId::kClassLoadingTotalTime:
51       return std::make_optional(
52           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_LOADING_TIME_COUNTER_MICROS);
53     case DatumId::kClassVerificationCount:
54       return std::make_optional(
55           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_CLASS_VERIFICATION_COUNT);
56     case DatumId::kWorldStopTimeDuringGCAvg:
57       return std::make_optional(
58           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_WORLD_STOP_TIME_AVG_MICROS);
59     case DatumId::kYoungGcCount:
60       return std::make_optional(
61           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_COUNT);
62     case DatumId::kFullGcCount:
63       return std::make_optional(
64           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_COUNT);
65     case DatumId::kTotalBytesAllocated:
66       return std::make_optional(
67           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_TOTAL_BYTES_ALLOCATED);
68     case DatumId::kYoungGcCollectionTime:
69       return std::make_optional(
70           statsd::
71               ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_TIME_HISTO_MILLIS);
72     case DatumId::kFullGcCollectionTime:
73       return std::make_optional(
74           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_TIME_HISTO_MILLIS);
75     case DatumId::kYoungGcThroughput:
76       return std::make_optional(
77           statsd::
78               ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_THROUGHPUT_HISTO_MB_PER_SEC);
79     case DatumId::kFullGcThroughput:
80       return std::make_optional(
81           statsd::
82               ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_THROUGHPUT_HISTO_MB_PER_SEC);
83     case DatumId::kJitMethodCompileCount:
84       return std::make_optional(
85           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_JIT_METHOD_COMPILE_COUNT);
86     case DatumId::kYoungGcTracingThroughput:
87       return std::make_optional(
88           statsd::
89               ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_TRACING_THROUGHPUT_HISTO_MB_PER_SEC);
90     case DatumId::kFullGcTracingThroughput:
91       return std::make_optional(
92           statsd::
93               ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_TRACING_THROUGHPUT_HISTO_MB_PER_SEC);
94     case DatumId::kTotalGcCollectionTime:
95       return std::make_optional(
96           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_TOTAL_COLLECTION_TIME_MS);
97     case DatumId::kYoungGcThroughputAvg:
98       return std::make_optional(
99           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_COLLECTION_THROUGHPUT_AVG_MB_PER_SEC);
100     case DatumId::kFullGcThroughputAvg:
101       return std::make_optional(
102           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_COLLECTION_THROUGHPUT_AVG_MB_PER_SEC);
103     case DatumId::kYoungGcTracingThroughputAvg:
104       return std::make_optional(
105           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_YOUNG_GENERATION_TRACING_THROUGHPUT_AVG_MB_PER_SEC);
106     case DatumId::kFullGcTracingThroughputAvg:
107       return std::make_optional(
108           statsd::ART_DATUM_REPORTED__KIND__ART_DATUM_GC_FULL_HEAP_TRACING_THROUGHPUT_AVG_MB_PER_SEC);
109   }
110 }
111 
EncodeCompileFilter(CompilerFilterReporting filter)112 constexpr int32_t EncodeCompileFilter(CompilerFilterReporting filter) {
113   switch (filter) {
114     case CompilerFilterReporting::kAssumeVerified:
115       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED;
116     case CompilerFilterReporting::kExtract:
117       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT;
118     case CompilerFilterReporting::kVerify:
119       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY;
120     case CompilerFilterReporting::kSpaceProfile:
121       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE;
122     case CompilerFilterReporting::kSpace:
123       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE;
124     case CompilerFilterReporting::kSpeedProfile:
125       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE;
126     case CompilerFilterReporting::kSpeed:
127       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED;
128     case CompilerFilterReporting::kEverythingProfile:
129       return statsd::
130           ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE;
131     case CompilerFilterReporting::kEverything:
132       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING;
133     case CompilerFilterReporting::kError:
134       return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ERROR;
135     case CompilerFilterReporting::kUnknown:
136        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN;
137     case CompilerFilterReporting::kRunFromApk:
138        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK;
139     case CompilerFilterReporting::kRunFromApkFallback:
140        return statsd::ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
141   }
142 }
143 
EncodeCompilationReason(CompilationReason reason)144 constexpr int32_t EncodeCompilationReason(CompilationReason reason) {
145   switch (reason) {
146     case CompilationReason::kUnknown:
147       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN;
148     case CompilationReason::kABOTA:
149       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA;
150     case CompilationReason::kBgDexopt:
151       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT;
152     case CompilationReason::kError:
153       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_ERROR;
154     case CompilationReason::kFirstBoot:
155       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT;
156     case CompilationReason::kInactive:
157       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE;
158     case CompilationReason::kInstall:
159       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL;
160     case CompilationReason::kInstallWithDexMetadata:
161       return statsd::
162           ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA;
163     case CompilationReason::kShared:
164       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED;
165     case CompilationReason::kPostBoot:
166       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT;
167     case CompilationReason::kInstallBulk:
168       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK;
169     case CompilationReason::kInstallBulkSecondary:
170       return statsd::
171           ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
172     case CompilationReason::kInstallBulkDowngraded:
173       return statsd::
174           ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
175     case CompilationReason::kInstallBulkSecondaryDowngraded:
176       return statsd::
177           ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
178     case CompilationReason::kBootAfterOTA:
179       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT_AFTER_OTA;
180     case CompilationReason::kInstallFast:
181       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST;
182     case CompilationReason::kPrebuilt:
183       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_PREBUILT;
184     case CompilationReason::kCmdLine:
185       return statsd::ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_CMDLINE;
186   }
187 }
188 
EncodeInstructionSet(InstructionSet isa)189 constexpr int32_t EncodeInstructionSet(InstructionSet isa) {
190   switch (isa) {
191     case InstructionSet::kArm:
192       // Fall-through.
193     case InstructionSet::kThumb2:
194       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_ARM;
195     case InstructionSet::kArm64:
196       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_ARM64;
197     case InstructionSet::kX86:
198       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_X86;
199     case InstructionSet::kX86_64:
200       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_X86_64;
201     case InstructionSet::kNone:
202       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN;
203   }
204 }
205 
206 class StatsdBackend : public MetricsBackend {
207  public:
BeginOrUpdateSession(const SessionData & session_data)208   void BeginOrUpdateSession(const SessionData& session_data) override {
209     session_data_ = session_data;
210   }
211 
212  protected:
BeginReport(uint64_t timestamp_since_start_ms)213   void BeginReport(uint64_t timestamp_since_start_ms) override {
214     current_timestamp_ = static_cast<int64_t>(timestamp_since_start_ms);
215   }
216 
ReportCounter(DatumId counter_type,uint64_t value)217   void ReportCounter(DatumId counter_type, uint64_t value) override {
218     std::optional<int32_t> datum_id = EncodeDatumId(counter_type);
219     if (datum_id.has_value()) {
220       statsd::stats_write(
221           statsd::ART_DATUM_REPORTED,
222           session_data_.session_id,
223           session_data_.uid,
224           EncodeCompileFilter(session_data_.compiler_filter),
225           EncodeCompilationReason(session_data_.compilation_reason),
226           current_timestamp_,
227           /*thread_type=*/0,  // TODO: collect and report thread type (0 means UNKNOWN, but that
228                               // constant is not present in all branches)
229           datum_id.value(),
230           static_cast<int64_t>(value),
231           statsd::ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN,
232           statsd::ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_UNKNOWN,
233           EncodeInstructionSet(kRuntimeISA));
234     }
235   }
236 
ReportHistogram(DatumId,int64_t,int64_t,const std::vector<uint32_t> &)237   void ReportHistogram(DatumId /*histogram_type*/,
238                        int64_t /*low_value*/,
239                        int64_t /*high_value*/,
240                        const std::vector<uint32_t>& /*buckets*/) override {
241     // TODO: implement this once ArtDatumReported in atoms.proto supports histograms.
242     LOG_STREAM(DEBUG) << "Attempting to write histogram to statsd. This is not supported yet.";
243   }
244 
EndReport()245   void EndReport() override {}
246 
247  private:
248   SessionData session_data_;
249   // The timestamp provided to the last call to BeginReport
250   int64_t current_timestamp_;
251 };
252 
253 }  // namespace
254 
CreateStatsdBackend()255 std::unique_ptr<MetricsBackend> CreateStatsdBackend() { return std::make_unique<StatsdBackend>(); }
256 
257 }  // namespace metrics
258 }  // namespace art
259 
260 #pragma clang diagnostic pop  // -Wconversion
261