Benchmarking armv8 Instruction Sets
I've been testing various old and newer Android phones recently, as a side effect of some programming I'm doing, and noticing how oddly the armv8 instruction set architecture extensions can behave when used in anger.
Specifically, I'm testing whisper.cpp to see if I could get a simple app to
record audio and convert it to text locally on my phone. The speech-to-text models are good,
how much CPU they use and how fast they can convert is important, i.e. realtime /
faster than realtime or not.
Here's what I see.
On the only device I have that can run it, armv9.0_1 is the worst or near-worst on every model,
it's even slower than NEON:
| model | armv8.0_1 | armv8.2_2 | armv9.0_1 (auto-selected) |
|---|---|---|---|
| base | 7880 | 4340 | 5970 |
| base.en-q5 | 4678 | 3256 | 7561 |
| tiny-q5 | 2047 | 1343 | 2923 |
| tiny.en-q5 | 1950 | 1593 | 2943 |
Running Arm's Scalable Vector Extensions 2 (SVE2 and imm8) isn't worth it on some smartphones.
Here's another look at the numbers with a 3-run average.
| model | armv8.2_2 | armv9.0_1 (auto-selected) |
|---|---|---|
| base | 1470 | 3687 |
| base.en-q5 | 1818 | 3999 |
| tiny-q5 | 1001 | 2061 |
Google, in their infinite wisdom, wants people to use their Tensor Processing Units, but they don't expose them in any friendly way to developers via the Android NDK.
In fact, it's so bad, that even internally their people don't know how to use them! This is a well-run company, I tells ya!
See: "Access to some functionality, like the chip’s integrated tensor processing unit, remains elusive."
George Hotz is right, these companies should hand over the ISA reference manuals and build stable enough drivers to let people compile and run code as close to the metal as possible.
A long time ago, I also had fun getting code to compile and run on the Qualcomm Hexagon DSP built into every phone using a Snapdragon processor. Their lockdown of the cDSP via FastRPC was kind of a nightmare, and only a small handful of very modern (for the time) phones, would allow any user processing on those devices at all.
Anyways, here are the whisper.cpp benchmark results on the devices I could get my hands on,
using the JFK speech sample. ("Ask not what your country can do for you...")
The INFER(ms) column is the one to pay attention to. In absolute terms, it tells you whether
the processor could handle real-time or near real-time processing.
The speech clip itself is 11 seconds long, so if the DECODE + INFER fields combined are less than that, then there's probably a good chance it will work.
max@ubuntu2604:~$ cat benchmark-20260702-105502.txt
DEVICE ABI MODEL BACKEND DECODE(ms) LOAD(ms) INFER(ms) N
Nexus 5 armeabi-v7a base CPU (linked) 762 1987 14885 3
Nexus 5 armeabi-v7a base.en-q5_1 CPU (linked) 931 1293 21031 3
Nexus 5 armeabi-v7a tiny-q5_1 CPU (linked) 909 847 10020 3
Nexus 5 armeabi-v7a tiny.en-q5_1 CPU (linked) 908 827 10077 3
Huawei M2 arm64-v8a base armv8.0_1 535 983 11802 3
Huawei M2 arm64-v8a base.en-q5_1 armv8.0_1 508 482 10271 3
Huawei M2 arm64-v8a tiny-q5_1 armv8.0_1 587 374 4745 3
Huawei M2 arm64-v8a tiny.en-q5_1 armv8.0_1 535 363 4775 3
Pixel 2 arm64-v8a base armv8.0_1 420 310 8078 3
Pixel 2 arm64-v8a base.en-q5_1 armv8.0_1 436 216 5898 3
Pixel 2 arm64-v8a tiny-q5_1 armv8.0_1 522 195 3100 3
Pixel 2 arm64-v8a tiny.en-q5_1 armv8.0_1 520 201 3080 3
Pixel 3a arm64-v8a base armv8.0_1 1214 339 9421 3
Pixel 3a arm64-v8a base.en-q5_1 armv8.0_1 1323 248 7263 3
Pixel 3a arm64-v8a tiny-q5_1 armv8.0_1 1340 195 3328 3
Pixel 3a arm64-v8a tiny.en-q5_1 armv8.0_1 1336 190 3307 3
Pixel 5 arm64-v8a base armv8.0_1 1456 286 7497 3
Pixel 5 arm64-v8a base armv8.2_2 1396 256 3469 3
Pixel 5 arm64-v8a base.en-q5_1 armv8.0_1 1395 257 5929 3
Pixel 5 arm64-v8a base.en-q5_1 armv8.2_2 1408 223 4779 3
Pixel 5 arm64-v8a tiny-q5_1 armv8.0_1 1402 187 2522 3
Pixel 5 arm64-v8a tiny-q5_1 armv8.2_2 1391 196 2061 3
Pixel 5 arm64-v8a tiny.en-q5_1 armv8.0_1 1511 161 2583 3
Pixel 5 arm64-v8a tiny.en-q5_1 armv8.2_2 1556 156 2221 3
Mi 11 arm64-v8a base armv8.0_1 300 130 3864 3
Mi 11 arm64-v8a base armv8.2_2 301 133 1472 3
Mi 11 arm64-v8a base.en-q5_1 armv8.0_1 301 86 2575 3
Mi 11 arm64-v8a base.en-q5_1 armv8.2_2 305 88 2052 3
Mi 11 arm64-v8a tiny-q5_1 armv8.0_1 287 66 1148 3
Mi 11 arm64-v8a tiny-q5_1 armv8.2_2 291 66 912 3
Mi 11 arm64-v8a tiny.en-q5_1 armv8.0_1 285 63 1152 3
Mi 11 arm64-v8a tiny.en-q5_1 armv8.2_2 300 65 918 3
Pixel 9 Pro arm64-v8a base armv8.0_1 980 218 3833 3
Pixel 9 Pro arm64-v8a base armv8.2_2 875 199 1470 3
Pixel 9 Pro arm64-v8a base armv9.0_1 964 220 3687 3
Pixel 9 Pro arm64-v8a base.en-q5_1 armv8.0_1 895 138 2407 3
Pixel 9 Pro arm64-v8a base.en-q5_1 armv8.2_2 905 163 1818 3
Pixel 9 Pro arm64-v8a base.en-q5_1 armv9.0_1 867 149 3999 3
Pixel 9 Pro arm64-v8a tiny-q5_1 armv8.0_1 940 127 1229 3
Pixel 9 Pro arm64-v8a tiny-q5_1 armv8.2_2 953 128 1001 3
Pixel 9 Pro arm64-v8a tiny-q5_1 armv9.0_1 934 141 2061 3
Pixel 9 Pro arm64-v8a tiny.en-q5_1 armv8.0_1 1058 138 1924 3
Pixel 9 Pro arm64-v8a tiny.en-q5_1 armv8.2_2 1028 148 2183 3
Pixel 9 Pro arm64-v8a tiny.en-q5_1 armv9.0_1 991 133 3941 3
In all cases, the armv8.2_2 backend was the fastest, and armv9.0_1 should probably just
be ignored. It's a somewhat sad situation, because I assume that most systems capable of
running SVE2 probably also have a proprietary TPU / NPU that can't be easily programmed.
Users are essentially stuck going back a generation to armv8.2_2 and not using the full
capabilities of the processors they paid good money for.
This is fine.
One other thing that I noticed is how bad midrange processors can be if you're not paying attention to multithreaded performance.
It's clear here that there was a "middle generation" of midrange processors with only 2 fast cores and not enough of a difference between the perf cores and the eff cores. These things actually need their efficiency cores in order to hit decent performance in multithreaded software.
| Device (oldest→newest) | ABI | CPU clusters (kHz × count) | Backend | Affinity | INFER (ms) |
|---|---|---|---|---|---|
| Nexus 5 | v7a | 2265×4 (homogeneous, hotplugs) | linked | no pin (ratio 1.0) | 16315 |
| Huawei M2 | arm64 | 1516×4 / 2016×4 | armv8.0_1 | no pin (4 cores but ratio 1.33) | 8752 |
| Pixel 2 | arm64 | 1900×4 / 2457×4 | armv8.0_1 | no pin (ratio 1.29) | 7243 |
| Pixel 3a | arm64 | 1708×6 / 1996×2 | armv8.0_1 | no pin (only 2 fast cores) | 6015 |
| Pixel 5 | arm64 | 1804×6 / 2208×1 / 2400×1 | armv8.2_2 | no pin (only 2 fast cores) | 3676 |
| Mi 11 | arm64 | 1804×4 / 2419×3 / 2841×1 | armv8.2_2 | pin 0xf0 (4 fast, ratio 1.57) | 1410 |
| Pixel 9 Pro | arm64 | 1950×4 / 2600×3 / 3105×1 | armv8.2_2 (Tensor G4 cap) | pin 0xf0 (4 fast, ratio 1.59) | 1415 |
- ← Previous
Auto binfmt Messing Things Up