1*58b9f456SAndroid Build Coastguard Worker# Benchmark Tools 2*58b9f456SAndroid Build Coastguard Worker 3*58b9f456SAndroid Build Coastguard Worker## compare.py 4*58b9f456SAndroid Build Coastguard Worker 5*58b9f456SAndroid Build Coastguard WorkerThe `compare.py` can be used to compare the result of benchmarks. 6*58b9f456SAndroid Build Coastguard Worker 7*58b9f456SAndroid Build Coastguard Worker**NOTE**: the utility relies on the scipy package which can be installed using [these instructions](https://www.scipy.org/install.html). 8*58b9f456SAndroid Build Coastguard Worker 9*58b9f456SAndroid Build Coastguard Worker### Displaying aggregates only 10*58b9f456SAndroid Build Coastguard Worker 11*58b9f456SAndroid Build Coastguard WorkerThe switch `-a` / `--display_aggregates_only` can be used to control the 12*58b9f456SAndroid Build Coastguard Workerdisplayment of the normal iterations vs the aggregates. When passed, it will 13*58b9f456SAndroid Build Coastguard Workerbe passthrough to the benchmark binaries to be run, and will be accounted for 14*58b9f456SAndroid Build Coastguard Workerin the tool itself; only the aggregates will be displayed, but not normal runs. 15*58b9f456SAndroid Build Coastguard WorkerIt only affects the display, the separate runs will still be used to calculate 16*58b9f456SAndroid Build Coastguard Workerthe U test. 17*58b9f456SAndroid Build Coastguard Worker 18*58b9f456SAndroid Build Coastguard Worker### Modes of operation 19*58b9f456SAndroid Build Coastguard Worker 20*58b9f456SAndroid Build Coastguard WorkerThere are three modes of operation: 21*58b9f456SAndroid Build Coastguard Worker 22*58b9f456SAndroid Build Coastguard Worker1. Just compare two benchmarks 23*58b9f456SAndroid Build Coastguard WorkerThe program is invoked like: 24*58b9f456SAndroid Build Coastguard Worker 25*58b9f456SAndroid Build Coastguard Worker``` bash 26*58b9f456SAndroid Build Coastguard Worker$ compare.py benchmarks <benchmark_baseline> <benchmark_contender> [benchmark options]... 27*58b9f456SAndroid Build Coastguard Worker``` 28*58b9f456SAndroid Build Coastguard WorkerWhere `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. 29*58b9f456SAndroid Build Coastguard Worker 30*58b9f456SAndroid Build Coastguard Worker`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes. 31*58b9f456SAndroid Build Coastguard Worker 32*58b9f456SAndroid Build Coastguard WorkerExample output: 33*58b9f456SAndroid Build Coastguard Worker``` 34*58b9f456SAndroid Build Coastguard Worker$ ./compare.py benchmarks ./a.out ./a.out 35*58b9f456SAndroid Build Coastguard WorkerRUNNING: ./a.out --benchmark_out=/tmp/tmprBT5nW 36*58b9f456SAndroid Build Coastguard WorkerRun on (8 X 4000 MHz CPU s) 37*58b9f456SAndroid Build Coastguard Worker2017-11-07 21:16:44 38*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 39*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Iterations 40*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 41*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8 36 ns 36 ns 19101577 211.669MB/s 42*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/64 76 ns 76 ns 9412571 800.199MB/s 43*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/512 84 ns 84 ns 8249070 5.64771GB/s 44*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/1024 116 ns 116 ns 6181763 8.19505GB/s 45*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8192 643 ns 643 ns 1062855 11.8636GB/s 46*58b9f456SAndroid Build Coastguard WorkerBM_copy/8 222 ns 222 ns 3137987 34.3772MB/s 47*58b9f456SAndroid Build Coastguard WorkerBM_copy/64 1608 ns 1608 ns 432758 37.9501MB/s 48*58b9f456SAndroid Build Coastguard WorkerBM_copy/512 12589 ns 12589 ns 54806 38.7867MB/s 49*58b9f456SAndroid Build Coastguard WorkerBM_copy/1024 25169 ns 25169 ns 27713 38.8003MB/s 50*58b9f456SAndroid Build Coastguard WorkerBM_copy/8192 201165 ns 201112 ns 3486 38.8466MB/s 51*58b9f456SAndroid Build Coastguard WorkerRUNNING: ./a.out --benchmark_out=/tmp/tmpt1wwG_ 52*58b9f456SAndroid Build Coastguard WorkerRun on (8 X 4000 MHz CPU s) 53*58b9f456SAndroid Build Coastguard Worker2017-11-07 21:16:53 54*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 55*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Iterations 56*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 57*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8 36 ns 36 ns 19397903 211.255MB/s 58*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/64 73 ns 73 ns 9691174 839.635MB/s 59*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/512 85 ns 85 ns 8312329 5.60101GB/s 60*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/1024 118 ns 118 ns 6438774 8.11608GB/s 61*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8192 656 ns 656 ns 1068644 11.6277GB/s 62*58b9f456SAndroid Build Coastguard WorkerBM_copy/8 223 ns 223 ns 3146977 34.2338MB/s 63*58b9f456SAndroid Build Coastguard WorkerBM_copy/64 1611 ns 1611 ns 435340 37.8751MB/s 64*58b9f456SAndroid Build Coastguard WorkerBM_copy/512 12622 ns 12622 ns 54818 38.6844MB/s 65*58b9f456SAndroid Build Coastguard WorkerBM_copy/1024 25257 ns 25239 ns 27779 38.6927MB/s 66*58b9f456SAndroid Build Coastguard WorkerBM_copy/8192 205013 ns 205010 ns 3479 38.108MB/s 67*58b9f456SAndroid Build Coastguard WorkerComparing ./a.out to ./a.out 68*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Time Old Time New CPU Old CPU New 69*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------------------------------------------------------ 70*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8 +0.0020 +0.0020 36 36 36 36 71*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/64 -0.0468 -0.0470 76 73 76 73 72*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/512 +0.0081 +0.0083 84 85 84 85 73*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/1024 +0.0098 +0.0097 116 118 116 118 74*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8192 +0.0200 +0.0203 643 656 643 656 75*58b9f456SAndroid Build Coastguard WorkerBM_copy/8 +0.0046 +0.0042 222 223 222 223 76*58b9f456SAndroid Build Coastguard WorkerBM_copy/64 +0.0020 +0.0020 1608 1611 1608 1611 77*58b9f456SAndroid Build Coastguard WorkerBM_copy/512 +0.0027 +0.0026 12589 12622 12589 12622 78*58b9f456SAndroid Build Coastguard WorkerBM_copy/1024 +0.0035 +0.0028 25169 25257 25169 25239 79*58b9f456SAndroid Build Coastguard WorkerBM_copy/8192 +0.0191 +0.0194 201165 205013 201112 205010 80*58b9f456SAndroid Build Coastguard Worker``` 81*58b9f456SAndroid Build Coastguard Worker 82*58b9f456SAndroid Build Coastguard WorkerWhat it does is for the every benchmark from the first run it looks for the benchmark with exactly the same name in the second run, and then compares the results. If the names differ, the benchmark is omitted from the diff. 83*58b9f456SAndroid Build Coastguard WorkerAs you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. 84*58b9f456SAndroid Build Coastguard Worker 85*58b9f456SAndroid Build Coastguard Worker2. Compare two different filters of one benchmark 86*58b9f456SAndroid Build Coastguard WorkerThe program is invoked like: 87*58b9f456SAndroid Build Coastguard Worker 88*58b9f456SAndroid Build Coastguard Worker``` bash 89*58b9f456SAndroid Build Coastguard Worker$ compare.py filters <benchmark> <filter_baseline> <filter_contender> [benchmark options]... 90*58b9f456SAndroid Build Coastguard Worker``` 91*58b9f456SAndroid Build Coastguard WorkerWhere `<benchmark>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. 92*58b9f456SAndroid Build Coastguard Worker 93*58b9f456SAndroid Build Coastguard WorkerWhere `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary. 94*58b9f456SAndroid Build Coastguard Worker 95*58b9f456SAndroid Build Coastguard Worker`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes. 96*58b9f456SAndroid Build Coastguard Worker 97*58b9f456SAndroid Build Coastguard WorkerExample output: 98*58b9f456SAndroid Build Coastguard Worker``` 99*58b9f456SAndroid Build Coastguard Worker$ ./compare.py filters ./a.out BM_memcpy BM_copy 100*58b9f456SAndroid Build Coastguard WorkerRUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmpBWKk0k 101*58b9f456SAndroid Build Coastguard WorkerRun on (8 X 4000 MHz CPU s) 102*58b9f456SAndroid Build Coastguard Worker2017-11-07 21:37:28 103*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 104*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Iterations 105*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 106*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8 36 ns 36 ns 17891491 211.215MB/s 107*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/64 74 ns 74 ns 9400999 825.646MB/s 108*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/512 87 ns 87 ns 8027453 5.46126GB/s 109*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/1024 111 ns 111 ns 6116853 8.5648GB/s 110*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8192 657 ns 656 ns 1064679 11.6247GB/s 111*58b9f456SAndroid Build Coastguard WorkerRUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpAvWcOM 112*58b9f456SAndroid Build Coastguard WorkerRun on (8 X 4000 MHz CPU s) 113*58b9f456SAndroid Build Coastguard Worker2017-11-07 21:37:33 114*58b9f456SAndroid Build Coastguard Worker---------------------------------------------------- 115*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Iterations 116*58b9f456SAndroid Build Coastguard Worker---------------------------------------------------- 117*58b9f456SAndroid Build Coastguard WorkerBM_copy/8 227 ns 227 ns 3038700 33.6264MB/s 118*58b9f456SAndroid Build Coastguard WorkerBM_copy/64 1640 ns 1640 ns 426893 37.2154MB/s 119*58b9f456SAndroid Build Coastguard WorkerBM_copy/512 12804 ns 12801 ns 55417 38.1444MB/s 120*58b9f456SAndroid Build Coastguard WorkerBM_copy/1024 25409 ns 25407 ns 27516 38.4365MB/s 121*58b9f456SAndroid Build Coastguard WorkerBM_copy/8192 202986 ns 202990 ns 3454 38.4871MB/s 122*58b9f456SAndroid Build Coastguard WorkerComparing BM_memcpy to BM_copy (from ./a.out) 123*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Time Old Time New CPU Old CPU New 124*58b9f456SAndroid Build Coastguard Worker-------------------------------------------------------------------------------------------------------------------- 125*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/8 +5.2829 +5.2812 36 227 36 227 126*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/64 +21.1719 +21.1856 74 1640 74 1640 127*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/512 +145.6487 +145.6097 87 12804 87 12801 128*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/1024 +227.1860 +227.1776 111 25409 111 25407 129*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/8192 +308.1664 +308.2898 657 202986 656 202990 130*58b9f456SAndroid Build Coastguard Worker``` 131*58b9f456SAndroid Build Coastguard Worker 132*58b9f456SAndroid Build Coastguard WorkerAs you can see, it applies filter to the benchmarks, both when running the benchmark, and before doing the diff. And to make the diff work, the matches are replaced with some common string. Thus, you can compare two different benchmark families within one benchmark binary. 133*58b9f456SAndroid Build Coastguard WorkerAs you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. 134*58b9f456SAndroid Build Coastguard Worker 135*58b9f456SAndroid Build Coastguard Worker3. Compare filter one from benchmark one to filter two from benchmark two: 136*58b9f456SAndroid Build Coastguard WorkerThe program is invoked like: 137*58b9f456SAndroid Build Coastguard Worker 138*58b9f456SAndroid Build Coastguard Worker``` bash 139*58b9f456SAndroid Build Coastguard Worker$ compare.py filters <benchmark_baseline> <filter_baseline> <benchmark_contender> <filter_contender> [benchmark options]... 140*58b9f456SAndroid Build Coastguard Worker``` 141*58b9f456SAndroid Build Coastguard Worker 142*58b9f456SAndroid Build Coastguard WorkerWhere `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. 143*58b9f456SAndroid Build Coastguard Worker 144*58b9f456SAndroid Build Coastguard WorkerWhere `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary. 145*58b9f456SAndroid Build Coastguard Worker 146*58b9f456SAndroid Build Coastguard Worker`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes. 147*58b9f456SAndroid Build Coastguard Worker 148*58b9f456SAndroid Build Coastguard WorkerExample output: 149*58b9f456SAndroid Build Coastguard Worker``` 150*58b9f456SAndroid Build Coastguard Worker$ ./compare.py benchmarksfiltered ./a.out BM_memcpy ./a.out BM_copy 151*58b9f456SAndroid Build Coastguard WorkerRUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmp_FvbYg 152*58b9f456SAndroid Build Coastguard WorkerRun on (8 X 4000 MHz CPU s) 153*58b9f456SAndroid Build Coastguard Worker2017-11-07 21:38:27 154*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 155*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Iterations 156*58b9f456SAndroid Build Coastguard Worker------------------------------------------------------ 157*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8 37 ns 37 ns 18953482 204.118MB/s 158*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/64 74 ns 74 ns 9206578 828.245MB/s 159*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/512 91 ns 91 ns 8086195 5.25476GB/s 160*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/1024 120 ns 120 ns 5804513 7.95662GB/s 161*58b9f456SAndroid Build Coastguard WorkerBM_memcpy/8192 664 ns 664 ns 1028363 11.4948GB/s 162*58b9f456SAndroid Build Coastguard WorkerRUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpDfL5iE 163*58b9f456SAndroid Build Coastguard WorkerRun on (8 X 4000 MHz CPU s) 164*58b9f456SAndroid Build Coastguard Worker2017-11-07 21:38:32 165*58b9f456SAndroid Build Coastguard Worker---------------------------------------------------- 166*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Iterations 167*58b9f456SAndroid Build Coastguard Worker---------------------------------------------------- 168*58b9f456SAndroid Build Coastguard WorkerBM_copy/8 230 ns 230 ns 2985909 33.1161MB/s 169*58b9f456SAndroid Build Coastguard WorkerBM_copy/64 1654 ns 1653 ns 419408 36.9137MB/s 170*58b9f456SAndroid Build Coastguard WorkerBM_copy/512 13122 ns 13120 ns 53403 37.2156MB/s 171*58b9f456SAndroid Build Coastguard WorkerBM_copy/1024 26679 ns 26666 ns 26575 36.6218MB/s 172*58b9f456SAndroid Build Coastguard WorkerBM_copy/8192 215068 ns 215053 ns 3221 36.3283MB/s 173*58b9f456SAndroid Build Coastguard WorkerComparing BM_memcpy (from ./a.out) to BM_copy (from ./a.out) 174*58b9f456SAndroid Build Coastguard WorkerBenchmark Time CPU Time Old Time New CPU Old CPU New 175*58b9f456SAndroid Build Coastguard Worker-------------------------------------------------------------------------------------------------------------------- 176*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/8 +5.1649 +5.1637 37 230 37 230 177*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/64 +21.4352 +21.4374 74 1654 74 1653 178*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/512 +143.6022 +143.5865 91 13122 91 13120 179*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/1024 +221.5903 +221.4790 120 26679 120 26666 180*58b9f456SAndroid Build Coastguard Worker[BM_memcpy vs. BM_copy]/8192 +322.9059 +323.0096 664 215068 664 215053 181*58b9f456SAndroid Build Coastguard Worker``` 182*58b9f456SAndroid Build Coastguard WorkerThis is a mix of the previous two modes, two (potentially different) benchmark binaries are run, and a different filter is applied to each one. 183*58b9f456SAndroid Build Coastguard WorkerAs you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. 184*58b9f456SAndroid Build Coastguard Worker 185*58b9f456SAndroid Build Coastguard Worker### U test 186*58b9f456SAndroid Build Coastguard Worker 187*58b9f456SAndroid Build Coastguard WorkerIf there is a sufficient repetition count of the benchmarks, the tool can do 188*58b9f456SAndroid Build Coastguard Workera [U Test](https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test), of the 189*58b9f456SAndroid Build Coastguard Workernull hypothesis that it is equally likely that a randomly selected value from 190*58b9f456SAndroid Build Coastguard Workerone sample will be less than or greater than a randomly selected value from a 191*58b9f456SAndroid Build Coastguard Workersecond sample. 192*58b9f456SAndroid Build Coastguard Worker 193*58b9f456SAndroid Build Coastguard WorkerIf the calculated p-value is below this value is lower than the significance 194*58b9f456SAndroid Build Coastguard Workerlevel alpha, then the result is said to be statistically significant and the 195*58b9f456SAndroid Build Coastguard Workernull hypothesis is rejected. Which in other words means that the two benchmarks 196*58b9f456SAndroid Build Coastguard Workeraren't identical. 197*58b9f456SAndroid Build Coastguard Worker 198*58b9f456SAndroid Build Coastguard Worker**WARNING**: requires **LARGE** (no less than 9) number of repetitions to be 199*58b9f456SAndroid Build Coastguard Workermeaningful! 200