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