Home | History | Annotate | Download | only in tvproviderperf
      1 /*
      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 
     17 package com.android.cts.tvproviderperf;
     18 
     19 import android.content.ComponentName;
     20 import android.content.ContentProviderOperation;
     21 import android.content.ContentProviderResult;
     22 import android.content.ContentResolver;
     23 import android.content.ContentUris;
     24 import android.content.ContentValues;
     25 import android.content.OperationApplicationException;
     26 import android.content.pm.PackageManager;
     27 import android.database.Cursor;
     28 import android.cts.util.CtsAndroidTestCase;
     29 import android.media.tv.TvContract;
     30 import android.media.tv.TvContract.Channels;
     31 import android.media.tv.TvContract.Programs;
     32 import android.net.Uri;
     33 import android.os.RemoteException;
     34 
     35 import com.android.cts.util.MeasureRun;
     36 import com.android.cts.util.MeasureTime;
     37 import com.android.cts.util.ResultType;
     38 import com.android.cts.util.ResultUnit;
     39 import com.android.cts.util.ReportLog;
     40 import com.android.cts.util.TimeoutReq;
     41 import com.android.cts.util.Stat;
     42 
     43 import java.util.ArrayList;
     44 import 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  */
     51 public class TvProviderPerfTest extends CtsAndroidTestCase {
     52     private ContentResolver mContentResolver;
     53     private String mInputId;
     54     private boolean mHasTvInputFramework;
     55 
     56     @Override
     57     protected void setUp() throws Exception {
     58         super.setUp();
     59         mHasTvInputFramework = getContext().getPackageManager().hasSystemFeature(
     60                 PackageManager.FEATURE_LIVE_TV);
     61         if (!mHasTvInputFramework) return;
     62         mContentResolver = getContext().getContentResolver();
     63         mInputId = TvContract.buildInputId(new ComponentName(getContext(), getClass()));
     64     }
     65 
     66     @Override
     67     protected void tearDown() throws Exception {
     68         try {
     69             if (!mHasTvInputFramework) return;
     70             mContentResolver.delete(Programs.CONTENT_URI, null, null);
     71             mContentResolver.delete(Channels.CONTENT_URI, null, null);
     72         } finally {
     73             super.tearDown();
     74         }
     75     }
     76 
     77     @TimeoutReq(minutes = 10)
     78     public void testChannels() throws Exception {
     79         if (!mHasTvInputFramework) return;
     80         double[] averages = new double[3];
     81 
     82         // Insert
     83         final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
     84         final int TRANSACTION_SIZE = 1000;
     85         final int TRANSACTION_RUNS = 100;
     86         double[] applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
     87             @Override
     88             public void run(int i) {
     89                 operations.clear();
     90                 for (int j = 0; j < TRANSACTION_SIZE; ++j) {
     91                     ContentValues values = new ContentValues();
     92                     values.put(Channels.COLUMN_INPUT_ID, mInputId);
     93                     values.put(Channels.COLUMN_SERVICE_TYPE,
     94                             Channels.SERVICE_TYPE_AUDIO_VIDEO);
     95                     values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
     96                     operations.add(
     97                             ContentProviderOperation.newInsert(Channels.CONTENT_URI)
     98                             .withValues(values).build());
     99                 }
    100                 try {
    101                     mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
    102                 } catch (OperationApplicationException | RemoteException e) {
    103                     throw new RuntimeException(e);
    104                 }
    105             }
    106         });
    107         getReportLog().printArray("Elapsed time for insert: ",
    108                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    109         averages[0] = Stat.getAverage(applyBatchTimes);
    110 
    111         // Update
    112         final String[] projection = { Channels._ID };
    113         try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
    114                 projection, null, null, null)) {
    115             applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
    116                 @Override
    117                 public void run(int i) {
    118                     operations.clear();
    119                     for (int j = 0; j < TRANSACTION_SIZE && cursor.moveToNext(); ++j) {
    120                         Uri channelUri = TvContract.buildChannelUri(cursor.getLong(0));
    121                         String number = Integer.toString(i * TRANSACTION_SIZE + j);
    122                         operations.add(
    123                                 ContentProviderOperation.newUpdate(channelUri)
    124                                 .withValue(Channels.COLUMN_DISPLAY_NUMBER, number)
    125                                 .build());
    126                     }
    127                     try {
    128                         mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
    129                     } catch (OperationApplicationException | RemoteException e) {
    130                         throw new RuntimeException(e);
    131                     }
    132                 }
    133             });
    134         }
    135         getReportLog().printArray("Elapsed time for update: ",
    136                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    137         averages[1] = Stat.getAverage(applyBatchTimes);
    138 
    139         // Delete
    140         applyBatchTimes = MeasureTime.measure(1, new MeasureRun() {
    141             @Override
    142             public void run(int i) {
    143                 mContentResolver.delete(TvContract.buildChannelsUriForInput(mInputId), null, null);
    144             }
    145         });
    146         getReportLog().printArray("Elapsed time for delete: ",
    147                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    148         averages[2] = Stat.getAverage(applyBatchTimes);
    149 
    150         // Query is not interesting for channels.
    151         getReportLog().printArray("Average elapsed time for (insert, update, delete): ",
    152                 averages, ResultType.LOWER_BETTER, ResultUnit.MS);
    153     }
    154 
    155     @TimeoutReq(minutes = 15)
    156     public void testPrograms() throws Exception {
    157         if (!mHasTvInputFramework) return;
    158         double[] averages = new double[5];
    159 
    160         // Prepare (insert channels)
    161         final ArrayList<ContentProviderOperation> operations = new ArrayList<>();
    162         final int TRANSACTION_SIZE = 1000;
    163         final int NUM_CHANNELS = 100;
    164         final List<Uri> channelUris = new ArrayList<>();
    165 
    166         operations.clear();
    167         for (int i = 0; i < NUM_CHANNELS; ++i) {
    168             ContentValues values = new ContentValues();
    169             values.put(Channels.COLUMN_INPUT_ID, mInputId);
    170             values.put(Channels.COLUMN_SERVICE_TYPE,
    171                     Channels.SERVICE_TYPE_AUDIO_VIDEO);
    172             values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER);
    173             operations.add(
    174                     ContentProviderOperation.newInsert(Channels.CONTENT_URI)
    175                     .withValues(values).build());
    176         }
    177         try {
    178             ContentProviderResult[] results =
    179                     mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
    180             for (ContentProviderResult result : results) {
    181                 channelUris.add(result.uri);
    182             }
    183         } catch (OperationApplicationException | RemoteException e) {
    184             throw new RuntimeException(e);
    185         }
    186 
    187         // Insert
    188         double[] applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
    189             @Override
    190             public void run(int i) {
    191                 operations.clear();
    192                 Uri channelUri = channelUris.get(i);
    193                 long channelId = ContentUris.parseId(channelUri);
    194                 for (int j = 0; j < TRANSACTION_SIZE; ++j) {
    195                     ContentValues values = new ContentValues();
    196                     values.put(Programs.COLUMN_CHANNEL_ID, channelId);
    197                     operations.add(
    198                             ContentProviderOperation.newInsert(Programs.CONTENT_URI)
    199                             .withValues(values).build());
    200                 }
    201                 try {
    202                     mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
    203                 } catch (OperationApplicationException | RemoteException e) {
    204                     throw new RuntimeException(e);
    205                 }
    206             }
    207         });
    208         getReportLog().printArray("Elapsed time for insert: ",
    209                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    210         averages[0] = Stat.getAverage(applyBatchTimes);
    211 
    212         // Update
    213         final long PROGRAM_DURATION_MS = 60 * 1000;
    214         final String[] projection = { Programs._ID };
    215         applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
    216             @Override
    217             public void run(int i) {
    218                 Uri channelUri = channelUris.get(i);
    219                 operations.clear();
    220                 try (final Cursor cursor = mContentResolver.query(
    221                         TvContract.buildProgramsUriForChannel(channelUri),
    222                         projection, null, null, null)) {
    223                     long startTimeMs = 0;
    224                     long endTimeMs = 0;
    225                     while (cursor.moveToNext()) {
    226                         Uri programUri = TvContract.buildProgramUri(cursor.getLong(0));
    227                         endTimeMs += PROGRAM_DURATION_MS;
    228                         operations.add(
    229                                 ContentProviderOperation.newUpdate(programUri)
    230                                 .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS, startTimeMs)
    231                                 .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS, endTimeMs)
    232                                 .build());
    233                         startTimeMs = endTimeMs;
    234                     }
    235                 }
    236                 try {
    237                     mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
    238                 } catch (OperationApplicationException | RemoteException e) {
    239                     throw new RuntimeException(e);
    240                 }
    241             }
    242         });
    243         getReportLog().printArray("Elapsed time for update: ",
    244                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    245         averages[1] = Stat.getAverage(applyBatchTimes);
    246 
    247         // Query
    248         applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
    249             @Override
    250             public void run(int i) {
    251                 Uri channelUri = channelUris.get(i);
    252                 int j = 0;
    253                 try (final Cursor cursor = mContentResolver.query(
    254                         TvContract.buildProgramsUriForChannel(
    255                                 channelUri, 0,
    256                                 PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2),
    257                         projection, null, null, null)) {
    258                     while (cursor.moveToNext()) {
    259                         ++j;
    260                     }
    261                 }
    262             }
    263         });
    264         getReportLog().printArray("Elapsed time for query: ",
    265                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    266         averages[2] = Stat.getAverage(applyBatchTimes);
    267 
    268         // Delete programs
    269         applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
    270             @Override
    271             public void run(int i) {
    272                 Uri channelUri = channelUris.get(i);
    273                 mContentResolver.delete(
    274                         TvContract.buildProgramsUriForChannel(
    275                                 channelUri,
    276                                 PROGRAM_DURATION_MS * TRANSACTION_SIZE / 2,
    277                                 PROGRAM_DURATION_MS * TRANSACTION_SIZE),
    278                         null, null);
    279             }
    280         });
    281         getReportLog().printArray("Elapsed time for delete programs: ",
    282                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    283         averages[3] = Stat.getAverage(applyBatchTimes);
    284 
    285         // Delete channels
    286         applyBatchTimes = MeasureTime.measure(NUM_CHANNELS, new MeasureRun() {
    287             @Override
    288             public void run(int i) {
    289                 Uri channelUri = channelUris.get(i);
    290                 mContentResolver.delete(channelUri, null, null);
    291             }
    292         });
    293         getReportLog().printArray("Elapsed time for delete channels: ",
    294                 applyBatchTimes, ResultType.LOWER_BETTER, ResultUnit.MS);
    295         averages[4] = Stat.getAverage(applyBatchTimes);
    296 
    297         getReportLog().printArray("Average elapsed time for (insert, update, query, "
    298                 + "delete channels, delete programs): ",
    299                 averages, ResultType.LOWER_BETTER, ResultUnit.MS);
    300     }
    301 }
    302