I mean, he's comparing 2024 Zen 5 and M4 against two generations behind 2022 Intel Raptor Lake. The Lion Cove should be roughly on par with the M4 on this test.
return n ? (1u + popcount(n & n - 1u)) : 0u;
which both Clang and GCC promptly optimize to a single popcnt. f(n) = 5226577487551039623 + 1537228672809129301*(1669582390241348315^n + 636260618972345635^n) + 3689348814741910322*(725554454131936870^n + 194643636704778390^n + 1781303817082419751^n + 1910184110508252890^n) mod (2^61-1).
This involves 6 exponentiations by n with constant bases. Because in fizzbuzz the inputs are sequential, one can further precompute c^(2^i) and c^(-2^i) and, having c^n, one can go to c^(n+1) in average 2 modular multiplications by multiplying the appropriate powers c^(+-2^i) corresponding to the flipped bits. The floating point schedulers have a slow region, in the oldest entries of a scheduler and only when the scheduler is full. If an operation is in the slow region and it is dependent on a 1-cycle latency operation, it will see a 1 cycle latency penalty.
There is no penalty for operations in the slow region that depend on longer latency operations or loads.
There is no penalty for any operations in the fast region.
To write a latency test that does not see this penalty, the test needs to keep the FP schedulers from filling up.
The latency test could interleave NOPs to prevent the scheduler from filling up.
Basically, short vector code sequences that don't fill up the scheduler will have better latency. 2,190,954,207 cpu_core/cycles:u/ ( +- 0.14% )
4,412,790,656 cpu_core/uops_issued.any:u/ ( +- 0.11% )
39,386,389 cpu_core/exe_activity.1_ports_util:u/ ( +- 11.57% )
2,121,401,346 cpu_core/exe_activity.2_ports_util:u/ ( +- 0.11% )
6,015,432 cpu_core/exe_activity.exe_bound_0_ports:u/ ( +- 8.87% )
593,599,670 cpu_core/uops_retired.stalls:u/ ( +- 0.85% )
Anomaly: 4,357,567,336 cpu_core/cycles:u/ ( +- 0.15% )
4,448,899,140 cpu_core/uops_issued.any:u/ ( +- 0.26% )
2,107,051,688 cpu_core/exe_activity.1_ports_util:u/ ( +- 0.14% )
1,106,699,503 cpu_core/exe_activity.2_ports_util:u/ ( +- 0.13% )
1,129,497,409 cpu_core/exe_activity.exe_bound_0_ports:u/ ( +- 0.42% )
2,502,226,997 cpu_core/uops_retired.stalls:u/ ( +- 0.38% )
Noise from the surrounding code aside, we see the same number of uops issued. However in the anomaly case, ~1/4th of the cycles are spent with no uops being executed, 1/2 are spent with only 1 uop being executed, and around 1/4 of the cycles have 2 uops being executed. I expected 0 and 2 being 50/50, consistently with there being one cycle stall, but if the uops are desynched and issued one cycle apart it would also explain the 1 being so prominent. 4,581,269,346 cpu_core/cycles:u/ ( +- 0.10% )
4,556,347,404 cpu_core/uops_issued.any:u/ ( +- 0.12% )
133,363,872 cpu_core/exe_activity.1_ports_util:u/ ( +- 7.73% )
2,082,838,530 cpu_core/exe_activity.2_ports_util:u/ ( +- 0.24% )
2,165,817,614 cpu_core/exe_activity.exe_bound_0_ports:u/ ( +- 0.06% )
3,090,362,239 cpu_core/uops_retired.stalls:u/ ( +- 0.16% )
Now the uops are split between 0 and 2 executed per cycle, as theorized.