A microbenchmark support library
If you see this error:
***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead.
you might want to disable the CPU frequency scaling while running the benchmark, as well as consider other ways to stabilize the performance of your system while benchmarking.
Exactly how to do this depends on the Linux distribution, desktop environment, and installed programs. Specific details are a moving target, so we will not attempt to exhaustively document them here.
One simple option is to use the cpupower program to change the
performance governor to “performance”. This tool is maintained along with
the Linux kernel and provided by your distribution.
It must be run as root, like this:
sudo cpupower frequency-set --governor performance
After this you can verify that all CPUs are using the performance governor by running this command:
cpupower frequency-info -o proc
The benchmarks you subsequently run will have less variance.
If you see this error:
***WARNING*** ASLR is enabled, the results may have unreproducible noise in them.
you might want to disable the ASLR security hardening feature while running the benchmark.
The simplest way is to add
benchmark::MaybeReenterWithoutASLR(argc, argv);
as the first line of your main() function. It will try to disable ASLR
for the current processor, and, if successful, re-execute the binary.
Note that personality(2) may be forbidden by e.g. seccomp (which happens
by default if you are running in a Docker container).
Note that if you link to benchmark_main already does that for you.
To globally disable ASLR on Linux, run
echo 0 > /proc/sys/kernel/randomize_va_space
To run a single benchmark with ASLR disabled on Linux, do:
setarch `uname -m` -R ./a_benchmark
Note that for the information on how to disable ASLR on other operating systems, please refer to their documentation.
The Linux CPU frequency governor discussed above is not the only source of noise in benchmarks. The advice in this section assumes a desktop or server; on a mobile device most of it does not apply, and the dominant sources of variance are different ones, so see Reducing Variance on Android. Some, but not all, of the sources of variance include:
These can cause variance in benchmarks results within a single run
(--benchmark_repetitions=N) or across multiple runs of the benchmark
program.
Reducing sources of variance is OS and architecture dependent, which is one reason some companies maintain machines dedicated to performance testing.
Some of the easier and effective ways of reducing variance on a typical Linux workstation are:
echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost
See the Linux kernel’s boost.txt for more information.
taskset -c 0 ./mybenchmark
nice or chrt:
sudo nice -n -20 ./mybenchmark
sudo chrt -f 80 ./mybenchmark
/sys file system (see the LLVM project’s Benchmarking
tips).Further resources on this topic:
On Android there is no cpupower, scaling_governor is often not readable or writable by
the shell user, and there is no BIOS in which to disable SMT. None of the following needs
root.
nice 10, so it yields the CPU readily and looks harmless,
but a nice’d process does not yield memory bandwidth or cache. On one device a
memory-bandwidth microbenchmark measured 6.35 GB/s while that job ran and 9.32 GB/s once
it had finished, 32% lower, with repetition-to-repetition variation of 15% in both cases.
Because the job runs for the whole measurement it depresses every repetition by a similar
amount, so a check based on the spread between repetitions does not catch it. Check for
it explicitly and record the result:
adb shell pgrep dex2oat
If that prints anything, wait. pgrep is deliberate here: listing every thread with
ps -A -T is enough work on a device with a few thousand threads that it can leave
adbd unresponsive, which is a poor way to find out your device is busy. The compiler
threads belong to dex2oat, so matching the process is sufficient.
On a retail device there is no reliable way to stop it:
cmd package cancel-bg-dexopt-job and cmd package bg-dexopt-job --disable are not
available on every build, and cmd jobscheduler cancel android 800 cancels the AOSP job
while vendor-scheduled compilation continues. A userdebug build or a rooted device can
stop the framework outright with adb shell stop, which is the stronger remedy where it
is available.
You can, however, wait for it programmatically, which is what a harness should do rather than leaving it to the operator to remember. This blocks until the device has been quiet for three consecutive checks, and combines it with item 2 below:
adb shell '
busy() { # percentage of total CPU capacity busy over a 3 second window
set -- $(head -1 /proc/stat); t0=$(($2+$3+$4+$5+$6+$7+$8+$9)); i0=$(($5+$6))
sleep 3
set -- $(head -1 /proc/stat); t1=$(($2+$3+$4+$5+$6+$7+$8+$9)); i1=$(($5+$6))
d=$((t1-t0)); echo $(( 100 * (d - (i1-i0)) / d ))
}
n=0
while [ $n -lt 3 ]; do
if [ -z "$(pgrep dex2oat)" ] && [ "$(busy)" -le 10 ]; then n=$((n+1)); else n=0; fi
done'
/proc/stat
twice and compute the fraction of CPU capacity that was busy over the window. Do not use
the load average: on Android it counts threads blocked in D state, and it read 19 to 21
on a device whose measured busy fraction was 3%.settings put global low_power 1 can leave scaling_max_freq at its full value, so
reading the frequency cap does not tell you the mode is on:
adb shell settings get global low_power
Record it and compare rather than assuming a direction. On the device above, measured on an idle machine with the state captured before and after every run, the mode made no difference worth reporting, although earlier runs on that same phone appeared to show it costing 33% before background compilation and post-boot settling were ruled out.
/sys/class/thermal generally needs root, which leaves
dumpsys battery, and battery temperature is a poor proxy for SoC temperature. On a
device at full charge it tracks the battery finishing its charge: during six minutes of
all-core compute it fell steadily while throughput stayed flat. If you report a
temperature, say which sensor it is.