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