mbutrovich commented on PR #11467: URL: https://github.com/apache/arrow-rs/pull/11467#issuecomment-6086197844
The benchmark bot reran the `divisor` benchmark on 63ae1539bf03bbea3302c06094984320ba89160b, which has the same benchmark code as the PR head, on [x86](https://github.com/apache/arrow-rs/pull/11467#issuecomment-6085819805) and [arm64](https://github.com/apache/arrow-rs/pull/11467#issuecomment-6085908520). Each run compares the commit to itself, so the charts show `operator` time divided by `divisor` time from the changed column. <img width="1600" height="1380" alt="divisor-types-enum-bot-x86" src="https://github.com/user-attachments/assets/568f551b-2a98-49e3-89af-345e97832fa4" /> <img width="1600" height="1380" alt="divisor-types-enum-bot-arm" src="https://github.com/user-attachments/assets/ecc4dff1-1c8b-4c3a-91ee-7fc2684da756" /> `wrapping_div_rem` is faster than `/` and `%` in all 32 cases on both runners. The smallest gain is 1.8x, for `i64 % 13` on x86. @andygrove, in your review you asked to > check that the inner loop is vectorized in the bot's thin-LTO build before using its numbers. I built the `divisor` benchmark with the bot's setting (`CARGO_PROFILE_BENCH_LTO=thin`) for aarch64 and for x86-64 without a `target-cpu`, and read the disassembly of the benchmark binary. Each benchmark matches on the variant once per batch, outside the loop. None of the inner loops branches on the divisor or reloads its fields. On aarch64, the 32-bit loops and the 64-bit `PowerOfTwo` loops are NEON loops. The 64-bit `Multiplier` division loops compute `umulh` or `smulh` in scalar registers for two values per iteration and do the rest in NEON registers, and the 64-bit `Multiplier` remainder loops are scalar. On x86-64, every case has an SSE2 main loop, and the 64-bit `Multiplier` loops compute the high multiplies with scalar `mul` for two values per iteration. On Neoverse-V2, `u32 % 16` now takes 0.41 us, the same as `u32 / 16`. In the [earlier run](https://github.com/apache/arrow-rs/pull/11467#issuecomment-6070944047) it took 5.5 us. `/` and `%` by 16 take 13.7 to 16.5 us there, against 30.0 to 56.2 us by 13, so three of the divide-by-16 bars are shorter than the divide-by-13 bars. <details><summary>Numbers behind the charts (us per 8192 values)</summary> | Case | x86 `operator` | x86 `divisor` | x86 speedup | arm64 `operator` | arm64 `divisor` | arm64 speedup | |---|---|---|---|---|---|---| | `u32 / 13` | 15.1 | 2.2 | 6.9x | 31.5 | 1.69 | 18.7x | | `u32 % 13` | 15.1 | 4.0 | 3.8x | 32.2 | 1.77 | 18.2x | | `i32 / 13` | 15.1 | 5.8 | 2.6x | 30.0 | 2.1 | 14.3x | | `i32 % 13` | 15.1 | 7.7 | 2.0x | 30.7 | 2.4 | 12.8x | | `u64 / 13` | 25.1 | 6.2 | 4.0x | 53.4 | 5.2 | 10.3x | | `u64 % 13` | 24.8 | 9.6 | 2.6x | 56.2 | 5.2 | 10.8x | | `i64 / 13` | 24.7 | 9.6 | 2.6x | 52.0 | 6.0 | 8.7x | | `i64 % 13` | 24.7 | 13.6 | 1.8x | 54.7 | 6.5 | 8.4x | | `u32 / 16` | 15.1 | 0.87 | 17.3x | 13.7 | 0.41 | 33.3x | | `u32 % 16` | 15.1 | 0.74 | 20.3x | 14.4 | 0.41 | 35.3x | | `i32 / 16` | 15.1 | 1.49 | 10.2x | 13.7 | 1.32 | 10.4x | | `i32 % 16` | 15.1 | 1.13 | 13.4x | 14.4 | 1.10 | 13.1x | | `u64 / 16` | 24.6 | 1.51 | 16.3x | 13.7 | 0.80 | 17.2x | | `u64 % 16` | 24.8 | 1.45 | 17.1x | 16.5 | 0.80 | 20.7x | | `i64 / 16` | 24.7 | 4.2 | 5.9x | 13.7 | 2.6 | 5.3x | | `i64 % 16` | 25.0 | 2.6 | 9.6x | 16.5 | 2.2 | 7.5x | </details> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
