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 
17 package com.android.benchmark.synthetic;
18 
19 import android.view.View;
20 import android.widget.TextView;
21 
22 import org.apache.commons.math.stat.StatUtils;
23 import org.apache.commons.math.stat.descriptive.SummaryStatistics;
24 
25 import java.util.LinkedList;
26 import java.util.Queue;
27 
28 
29 public class TestInterface {
nInit(long options)30     native long nInit(long options);
nDestroy(long b)31     native long nDestroy(long b);
nGetData(long b, float[] data)32     native float nGetData(long b, float[] data);
nRunPowerManagementTest(long b, long options)33     native boolean nRunPowerManagementTest(long b, long options);
nRunCPUHeatSoakTest(long b, long options)34     native boolean nRunCPUHeatSoakTest(long b, long options);
35 
nMemTestStart(long b)36     native boolean nMemTestStart(long b);
nMemTestBandwidth(long b, long size)37     native float nMemTestBandwidth(long b, long size);
nMemTestLatency(long b, long size)38     native float nMemTestLatency(long b, long size);
nMemTestEnd(long b)39     native void nMemTestEnd(long b);
40 
nGFlopsTest(long b, long opt)41     native float nGFlopsTest(long b, long opt);
42 
43     public static class TestResultCallback {
onTestResult(int command, float result)44         void onTestResult(int command, float result) { }
45     }
46 
47     static {
48         System.loadLibrary("nativebench");
49     }
50 
51     float[] mLinesLow;
52     float[] mLinesHigh;
53     float[] mLinesValue;
54     TextView mTextStatus;
55     TextView mTextMin;
56     TextView mTextMax;
57     TextView mTextTypical;
58 
59     private View mViewToUpdate;
60 
61     private LooperThread mLT;
62 
TestInterface(View v, int runtimeSeconds, TestResultCallback callback)63     TestInterface(View v, int runtimeSeconds, TestResultCallback callback) {
64         int buckets = runtimeSeconds * 1000;
65         mLinesLow = new float[buckets * 4];
66         mLinesHigh = new float[buckets * 4];
67         mLinesValue = new float[buckets * 4];
68         mViewToUpdate = v;
69 
70         mLT = new LooperThread(this, callback);
71         mLT.start();
72     }
73 
74     static class LooperThread extends Thread {
75         public static final int CommandExit = 1;
76         public static final int TestPowerManagement = 2;
77         public static final int TestMemoryBandwidth = 3;
78         public static final int TestMemoryLatency = 4;
79         public static final int TestHeatSoak = 5;
80         public static final int TestGFlops = 6;
81 
82         private volatile boolean mRun = true;
83         private TestInterface mTI;
84         private TestResultCallback mCallback;
85 
86         Queue<Integer> mCommandQueue = new LinkedList<Integer>();
87 
LooperThread(TestInterface ti, TestResultCallback callback)88         LooperThread(TestInterface ti, TestResultCallback callback) {
89             super("BenchmarkTestThread");
90             mTI = ti;
91             mCallback = callback;
92         }
93 
runCommand(int command)94         void runCommand(int command) {
95             Integer i = Integer.valueOf(command);
96 
97             synchronized (this) {
98                 mCommandQueue.add(i);
99                 notifyAll();
100             }
101         }
102 
run()103         public void run() {
104             long b = mTI.nInit(0);
105             if (b == 0) {
106                 return;
107             }
108 
109             while (mRun) {
110                 int command = 0;
111                 synchronized (this) {
112                     if (mCommandQueue.isEmpty()) {
113                         try {
114                             wait();
115                         } catch (InterruptedException e) {
116                         }
117                     }
118 
119                     if (!mCommandQueue.isEmpty()) {
120                         command = mCommandQueue.remove();
121                     }
122                 }
123 
124                 switch (command) {
125                     case CommandExit:
126                         mRun = false;
127                         break;
128                     case TestPowerManagement:
129                         float score = mTI.testPowerManagement(b);
130                         mCallback.onTestResult(command, 0);
131                         break;
132                     case TestMemoryBandwidth:
133                         mTI.testCPUMemoryBandwidth(b);
134                         break;
135                     case TestMemoryLatency:
136                         mTI.testCPUMemoryLatency(b);
137                         break;
138                     case TestHeatSoak:
139                         mTI.testCPUHeatSoak(b);
140                         break;
141                     case TestGFlops:
142                         mTI.testCPUGFlops(b);
143                         break;
144 
145                 }
146 
147                 //mViewToUpdate.post(new Runnable() {
148                   //  public void run() {
149                    //     mViewToUpdate.invalidate();
150                     //}
151                 //});
152             }
153 
154             mTI.nDestroy(b);
155         }
156 
exit()157         void exit() {
158             mRun = false;
159         }
160     }
161 
postTextToView(TextView v, String s)162     void postTextToView(TextView v, String s) {
163         final TextView tv = v;
164         final String ts = s;
165 
166         v.post(new Runnable() {
167             public void run() {
168                 tv.setText(ts);
169             }
170         });
171 
172     }
173 
calcAverage(float[] data)174     float calcAverage(float[] data) {
175         float total = 0.f;
176         for (int ct=0; ct < data.length; ct++) {
177             total += data[ct];
178         }
179         return total / data.length;
180     }
181 
makeGraph(float[] data, float[] lines)182     void makeGraph(float[] data, float[] lines) {
183         for (int ct = 0; ct < data.length; ct++) {
184             lines[ct * 4 + 0] = (float)ct;
185             lines[ct * 4 + 1] = 500.f - data[ct];
186             lines[ct * 4 + 2] = (float)ct;
187             lines[ct * 4 + 3] = 500.f;
188         }
189     }
190 
testPowerManagement(long b)191     float testPowerManagement(long b) {
192         float[] dat = new float[mLinesLow.length / 4];
193         postTextToView(mTextStatus, "Running single-threaded");
194         nRunPowerManagementTest(b, 1);
195         nGetData(b, dat);
196         makeGraph(dat, mLinesLow);
197         mViewToUpdate.postInvalidate();
198         float avgMin = calcAverage(dat);
199 
200         postTextToView(mTextMin, "Single threaded " + avgMin + " per second");
201 
202         postTextToView(mTextStatus, "Running multi-threaded");
203         nRunPowerManagementTest(b, 4);
204         nGetData(b, dat);
205         makeGraph(dat, mLinesHigh);
206         mViewToUpdate.postInvalidate();
207         float avgMax = calcAverage(dat);
208         postTextToView(mTextMax, "Multi threaded " + avgMax + " per second");
209 
210         postTextToView(mTextStatus, "Running typical");
211         nRunPowerManagementTest(b, 0);
212         nGetData(b, dat);
213         makeGraph(dat, mLinesValue);
214         mViewToUpdate.postInvalidate();
215         float avgTypical = calcAverage(dat);
216 
217         float ofIdeal = avgTypical / (avgMax + avgMin) * 200.f;
218         postTextToView(mTextTypical, String.format("Typical mix (50/50) %%%2.0f of ideal", ofIdeal));
219         return ofIdeal * (avgMax + avgMin);
220     }
221 
testCPUHeatSoak(long b)222     float testCPUHeatSoak(long b) {
223         float[] dat = new float[1000];
224         postTextToView(mTextStatus, "Running heat soak test");
225         for (int t = 0; t < 1000; t++) {
226             mLinesLow[t * 4 + 0] = (float)t;
227             mLinesLow[t * 4 + 1] = 498.f;
228             mLinesLow[t * 4 + 2] = (float)t;
229             mLinesLow[t * 4 + 3] = 500.f;
230         }
231 
232         float peak = 0.f;
233         float total = 0.f;
234         float dThroughput = 0;
235         float prev = 0;
236         SummaryStatistics stats = new SummaryStatistics();
237         for (int t = 0; t < 1000; t++) {
238             nRunCPUHeatSoakTest(b, 1);
239             nGetData(b, dat);
240 
241             float p = calcAverage(dat);
242             if (prev != 0) {
243                 dThroughput += (prev - p);
244             }
245 
246             prev = p;
247 
248             mLinesLow[t * 4 + 1] = 499.f - p;
249             if (peak < p) {
250                 peak = p;
251             }
252             for (float f : dat) {
253                 stats.addValue(f);
254             }
255 
256             total += p;
257 
258             mViewToUpdate.postInvalidate();
259             postTextToView(mTextMin, "Peak " + peak + " per second");
260             postTextToView(mTextMax, "Current " + p + " per second");
261             postTextToView(mTextTypical, "Average " + (total / (t + 1)) + " per second");
262         }
263 
264 
265         float decreaseOverTime = dThroughput / 1000;
266 
267         System.out.println("dthroughput/dt: " + decreaseOverTime);
268 
269         float score = (float) (stats.getMean() / (stats.getStandardDeviation() * decreaseOverTime));
270 
271         postTextToView(mTextStatus, "Score: " + score);
272         return score;
273     }
274 
testCPUMemoryBandwidth(long b)275     void testCPUMemoryBandwidth(long b) {
276         int[] sizeK = {1, 2, 3, 4, 5, 6, 7,
277                     8, 10, 12, 14, 16, 20, 24, 28,
278                     32, 40, 48, 56, 64, 80, 96, 112,
279                     128, 160, 192, 224, 256, 320, 384, 448,
280                     512, 640, 768, 896, 1024, 1280, 1536, 1792,
281                     2048, 2560, 3584, 4096, 5120, 6144, 7168,
282                     8192, 10240, 12288, 14336, 16384
283         };
284         final int subSteps = 15;
285         float[] results = new float[sizeK.length * subSteps];
286 
287         nMemTestStart(b);
288 
289         float[] dat = new float[1000];
290         postTextToView(mTextStatus, "Running Memory Bandwidth test");
291         for (int t = 0; t < 1000; t++) {
292             mLinesLow[t * 4 + 0] = (float)t;
293             mLinesLow[t * 4 + 1] = 498.f;
294             mLinesLow[t * 4 + 2] = (float)t;
295             mLinesLow[t * 4 + 3] = 500.f;
296         }
297 
298         for (int i = 0; i < sizeK.length; i++) {
299             postTextToView(mTextStatus, "Running " + sizeK[i] + " K");
300 
301             float rtot = 0.f;
302             for (int j = 0; j < subSteps; j++) {
303                 float ret = nMemTestBandwidth(b, sizeK[i] * 1024);
304                 rtot += ret;
305                 results[i * subSteps + j] = ret;
306                 mLinesLow[(i * subSteps + j) * 4 + 1] = 499.f - (results[i*15+j] * 20.f);
307                 mViewToUpdate.postInvalidate();
308             }
309             rtot /= subSteps;
310 
311             if (sizeK[i] == 2) {
312                 postTextToView(mTextMin, "2K " + rtot + " GB/s");
313             }
314             if (sizeK[i] == 128) {
315                 postTextToView(mTextMax, "128K " + rtot + " GB/s");
316             }
317             if (sizeK[i] == 8192) {
318                 postTextToView(mTextTypical, "8M " + rtot + " GB/s");
319             }
320 
321         }
322 
323         nMemTestEnd(b);
324         postTextToView(mTextStatus, "Done");
325     }
326 
testCPUMemoryLatency(long b)327     void testCPUMemoryLatency(long b) {
328         int[] sizeK = {1, 2, 3, 4, 5, 6, 7,
329                 8, 10, 12, 14, 16, 20, 24, 28,
330                 32, 40, 48, 56, 64, 80, 96, 112,
331                 128, 160, 192, 224, 256, 320, 384, 448,
332                 512, 640, 768, 896, 1024, 1280, 1536, 1792,
333                 2048, 2560, 3584, 4096, 5120, 6144, 7168,
334                 8192, 10240, 12288, 14336, 16384
335         };
336         final int subSteps = 15;
337         float[] results = new float[sizeK.length * subSteps];
338 
339         nMemTestStart(b);
340 
341         float[] dat = new float[1000];
342         postTextToView(mTextStatus, "Running Memory Latency test");
343         for (int t = 0; t < 1000; t++) {
344             mLinesLow[t * 4 + 0] = (float)t;
345             mLinesLow[t * 4 + 1] = 498.f;
346             mLinesLow[t * 4 + 2] = (float)t;
347             mLinesLow[t * 4 + 3] = 500.f;
348         }
349 
350         for (int i = 0; i < sizeK.length; i++) {
351             postTextToView(mTextStatus, "Running " + sizeK[i] + " K");
352 
353             float rtot = 0.f;
354             for (int j = 0; j < subSteps; j++) {
355                 float ret = nMemTestLatency(b, sizeK[i] * 1024);
356                 rtot += ret;
357                 results[i * subSteps + j] = ret;
358 
359                 if (ret > 400.f) ret = 400.f;
360                 if (ret < 0.f) ret = 0.f;
361                 mLinesLow[(i * subSteps + j) * 4 + 1] = 499.f - ret;
362                 //android.util.Log.e("bench", "test bw " + sizeK[i] + " - " + ret);
363                 mViewToUpdate.postInvalidate();
364             }
365             rtot /= subSteps;
366 
367             if (sizeK[i] == 2) {
368                 postTextToView(mTextMin, "2K " + rtot + " ns");
369             }
370             if (sizeK[i] == 128) {
371                 postTextToView(mTextMax, "128K " + rtot + " ns");
372             }
373             if (sizeK[i] == 8192) {
374                 postTextToView(mTextTypical, "8M " + rtot + " ns");
375             }
376 
377         }
378 
379         nMemTestEnd(b);
380         postTextToView(mTextStatus, "Done");
381     }
382 
testCPUGFlops(long b)383     void testCPUGFlops(long b) {
384         int[] sizeK = {1, 2, 3, 4, 5, 6, 7
385         };
386         final int subSteps = 15;
387         float[] results = new float[sizeK.length * subSteps];
388 
389         nMemTestStart(b);
390 
391         float[] dat = new float[1000];
392         postTextToView(mTextStatus, "Running Memory Latency test");
393         for (int t = 0; t < 1000; t++) {
394             mLinesLow[t * 4 + 0] = (float)t;
395             mLinesLow[t * 4 + 1] = 498.f;
396             mLinesLow[t * 4 + 2] = (float)t;
397             mLinesLow[t * 4 + 3] = 500.f;
398         }
399 
400         for (int i = 0; i < sizeK.length; i++) {
401             postTextToView(mTextStatus, "Running " + sizeK[i] + " K");
402 
403             float rtot = 0.f;
404             for (int j = 0; j < subSteps; j++) {
405                 float ret = nGFlopsTest(b, sizeK[i] * 1024);
406                 rtot += ret;
407                 results[i * subSteps + j] = ret;
408 
409                 if (ret > 400.f) ret = 400.f;
410                 if (ret < 0.f) ret = 0.f;
411                 mLinesLow[(i * subSteps + j) * 4 + 1] = 499.f - ret;
412                 mViewToUpdate.postInvalidate();
413             }
414             rtot /= subSteps;
415 
416             if (sizeK[i] == 2) {
417                 postTextToView(mTextMin, "2K " + rtot + " ns");
418             }
419             if (sizeK[i] == 128) {
420                 postTextToView(mTextMax, "128K " + rtot + " ns");
421             }
422             if (sizeK[i] == 8192) {
423                 postTextToView(mTextTypical, "8M " + rtot + " ns");
424             }
425 
426         }
427 
428         nMemTestEnd(b);
429         postTextToView(mTextStatus, "Done");
430     }
431 
runPowerManagement()432     public void runPowerManagement() {
433         mLT.runCommand(mLT.TestPowerManagement);
434     }
435 
runMemoryBandwidth()436     public void runMemoryBandwidth() {
437         mLT.runCommand(mLT.TestMemoryBandwidth);
438     }
439 
runMemoryLatency()440     public void runMemoryLatency() {
441         mLT.runCommand(mLT.TestMemoryLatency);
442     }
443 
runCPUHeatSoak()444     public void runCPUHeatSoak() {
445         mLT.runCommand(mLT.TestHeatSoak);
446     }
447 
runCPUGFlops()448     public void runCPUGFlops() {
449         mLT.runCommand(mLT.TestGFlops);
450     }
451 }
452