Add perf tests for JobStore file reading & writing.
1. Add perf tests to evaluate changes to JobStore's persisted file reading
and writing.
2. Renaming parameters to make it clearer what they're for.
3. Removing targetSdkVersion from JobStatus because it's not being used and
made testing a little harder.
Current results (times are in nanoseconds):
JobSchedulerPerfTests (6 Tests)
------------------------------
[1/6] com.android.frameworks.perftests.job.JobStorePerfTests#testPersistedJobReading_fewJobs_badRTC: PASSED (37.082s)
testPersistedJobReading_fewJobs_badRTC_median: 16333804
testPersistedJobReading_fewJobs_badRTC_percentile95: 17523439
testPersistedJobReading_fewJobs_badRTC_stddev: 1402393
testPersistedJobReading_fewJobs_badRTC_percentile90: 17523439
testPersistedJobReading_fewJobs_badRTC_mean: 16193033
[2/6] com.android.frameworks.perftests.job.JobStorePerfTests#testPersistedJobWriting_manyJobs: PASSED (42.610s)
testPersistedJobWriting_manyJobs_stddev: 47895383
testPersistedJobWriting_manyJobs_percentile95: 235706638
testPersistedJobWriting_manyJobs_median: 214356219
testPersistedJobWriting_manyJobs_percentile90: 235706638
testPersistedJobWriting_manyJobs_mean: 197006269
[3/6] com.android.frameworks.perftests.job.JobStorePerfTests#testPersistedJobReading_manyJobs_goodRTC: PASSED (40.855s)
testPersistedJobReading_manyJobs_goodRTC_percentile95: 107394438
testPersistedJobReading_manyJobs_goodRTC_mean: 96397639
testPersistedJobReading_manyJobs_goodRTC_median: 95545374
testPersistedJobReading_manyJobs_goodRTC_percentile90: 107394438
testPersistedJobReading_manyJobs_goodRTC_stddev: 7879676
[4/6] com.android.frameworks.perftests.job.JobStorePerfTests#testPersistedJobWriting_fewJobs: PASSED (37.131s)
testPersistedJobWriting_fewJobs_percentile90: 18209220
testPersistedJobWriting_fewJobs_stddev: 2401331
testPersistedJobWriting_fewJobs_percentile95: 18209220
testPersistedJobWriting_fewJobs_median: 13676251
testPersistedJobWriting_fewJobs_mean: 14685137
[5/6] com.android.frameworks.perftests.job.JobStorePerfTests#testPersistedJobReading_fewJobs_goodRTC: PASSED (37.170s)
testPersistedJobReading_fewJobs_goodRTC_median: 13792865
testPersistedJobReading_fewJobs_goodRTC_mean: 15065688
testPersistedJobReading_fewJobs_goodRTC_percentile90: 19445106
testPersistedJobReading_fewJobs_goodRTC_percentile95: 19445106
testPersistedJobReading_fewJobs_goodRTC_stddev: 3025478
[6/6] com.android.frameworks.perftests.job.JobStorePerfTests#testPersistedJobReading_manyJobs_badRTC: PASSED (40.725s)
testPersistedJobReading_manyJobs_badRTC_percentile90: 96233552
testPersistedJobReading_manyJobs_badRTC_stddev: 6633074
testPersistedJobReading_manyJobs_badRTC_mean: 89815566
testPersistedJobReading_manyJobs_badRTC_median: 91038758
testPersistedJobReading_manyJobs_badRTC_percentile95: 96233552
Bug: 135200955
Test: atest com.android.frameworks.perftests.job.JobStorePerfTests
Test: atest com.android.server.job.JobStoreTest
Test: atest com.android.server.job.controllers.ConnectivityControllerTest
Test: atest com.android.server.job.controllers.JobStatusTest
Test: atest com.android.server.job.controllers.QuotaControllerTest
Change-Id: Id5cc72d6703b2b1c5d553de91b8a1837b360bc7f
diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp
new file mode 100644
index 0000000..2230807
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 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.
+
+android_test {
+ name: "JobSchedulerPerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "apct-perftests-utils",
+ "services",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/JobSchedulerPerfTests/AndroidManifest.xml b/tests/JobSchedulerPerfTests/AndroidManifest.xml
new file mode 100644
index 0000000..39e751c
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.job">
+ <uses-sdk
+ android:minSdkVersion="21" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.perftests.job"/>
+</manifest>
diff --git a/tests/JobSchedulerPerfTests/AndroidTest.xml b/tests/JobSchedulerPerfTests/AndroidTest.xml
new file mode 100644
index 0000000..ca4b6c8
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/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 JobScheduler Performance Tests">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="JobSchedulerPerfTests.apk"/>
+ <option name="cleanup-apks" value="true"/>
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="JobSchedulerPerfTests"/>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.perftests.job"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
new file mode 100644
index 0000000..e956be3
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2019 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.job;
+
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.SystemClock;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.job.JobStore;
+import com.android.server.job.JobStore.JobSet;
+import com.android.server.job.controllers.JobStatus;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class JobStorePerfTests {
+ private static final String SOURCE_PACKAGE = "com.android.frameworks.perftests.job";
+ private static final int SOURCE_USER_ID = 0;
+ private static final int CALLING_UID = 10079;
+
+ private static Context sContext;
+ private static File sTestDir;
+ private static JobStore sJobStore;
+
+ private static List<JobStatus> sFewJobs = new ArrayList<>();
+ private static List<JobStatus> sManyJobs = new ArrayList<>();
+
+ @Rule
+ public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
+
+ @BeforeClass
+ public static void setUpOnce() {
+ sContext = InstrumentationRegistry.getTargetContext();
+ sTestDir = new File(sContext.getFilesDir(), "JobStorePerfTests");
+ sJobStore = JobStore.initAndGetForTesting(sContext, sTestDir);
+
+ for (int i = 0; i < 50; i++) {
+ sFewJobs.add(createJobStatus("fewJobs", i));
+ }
+ for (int i = 0; i < 500; i++) {
+ sManyJobs.add(createJobStatus("manyJobs", i));
+ }
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ sTestDir.deleteOnExit();
+ }
+
+ private void runPersistedJobWriting(List<JobStatus> jobList) {
+ final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
+
+ long elapsedTimeNs = 0;
+ while (benchmarkState.keepRunning(elapsedTimeNs)) {
+ sJobStore.clear();
+ for (JobStatus job : jobList) {
+ sJobStore.add(job);
+ }
+ sJobStore.waitForWriteToCompleteForTesting(10_000);
+
+ final long startTime = SystemClock.elapsedRealtimeNanos();
+ sJobStore.writeStatusToDiskForTesting();
+ final long endTime = SystemClock.elapsedRealtimeNanos();
+ elapsedTimeNs = endTime - startTime;
+ }
+ }
+
+ @Test
+ public void testPersistedJobWriting_fewJobs() {
+ runPersistedJobWriting(sFewJobs);
+ }
+
+ @Test
+ public void testPersistedJobWriting_manyJobs() {
+ runPersistedJobWriting(sManyJobs);
+ }
+
+ private void runPersistedJobReading(List<JobStatus> jobList, boolean rtcIsGood) {
+ final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
+
+ long elapsedTimeNs = 0;
+ while (benchmarkState.keepRunning(elapsedTimeNs)) {
+ sJobStore.clear();
+ for (JobStatus job : jobList) {
+ sJobStore.add(job);
+ }
+ sJobStore.waitForWriteToCompleteForTesting(10_000);
+
+ JobSet jobSet = new JobSet();
+
+ final long startTime = SystemClock.elapsedRealtimeNanos();
+ sJobStore.readJobMapFromDisk(jobSet, rtcIsGood);
+ final long endTime = SystemClock.elapsedRealtimeNanos();
+ elapsedTimeNs = endTime - startTime;
+ }
+ }
+
+ @Test
+ public void testPersistedJobReading_fewJobs_goodRTC() {
+ runPersistedJobReading(sFewJobs, true);
+ }
+
+ @Test
+ public void testPersistedJobReading_fewJobs_badRTC() {
+ runPersistedJobReading(sFewJobs, false);
+ }
+
+ @Test
+ public void testPersistedJobReading_manyJobs_goodRTC() {
+ runPersistedJobReading(sManyJobs, true);
+ }
+
+ @Test
+ public void testPersistedJobReading_manyJobs_badRTC() {
+ runPersistedJobReading(sManyJobs, false);
+ }
+
+ private static JobStatus createJobStatus(String testTag, int jobId) {
+ JobInfo jobInfo = new JobInfo.Builder(jobId,
+ new ComponentName(sContext, "JobStorePerfTestJobService"))
+ .setPersisted(true)
+ .build();
+ return JobStatus.createFromJobInfo(
+ jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+ }
+}