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 "metrics.h"
18 
19 #include "gtest/gtest.h"
20 #include "metrics_test.h"
21 
22 #pragma clang diagnostic push
23 #pragma clang diagnostic error "-Wconversion"
24 
25 namespace art {
26 namespace metrics {
27 
28 using test::CounterValue;
29 using test::GetBuckets;
30 using test::TestBackendBase;
31 
32 class MetricsTest : public testing::Test {};
33 
34 TEST_F(MetricsTest, SimpleCounter) {
35   MetricsCounter<DatumId::kClassVerificationTotalTime> test_counter;
36 
37   EXPECT_EQ(0u, CounterValue(test_counter));
38 
39   test_counter.AddOne();
40   EXPECT_EQ(1u, CounterValue(test_counter));
41 
42   test_counter.Add(5);
43   EXPECT_EQ(6u, CounterValue(test_counter));
44 }
45 
46 TEST_F(MetricsTest, CounterTimer) {
47   MetricsCounter<DatumId::kClassVerificationTotalTime> test_counter;
48   {
49     AutoTimer timer{&test_counter};
50     // Sleep for 2µs so the counter will be greater than 0.
51     NanoSleep(2'000);
52   }
53   EXPECT_GT(CounterValue(test_counter), 0u);
54 }
55 
56 TEST_F(MetricsTest, CounterTimerExplicitStop) {
57   MetricsCounter<DatumId::kClassVerificationTotalTime> test_counter;
58   AutoTimer timer{&test_counter};
59   // Sleep for 2µs so the counter will be greater than 0.
60   NanoSleep(2'000);
61   timer.Stop();
62   EXPECT_GT(CounterValue(test_counter), 0u);
63 }
64 
65 TEST_F(MetricsTest, CounterTimerExplicitStart) {
66   MetricsCounter<DatumId::kClassVerificationTotalTime> test_counter;
67   {
68     AutoTimer timer{&test_counter, /*autostart=*/false};
69     // Sleep for 2µs so the counter will be greater than 0.
70     NanoSleep(2'000);
71   }
72   EXPECT_EQ(CounterValue(test_counter), 0u);
73 
74   {
75     AutoTimer timer{&test_counter, /*autostart=*/false};
76     timer.Start();
77     // Sleep for 2µs so the counter will be greater than 0.
78     NanoSleep(2'000);
79   }
80   EXPECT_GT(CounterValue(test_counter), 0u);
81 }
82 
83 TEST_F(MetricsTest, CounterTimerExplicitStartStop) {
84   MetricsCounter<DatumId::kClassVerificationTotalTime> test_counter;
85   AutoTimer timer{&test_counter, /*autostart=*/false};
86   // Sleep for 2µs so the counter will be greater than 0.
87   timer.Start();
88   NanoSleep(2'000);
89   timer.Stop();
90   EXPECT_GT(CounterValue(test_counter), 0u);
91 }
92 
93 TEST_F(MetricsTest, AccumulatorMetric) {
94   MetricsAccumulator<DatumId::kClassLoadingTotalTime, uint64_t, std::max> accumulator;
95 
96   std::vector<std::thread> threads;
97 
98   constexpr uint64_t kMaxValue = 100;
99 
100   for (uint64_t i = 0; i <= kMaxValue; i++) {
101     threads.emplace_back(std::thread{[&accumulator, i]() {
102       accumulator.Add(i);
103     }});
104   }
105 
106   for (auto& thread : threads) {
107     thread.join();
108   }
109 
110   EXPECT_EQ(CounterValue(accumulator), kMaxValue);
111 }
112 
113 TEST_F(MetricsTest, AverageMetric) {
114   MetricsAverage<DatumId::kClassLoadingTotalTime, uint64_t> avg;
115 
116   std::vector<std::thread> threads;
117 
118   constexpr uint64_t kMaxValue = 100;
119 
120   for (uint64_t i = 0; i <= kMaxValue; i++) {
121     threads.emplace_back(std::thread{[&avg, i]() {
122       avg.Add(i);
123     }});
124   }
125 
126   for (auto& thread : threads) {
127     thread.join();
128   }
129 
130   EXPECT_EQ(CounterValue(avg), (kMaxValue + 1) / 2);
131 }
132 
133 TEST_F(MetricsTest, DatumName) {
134   EXPECT_EQ("ClassVerificationTotalTime", DatumName(DatumId::kClassVerificationTotalTime));
135 }
136 
137 TEST_F(MetricsTest, SimpleHistogramTest) {
138   MetricsHistogram<DatumId::kYoungGcCollectionTime, 5, 0, 100> histogram;
139 
140   // bucket 0: 0-19
141   histogram.Add(10);
142 
143   // bucket 1: 20-39
144   histogram.Add(20);
145   histogram.Add(25);
146 
147   // bucket 2: 40-59
148   histogram.Add(56);
149   histogram.Add(57);
150   histogram.Add(58);
151   histogram.Add(59);
152 
153   // bucket 3: 60-79
154   histogram.Add(70);
155   histogram.Add(70);
156   histogram.Add(70);
157 
158   // bucket 4: 80-99
159   // leave this bucket empty
160 
161   std::vector<uint32_t> buckets{GetBuckets(histogram)};
162   EXPECT_EQ(1u, buckets[0u]);
163   EXPECT_EQ(2u, buckets[1u]);
164   EXPECT_EQ(4u, buckets[2u]);
165   EXPECT_EQ(3u, buckets[3u]);
166   EXPECT_EQ(0u, buckets[4u]);
167 }
168 
169 // Make sure values added outside the range of the histogram go into the first or last bucket.
170 TEST_F(MetricsTest, HistogramOutOfRangeTest) {
171   MetricsHistogram<DatumId::kYoungGcCollectionTime, 2, 0, 100> histogram;
172 
173   // bucket 0: 0-49
174   histogram.Add(-500);
175 
176   // bucket 1: 50-99
177   histogram.Add(250);
178   histogram.Add(1000);
179 
180   std::vector<uint32_t> buckets{GetBuckets(histogram)};
181   EXPECT_EQ(1u, buckets[0u]);
182   EXPECT_EQ(2u, buckets[1u]);
183 }
184 
185 // Test adding values to ArtMetrics and reporting them through a test backend.
186 TEST_F(MetricsTest, ArtMetricsReport) {
187   ArtMetrics metrics;
188 
189   // Collect some data
190   static constexpr uint64_t verification_time = 42;
191   metrics.ClassVerificationTotalTime()->Add(verification_time);
192   // Add a negative value so we are guaranteed that it lands in the first bucket.
193   metrics.YoungGcCollectionTime()->Add(-5);
194 
195   // Report and check the data
196   class TestBackend : public TestBackendBase {
197    public:
198     ~TestBackend() {
199       EXPECT_TRUE(found_counter_);
200       EXPECT_TRUE(found_histogram_);
201     }
202 
203     void ReportCounter(DatumId counter_type, uint64_t value) override {
204       if (counter_type == DatumId::kClassVerificationTotalTime) {
205         EXPECT_EQ(value, verification_time);
206         found_counter_ = true;
207       } else {
208         EXPECT_EQ(value, 0u);
209       }
210     }
211 
212     void ReportHistogram(DatumId histogram_type,
213                          int64_t,
214                          int64_t,
215                          const std::vector<uint32_t>& buckets) override {
216       if (histogram_type == DatumId::kYoungGcCollectionTime) {
217         EXPECT_EQ(buckets[0], 1u);
218         for (size_t i = 1; i < buckets.size(); ++i) {
219           EXPECT_EQ(buckets[i], 0u);
220         }
221         found_histogram_ = true;
222       } else {
223         for (size_t i = 0; i < buckets.size(); ++i) {
224           EXPECT_EQ(buckets[i], 0u);
225         }
226       }
227     }
228 
229    private:
230     bool found_counter_{false};
231     bool found_histogram_{false};
232   } backend;
233 
234   metrics.ReportAllMetrics(&backend);
235 }
236 
237 TEST_F(MetricsTest, HistogramTimer) {
238   MetricsHistogram<DatumId::kYoungGcCollectionTime, 1, 0, 100> test_histogram;
239   {
240     AutoTimer timer{&test_histogram};
241     // Sleep for 2µs so the counter will be greater than 0.
242     NanoSleep(2'000);
243   }
244 
245   EXPECT_GT(GetBuckets(test_histogram)[0], 0u);
246 }
247 
248 // Makes sure all defined metrics are included when dumping through StreamBackend.
249 TEST_F(MetricsTest, StreamBackendDumpAllMetrics) {
250   ArtMetrics metrics;
251   StringBackend backend;
252 
253   metrics.ReportAllMetrics(&backend);
254 
255   // Make sure the resulting string lists all the metrics.
256   const std::string result = backend.GetAndResetBuffer();
257 #define METRIC(name, type, ...) \
258   EXPECT_NE(result.find(DatumName(DatumId::k##name)), std::string::npos);
259   ART_METRICS(METRIC);
260 #undef METRIC
261 }
262 
263 TEST_F(MetricsTest, ResetMetrics) {
264   ArtMetrics metrics;
265 
266   // Add something to each of the metrics.
267 #define METRIC(name, type, ...) metrics.name()->Add(42);
268   ART_METRICS(METRIC)
269 #undef METRIC
270 
271   class NonZeroBackend : public TestBackendBase {
272    public:
273     void ReportCounter(DatumId, uint64_t value) override {
274       EXPECT_NE(value, 0u);
275     }
276 
277     void ReportHistogram(DatumId, int64_t, int64_t, const std::vector<uint32_t>& buckets) override {
278       bool nonzero = false;
279       for (const auto value : buckets) {
280         nonzero |= (value != 0u);
281       }
282       EXPECT_TRUE(nonzero);
283     }
284   } non_zero_backend;
285 
286   // Make sure the metrics all have a nonzero value.
287   metrics.ReportAllMetrics(&non_zero_backend);
288 
289   // Reset the metrics and make sure they are all zero again
290   metrics.Reset();
291 
292   class ZeroBackend : public TestBackendBase {
293    public:
294     void ReportCounter(DatumId, uint64_t value) override {
295       EXPECT_EQ(value, 0u);
296     }
297 
298     void ReportHistogram(DatumId, int64_t, int64_t, const std::vector<uint32_t>& buckets) override {
299       for (const auto value : buckets) {
300         EXPECT_EQ(value, 0u);
301       }
302     }
303   } zero_backend;
304 
305   metrics.ReportAllMetrics(&zero_backend);
306 }
307 
308 TEST(CompilerFilterReportingTest, FromName) {
309   ASSERT_EQ(CompilerFilterReportingFromName("error"),
310             CompilerFilterReporting::kError);
311   ASSERT_EQ(CompilerFilterReportingFromName("unknown"),
312             CompilerFilterReporting::kUnknown);
313   ASSERT_EQ(CompilerFilterReportingFromName("assume-verified"),
314             CompilerFilterReporting::kAssumeVerified);
315   ASSERT_EQ(CompilerFilterReportingFromName("extract"),
316             CompilerFilterReporting::kExtract);
317   ASSERT_EQ(CompilerFilterReportingFromName("verify"),
318             CompilerFilterReporting::kVerify);
319   ASSERT_EQ(CompilerFilterReportingFromName("space-profile"),
320             CompilerFilterReporting::kSpaceProfile);
321   ASSERT_EQ(CompilerFilterReportingFromName("space"),
322             CompilerFilterReporting::kSpace);
323   ASSERT_EQ(CompilerFilterReportingFromName("speed-profile"),
324             CompilerFilterReporting::kSpeedProfile);
325   ASSERT_EQ(CompilerFilterReportingFromName("speed"),
326             CompilerFilterReporting::kSpeed);
327   ASSERT_EQ(CompilerFilterReportingFromName("everything-profile"),
328             CompilerFilterReporting::kEverythingProfile);
329   ASSERT_EQ(CompilerFilterReportingFromName("everything"),
330             CompilerFilterReporting::kEverything);
331   ASSERT_EQ(CompilerFilterReportingFromName("run-from-apk"),
332             CompilerFilterReporting::kRunFromApk);
333   ASSERT_EQ(CompilerFilterReportingFromName("run-from-apk-fallback"),
334             CompilerFilterReporting::kRunFromApkFallback);
335 }
336 
337 TEST(CompilerFilterReportingTest, Name) {
338   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kError),
339             "error");
340   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kUnknown),
341             "unknown");
342   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kAssumeVerified),
343             "assume-verified");
344   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kExtract),
345             "extract");
346   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kVerify),
347             "verify");
348   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kSpaceProfile),
349             "space-profile");
350   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kSpace),
351             "space");
352   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kSpeedProfile),
353             "speed-profile");
354   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kSpeed),
355             "speed");
356   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kEverythingProfile),
357             "everything-profile");
358   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kEverything),
359             "everything");
360   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kRunFromApk),
361             "run-from-apk");
362   ASSERT_EQ(CompilerFilterReportingName(CompilerFilterReporting::kRunFromApkFallback),
363             "run-from-apk-fallback");
364 }
365 
366 TEST(CompilerReason, FromName) {
367   ASSERT_EQ(CompilationReasonFromName("unknown"),
368             CompilationReason::kUnknown);
369   ASSERT_EQ(CompilationReasonFromName("first-boot"),
370             CompilationReason::kFirstBoot);
371   ASSERT_EQ(CompilationReasonFromName("boot-after-ota"),
372             CompilationReason::kBootAfterOTA);
373   ASSERT_EQ(CompilationReasonFromName("post-boot"),
374             CompilationReason::kPostBoot);
375   ASSERT_EQ(CompilationReasonFromName("install"),
376             CompilationReason::kInstall);
377   ASSERT_EQ(CompilationReasonFromName("install-fast"),
378             CompilationReason::kInstallFast);
379   ASSERT_EQ(CompilationReasonFromName("install-bulk"),
380             CompilationReason::kInstallBulk);
381   ASSERT_EQ(CompilationReasonFromName("install-bulk-secondary"),
382             CompilationReason::kInstallBulkSecondary);
383   ASSERT_EQ(CompilationReasonFromName("install-bulk-downgraded"),
384             CompilationReason::kInstallBulkDowngraded);
385   ASSERT_EQ(CompilationReasonFromName("install-bulk-secondary-downgraded"),
386             CompilationReason::kInstallBulkSecondaryDowngraded);
387   ASSERT_EQ(CompilationReasonFromName("bg-dexopt"),
388             CompilationReason::kBgDexopt);
389   ASSERT_EQ(CompilationReasonFromName("ab-ota"),
390             CompilationReason::kABOTA);
391   ASSERT_EQ(CompilationReasonFromName("inactive"),
392             CompilationReason::kInactive);
393   ASSERT_EQ(CompilationReasonFromName("shared"),
394             CompilationReason::kShared);
395   ASSERT_EQ(CompilationReasonFromName("install-with-dex-metadata"),
396             CompilationReason::kInstallWithDexMetadata);
397   ASSERT_EQ(CompilationReasonFromName("prebuilt"),
398             CompilationReason::kPrebuilt);
399   ASSERT_EQ(CompilationReasonFromName("cmdline"),
400             CompilationReason::kCmdLine);
401   ASSERT_EQ(CompilationReasonFromName("error"),
402             CompilationReason::kError);
403 }
404 
405 TEST(CompilerReason, Name) {
406   ASSERT_EQ(CompilationReasonName(CompilationReason::kUnknown),
407             "unknown");
408   ASSERT_EQ(CompilationReasonName(CompilationReason::kFirstBoot),
409             "first-boot");
410   ASSERT_EQ(CompilationReasonName(CompilationReason::kBootAfterOTA),
411             "boot-after-ota");
412   ASSERT_EQ(CompilationReasonName(CompilationReason::kPostBoot),
413             "post-boot");
414   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstall),
415             "install");
416   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstallFast),
417             "install-fast");
418   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstallBulk),
419             "install-bulk");
420   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstallBulkSecondary),
421             "install-bulk-secondary");
422   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstallBulkDowngraded),
423             "install-bulk-downgraded");
424   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstallBulkSecondaryDowngraded),
425             "install-bulk-secondary-downgraded");
426   ASSERT_EQ(CompilationReasonName(CompilationReason::kBgDexopt),
427             "bg-dexopt");
428   ASSERT_EQ(CompilationReasonName(CompilationReason::kABOTA),
429             "ab-ota");
430   ASSERT_EQ(CompilationReasonName(CompilationReason::kInactive),
431             "inactive");
432   ASSERT_EQ(CompilationReasonName(CompilationReason::kShared),
433             "shared");
434   ASSERT_EQ(CompilationReasonName(CompilationReason::kInstallWithDexMetadata),
435             "install-with-dex-metadata");
436   ASSERT_EQ(CompilationReasonName(CompilationReason::kPrebuilt),
437             "prebuilt");
438   ASSERT_EQ(CompilationReasonName(CompilationReason::kCmdLine),
439             "cmdline");
440   ASSERT_EQ(CompilationReasonName(CompilationReason::kError),
441             "error");
442 }
443 }  // namespace metrics
444 }  // namespace art
445 
446 #pragma clang diagnostic pop  // -Wconversion
447