/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <vector> #include "benchmark/benchmark.h" #include "FieldValue.h" #include "HashableDimensionKey.h" #include "logd/LogEvent.h" #include "stats_log_util.h" #include "metric_util.h" namespace android { namespace os { namespace statsd { using std::vector; static StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition( DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { StatsdConfig config; *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); *config.add_atom_matcher() = CreateSyncEndAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); auto scheduledJobPredicate = CreateScheduledJobPredicate(); auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions(); dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED); dimensions->add_child()->set_field(2); // job name field. auto screenIsOffPredicate = CreateScreenIsOffPredicate(); auto isSyncingPredicate = CreateIsSyncingPredicate(); auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions(); *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST}); if (addExtraDimensionInCondition) { syncDimension->add_child()->set_field(2 /* name field*/); } *config.add_predicate() = scheduledJobPredicate; *config.add_predicate() = screenIsOffPredicate; *config.add_predicate() = isSyncingPredicate; auto combinationPredicate = config.add_predicate(); combinationPredicate->set_id(StringToId("CombinationPredicate")); combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND); addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate); addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate); auto metric = config.add_duration_metric(); metric->set_bucket(FIVE_MINUTES); metric->set_id(StringToId("scheduledJob")); metric->set_what(scheduledJobPredicate.id()); metric->set_condition(combinationPredicate->id()); metric->set_aggregation_type(aggregationType); auto dimensionWhat = metric->mutable_dimensions_in_what(); dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED); dimensionWhat->add_child()->set_field(2); // job name field. *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions( android::util::SYNC_STATE_CHANGED, {Position::FIRST}); return config; } static StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition( DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { StatsdConfig config; *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); *config.add_atom_matcher() = CreateSyncEndAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); auto scheduledJobPredicate = CreateScheduledJobPredicate(); auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions(); *dimensions = CreateAttributionUidDimensions( android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); dimensions->add_child()->set_field(2); // job name field. auto isSyncingPredicate = CreateIsSyncingPredicate(); auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions(); *syncDimension = CreateAttributionUidDimensions( android::util::SYNC_STATE_CHANGED, {Position::FIRST}); if (addExtraDimensionInCondition) { syncDimension->add_child()->set_field(2 /* name field*/); } auto screenIsOffPredicate = CreateScreenIsOffPredicate(); *config.add_predicate() = scheduledJobPredicate; *config.add_predicate() = screenIsOffPredicate; *config.add_predicate() = isSyncingPredicate; auto combinationPredicate = config.add_predicate(); combinationPredicate->set_id(StringToId("CombinationPredicate")); combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND); addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate); addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate); auto metric = config.add_duration_metric(); metric->set_bucket(FIVE_MINUTES); metric->set_id(StringToId("scheduledJob")); metric->set_what(scheduledJobPredicate.id()); metric->set_condition(combinationPredicate->id()); metric->set_aggregation_type(aggregationType); *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions( android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); auto links = metric->add_links(); links->set_condition(isSyncingPredicate.id()); *links->mutable_fields_in_what() = CreateAttributionUidDimensions( android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST}); *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST}); return config; } static void BM_DurationMetricNoLink(benchmark::State& state) { ConfigKey cfgKey; auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition( DurationMetric::SUM, false); int64_t bucketStartTimeNs = 10000000000; int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; std::vector<AttributionNodeInternal> attributions1 = { CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(222, "GMSCoreModule2")}; std::vector<AttributionNodeInternal> attributions2 = { CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(555, "GMSCoreModule2")}; std::vector<std::unique_ptr<LogEvent>> events; events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 11)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 40)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 102)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 450)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 650)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + bucketSizeNs + 100)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + bucketSizeNs + 640)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + bucketSizeNs + 650)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900)); events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 10)); events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + 50)); events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200)); events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300)); events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400)); events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1)); events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401)); events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 700)); sortLogEventsByTimestamp(&events); while (state.KeepRunning()) { auto processor = CreateStatsLogProcessor( bucketStartTimeNs / NS_PER_SEC, config, cfgKey); for (const auto& event : events) { processor->OnLogEvent(event.get()); } } } BENCHMARK(BM_DurationMetricNoLink); static void BM_DurationMetricLink(benchmark::State& state) { ConfigKey cfgKey; auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition( DurationMetric::SUM, false); int64_t bucketStartTimeNs = 10000000000; int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; std::vector<AttributionNodeInternal> attributions1 = { CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(222, "GMSCoreModule2")}; std::vector<AttributionNodeInternal> attributions2 = { CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(555, "GMSCoreModule2")}; std::vector<AttributionNodeInternal> attributions3 = { CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(555, "GMSCoreModule2")}; std::vector<std::unique_ptr<LogEvent>> events; events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 55)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 120)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 121)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 450)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 501)); events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + bucketSizeNs + 100)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500)); events.push_back(CreateStartScheduledJobEvent( {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600)); events.push_back(CreateFinishScheduledJobEvent( {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850)); events.push_back( CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3", bucketStartTimeNs + bucketSizeNs - 2)); events.push_back( CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3", bucketStartTimeNs + bucketSizeNs + 900)); events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 50)); events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + 110)); events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 300)); events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 700)); events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc", bucketStartTimeNs + 400)); events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1)); events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc", bucketStartTimeNs + 550)); events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc", bucketStartTimeNs + 800)); events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1)); events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 700)); sortLogEventsByTimestamp(&events); while (state.KeepRunning()) { auto processor = CreateStatsLogProcessor( bucketStartTimeNs / NS_PER_SEC, config, cfgKey); for (const auto& event : events) { processor->OnLogEvent(event.get()); } } } BENCHMARK(BM_DurationMetricLink); } // namespace statsd } // namespace os } // namespace android