1 /*
2  * Copyright (C) 2024 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 <memory>
18 
19 #include "benchmark/benchmark.h"
20 #include "src/statsd_config.pb.h"
21 #include "tests/statsd_test_util.h"
22 
23 using namespace std;
24 
25 namespace android {
26 namespace os {
27 namespace statsd {
28 namespace {
29 
30 const ConfigKey cfgKey(0, 12345);
31 const int numOfMetrics = 4;
32 
createExpressEventReportedEvents()33 vector<shared_ptr<LogEvent>> createExpressEventReportedEvents() {
34     vector<shared_ptr<LogEvent>> events;
35     for (int i = 0; i < numOfMetrics; i++) {
36         events.push_back(CreateTwoValueLogEvent(/* atomId */ util::EXPRESS_EVENT_REPORTED,
37                                                 /* eventTimeNs */ i,
38                                                 /* metric_id */ i % numOfMetrics, /* value */ 1));
39     }
40     return events;
41 }
42 
CreateExpressEventReportedAtomMatcher(const string & name,int64_t metricIdHash)43 AtomMatcher CreateExpressEventReportedAtomMatcher(const string& name, int64_t metricIdHash) {
44     AtomMatcher atom_matcher = CreateSimpleAtomMatcher(name, util::EXPRESS_EVENT_REPORTED);
45     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
46     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
47     field_value_matcher->set_field(1);  // metric id hash as int64
48     field_value_matcher->set_eq_int(metricIdHash);
49     return atom_matcher;
50 }
51 
createTexConfig()52 StatsdConfig createTexConfig() {
53     StatsdConfig config;
54     *config.add_atom_matcher() = CreateExpressEventReportedAtomMatcher("texMatcher1", 0);
55     *config.add_atom_matcher() = CreateExpressEventReportedAtomMatcher("texMatcher2", 1);
56     *config.add_atom_matcher() = CreateExpressEventReportedAtomMatcher("texMatcher3", 2);
57     *config.add_atom_matcher() = CreateExpressEventReportedAtomMatcher("texMatcher4", 3);
58 
59     *config.add_value_metric() =
60             createValueMetric("texValue1", config.atom_matcher(0), /* valueField */ 2,
61                               /* condition */ nullopt, /* states */ {});
62     *config.add_value_metric() =
63             createValueMetric("texValue2", config.atom_matcher(1), /* valueField */ 2,
64                               /* condition */ nullopt, /* states */ {});
65     *config.add_value_metric() =
66             createValueMetric("texValue3", config.atom_matcher(2), /* valueField */ 2,
67                               /* condition */ nullopt, /* states */ {});
68     *config.add_value_metric() =
69             createValueMetric("texValue4", config.atom_matcher(3), /* valueField */ 2,
70                               /* condition */ nullopt, /* states */ {});
71     return config;
72 }
73 
createCountMetricConfig()74 StatsdConfig createCountMetricConfig() {
75     StatsdConfig config;
76     *config.add_atom_matcher() =
77             CreateSimpleAtomMatcher("someCounterMatcher", /*atomId*/ util::EXPRESS_EVENT_REPORTED);
78 
79     CountMetric* countMetric = config.add_count_metric();
80     *countMetric = createCountMetric("CountMetricAsCounter", /* what */ config.atom_matcher(0).id(),
81                                      /* condition */ nullopt, /* states */ {});
82     countMetric->mutable_dimensions_in_what()->set_field(util::EXPRESS_EVENT_REPORTED);
83     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);
84     return config;
85 }
86 
createValueMetricConfig()87 StatsdConfig createValueMetricConfig() {
88     StatsdConfig config;
89     *config.add_atom_matcher() =
90             CreateSimpleAtomMatcher("someValueMatcher", /*atomId*/ util::EXPRESS_EVENT_REPORTED);
91 
92     ValueMetric* valueMetric = config.add_value_metric();
93     *valueMetric = createValueMetric("ValueMetricAsCounter", /* what */ config.atom_matcher(0),
94                                      /* valueField */ 2,
95                                      /* condition */ nullopt,
96                                      /* states */ {});
97     valueMetric->mutable_dimensions_in_what()->set_field(util::EXPRESS_EVENT_REPORTED);
98     valueMetric->mutable_dimensions_in_what()->add_child()->set_field(1);
99     return config;
100 }
101 
testScenario(benchmark::State & state,sp<StatsLogProcessor> & processor)102 void testScenario(benchmark::State& state, sp<StatsLogProcessor>& processor) {
103     const int64_t elevenMinutesInNanos = NS_PER_SEC * 60 * 11;
104     vector<shared_ptr<LogEvent>> events = createExpressEventReportedEvents();
105     state.counters["MetricsSize"] = processor->GetMetricsSize(cfgKey);
106     int64_t eventIndex = 0;
107     for (auto _ : state) {
108         for (int i = 0; i < 1000; i++) {
109             auto event = events[eventIndex % numOfMetrics].get();
110             event->setElapsedTimestampNs(eventIndex * 10);
111             processor->OnLogEvent(event);
112             benchmark::DoNotOptimize(processor);
113             eventIndex++;
114         }
115     }
116     vector<uint8_t> buffer;
117     processor->onDumpReport(cfgKey, elevenMinutesInNanos, true, false, ADB_DUMP, FAST, &buffer);
118     state.counters["ReportBufferSize"] = buffer.size();
119     state.counters["MetricsSizeFinal"] = processor->GetMetricsSize(cfgKey);
120 }
121 
BM_TexCounter(benchmark::State & state)122 void BM_TexCounter(benchmark::State& state) {
123     // idea is to have 1 standalone value metric with dimensions to mimic 4 tex metrics
124     // and compare performance - see BM_TexCounterAsValueMetric
125     StatsdConfig config = createTexConfig();
126     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
127     testScenario(state, processor);
128 }
129 BENCHMARK(BM_TexCounter);
130 
BM_TexCounterAsValueMetric(benchmark::State & state)131 void BM_TexCounterAsValueMetric(benchmark::State& state) {
132     // idea is to have 1 standalone value metric with dimensions to mimic 4 tex metrics
133     // and compare performance - see BM_TexCounter
134     StatsdConfig config = createValueMetricConfig();
135     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
136     testScenario(state, processor);
137 }
138 BENCHMARK(BM_TexCounterAsValueMetric);
139 
BM_TexCounterAsCountMetric(benchmark::State & state)140 void BM_TexCounterAsCountMetric(benchmark::State& state) {
141     // idea is to have 1 standalone count metric with dimensions to mimic 4 tex metrics
142     // and compare performance - see BM_TexCounter
143     StatsdConfig config = createCountMetricConfig();
144     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
145     testScenario(state, processor);
146 }
147 BENCHMARK(BM_TexCounterAsCountMetric);
148 
149 }  // anonymous namespace
150 }  // namespace statsd
151 }  // namespace os
152 }  // namespace android
153