Precomputed compression mask parts and replacements
This is the improvement on Intel:
before:
```
Benchmark (size) (specialCharPercentage) Mode Cnt Score Error Units
MyBenchmark.benchReplaceBackslashRawCompressedTable3 65536 3 thrpt 20 18139.485 ± 264.275 ops/s
MyBenchmark.benchReplaceBackslashRawCompressedTable3 65536 50 thrpt 20 18368.666 ± 47.128 ops/s
```
after:
```
Benchmark (size) (specialCharPercentage) Mode Cnt Score Error Units
MyBenchmark.benchReplaceBackslashRawCompressedTable3 65536 3 thrpt 20 19460.961 ± 53.448 ops/s
MyBenchmark.benchReplaceBackslashRawCompressedTable3 65536 50 thrpt 20 19445.190 ± 86.502 ops/s
```
While the original table lookup in the blog post is:
```
Benchmark (size) (specialCharPercentage) Mode Cnt Score Error Units
MyBenchmark.benchReplaceBackslashTable3 65536 3 thrpt 20 20789.392 ± 401.696 ops/s
MyBenchmark.benchReplaceBackslashTable3 65536 50 thrpt 20 4261.030 ± 22.246 ops/s
```
Meaning that we're approaching the same performance of the table lookup version when the branch predictor work as expected
I'll have some fun with https://uica.uops.info/ with the produced assembly and try on Ryzen.
Since we now have "just" 2 `pext` i can try transform them for Apple M1 using https://orlp.net/blog/extracting-depositing-bits/
The assembly for x86 for the main loop is
```asm
0x00007fd4f01d9240: mov %r8d,%r13d
0x00007fd4f01d9243: lea 0x0(,%rbp,8),%r11d
0x00007fd4f01d924b: vmovq %xmm0,%r10
0x00007fd4f01d9250: mov 0x10(%r10,%r11,1),%rcx
0x00007fd4f01d9255: mov %ecx,%r8d
0x00007fd4f01d9258: movzbl %r8b,%r11d
0x00007fd4f01d925c: mov 0x10(%r14,%r11,4),%r10d
0x00007fd4f01d9261: mov %r8d,%r11d
0x00007fd4f01d9264: shr $0x18,%r11d
0x00007fd4f01d9268: mov 0x10(%r14,%r11,4),%r9d
0x00007fd4f01d926d: mov %r10d,%r11d
0x00007fd4f01d9270: shr $0x10,%r11d
0x00007fd4f01d9274: mov %r9d,%edx
0x00007fd4f01d9277: shr $0x10,%edx
0x00007fd4f01d927a: movslq %r11d,%rdi
0x00007fd4f01d927d: movslq %edx,%rax
0x00007fd4f01d9280: movzwl %r9w,%edx
0x00007fd4f01d9284: shl $0x30,%rax
0x00007fd4f01d9288: shl $0x30,%rdx
0x00007fd4f01d928c: movzwl %r10w,%ebx
0x00007fd4f01d9290: mov %r8d,%r10d
0x00007fd4f01d9293: shr $0x10,%r10d
0x00007fd4f01d9297: shr $0x8,%r8d
0x00007fd4f01d929b: movzbl %r10b,%r10d
0x00007fd4f01d929f: mov 0x10(%r14,%r10,4),%r11d
0x00007fd4f01d92a4: movzbl %r8b,%r8d
0x00007fd4f01d92a8: mov 0x10(%r14,%r8,4),%r8d
0x00007fd4f01d92ad: mov %r11d,%r10d
0x00007fd4f01d92b0: shr $0x10,%r10d
0x00007fd4f01d92b4: mov %r8d,%r9d
0x00007fd4f01d92b7: shr $0x10,%r9d
0x00007fd4f01d92bb: movslq %r10d,%r10
0x00007fd4f01d92be: movslq %r9d,%r9
0x00007fd4f01d92c1: shl $0x20,%r10
0x00007fd4f01d92c5: shl $0x10,%r9
0x00007fd4f01d92c9: or %r9,%rdi
0x00007fd4f01d92cc: or %r10,%rdi
0x00007fd4f01d92cf: or %rax,%rdi
0x00007fd4f01d92d2: movzwl %r8w,%r10d
0x00007fd4f01d92d6: movzwl %r11w,%r11d
0x00007fd4f01d92da: shl $0x10,%r10
0x00007fd4f01d92de: or %r10,%rbx
0x00007fd4f01d92e1: shl $0x20,%r11
0x00007fd4f01d92e5: or %r11,%rbx
0x00007fd4f01d92e8: or %rdx,%rbx
0x00007fd4f01d92eb: pext %rdi,%rbx,%r11
0x00007fd4f01d92f0: cmp 0x3c(%rsp),%r13d
0x00007fd4f01d92f5: jae 0x00007fd4f01d9474
0x00007fd4f01d92fb: shr $0x20,%rcx
0x00007fd4f01d92ff: mov %ecx,%r10d
0x00007fd4f01d9302: movslq %r13d,%rax
0x00007fd4f01d9305: vmovq %xmm2,%r8
0x00007fd4f01d930a: mov %r11,0x10(%r8,%rax,1)
0x00007fd4f01d930f: movzbl %r10b,%r11d
0x00007fd4f01d9313: mov 0x10(%r14,%r11,4),%r8d
0x00007fd4f01d9318: mov %r10d,%r9d
0x00007fd4f01d931b: shr $0x18,%r9d
0x00007fd4f01d931f: mov 0x10(%r14,%r9,4),%r11d
0x00007fd4f01d9324: mov %r8d,%ecx
0x00007fd4f01d9327: shr $0x10,%ecx
0x00007fd4f01d932a: mov %r11d,%r9d
0x00007fd4f01d932d: shr $0x10,%r9d
0x00007fd4f01d9331: movslq %ecx,%rdx
0x00007fd4f01d9334: movslq %r9d,%rcx
0x00007fd4f01d9337: movzwl %r11w,%ebx
0x00007fd4f01d933b: shl $0x30,%rcx
0x00007fd4f01d933f: shl $0x30,%rbx
0x00007fd4f01d9343: movzwl %r8w,%esi
0x00007fd4f01d9347: mov %r10d,%r8d
0x00007fd4f01d934a: shr $0x10,%r8d
0x00007fd4f01d934e: shr $0x8,%r10d
0x00007fd4f01d9352: movzbl %r8b,%r8d
0x00007fd4f01d9356: mov 0x10(%r14,%r8,4),%r11d
0x00007fd4f01d935b: movzbl %r10b,%r10d
0x00007fd4f01d935f: mov 0x10(%r14,%r10,4),%r10d
0x00007fd4f01d9364: mov %r11d,%r9d
0x00007fd4f01d9367: shr $0x10,%r9d
0x00007fd4f01d936b: mov %r10d,%r8d
0x00007fd4f01d936e: shr $0x10,%r8d
0x00007fd4f01d9372: movslq %r9d,%r9
0x00007fd4f01d9375: movslq %r8d,%r8
0x00007fd4f01d9378: shl $0x20,%r9
0x00007fd4f01d937c: shl $0x10,%r8
0x00007fd4f01d9380: or %r8,%rdx
0x00007fd4f01d9383: or %r9,%rdx
0x00007fd4f01d9386: or %rcx,%rdx
0x00007fd4f01d9389: movzwl %r10w,%r10d
0x00007fd4f01d938d: movzwl %r11w,%r11d
0x00007fd4f01d9391: shl $0x10,%r10
0x00007fd4f01d9395: or %r10,%rsi
0x00007fd4f01d9398: shl $0x20,%r11
0x00007fd4f01d939c: or %r11,%rsi
0x00007fd4f01d939f: or %rbx,%rsi
0x00007fd4f01d93a2: pext %rdx,%rsi,%r9
0x00007fd4f01d93a7: popcnt %rdi,%r11
0x00007fd4f01d93ac: mov %r11d,%r10d
0x00007fd4f01d93af: sar $0x1f,%r10d
0x00007fd4f01d93b3: shr $0x1d,%r10d
0x00007fd4f01d93b7: add %r11d,%r10d
0x00007fd4f01d93ba: sar $0x3,%r10d
0x00007fd4f01d93be: lea (%r10,%r13,1),%r8d
0x00007fd4f01d93c2: cmp 0x3c(%rsp),%r8d
0x00007fd4f01d93c7: jae 0x00007fd4f01d94a8
0x00007fd4f01d93cd: popcnt %rdx,%r11
0x00007fd4f01d93d2: movslq %r10d,%r8
0x00007fd4f01d93d5: add %rax,%r8
0x00007fd4f01d93d8: vmovq %xmm2,%rcx
0x00007fd4f01d93dd: mov %r9,0x10(%rcx,%r8,1)
0x00007fd4f01d93e2: mov %r11d,%r8d
0x00007fd4f01d93e5: sar $0x1f,%r8d
0x00007fd4f01d93e9: shr $0x1d,%r8d
0x00007fd4f01d93ed: add %r11d,%r8d
0x00007fd4f01d93f0: sar $0x3,%r8d
0x00007fd4f01d93f4: add %r10d,%r8d
0x00007fd4f01d93f7: add %r13d,%r8d
0x00007fd4f01d93fa: inc %ebp
0x00007fd4f01d93fc: cmp (%rsp),%ebp
0x00007fd4f01d93ff: jl 0x00007fd4f01d9240
```
I see very few xmm spilling (which is good) and the lookup table is keep in a register (which means again, not much register pressure).
Sadly the jmps to `7fd4f01d9474` and `7fd4f01d94a8` with their `cmp` (and previous loads) are not something necessary for the computation itself and related the two `VarHandle` 64 bit writes bound checks:
since the next output index is based on a computation, it's "fair enough" that the JIT need to check if everything it's fine, but using `Unsafe` would fix it (as usual, sigh!!).
合并状态:未合并 关闭于 2024-12-31 10 条评论