Home | History | Annotate | Download | only in benchmark
      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