Performance Testing
Measured overhead on systems with hardware shadow stacks
The numbers below are the performance overhead of running protected builds on systems with hardware shadow stacks. Each workload was run 20 times, interleaving the protected and baseline builds so that any drift in machine state over the session lands on both equally, and the figures below are the medians of those runs. Both builds were produced with the same compiler and flags and measured on the same machine in the same session.
| Program / workload | Baseline median | Protected median | Change |
|---|---|---|---|
| FFmpeg MPEG-4 encode | 1.518 s | 1.533 s | +0.98% |
| FFmpeg MPEG-4 decode | 1.208 s | 1.234 s | +2.09% |
| FFmpeg MJPEG encode | 4.515 s | 4.575 s | +1.34% |
| FFmpeg AAC encode | 0.1289 s | 0.1341 s | +4.01% |
| FFmpeg AAC decode | 0.0167 s | 0.0173 s | +3.68% |
| OpenSSL AES-128-CBC | 1.953 GB/s | 1.950 GB/s | −0.15% |
| OpenSSL AES-256-GCM | 13.047 GB/s | 13.052 GB/s | +0.04% |
| OpenSSL SHA-256 | 2.441 GB/s | 2.389 GB/s | −2.14% |
| OpenSSL RSA-2048 | 5,509 ops/s | 5,453 ops/s | −1.02% |
| OpenSSL ECDSA-P256 | 23,405 ops/s | 23,324 ops/s | −0.35% |
SQLite speedtest1 | 4.004 s | 4.029 s | +0.63% |
Change is reported against the raw metric. For the time-based rows (seconds) lower is better, so a positive change is slower. For the throughput rows (GB/s, ops/s) higher is better, so a negative change is slower.
Reading the numbers
Every workload lands within a few percent of baseline. The largest movements are on the shortest runs. AAC encode and decode complete in well under a fifth of a second, where fixed startup costs make up a visible share of the total, so their percentages overstate the steady-state cost. The long-running workloads, which are the ones that matter for throughput, stay near or under 1%.
The cryptographic rows are a pathological case to measure, and they move in both directions. Code of this kind spends nearly all its time inside tight, hand-tuned inner loops that make almost no indirect calls, so there is very little for the protection to act on and correspondingly little real cost to find. What is left is a measurement problem rather than an overhead: at this magnitude the gap between two builds is dominated by incidental effects such as code and data layout, which shift whenever a binary is rebuilt at all. That is why one protected build comes out marginally faster than baseline. Neither direction is signal, and the honest reading is that the protection is not measurably visible on this kind of code.