1 /* 2 * Copyright (C) 2017 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.example.android.nn.benchmark; 18 19 import android.app.Activity; 20 import android.content.Intent; 21 import android.os.Bundle; 22 import android.util.Log; 23 import android.widget.TextView; 24 25 public class NNBenchmark extends Activity { 26 protected static final String TAG = "NN_BENCHMARK"; 27 28 private int mTestList[]; 29 private float mTestResults[]; 30 private String mTestInfo[]; 31 32 private TextView mTextView; 33 private boolean mToggleLong; 34 private boolean mTogglePause; 35 36 // In demo mode this is used to count updates in the pipeline. It's 37 // incremented when work is submitted to RS and decremented when invalidate is 38 // called to display a result. 39 private boolean mDemoMode; 40 41 // Initialize the parameters for Instrumentation tests. 42 protected void prepareInstrumentationTest() { 43 mTestList = new int[1]; 44 mTestResults = new float[1]; 45 mTestInfo = new String[1]; 46 mDemoMode = false; 47 mProcessor = new Processor(!mDemoMode); 48 } 49 50 ///////////////////////////////////////////////////////////////////////// 51 // Processor is a helper thread for running the work without 52 // blocking the UI thread. 53 class Processor extends Thread { 54 55 private float mLastResult; 56 private boolean mRun = true; 57 private boolean mDoingBenchmark; 58 private NNTestBase mTest; 59 60 private boolean mBenchmarkMode; 61 62 void runTest() { 63 mTest.runTest(); 64 } 65 66 Processor(boolean benchmarkMode) { 67 mBenchmarkMode = benchmarkMode; 68 } 69 70 class Result { 71 float totalTime; 72 int iterations; 73 String testInfo; 74 } 75 76 // Method to retreive benchmark results for instrumentation tests. 77 float getInstrumentationResult(NNTestList.TestName t) { 78 mTest = changeTest(t); 79 Result r = getBenchmark(); 80 return r.totalTime / r.iterations * 1000.f; 81 } 82 83 // Run one loop of kernels for at least the specified minimum time. 84 // The function returns the average time in ms for the test run 85 private Result runBenchmarkLoop(float minTime) { 86 Result r = new Result(); 87 long start = java.lang.System.currentTimeMillis(); 88 89 r.testInfo = mTest.getTestInfo(); 90 do { 91 // Run the kernel 92 mTest.runTest(); 93 r.iterations ++; 94 95 long current = java.lang.System.currentTimeMillis(); 96 r.totalTime = (current - start) / 1000.f; 97 } while (r.totalTime < minTime); 98 99 return r; 100 } 101 102 103 // Get a benchmark result for a specific test 104 private Result getBenchmark() { 105 mDoingBenchmark = true; 106 107 long result = 0; 108 float runtime = 1.f; 109 if (mToggleLong) { 110 runtime = 10.f; 111 } 112 113 // We run a short bit of work before starting the actual test 114 // this is to let any power management do its job and respond 115 runBenchmarkLoop(0.3f); 116 117 // Run the actual benchmark 118 Result r = runBenchmarkLoop(runtime); 119 120 Log.v(TAG, "Test: time=" + r.totalTime +"s, iterations=" + r.iterations + 121 ", avg=" + r.totalTime / r.iterations * 1000.f + " " + r.testInfo); 122 123 mDoingBenchmark = false; 124 return r; 125 } 126 127 public void run() { 128 while (mRun) { 129 // Our loop for launching tests or benchmarks 130 synchronized(this) { 131 // We may have been asked to exit while waiting 132 if (!mRun) return; 133 } 134 135 if (mBenchmarkMode) { 136 // Loop over the tests we want to benchmark 137 for (int ct=0; (ct < mTestList.length) && mRun; ct++) { 138 139 // For reproducibility we wait a short time for any sporadic work 140 // created by the user touching the screen to launch the test to pass. 141 // Also allows for things to settle after the test changes. 142 try { 143 sleep(250); 144 } catch(InterruptedException e) { 145 } 146 147 // If we just ran a test, we destroy it here to relieve some memory pressure 148 if (mTest != null) { 149 mTest.destroy(); 150 } 151 152 // Select the next test 153 mTest = changeTest(mTestList[ct]); 154 // If the user selected the "long pause" option, wait 155 if (mTogglePause) { 156 for (int i=0; (i < 100) && mRun; i++) { 157 try { 158 sleep(100); 159 } catch(InterruptedException e) { 160 } 161 } 162 } 163 164 // Run the test 165 Result r = getBenchmark(); 166 mTestResults[ct] = r.totalTime / r.iterations * 1000.f; 167 mTestInfo[ct] = r.testInfo; 168 } 169 onBenchmarkFinish(mRun); 170 } else { 171 // Run the kernel 172 runTest(); 173 } 174 } 175 176 } 177 178 public void exit() { 179 mRun = false; 180 181 synchronized(this) { 182 notifyAll(); 183 } 184 185 try { 186 this.join(); 187 } catch(InterruptedException e) { 188 } 189 190 if (mTest != null) { 191 mTest.destroy(); 192 mTest = null; 193 } 194 } 195 } 196 197 198 private boolean mDoingBenchmark; 199 public Processor mProcessor; 200 201 NNTestBase changeTest(NNTestList.TestName t) { 202 NNTestBase tb = NNTestList.newTest(t); 203 tb.createBaseTest(this); 204 return tb; 205 } 206 207 NNTestBase changeTest(int id) { 208 NNTestList.TestName t = NNTestList.TestName.values()[id]; 209 return changeTest(t); 210 } 211 212 @Override 213 protected void onCreate(Bundle savedInstanceState) { 214 super.onCreate(savedInstanceState); 215 TextView textView = new TextView(this); 216 textView.setTextSize(20); 217 textView.setText("NN BenchMark Running."); 218 setContentView(textView); 219 } 220 221 @Override 222 protected void onPause() { 223 super.onPause(); 224 if (mProcessor != null) { 225 mProcessor.exit(); 226 } 227 } 228 229 public void onBenchmarkFinish(boolean ok) { 230 if (ok) { 231 Intent intent = new Intent(); 232 intent.putExtra("tests", mTestList); 233 intent.putExtra("results", mTestResults); 234 intent.putExtra("testinfo", mTestInfo); 235 setResult(RESULT_OK, intent); 236 } else { 237 setResult(RESULT_CANCELED); 238 } 239 finish(); 240 } 241 242 @Override 243 protected void onResume() { 244 super.onResume(); 245 Intent i = getIntent(); 246 mTestList = i.getIntArrayExtra("tests"); 247 248 mToggleLong = i.getBooleanExtra("enable long", false); 249 mTogglePause = i.getBooleanExtra("enable pause", false); 250 mDemoMode = i.getBooleanExtra("demo", false); 251 252 if (mTestList != null) { 253 mTestResults = new float[mTestList.length]; 254 mTestInfo = new String[mTestList.length]; 255 mProcessor = new Processor(!mDemoMode); 256 if (mDemoMode) { 257 mProcessor.mTest = changeTest(mTestList[0]); 258 } 259 mProcessor.start(); 260 } 261 } 262 263 @Override 264 protected void onDestroy() { 265 super.onDestroy(); 266 } 267 } 268