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
141 std::vector<AttributionNodeInternal> attributions1 = {
142 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
143 CreateAttribution(222, "GMSCoreModule2")};
144
145 std::vector<AttributionNodeInternal> attributions2 = {
146 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
147 CreateAttribution(555, "GMSCoreModule2")};
148
149 std::vector<std::unique_ptr<LogEvent>> events;
150
151 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
152 bucketStartTimeNs + 11));
153 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
154 bucketStartTimeNs + 40));
155
156 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
157 bucketStartTimeNs + 102));
158 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
159 bucketStartTimeNs + 450));
160
161 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
162 bucketStartTimeNs + 650));
163 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
164 bucketStartTimeNs + bucketSizeNs + 100));
165
166 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
167 bucketStartTimeNs + bucketSizeNs + 640));
168 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
169 bucketStartTimeNs + bucketSizeNs + 650));
170
171 events.push_back(CreateStartScheduledJobEvent(
172 {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
173 events.push_back(CreateFinishScheduledJobEvent(
174 {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
175
176 events.push_back(CreateStartScheduledJobEvent(
177 {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
178 events.push_back(CreateFinishScheduledJobEvent(
179 {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
180
181 events.push_back(CreateStartScheduledJobEvent(
182 {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
183 events.push_back(CreateFinishScheduledJobEvent(
184 {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
185
186 events.push_back(CreateStartScheduledJobEvent(
187 {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
188 events.push_back(CreateFinishScheduledJobEvent(
189 {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
190
191 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
192 bucketStartTimeNs + 10));
193 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
194 bucketStartTimeNs + 50));
195
196 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
197 bucketStartTimeNs + 200));
198 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
199 bucketStartTimeNs + bucketSizeNs + 300));
200
201 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
202 bucketStartTimeNs + 400));
203 events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
204 bucketStartTimeNs + bucketSizeNs - 1));
205
206 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
207 bucketStartTimeNs + 401));
208 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
209 bucketStartTimeNs + bucketSizeNs + 700));
210
211 sortLogEventsByTimestamp(&events);
212
213 while (state.KeepRunning()) {
214 auto processor = CreateStatsLogProcessor(
215 bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
216 for (const auto& event : events) {
217 processor->OnLogEvent(event.get());
218 }
219 }
220 }
221
222 BENCHMARK(BM_DurationMetricNoLink);
223
224
BM_DurationMetricLink(benchmark::State & state)225 static void BM_DurationMetricLink(benchmark::State& state) {
226 ConfigKey cfgKey;
227 auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
228 DurationMetric::SUM, false);
229 int64_t bucketStartTimeNs = 10000000000;
230 int64_t bucketSizeNs =
231 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
232
233 std::vector<AttributionNodeInternal> attributions1 = {
234 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
235 CreateAttribution(222, "GMSCoreModule2")};
236
237 std::vector<AttributionNodeInternal> attributions2 = {
238 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
239 CreateAttribution(555, "GMSCoreModule2")};
240
241 std::vector<AttributionNodeInternal> attributions3 = {
242 CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
243 CreateAttribution(555, "GMSCoreModule2")};
244
245 std::vector<std::unique_ptr<LogEvent>> events;
246
247 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
248 bucketStartTimeNs + 55));
249 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
250 bucketStartTimeNs + 120));
251 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
252 bucketStartTimeNs + 121));
253 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
254 bucketStartTimeNs + 450));
255
256 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
257 bucketStartTimeNs + 501));
258 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
259 bucketStartTimeNs + bucketSizeNs + 100));
260
261 events.push_back(CreateStartScheduledJobEvent(
262 {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
263 events.push_back(CreateFinishScheduledJobEvent(
264 {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
265
266 events.push_back(CreateStartScheduledJobEvent(
267 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
268 events.push_back(CreateFinishScheduledJobEvent(
269 {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
270 events.push_back(CreateStartScheduledJobEvent(
271 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
272 events.push_back(CreateFinishScheduledJobEvent(
273 {CreateAttribution(333, "App2")}, "job2",
274 bucketStartTimeNs + bucketSizeNs + 850));
275
276 events.push_back(
277 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
278 bucketStartTimeNs + bucketSizeNs - 2));
279 events.push_back(
280 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
281 bucketStartTimeNs + bucketSizeNs + 900));
282
283 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
284 bucketStartTimeNs + 50));
285 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
286 bucketStartTimeNs + 110));
287
288 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
289 bucketStartTimeNs + 300));
290 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
291 bucketStartTimeNs + bucketSizeNs + 700));
292 events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
293 bucketStartTimeNs + 400));
294 events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
295 bucketStartTimeNs + bucketSizeNs - 1));
296
297 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
298 bucketStartTimeNs + 550));
299 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
300 bucketStartTimeNs + 800));
301 events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
302 bucketStartTimeNs + bucketSizeNs - 1));
303 events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
304 bucketStartTimeNs + bucketSizeNs + 700));
305 sortLogEventsByTimestamp(&events);
306
307 while (state.KeepRunning()) {
308 auto processor = CreateStatsLogProcessor(
309 bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
310 for (const auto& event : events) {
311 processor->OnLogEvent(event.get());
312 }
313 }
314 }
315
316 BENCHMARK(BM_DurationMetricLink);
317
318 } // namespace statsd
319 } // namespace os
320 } // namespace android
321