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