Achieve peak performance on x86 CPUs and NVIDIA GPUs
GPL-2.0 License
Microbenchmark to achieve peak performance on x86_64 CPUs and NVIDIA GPUs.
Table of Contents
peakperf only works properly in Linux. peakperf under Windows / macOS has not been tested, so performance may not be optimal. Windows port may be implemented in the future (see Issue #1)
Supported microarchitectures are:
For a complete list of supported microarchitectures, see section 5.
NOTES:
There is a peakperf package available in Arch Linux (peakperf-git).
If you are in another distro, you can build peakperf
from source.
Build the microbenchmark with the build script, which uses cmake
:
git clone https://github.com/Dr-Noob/peakperf
cd peakperf
./build.sh
./peakperf
By default, peakperf will be built with support for CPU and GPU. The support for the GPU will only be enabled if CUDA is found. During the cmake
execution, peakperf will print a summary where you can check which devices peakperf was compiled for.
-- ----------------------
-- peakperf build report:
-- CPU mode: ON
-- GPU mode: ON
-- ----------------------
Sometimes, cmake
will fail to find CUDA even tough it is installed. To let cmake
find CUDA, edit the build.sh script and use:
-DCMAKE_CUDA_COMPILER=/path/to/nvcc
-DCMAKE_CUDA_COMPILER_TOOLKIT_ROOT=/path/to/cuda
Use cmake
variables:
-DENABLE_CPU_DEVICE=[ON|OFF]
-DENABLE_GPU_DEVICE=[ON|OFF]
For example, building with -DENABLE_CPU_DEVICE=OFF
results in:
-- ----------------------
-- peakperf build report:
-- CPU mode: OFF
-- GPU mode: ON
-- ----------------------
By default, peakperf will run on the CPU:
[noob@drnoob peakperf]$ ./peakperf -t 4
-----------------------------------------------------
peakperf (https://github.com/Dr-Noob/peakperf)
-----------------------------------------------------
CPU: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
Microarch: Haswell
Benchmark: Haswell (AVX2)
Iterations: 1.00e+09
GFLOP: 640.00
Threads: 4
N Time(s) GFLOP/s
1 1.25743 508.97 *
2 1.25137 511.44 *
3 1.25141 511.42
...................
12 1.25136 511.44
-----------------------------------------------------
Average performance: 511.43 +- 0.01 GFLOP/s
-----------------------------------------------------
* - warm-up, not included in average
To manually select the device, use -d [cpu|gpu]
. To run peakpef on the GPU:
[noob@drnoob peakperf]$ ./peakperf -d gpu
------------------------------------------------------
peakperf (https://github.com/Dr-Noob/peakperf)
------------------------------------------------------
GPU: GeForce GTX 970
Microarch: Maxwell
Iterations: 4.00e+08
GFLOP: 7987.20
Blocks: 13
Threads/block: 768
N Time(s) GFLOP/s
1 1.87078 4269.44 *
2 1.84159 4337.12 *
3 1.84205 4336.03
...................
12 1.84194 4336.31
------------------------------------------------------
Average performance: 4336.69 +- 0.91 GFLOP/s
------------------------------------------------------
* - warm-up, not included in average
To achieve the best performance, you should run this test with the computer working under minimum load (e.g, in non-graphics mode). If you are in a desktop machine, a good way to do this is by issuing systemctl isolate multi-user.target
.
peakperf automatically detects your CPU/GPU and runs the best benchmark for your architecture.
[noob@drnoob peakperf]$ ./peakperf -l
Available benchmark types:
...
[noob@drnoob peakperf]$ ./peakperf -b haswell
peakperf has many different options to tweak and expriment with your hardware. Use -h
to print all available options
NOTE: Some options are available only on CPU or GPU
Peak performance refers to the maximum performance that a chip (a CPU) can achieve. The more powerful the CPU is, the greater the peak performance can achieve. This performance is a theoretical limit, computed using a formula (see next section), measured in floating point operation per seconds (FLOP/s or GFLOP/s, which stands for gigaflops). This value establishes a performance limit that the CPU is unable to overcome. However, achieving the peak performance (the maximum performance for a given CPU) is a very hard (but also interesting) task. To do so, the software must take advantage of the full power of the CPU. peakperf is a microbenchmark that achieves peak performance on many different x86_64 microarchitectures.
N_CORES * FREQUENCY * FMA * UNITS * (SIZE_OF_VECTOR/32)
For the example of a i7-4790K, we have:
4 * 3.997 * 10^9 * 2 * 2 * (256/32) = 511.61 GFLOP/s
And, as you can see in the previous test, we got 511.43 GFLOP/S, which tell us that peakperf is working properly and our CPU is behaving exactly as we expected.
N_CORES * FREQUENCY * FMA
The GPU formula is simpler. N_CORES
in this case is simply the number of CUDA cores (in the case of NVIDIA GPUs). Modern GPUs usually support FMA.
While running this microbenchmark, your CPU will be executing AVX code, so the frequency of your CPU running this code is neither your base nor your turbo frequency. Please, have a look at this document (on section IV.B) for more information.
The AVX frequency for a specific CPU is sometimes available online. The most effective way I know to get this frequency is to to actually measure your CPU frequency on real time while running AVX code. You can use the script freq.sh to achieve this:
./peakperf -r 4 -w 0 > /dev/null &
)./freq.sh
) which will fetch your CPU frequency in real time (use .req.sh gpu
for measuring the GPU). In my case, I get:Every 0,2s: grep 'MHz' /proc/cpuinfo
cpu MHz : 3997.629
cpu MHz : 3997.629
cpu MHz : 3997.630
cpu MHz : 3997.630
cpu MHz : 3997.630
cpu MHz : 3997.630
cpu MHz : 3997.629
cpu MHz : 3997.630
As you can see, i7-4790K's frequency while running AVX code is ~3997.630 MHz, which equals to 3.997 GHz. However, you may see that your frequency fluctuates too much, so that it's impossible to estimate the frequency of your CPU. This may happen because:
Please create a issue in github, posting the output of peakperf.
This tables shows the performance of peakperf for each of the microarchitecture supported by the microbenchmark. To see all the hardware tested, see benchmarks
uarch | CPU | AVX Clock | PP (Formula) | PP (Experimental) | Loss |
---|---|---|---|---|---|
Sandy Bridge | i5-2400 | 3.192 GHz |
102.14 |
100.64 +- 0.00 |
1.46% |
Ivy Bridge | 2x Xeon E5-2650 v2 | 2.999 GHz |
767.74 |
744.24 +- 3.85 |
3.15% |
Haswell | i7-4790K | 3.997 GHz |
511.61 |
511.43 +- 0.01 |
0.03% |
Broadwell | 2x Xeon E5-2698 v4 | 2.599 GHz |
3326.72 |
3269.87 +- 14.42 |
1.73% |
Skylake | i5-6400 | 3.099 GHz |
396.67 |
396.61 +- 0.01 |
0.06% |
Knights Landing | Xeon Phi 7250 | 1.499 GHz |
5991.69 |
5390.84 +- 7.83 |
3.72% |
Kaby Lake | i5-8250U | 2.700 GHz |
345.60 |
343.57 +- 1.38 |
0.59% |
Coffee Lake | i9-9900K | 3.600 GHz |
921.60 |
918.72 +- 1.13 |
0.31% |
Comet Lake | i9-10900KF | 4.100 GHz |
1312.00 |
1308.24 +- 0.30 |
0.30% |
Cascade Lake | 2x Xeon Gold 6238 | 2.099 GHz |
5910.78 |
5851.60 +- 2.69 |
1.01% |
Ice Lake | i5-1035G1 | 2.990 GHz |
382.72 |
382.22 +- 0.18 |
0.13% |
Tiger Lake | - | - | - | - | - |
Rocket Lake | i7-11700 | 4.400 GHz |
1126.4 |
1121.69 +- 0.60 |
0.41% |
Alder Lake | i9-12900K | 4.900 GHz |
1727.8 |
1709.28 +- 0.22 |
1.07% |
uarch | CPU | AVX Clock | PP (Formula) | PP (Experimental) | Loss |
---|---|---|---|---|---|
Zen | - | - | - | - | - |
Zen+ | AMD Ryzen 5 2600 | 3.724 GHz |
357.50 |
357.08 +- 0.03 |
0.11% |
Zen 2 | - | - | - | - | - |
Zen 3 | 2x AMD EPYC 7413 | 3.000 GHz |
4608.00 |
4551.55 +- 21.45 |
1.24% |
C.C | uarch | GPU | Clock | PP (Formula) | PP (Experimental) | Loss |
---|---|---|---|---|---|---|
5.2 | Maxwell | GTX 970 | 1.341 GHz |
4462.84 |
4333.92 +- 0.90 |
2.97% |
6.1 | Pascal | GTX 1080 | 1.860 GHz |
9523.20 |
9397.97 +- 0.10 |
1.33% |
7.5 | Turing | RTX 2080 Ti | 1.905 GHz |
16581.12 |
16373.28 +- 16.07 |
1.26% |
8.6 | Ampere | - | - | - | - | - |
9.0 | Ada Lovelace | - | - | - | - | - |
NOTE 1: Performance measured on simple precision and GFLOP/s (gigaflops per second).
NOTE 2: The clock information is retrieved experimentally. In other words, this data is not the theoretical values for each device, but the actual frequency measured on each device (using freq.sh
script).
NOTE 3: KNL performance is computed as PP * (6/7) (see explanation).
NOTE 4: Sandy Bridge and Ivy Bridge have ADD and MUL VPUs that can be used in parallel. Therefore, Xeon E5-2650 v2 formula is computed as FREQ * CORES * 2 * 2 * 8
. However, i5-2400 peak performance is computed as the half. The explanation for this is that ADD and MUL VPUs can only be used if CPU supports hyperthreading. If CPU do not support hyperthreading, one core is unable to fill both VPUs fast enough.
The following tables act as a summary of all supported microarchitectures with their characteristics.
uarch | FMA | AVX512 | Slots | FPUs | Latency | Tested | Refs |
---|---|---|---|---|---|---|---|
Sandy Bridge | ❌ | ❌ | 6 | 2 (ADD+MUL AVX) | 3 (ADD) 5 (MUL) | ✔️ | [1] |
Ivy Bridge | ❌ | ❌ | 6 | 2 (ADD+MUL AVX) | 3 (ADD) 5 (MUL) | ✔️ | [2] |
Haswell | ✔️ | ❌ | 10 | 2 (FMA AVX2) | 5 (FMA) | ✔️ | [3] |
Broadwell | ✔️ | ❌ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [3] |
Skylake | ✔️ | ❌ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [3] |
Kaby Lake | ✔️ | ❌ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [4] |
Coffee Lake | ✔️ | ❌ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [5] |
Comet Lake | ✔️ | ❌ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [10] |
Ice Lake | ✔️ | ✔️ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [12] |
Tiger Lake | ✔️ | ✔️ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [12] |
Rocket Lake | ✔️ | ✔️ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [?] |
Alder Lake | ✔️ | ✔️ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [?] |
Knights Landing | ✔️ | ✔️ | 12 | 2 (FMA AVX512) | 6 (FMA) | ✔️ | [6] |
Piledriver | ✔️ | ❌ | 5 | 1 (FMA AVX) | 5 (FMA) | ❌ | [?] |
Zen | ✔️ | ❌ | 5 | 1 (FMA AVX2) | 5 (FMA) | ❌ | [7] |
Zen+ | ✔️ | ❌ | 5 | 1 (FMA AVX2) | 5 (FMA) | ✔️ | [8] |
Zen 2 | ✔️ | ❌ | 10 | 2 (FMA AVX2) | 5 (FMA) | ❌ | [9] |
Zen 3 | ✔️ | ❌ | 8 | 2 (FMA AVX2) | 4 (FMA) | ✔️ | [11] |
References:
uarch | Latency | Tested | Refs |
---|---|---|---|
Maxwell | 6 | ✔️ | [] |
Pascal | 6 | ✔️ | [] |
Turing | 4 | ✔️ | [] |
Ampere | ? | ❌ | [] |
NOTES:
FPUs x Latency
.