Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2016 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 android.sustainedPerformance.cts;
     18 
     19 import com.android.compatibility.common.util.CddTest;
     20 import com.android.ddmlib.IShellOutputReceiver;
     21 import com.android.ddmlib.Log;
     22 import com.android.ddmlib.MultiLineReceiver;
     23 import com.android.tradefed.device.ITestDevice;
     24 import com.android.tradefed.testtype.DeviceTestCase;
     25 import java.util.*;
     26 import java.util.ArrayList;
     27 import java.util.Arrays;
     28 import java.util.Scanner;
     29 import java.util.concurrent.TimeUnit;
     30 /**
     31  * Test to check if device implements Sustained Performance Mode
     32  */
     33 @CddTest(requirement="8.5/C-0-1,C-1-1,C-1-2")
     34 public class SustainedPerformanceHostTest extends DeviceTestCase {
     35 
     36     ITestDevice device;
     37     private static final String PACKAGE = "com.android.gputest";
     38     private static final String CLASS = "GPUStressTestActivity";
     39     private static final String START_COMMAND = String.format(
     40             "am start -W -a android.intent.action.MAIN -n %s/%s.%s",
     41             PACKAGE, PACKAGE, CLASS);
     42     private static final String START_COMMAND_MODE = String.format(
     43             "am start -W -a android.intent.action.MAIN -n %s/%s.%s --ez SustainedPerformanceMode true",
     44             PACKAGE, PACKAGE, CLASS);
     45     private static final String STOP_COMMAND = String.format(
     46             "am force-stop %s", PACKAGE);
     47     private static final String TEST_PACKAGE = "android.test.app";
     48     private static final String TEST_CLASS = "DeviceTestActivity";
     49     private static final String START_TEST_COMMAND = String.format(
     50             "am start -W -a android.intent.action.MAIN -n %s/%s.%s",
     51             TEST_PACKAGE, TEST_PACKAGE, TEST_CLASS);
     52     private static final String DHRYSTONE = "/data/local/tmp/";
     53     private static final String LOG_TAG = "sustainedPerfTest";
     54 
     55     private static ArrayList<Double> appResultsWithMode = new ArrayList<Double>();
     56     private static ArrayList<Double> appResultsWithoutMode = new ArrayList<Double>();
     57     private static ArrayList<Double> dhrystoneResultsWithMode = new ArrayList<Double>();
     58     private static ArrayList<Double> dhrystoneResultsWithoutMode = new ArrayList<Double>();
     59     private double dhryMin = Double.MAX_VALUE, dhryMax = Double.MIN_VALUE;
     60     private static long testDuration = 1800000; //30 minutes
     61 
     62     public class Dhrystone implements Runnable {
     63         private boolean modeEnabled;
     64         private long startTime;
     65         private long loopCount = 300000000;
     66         private long cpumask = 1;
     67 
     68         public Dhrystone(boolean enabled, long cm) {
     69             cpumask = cm;
     70             modeEnabled = enabled;
     71             startTime = System.currentTimeMillis();
     72         }
     73 
     74         public void run() {
     75             double[] testSet = new double[3];
     76             int index = 0;
     77             try {
     78                 device.executeShellCommand("cd " + DHRYSTONE + " ; chmod 777 dhry");
     79                 while (true) {
     80                     String result = device.executeShellCommand("echo " + loopCount
     81                           + " | taskset -a " + cpumask + " " + DHRYSTONE + "dhry");
     82                     if (Math.abs(System.currentTimeMillis() - startTime) >= testDuration) {
     83                         break;
     84                     } else if (result.contains("Measured time too small")) {
     85                          loopCount = loopCount*10;
     86                     } else if (!result.isEmpty()){
     87                          double dmips = Double.parseDouble(result);
     88                          testSet[index++] = dmips;
     89                          if (index == 3) {
     90                              synchronized(this) {
     91                                  if (modeEnabled) {
     92                                      dhrystoneResultsWithMode.add(testSet[1]);
     93                                  } else {
     94                                      dhrystoneResultsWithoutMode.add(testSet[1]);
     95                                  }
     96                                  if (testSet[1] > dhryMax) {
     97                                      dhryMax = testSet[1];
     98                                  }
     99                                  if (testSet[1] < dhryMin) {
    100                                      dhryMin = testSet[1];
    101                                  }
    102                                  index = 0;
    103                              }
    104                         }
    105                     }
    106                }
    107            } catch (Exception e) {
    108                Log.e(LOG_TAG, e.toString());
    109 
    110            }
    111         }
    112     }
    113 
    114     public void analyzeResults(String logs, boolean mode) {
    115         Double[] testSet = new Double[10];
    116         int index = 0;
    117         double min = Double.MAX_VALUE, max = Double.MIN_VALUE;
    118         boolean first = true;
    119 
    120         Scanner in = new Scanner(logs);
    121         while (in.hasNextLine()) {
    122             String line = in.nextLine();
    123             if(line.startsWith("I/"+CLASS)) {
    124                 Double time = Double.parseDouble(line.split(":")[1]);
    125                 testSet[index++] = time;
    126                 if (index == 10) {
    127                     if (first) {
    128                         first = false;
    129                         index = 0;
    130                         continue;
    131                     }
    132                     Arrays.sort(testSet);
    133                     if (mode) {
    134                         appResultsWithMode.add(testSet[5]);
    135                     } else {
    136                         appResultsWithoutMode.add(testSet[5]);
    137                     }
    138                     if (testSet[5] > max) {
    139                         max = testSet[5];
    140                     }
    141                     if (testSet[5] < min) {
    142                         min = testSet[5];
    143                     }
    144                     index = 0;
    145                 }
    146             }
    147         }
    148         in.close();
    149         double diff = (max - min)*100/max;
    150         if (mode) {
    151             appResultsWithMode.add(0, min);
    152             appResultsWithMode.add(1, max);
    153             appResultsWithMode.add(2, diff);
    154         } else {
    155             appResultsWithoutMode.add(0, min);
    156             appResultsWithoutMode.add(1, max);
    157             appResultsWithoutMode.add(2, diff);
    158         }
    159     }
    160 
    161     private void setUpEnvironment() throws Exception {
    162         dhryMin = Double.MAX_VALUE;
    163         dhryMax = Double.MIN_VALUE;
    164         Thread.sleep(600000);
    165         device.executeAdbCommand("logcat", "-c");
    166         device.executeShellCommand("settings put global airplane_mode_on 1");
    167         device.executeShellCommand("am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true");
    168     }
    169 
    170     public void testShader() throws Exception {
    171         device = getDevice();
    172 
    173         /**
    174          * Check if the device supports Sustained Performance Mode.
    175          * If not then assert true and return.
    176          **/
    177         device.executeAdbCommand("logcat", "-c");
    178         device.executeShellCommand(START_TEST_COMMAND);
    179         String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", TEST_CLASS + ":I", "*:S");
    180         String testString = "";
    181         Scanner in = new Scanner(logs);
    182         while (in.hasNextLine()) {
    183             String line = in.nextLine();
    184             if(line.startsWith("I/"+TEST_CLASS)) {
    185                 testString = line.split(":")[1].trim();
    186             }
    187         }
    188         in.close();
    189         if (testString.isEmpty()) {
    190             assertTrue(true);
    191             return;
    192         }
    193 
    194         appResultsWithoutMode.clear();
    195         appResultsWithMode.clear();
    196         dhrystoneResultsWithoutMode.clear();
    197         dhrystoneResultsWithMode.clear();
    198 
    199         /*
    200          * Run the test with the mode.
    201          * Start the application and collect stats.
    202          * Run two threads of dhrystone and collect stats.
    203          */
    204         setUpEnvironment();
    205         device.executeShellCommand(START_COMMAND_MODE);
    206         Thread dhrystone = new Thread(new Dhrystone(true, 1));
    207         Thread dhrystone1 = new Thread(new Dhrystone(true, 2));
    208         dhrystone.start();
    209         dhrystone1.start();
    210         Thread.sleep(testDuration);
    211         device.executeShellCommand(STOP_COMMAND);
    212         dhrystone.join();
    213         dhrystone1.join();
    214         logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
    215         analyzeResults(logs, true);
    216         double diff = (dhryMax - dhryMin)*100/dhryMax;
    217         dhrystoneResultsWithMode.add(0, dhryMin);
    218         dhrystoneResultsWithMode.add(1, dhryMax);
    219         dhrystoneResultsWithMode.add(2, diff);
    220 
    221         device.executeShellCommand("settings put global airplane_mode_on 0");
    222         device.executeShellCommand("am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false");
    223 
    224         double resDhry = dhrystoneResultsWithMode.get(2);
    225         double resApp = appResultsWithMode.get(2);
    226 
    227         /* Report if performance is below 5% margin for both dhrystone and shader */
    228         if ((resDhry > 5) || (resApp > 5)) {
    229             Log.w("SustainedPerformanceHostTests",
    230                   "Sustainable mode results, Dhrystone: " + resDhry + " App: " + resApp);
    231         }
    232 
    233         /*
    234          * Error if the performance in the mode is not consistent with
    235          * 5% error margin for shader and 10% error margin for dhrystone.
    236          */
    237         assertFalse("Results in the mode are not sustainable",
    238                     (resDhry > 15) ||
    239                     (resApp > 5));
    240     }
    241 }
    242