diff options
author | Michael Wachenschwanz <mwachens@google.com> | 2018-06-19 14:44:35 -0700 |
---|---|---|
committer | Michael Wachenschwanz <mwachens@google.com> | 2018-06-21 15:59:49 -0700 |
commit | e717e0cb4eb2465c62d31cfd46275484c5a3ad07 (patch) | |
tree | b46f775bde78cc59fb3a28ea6189121b9caec2b7 | |
parent | f52474bc41e2f58b8b8b8bfabe3c66b9197ff148 (diff) |
Initial UsageStatsDatabase Perf tests
A suite of simple performance test for UsageStatsDatabase. They measure
the time it take to write and read UsageEvents to and from a file.
Bug: 110428559
Test: atest UsageStatsPerfTests
Change-Id: If1558515e1da9e22fb56bc13f8e89c10c51a1625
6 files changed, 284 insertions, 4 deletions
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 0dce7382290c..4b7e21f2d536 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -27,7 +27,9 @@ import android.util.ArraySet; import java.util.List; -class IntervalStats { +import com.android.internal.annotations.VisibleForTesting; + +public class IntervalStats { public long beginTime; public long endTime; public long lastTimeSaved; @@ -149,7 +151,11 @@ class IntervalStats { && eventType != UsageEvents.Event.STANDBY_BUCKET_CHANGED; } - void update(String packageName, long timeStamp, int eventType) { + /** + * @hide + */ + @VisibleForTesting + public void update(String packageName, long timeStamp, int eventType) { UsageStats usageStats = getOrCreateUsageStats(packageName); // TODO(adamlesinski): Ensure that we recover from incorrect event sequences diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index 970546976336..5ab5dc223d9e 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -42,7 +42,7 @@ import java.util.List; /** * Provides an interface to query for UsageStat data from an XML database. */ -class UsageStatsDatabase { +public class UsageStatsDatabase { private static final int CURRENT_VERSION = 3; // Current version of the backup schema @@ -369,7 +369,7 @@ class UsageStatsDatabase { /** * Figures out what to extract from the given IntervalStats object. */ - interface StatCombiner<T> { + public interface StatCombiner<T> { /** * Implementations should extract interesting from <code>stats</code> and add it diff --git a/tests/UsageStatsPerfTests/Android.mk b/tests/UsageStatsPerfTests/Android.mk new file mode 100644 index 000000000000..cd29b51e5a24 --- /dev/null +++ b/tests/UsageStatsPerfTests/Android.mk @@ -0,0 +1,34 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + apct-perftests-utils \ + services.usage + +LOCAL_PACKAGE_NAME := UsageStatsPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true + +# For android.permission.FORCE_STOP_PACKAGES permission +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsPerfTests/AndroidManifest.xml b/tests/UsageStatsPerfTests/AndroidManifest.xml new file mode 100644 index 000000000000..596a79cd8948 --- /dev/null +++ b/tests/UsageStatsPerfTests/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.frameworks.perftests.usage"> + <uses-sdk + android:minSdkVersion="21" /> + <uses-permission android:name="android.permission.DUMP" /> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" /> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.frameworks.perftests.usage"/> +</manifest> diff --git a/tests/UsageStatsPerfTests/AndroidTest.xml b/tests/UsageStatsPerfTests/AndroidTest.xml new file mode 100644 index 000000000000..c9b51dc5ba07 --- /dev/null +++ b/tests/UsageStatsPerfTests/AndroidTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Runs UsageStats Performance Tests"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="UsageStatsPerfTests.apk"/> + <option name="cleanup-apks" value="true"/> + </target_preparer> + + <option name="test-suite-tag" value="apct"/> + <option name="test-tag" value="UsageStatsPerfTests"/> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.frameworks.perftests.usage"/> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java new file mode 100644 index 000000000000..8467bee819cb --- /dev/null +++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java @@ -0,0 +1,183 @@ +/* + * 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. + */ + +package com.android.frameworks.perftests.usage.tests; + +import static junit.framework.Assert.assertEquals; + +import com.android.server.usage.UsageStatsDatabase; +import com.android.server.usage.UsageStatsDatabase.StatCombiner; +import com.android.server.usage.IntervalStats; + +import android.app.usage.EventList; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.os.SystemClock; +import android.perftests.utils.ManualBenchmarkState; +import android.perftests.utils.PerfManualStatusReporter; +import android.support.test.filters.LargeTest; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class UsageStatsDatabasePerfTest { + protected static Context sContext; + private static UsageStatsDatabase sUsageStatsDatabase; + private static File mTestDir; + + // Represents how many apps might have used in a day by a user with a few apps + final static int FEW_PKGS = 10; + // Represent how many apps might have used in a day by a user with many apps + final static int MANY_PKGS = 50; + // Represents how many usage events per app a device might have with light usage + final static int LIGHT_USE = 10; + // Represents how many usage events per app a device might have with heavy usage + final static int HEAVY_USE = 50; + + private static final StatCombiner<UsageEvents.Event> sUsageStatsCombiner = + new StatCombiner<UsageEvents.Event>() { + @Override + public void combine(IntervalStats stats, boolean mutable, + List<UsageEvents.Event> accResult) { + final int size = stats.events.size(); + for (int i = 0; i < size; i++) { + accResult.add(stats.events.get(i)); + } + } + }; + + + @Rule + public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter(); + + @BeforeClass + public static void setUpOnce() { + sContext = InstrumentationRegistry.getTargetContext(); + mTestDir = new File(sContext.getFilesDir(), "UsageStatsDatabasePerfTest"); + sUsageStatsDatabase = new UsageStatsDatabase(mTestDir); + sUsageStatsDatabase.init(1); + } + + private static void populateIntervalStats(IntervalStats intervalStats, int packageCount, + int eventsPerPackage) { + if (intervalStats.events == null) { + intervalStats.events = new EventList(); + } + for (int pkg = 0; pkg < packageCount; pkg++) { + UsageEvents.Event event = new UsageEvents.Event(); + event.mPackage = "fake.package.name" + pkg; + event.mTimeStamp = 1; + event.mEventType = UsageEvents.Event.MOVE_TO_FOREGROUND; + for (int evt = 0; evt < eventsPerPackage; evt++) { + intervalStats.events.insert(event); + intervalStats.update(event.mPackage, event.mTimeStamp, event.mEventType); + } + } + } + + private static void clearUsageStatsFiles() { + File[] intervalDirs = mTestDir.listFiles(); + for (File intervalDir : intervalDirs) { + if (intervalDir.isDirectory()) { + File[] usageFiles = intervalDir.listFiles(); + for (File f : usageFiles) { + f.delete(); + } + } + } + } + + private void runQueryUsageStatsTest(int packageCount, int eventsPerPackage) throws IOException { + final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState(); + IntervalStats intervalStats = new IntervalStats(); + populateIntervalStats(intervalStats, packageCount, eventsPerPackage); + sUsageStatsDatabase.putUsageStats(0, intervalStats); + long elapsedTimeNs = 0; + while (benchmarkState.keepRunning(elapsedTimeNs)) { + final long startTime = SystemClock.elapsedRealtimeNanos(); + List<UsageEvents.Event> temp = sUsageStatsDatabase.queryUsageStats( + UsageStatsManager.INTERVAL_DAILY, 0, 2, sUsageStatsCombiner); + final long endTime = SystemClock.elapsedRealtimeNanos(); + elapsedTimeNs = endTime - startTime; + assertEquals(packageCount * eventsPerPackage, temp.size()); + } + } + + private void runPutUsageStatsTest(int packageCount, int eventsPerPackage) throws IOException { + final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState(); + IntervalStats intervalStats = new IntervalStats(); + populateIntervalStats(intervalStats, packageCount, eventsPerPackage); + long elapsedTimeNs = 0; + while (benchmarkState.keepRunning(elapsedTimeNs)) { + final long startTime = SystemClock.elapsedRealtimeNanos(); + sUsageStatsDatabase.putUsageStats(0, intervalStats); + final long endTime = SystemClock.elapsedRealtimeNanos(); + elapsedTimeNs = endTime - startTime; + clearUsageStatsFiles(); + } + } + + @Test + public void testQueryUsageStats_FewPkgsLightUse() throws IOException { + runQueryUsageStatsTest(FEW_PKGS, LIGHT_USE); + } + + @Test + public void testPutUsageStats_FewPkgsLightUse() throws IOException { + runPutUsageStatsTest(FEW_PKGS, LIGHT_USE); + } + + @Test + public void testQueryUsageStats_FewPkgsHeavyUse() throws IOException { + runQueryUsageStatsTest(FEW_PKGS, HEAVY_USE); + } + + @Test + public void testPutUsageStats_FewPkgsHeavyUse() throws IOException { + runPutUsageStatsTest(FEW_PKGS, HEAVY_USE); + } + + @Test + public void testQueryUsageStats_ManyPkgsLightUse() throws IOException { + runQueryUsageStatsTest(MANY_PKGS, LIGHT_USE); + } + + @Test + public void testPutUsageStats_ManyPkgsLightUse() throws IOException { + runPutUsageStatsTest(MANY_PKGS, LIGHT_USE); + } + + @Test + public void testQueryUsageStats_ManyPkgsHeavyUse() throws IOException { + runQueryUsageStatsTest(MANY_PKGS, HEAVY_USE); + } + + @Test + public void testPutUsageStats_ManyPkgsHeavyUse() throws IOException { + runPutUsageStatsTest(MANY_PKGS, HEAVY_USE); + } +} |