blob: 8eef86d0010b66749538693fb3a06371164328c3 [file] [log] [blame]
Wonsik Kim37388882014-09-07 12:24:20 +09001/*
2 * Copyright (C) 2014 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
17package com.android.cts.tvproviderperf;
18
19import android.content.ComponentName;
20import android.content.ContentProviderOperation;
21import android.content.ContentProviderResult;
22import android.content.ContentResolver;
23import android.content.ContentUris;
24import android.content.ContentValues;
25import android.content.OperationApplicationException;
26import android.content.pm.PackageManager;
27import android.database.Cursor;
28import android.cts.util.CtsAndroidTestCase;
29import android.media.tv.TvContract;
30import android.media.tv.TvContract.Channels;
31import android.media.tv.TvContract.Programs;
32import android.net.Uri;
33import android.os.RemoteException;
34
35import com.android.cts.util.MeasureRun;
36import com.android.cts.util.MeasureTime;
37import com.android.cts.util.ResultType;
38import com.android.cts.util.ResultUnit;
39import com.android.cts.util.ReportLog;
40import com.android.cts.util.TimeoutReq;
41import com.android.cts.util.Stat;
42
43import java.util.ArrayList;
44import java.util.List;
45
46/**
47 * Test performance of TvProvider on a device. TvProvider typically handles hundreds of
48 * thousands of records periodically, so it is desirable to have performance under a reasonable
49 * bar.
50 */
51public class TvProviderPerfTest extends CtsAndroidTestCase {
Dongwon Kang9fd4e242015-04-14 15:11:09 +090052 private static final int TRANSACTION_RUNS = 100;
Dongwon Kanga1c03052015-05-11 16:55:39 +090053 private static final int QUERY_RUNS = 10;
Dongwon Kang9fd4e242015-04-14 15:11:09 +090054
Wonsik Kim37388882014-09-07 12:24:20 +090055 private ContentResolver mContentResolver;
56 private String mInputId;
57 private boolean mHasTvInputFramework;
58
59 @Override
60 protected void setUp() throws Exception {
61 super.setUp();
62 mHasTvInputFramework = getContext().getPackageManager().hasSystemFeature(
63 PackageManager.FEATURE_LIVE_TV);
64 if (!mHasTvInputFramework) return;
65 mContentResolver = getContext().getContentResolver();
66 mInputId = TvContract.buildInputId(new ComponentName(getContext(), getClass()));
67 }
68
69 @Override
70 protected void tearDown() throws Exception {
71 try {
72 if (!mHasTvInputFramework) return;
73 mContentResolver.delete(Programs.CONTENT_URI, null, null);
74 mContentResolver.delete(Channels.CONTENT_URI, null, null);
75 } finally {
76 super.tearDown();
77 }
78 }
79
Dongwon Kanga1c03052015-05-11 16:55:39 +090080 @TimeoutReq(minutes = 8)
Wonsik Kim37388882014-09-07 12:24:20 +090081 public void testChannels() throws Exception {
82 if (!mHasTvInputFramework) return;
Dongwon Kang223816c2015-06-30 14:45:18 -070083 double[] averages = new double[5];
Wonsik Kim37388882014-09-07 12:24:20 +090084
85 // Insert
86 final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
87 final int TRANSACTION_SIZE = 1000;
Wonsik Kim37388882014-09-07 12:24:20 +090088 double[] applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
89 @Override
90 public void run(int i) {
91 operations.clear();
92 for (int j = 0; j < TRANSACTION_SIZE; ++j) {
93 ContentValues values = new ContentValues();
94 values.put(Channels.COLUMN_INPUT_ID, mInputId);
95 values.put(Channels.COLUMN_SERVICE_TYPE,
96 Channels.SERVICE_TYPE_AUDIO_VIDEO);
97 values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
98 operations.add(
99 ContentProviderOperation.newInsert(Channels.CONTENT_URI)
100 .withValues(values).build());
101 }
102 try {
103 mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
104 } catch (OperationApplicationException | RemoteException e) {
105 throw new RuntimeException(e);
106 }
107 }
108 });
109 getReportLog().printArray("Elapsed time for insert: ",
110 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
111 averages[0] = Stat.getAverage(applyBatchTimes);
112
113 // Update
114 final String[] projection = { Channels._ID };
115 try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
116 projection, null, null, null)) {
117 applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
118 @Override
119 public void run(int i) {
120 operations.clear();
121 for (int j = 0; j < TRANSACTION_SIZE && cursor.moveToNext(); ++j) {
122 Uri channelUri = TvContract.buildChannelUri(cursor.getLong(0));
123 String number = Integer.toString(i * TRANSACTION_SIZE + j);
124 operations.add(
125 ContentProviderOperation.newUpdate(channelUri)
126 .withValue(Channels.COLUMN_DISPLAY_NUMBER, number)
127 .build());
128 }
129 try {
130 mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
131 } catch (OperationApplicationException | RemoteException e) {
132 throw new RuntimeException(e);
133 }
134 }
135 });
136 }
137 getReportLog().printArray("Elapsed time for update: ",
138 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
139 averages[1] = Stat.getAverage(applyBatchTimes);
140
Dongwon Kang223816c2015-06-30 14:45:18 -0700141 // Query channels
Dongwon Kanga1c03052015-05-11 16:55:39 +0900142 applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900143 @Override
144 public void run(int i) {
Dongwon Kanga1c03052015-05-11 16:55:39 +0900145 try (Cursor cursor = mContentResolver.query(Channels.CONTENT_URI, null, null,
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900146 null, null)) {
147 while (cursor.moveToNext()) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700148 // Do nothing. Just iterate all the items.
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900149 }
150 }
151 }
152 });
Dongwon Kang223816c2015-06-30 14:45:18 -0700153 getReportLog().printArray("Elapsed time for query (channels): ",
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900154 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
155 averages[2] = Stat.getAverage(applyBatchTimes);
156
Dongwon Kang223816c2015-06-30 14:45:18 -0700157 // Query a channel
158 try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
159 projection, null, null, null)) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700160 applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
161 @Override
162 public void run(int i) {
163 assertTrue(cursor.moveToNext());
Dongwon Kangc004f8f2015-10-22 16:18:44 -0700164 try (Cursor c = mContentResolver.query(TvContract.buildChannelUri(
165 cursor.getLong(0)), null, null, null, null)) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700166 while (c.moveToNext()) {
167 // Do nothing. Just iterate all the items.
168 }
169 }
170 }
171 });
172 }
173 getReportLog().printArray("Elapsed time for query (a channel): ",
174 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
175 averages[3] = Stat.getAverage(applyBatchTimes);
176
Wonsik Kim37388882014-09-07 12:24:20 +0900177 // Delete
178 applyBatchTimes = MeasureTime.measure(1, new MeasureRun() {
179 @Override
180 public void run(int i) {
181 mContentResolver.delete(TvContract.buildChannelsUriForInput(mInputId), null, null);
182 }
183 });
184 getReportLog().printArray("Elapsed time for delete: ",
185 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
Dongwon Kang223816c2015-06-30 14:45:18 -0700186 averages[4] = Stat.getAverage(applyBatchTimes);
Wonsik Kim37388882014-09-07 12:24:20 +0900187
Dongwon Kang223816c2015-06-30 14:45:18 -0700188 getReportLog().printArray("Average elapsed time for insert, update, query (channels), "
189 + "query (a channel), delete: ",
Wonsik Kim37388882014-09-07 12:24:20 +0900190 averages, ResultType.LOWER_BETTER, ResultUnit.MS);
191 }
192
Dongwon Kanga1c03052015-05-11 16:55:39 +0900193 @TimeoutReq(minutes = 12)
Wonsik Kim37388882014-09-07 12:24:20 +0900194 public void testPrograms() throws Exception {
195 if (!mHasTvInputFramework) return;
Dongwon Kang223816c2015-06-30 14:45:18 -0700196 double[] averages = new double[7];
Wonsik Kim37388882014-09-07 12:24:20 +0900197
198 // Prepare (insert channels)
199 final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
200 final int TRANSACTION_SIZE = 1000;
201 final int NUM_CHANNELS = 100;
202 final List<Uri> channelUris = new ArrayList<>();
203
204 operations.clear();
205 for (int i = 0; i < NUM_CHANNELS; ++i) {
206 ContentValues values = new ContentValues();
207 values.put(Channels.COLUMN_INPUT_ID, mInputId);
208 values.put(Channels.COLUMN_SERVICE_TYPE,
209 Channels.SERVICE_TYPE_AUDIO_VIDEO);
210 values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
211 operations.add(
212 ContentProviderOperation.newInsert(Channels.CONTENT_URI)
213 .withValues(values).build());
214 }
215 try {
216 ContentProviderResult[] results =
217 mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
218 for (ContentProviderResult result : results) {
219 channelUris.add(result.uri);
220 }
221 } catch (OperationApplicationException | RemoteException e) {
222 throw new RuntimeException(e);
223 }
224
225 // Insert
226 double[] applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
227 @Override
228 public void run(int i) {
229 operations.clear();
230 Uri channelUri = channelUris.get(i);
231 long channelId = ContentUris.parseId(channelUri);
232 for (int j = 0; j < TRANSACTION_SIZE; ++j) {
233 ContentValues values = new ContentValues();
234 values.put(Programs.COLUMN_CHANNEL_ID, channelId);
235 operations.add(
236 ContentProviderOperation.newInsert(Programs.CONTENT_URI)
237 .withValues(values).build());
238 }
239 try {
240 mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
241 } catch (OperationApplicationException | RemoteException e) {
242 throw new RuntimeException(e);
243 }
244 }
245 });
246 getReportLog().printArray("Elapsed time for insert: ",
247 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
248 averages[0] = Stat.getAverage(applyBatchTimes);
249
250 // Update
251 final long PROGRAM_DURATION_MS = 60 * 1000;
252 final String[] projection = { Programs._ID };
253 applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
254 @Override
255 public void run(int i) {
256 Uri channelUri = channelUris.get(i);
257 operations.clear();
Dongwon Kanga1c03052015-05-11 16:55:39 +0900258 try (Cursor cursor = mContentResolver.query(
Wonsik Kim37388882014-09-07 12:24:20 +0900259 TvContract.buildProgramsUriForChannel(channelUri),
260 projection, null, null, null)) {
261 long startTimeMs = 0;
262 long endTimeMs = 0;
263 while (cursor.moveToNext()) {
264 Uri programUri = TvContract.buildProgramUri(cursor.getLong(0));
265 endTimeMs += PROGRAM_DURATION_MS;
266 operations.add(
267 ContentProviderOperation.newUpdate(programUri)
268 .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS, startTimeMs)
269 .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS, endTimeMs)
270 .build());
271 startTimeMs = endTimeMs;
272 }
273 }
274 try {
275 mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
276 } catch (OperationApplicationException | RemoteException e) {
277 throw new RuntimeException(e);
278 }
279 }
280 });
281 getReportLog().printArray("Elapsed time for update: ",
282 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
283 averages[1] = Stat.getAverage(applyBatchTimes);
284
Dongwon Kang223816c2015-06-30 14:45:18 -0700285 // Query programs
Dongwon Kanga1c03052015-05-11 16:55:39 +0900286 applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
Wonsik Kim37388882014-09-07 12:24:20 +0900287 @Override
288 public void run(int i) {
Dongwon Kanga1c03052015-05-11 16:55:39 +0900289 try (Cursor cursor = mContentResolver.query(Programs.CONTENT_URI, null, null,
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900290 null, null)) {
Wonsik Kim37388882014-09-07 12:24:20 +0900291 while (cursor.moveToNext()) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700292 // Do nothing. Just iterate all the items.
Wonsik Kim37388882014-09-07 12:24:20 +0900293 }
294 }
295 }
296 });
Dongwon Kang223816c2015-06-30 14:45:18 -0700297 getReportLog().printArray("Elapsed time for query (programs): ",
Wonsik Kim37388882014-09-07 12:24:20 +0900298 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
299 averages[2] = Stat.getAverage(applyBatchTimes);
300
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900301 // Query programs with selection
Dongwon Kanga1c03052015-05-11 16:55:39 +0900302 applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900303 @Override
304 public void run(int i) {
305 Uri channelUri = channelUris.get(i);
Dongwon Kanga1c03052015-05-11 16:55:39 +0900306 try (Cursor cursor = mContentResolver.query(
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900307 TvContract.buildProgramsUriForChannel(
308 channelUri, 0,
309 PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2),
310 null, null, null, null)) {
311 while (cursor.moveToNext()) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700312 // Do nothing. Just iterate all the items.
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900313 }
314 }
315 }
316 });
Dongwon Kang223816c2015-06-30 14:45:18 -0700317 getReportLog().printArray("Elapsed time for query (programs with selection): ",
Dongwon Kang9fd4e242015-04-14 15:11:09 +0900318 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
319 averages[3] = Stat.getAverage(applyBatchTimes);
320
Dongwon Kang223816c2015-06-30 14:45:18 -0700321 // Query a program
322 try (final Cursor cursor = mContentResolver.query(Programs.CONTENT_URI,
323 projection, null, null, null)) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700324 applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
325 @Override
326 public void run(int i) {
327 assertTrue(cursor.moveToNext());
Dongwon Kangc004f8f2015-10-22 16:18:44 -0700328 try (Cursor c = mContentResolver.query(TvContract.buildProgramUri(
329 cursor.getLong(0)), null, null, null, null)) {
Dongwon Kang223816c2015-06-30 14:45:18 -0700330 while (c.moveToNext()) {
331 // Do nothing. Just iterate all the items.
332 }
333 }
334 }
335 });
336 }
337 getReportLog().printArray("Elapsed time for query (a program): ",
338 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
339 averages[4] = Stat.getAverage(applyBatchTimes);
340
Wonsik Kim37388882014-09-07 12:24:20 +0900341 // Delete programs
342 applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
343 @Override
344 public void run(int i) {
345 Uri channelUri = channelUris.get(i);
346 mContentResolver.delete(
347 TvContract.buildProgramsUriForChannel(
348 channelUri,
349 PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2,
350 PROGRAM_DURATION_MS * TRANSACTION_SIZE),
351 null, null);
352 }
353 });
354 getReportLog().printArray("Elapsed time for delete programs: ",
355 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
Dongwon Kang223816c2015-06-30 14:45:18 -0700356 averages[5] = Stat.getAverage(applyBatchTimes);
Wonsik Kim37388882014-09-07 12:24:20 +0900357
358 // Delete channels
359 applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
360 @Override
361 public void run(int i) {
362 Uri channelUri = channelUris.get(i);
363 mContentResolver.delete(channelUri, null, null);
364 }
365 });
366 getReportLog().printArray("Elapsed time for delete channels: ",
367 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
Dongwon Kang223816c2015-06-30 14:45:18 -0700368 averages[6] = Stat.getAverage(applyBatchTimes);
Wonsik Kim37388882014-09-07 12:24:20 +0900369
Dongwon Kang223816c2015-06-30 14:45:18 -0700370 getReportLog().printArray("Average elapsed time for insert, update, query (programs), "
371 + "query (programs with selection), query (a channel), delete (channels), "
372 + "delete (programs): ",
Wonsik Kim37388882014-09-07 12:24:20 +0900373 averages, ResultType.LOWER_BETTER, ResultUnit.MS);
374 }
375}