1 /*
2  * Copyright (C) 2018 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 #include <vector>
17 
18 #include "FieldValue.h"
19 #include "HashableDimensionKey.h"
20 #include "benchmark/benchmark.h"
21 #include "logd/LogEvent.h"
22 #include "stats_log_util.h"
23 #include "tests/statsd_test_util.h"
24 
25 namespace android {
26 namespace os {
27 namespace statsd {
28 
29 using std::vector;
30 
CreateDurationMetricConfig_NoLink_AND_CombinationCondition(DurationMetric::AggregationType aggregationType,bool addExtraDimensionInCondition)31 static StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
32         DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
33     StatsdConfig config;
34     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
35     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
36     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
37     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
38     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
39     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
40 
41     auto scheduledJobPredicate = CreateScheduledJobPredicate();
42     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
43     dimensions->set_field(util::SCHEDULED_JOB_STATE_CHANGED);
44     dimensions->add_child()->set_field(2);  // job name field.
45 
46     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
47 
48     auto isSyncingPredicate = CreateIsSyncingPredicate();
49     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
50     *syncDimension =
51             CreateAttributionUidAndTagDimensions(util::SYNC_STATE_CHANGED, {Position::FIRST});
52     if (addExtraDimensionInCondition) {
53         syncDimension->add_child()->set_field(2 /* name field*/);
54     }
55 
56     *config.add_predicate() = scheduledJobPredicate;
57     *config.add_predicate() = screenIsOffPredicate;
58     *config.add_predicate() = isSyncingPredicate;
59     auto combinationPredicate = config.add_predicate();
60     combinationPredicate->set_id(StringToId("CombinationPredicate"));
61     combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
62     addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
63     addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
64 
65     auto metric = config.add_duration_metric();
66     metric->set_bucket(FIVE_MINUTES);
67     metric->set_id(StringToId("scheduledJob"));
68     metric->set_what(scheduledJobPredicate.id());
69     metric->set_condition(combinationPredicate->id());
70     metric->set_aggregation_type(aggregationType);
71     auto dimensionWhat = metric->mutable_dimensions_in_what();
72     dimensionWhat->set_field(util::SCHEDULED_JOB_STATE_CHANGED);
73     dimensionWhat->add_child()->set_field(2);  // job name field.
74     *metric->mutable_dimensions_in_condition() =
75             CreateAttributionUidAndTagDimensions(util::SYNC_STATE_CHANGED, {Position::FIRST});
76     return config;
77 }
78 
CreateDurationMetricConfig_Link_AND_CombinationCondition(DurationMetric::AggregationType aggregationType,bool addExtraDimensionInCondition)79 static StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
80         DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
81     StatsdConfig config;
82     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
83     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
84     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
85     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
86     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
87     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
88 
89     auto scheduledJobPredicate = CreateScheduledJobPredicate();
90     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
91     *dimensions =
92             CreateAttributionUidDimensions(util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
93     dimensions->add_child()->set_field(2);  // job name field.
94 
95     auto isSyncingPredicate = CreateIsSyncingPredicate();
96     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
97     *syncDimension = CreateAttributionUidDimensions(util::SYNC_STATE_CHANGED, {Position::FIRST});
98     if (addExtraDimensionInCondition) {
99         syncDimension->add_child()->set_field(2 /* name field*/);
100     }
101 
102     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
103 
104     *config.add_predicate() = scheduledJobPredicate;
105     *config.add_predicate() = screenIsOffPredicate;
106     *config.add_predicate() = isSyncingPredicate;
107     auto combinationPredicate = config.add_predicate();
108     combinationPredicate->set_id(StringToId("CombinationPredicate"));
109     combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
110     addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
111     addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
112 
113     auto metric = config.add_duration_metric();
114     metric->set_bucket(FIVE_MINUTES);
115     metric->set_id(StringToId("scheduledJob"));
116     metric->set_what(scheduledJobPredicate.id());
117     metric->set_condition(combinationPredicate->id());
118     metric->set_aggregation_type(aggregationType);
119     *metric->mutable_dimensions_in_what() =
120             CreateAttributionUidDimensions(util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
121 
122     auto links = metric->add_links();
123     links->set_condition(isSyncingPredicate.id());
124     *links->mutable_fields_in_what() =
125             CreateAttributionUidDimensions(util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
126     *links->mutable_fields_in_condition() =
127             CreateAttributionUidDimensions(util::SYNC_STATE_CHANGED, {Position::FIRST});
128     return config;
129 }
130 
BM_DurationMetricNoLink(benchmark::State & state)131 static void BM_DurationMetricNoLink(benchmark::State& state) {
132     ConfigKey cfgKey;
133     auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
134             DurationMetric::SUM, false);
135     int64_t bucketStartTimeNs = 10000000000;
136     int64_t bucketSizeNs =
137             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
138 
139     std::vector<std::unique_ptr<LogEvent>> events;
140 
141     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 11,
142                                                    android::view::DISPLAY_STATE_OFF));
143     events.push_back(
144             CreateScreenStateChangedEvent(bucketStartTimeNs + 40, android::view::DISPLAY_STATE_ON));
145 
146     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 102,
147                                                    android::view::DISPLAY_STATE_OFF));
148     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
149                                                    android::view::DISPLAY_STATE_ON));
150 
151     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 650,
152                                                    android::view::DISPLAY_STATE_OFF));
153     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
154                                                    android::view::DISPLAY_STATE_ON));
155 
156     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 640,
157                                                    android::view::DISPLAY_STATE_OFF));
158     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 650,
159                                                    android::view::DISPLAY_STATE_ON));
160 
161     vector<int> attributionUids1 = {9999};
162     vector<string> attributionTags1 = {""};
163     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 2, attributionUids1,
164                                                   attributionTags1, "job0"));
165     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
166                                                    attributionTags1, "job0"));
167 
168     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids1,
169                                                   attributionTags1, "job2"));
170     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids1,
171                                                    attributionTags1, "job2"));
172 
173     vector<int> attributionUids2 = {8888};
174     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
175                                                   attributionTags1, "job2"));
176     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
177                                                    attributionUids2, attributionTags1, "job2"));
178 
179     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 600,
180                                                   attributionUids2, attributionTags1, "job1"));
181     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
182                                                    attributionUids2, attributionTags1, "job1"));
183 
184     vector<int> attributionUids3 = {111, 222, 222};
185     vector<string> attributionTags3 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
186     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 10, attributionUids3,
187                                           attributionTags3, "ReadEmail"));
188     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 50, attributionUids3, attributionTags3,
189                                         "ReadEmail"));
190 
191     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200, attributionUids3,
192                                           attributionTags3, "ReadEmail"));
193     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids3,
194                                         attributionTags3, "ReadEmail"));
195 
196     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids3,
197                                           attributionTags3, "ReadDoc"));
198     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids3,
199                                         attributionTags3, "ReadDoc"));
200 
201     vector<int> attributionUids4 = {333, 222, 555};
202     vector<string> attributionTags4 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
203     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 401, attributionUids4,
204                                           attributionTags4, "ReadEmail"));
205     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids4,
206                                         attributionTags4, "ReadEmail"));
207     sortLogEventsByTimestamp(&events);
208 
209     while (state.KeepRunning()) {
210         auto processor =
211                 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
212         for (const auto& event : events) {
213             processor->OnLogEvent(event.get());
214         }
215     }
216 }
217 
218 BENCHMARK(BM_DurationMetricNoLink);
219 
220 
BM_DurationMetricLink(benchmark::State & state)221 static void BM_DurationMetricLink(benchmark::State& state) {
222     ConfigKey cfgKey;
223     auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
224         DurationMetric::SUM, false);
225     int64_t bucketStartTimeNs = 10000000000;
226     int64_t bucketSizeNs =
227             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
228 
229     std::vector<std::unique_ptr<LogEvent>> events;
230 
231     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 55,
232                                                    android::view::DISPLAY_STATE_OFF));
233     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 120,
234                                                    android::view::DISPLAY_STATE_ON));
235     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 121,
236                                                    android::view::DISPLAY_STATE_OFF));
237     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
238                                                    android::view::DISPLAY_STATE_ON));
239 
240     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 501,
241                                                    android::view::DISPLAY_STATE_OFF));
242     events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
243                                                    android::view::DISPLAY_STATE_ON));
244 
245     vector<int> attributionUids1 = {111};
246     vector<string> attributionTags1 = {"App1"};
247     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 1, attributionUids1,
248                                                   attributionTags1, "job1"));
249     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
250                                                    attributionTags1, "job1"));
251 
252     vector<int> attributionUids2 = {333};
253     vector<string> attributionTags2 = {"App2"};
254     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids2,
255                                                   attributionTags2, "job2"));
256     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids2,
257                                                    attributionTags2, "job2"));
258     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
259                                                   attributionTags2, "job2"));
260     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
261                                                    attributionUids2, attributionTags2, "job2"));
262 
263     vector<int> attributionUids3 = {444};
264     vector<string> attributionTags3 = {"App3"};
265     events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs - 2,
266                                                   attributionUids3, attributionTags3, "job3"));
267     events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
268                                                    attributionUids3, attributionTags3, "job3"));
269 
270     vector<int> attributionUids4 = {111, 222, 222};
271     vector<string> attributionTags4 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
272     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids4,
273                                           attributionTags4, "ReadEmail"));
274     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 110, attributionUids4, attributionTags4,
275                                         "ReadEmail"));
276 
277     vector<int> attributionUids5 = {333, 222, 555};
278     vector<string> attributionTags5 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
279     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 300, attributionUids5,
280                                           attributionTags5, "ReadEmail"));
281     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids5,
282                                         attributionTags5, "ReadEmail"));
283     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids5,
284                                           attributionTags5, "ReadDoc"));
285     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids5,
286                                         attributionTags5, "ReadDoc"));
287 
288     vector<int> attributionUids6 = {444, 222, 555};
289     vector<string> attributionTags6 = {"App3", "GMSCoreModule1", "GMSCoreModule2"};
290     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 550, attributionUids6,
291                                           attributionTags6, "ReadDoc"));
292     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 800, attributionUids6, attributionTags6,
293                                         "ReadDoc"));
294     events.push_back(CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids6,
295                                           attributionTags6, "ReadDoc"));
296     events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids6,
297                                         attributionTags6, "ReadDoc"));
298     sortLogEventsByTimestamp(&events);
299 
300     while (state.KeepRunning()) {
301         auto processor =
302                 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
303         for (const auto& event : events) {
304             processor->OnLogEvent(event.get());
305         }
306     }
307 }
308 
309 BENCHMARK(BM_DurationMetricLink);
310 
311 }  //  namespace statsd
312 }  //  namespace os
313 }  //  namespace android
314