1 /*
2  * Copyright (C) 2019 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 package com.android.frameworks.perftests.job;
17 
18 import android.app.job.JobInfo;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.os.SystemClock;
22 import android.perftests.utils.ManualBenchmarkState;
23 import android.perftests.utils.PerfManualStatusReporter;
24 
25 import androidx.test.InstrumentationRegistry;
26 import androidx.test.filters.LargeTest;
27 import androidx.test.runner.AndroidJUnit4;
28 
29 import com.android.server.job.JobStore;
30 import com.android.server.job.JobStore.JobSet;
31 import com.android.server.job.controllers.JobStatus;
32 
33 import org.junit.AfterClass;
34 import org.junit.BeforeClass;
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 
39 import java.io.File;
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 @RunWith(AndroidJUnit4.class)
44 @LargeTest
45 public class JobStorePerfTests {
46     private static final String SOURCE_PACKAGE = "com.android.frameworks.perftests.job";
47     private static final int SOURCE_USER_ID = 0;
48     private static final int BASE_CALLING_UID = 10079;
49     private static final int MAX_UID_COUNT = 10;
50 
51     private static Context sContext;
52     private static File sTestDir;
53     private static JobStore sJobStore;
54 
55     private static List<JobStatus> sFewJobs = new ArrayList<>();
56     private static List<JobStatus> sManyJobs = new ArrayList<>();
57 
58     @Rule
59     public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
60 
61     @BeforeClass
setUpOnce()62     public static void setUpOnce() {
63         sContext = InstrumentationRegistry.getTargetContext();
64         sTestDir = new File(sContext.getFilesDir(), "JobStorePerfTests");
65         sJobStore = JobStore.initAndGetForTesting(sContext, sTestDir);
66 
67         for (int i = 0; i < 50; i++) {
68             sFewJobs.add(createJobStatus("fewJobs", i, BASE_CALLING_UID + (i % MAX_UID_COUNT)));
69         }
70         for (int i = 0; i < 500; i++) {
71             sManyJobs.add(createJobStatus("manyJobs", i, BASE_CALLING_UID + (i % MAX_UID_COUNT)));
72         }
73     }
74 
75     @AfterClass
tearDownOnce()76     public static void tearDownOnce() {
77         sTestDir.deleteOnExit();
78     }
79 
runPersistedJobWriting(List<JobStatus> jobList)80     private void runPersistedJobWriting(List<JobStatus> jobList) {
81         final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
82 
83         long elapsedTimeNs = 0;
84         while (benchmarkState.keepRunning(elapsedTimeNs)) {
85             sJobStore.clearForTesting();
86             for (JobStatus job : jobList) {
87                 sJobStore.addForTesting(job);
88             }
89 
90             final long startTime = SystemClock.elapsedRealtimeNanos();
91             sJobStore.writeStatusToDiskForTesting();
92             final long endTime = SystemClock.elapsedRealtimeNanos();
93             elapsedTimeNs = endTime - startTime;
94         }
95     }
96 
97     @Test
testPersistedJobWriting_fewJobs()98     public void testPersistedJobWriting_fewJobs() {
99         runPersistedJobWriting(sFewJobs);
100     }
101 
102     @Test
testPersistedJobWriting_manyJobs()103     public void testPersistedJobWriting_manyJobs() {
104         runPersistedJobWriting(sManyJobs);
105     }
106 
runPersistedJobWriting_delta(List<JobStatus> jobList, List<JobStatus> jobAdditions, List<JobStatus> jobRemovals)107     private void runPersistedJobWriting_delta(List<JobStatus> jobList,
108             List<JobStatus> jobAdditions, List<JobStatus> jobRemovals) {
109         final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
110 
111         long elapsedTimeNs = 0;
112         while (benchmarkState.keepRunning(elapsedTimeNs)) {
113             sJobStore.clearForTesting();
114             for (JobStatus job : jobList) {
115                 sJobStore.addForTesting(job);
116             }
117             sJobStore.writeStatusToDiskForTesting();
118 
119             for (JobStatus job : jobAdditions) {
120                 sJobStore.addForTesting(job);
121             }
122             for (JobStatus job : jobRemovals) {
123                 sJobStore.removeForTesting(job);
124             }
125 
126             final long startTime = SystemClock.elapsedRealtimeNanos();
127             sJobStore.writeStatusToDiskForTesting();
128             final long endTime = SystemClock.elapsedRealtimeNanos();
129             elapsedTimeNs = endTime - startTime;
130         }
131     }
132 
133     @Test
testPersistedJobWriting_delta_fewJobs()134     public void testPersistedJobWriting_delta_fewJobs() {
135         List<JobStatus> additions = new ArrayList<>();
136         List<JobStatus> removals = new ArrayList<>();
137         final int numModifiedUids = MAX_UID_COUNT / 2;
138         for (int i = 0; i < sFewJobs.size() / 3; ++i) {
139             JobStatus job = createJobStatus("fewJobs", i, BASE_CALLING_UID + (i % numModifiedUids));
140             if (i % 2 == 0) {
141                 additions.add(job);
142             } else {
143                 removals.add(job);
144             }
145         }
146         runPersistedJobWriting_delta(sFewJobs, additions, removals);
147     }
148 
149     @Test
testPersistedJobWriting_delta_manyJobs()150     public void testPersistedJobWriting_delta_manyJobs() {
151         List<JobStatus> additions = new ArrayList<>();
152         List<JobStatus> removals = new ArrayList<>();
153         final int numModifiedUids = MAX_UID_COUNT / 2;
154         for (int i = 0; i < sManyJobs.size() / 3; ++i) {
155             JobStatus job = createJobStatus("fewJobs", i, BASE_CALLING_UID + (i % numModifiedUids));
156             if (i % 2 == 0) {
157                 additions.add(job);
158             } else {
159                 removals.add(job);
160             }
161         }
162         runPersistedJobWriting_delta(sManyJobs, additions, removals);
163     }
164 
runPersistedJobReading(List<JobStatus> jobList, boolean rtcIsGood)165     private void runPersistedJobReading(List<JobStatus> jobList, boolean rtcIsGood) {
166         final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
167 
168         long elapsedTimeNs = 0;
169         while (benchmarkState.keepRunning(elapsedTimeNs)) {
170             sJobStore.clearForTesting();
171             for (JobStatus job : jobList) {
172                 sJobStore.addForTesting(job);
173             }
174             sJobStore.writeStatusToDiskForTesting();
175 
176             JobSet jobSet = new JobSet();
177 
178             final long startTime = SystemClock.elapsedRealtimeNanos();
179             sJobStore.readJobMapFromDisk(jobSet, rtcIsGood);
180             final long endTime = SystemClock.elapsedRealtimeNanos();
181             elapsedTimeNs = endTime - startTime;
182         }
183     }
184 
185     @Test
testPersistedJobReading_fewJobs_goodRTC()186     public void testPersistedJobReading_fewJobs_goodRTC() {
187         runPersistedJobReading(sFewJobs, true);
188     }
189 
190     @Test
testPersistedJobReading_fewJobs_badRTC()191     public void testPersistedJobReading_fewJobs_badRTC() {
192         runPersistedJobReading(sFewJobs, false);
193     }
194 
195     @Test
testPersistedJobReading_manyJobs_goodRTC()196     public void testPersistedJobReading_manyJobs_goodRTC() {
197         runPersistedJobReading(sManyJobs, true);
198     }
199 
200     @Test
testPersistedJobReading_manyJobs_badRTC()201     public void testPersistedJobReading_manyJobs_badRTC() {
202         runPersistedJobReading(sManyJobs, false);
203     }
204 
createJobStatus(String testTag, int jobId, int callingUid)205     private static JobStatus createJobStatus(String testTag, int jobId, int callingUid) {
206         JobInfo jobInfo = new JobInfo.Builder(jobId,
207                 new ComponentName(sContext, "JobStorePerfTestJobService"))
208                 .setPersisted(true)
209                 .build();
210         return JobStatus.createFromJobInfo(
211                 jobInfo, callingUid, SOURCE_PACKAGE, SOURCE_USER_ID, null, testTag);
212     }
213 }
214