亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java Math.abs(int) 優化,為什么這段代碼慢了 6 倍?

Java Math.abs(int) 優化,為什么這段代碼慢了 6 倍?

RISEBY 2023-08-04 09:55:45
如您所知,Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE為了防止出現負值,該safeAbs方法在我的項目中實現了:    public static int safeAbs(int i) {        i = Math.abs(i);        return i < 0 ? 0 : i;    }我將性能與以下性能進行了比較:    public static int safeAbs(int i) {        return i == Integer.MIN_VALUE ? 0 : Math.abs(i);    }第一個幾乎比第二個慢 6 倍(第二個性能幾乎與“純”Math.abs(int) 相同)。從我的角度來看,字節碼沒有顯著差異,但我猜差異存在于 JIT“匯編”代碼中:“慢”版本:  0x00007f0149119720: mov     %eax,0xfffffffffffec000(%rsp)  0x00007f0149119727: push    %rbp  0x00007f0149119728: sub     $0x20,%rsp  0x00007f014911972c: test    %esi,%esi  0x00007f014911972e: jl      0x7f0149119734  0x00007f0149119730: mov     %esi,%eax  0x00007f0149119732: jmp     0x7f014911973c  0x00007f0149119734: neg     %esi  0x00007f0149119736: test    %esi,%esi  0x00007f0149119738: jl      0x7f0149119748  0x00007f014911973a: mov     %esi,%eax  0x00007f014911973c: add     $0x20,%rsp  0x00007f0149119740: pop     %rbp  0x00007f0149119741: test    %eax,0x1772e8b9(%rip)  ;   {poll_return}  0x00007f0149119747: retq  0x00007f0149119748: mov     %esi,(%rsp)  0x00007f014911974b: mov     $0xffffff65,%esi  0x00007f0149119750: nop  0x00007f0149119753: callq   0x7f01490051a0    ; OopMap{off=56}                                                ;*ifge                                                ; - math.FastAbs::safeAbsSlow@6 (line 16)                                                ;   {runtime_call}  0x00007f0149119758: callq   0x7f015f521d20    ;   {runtime_call}
查看完整描述

1 回答

?
Smart貓小萌

TA貢獻1911條經驗 獲得超7個贊

safeAbsSlow和方法生成的本機代碼存在差異safeAbsFast。


safeAbsSlow(C2,4 級):


0x0000023d12ec4b14: add     eax,ecx

0x0000023d12ec4b16: inc     ebx


0x0000023d12ec4b18: cmp     ebx,989680h

0x0000023d12ec4b1e: jnl     23d12ec4b4eh ; jump if `ebx` was not less than `10_000_000`


0x0000023d12ec4b20: mov     ecx,dword ptr [r9+rbx*4+10h]


0x0000023d12ec4b25: test    ecx,ecx

0x0000023d12ec4b27: jnl     23d12ec4b14h ; jump if `ecx` was not less-than `0`


0x0000023d12ec4b29: neg     ecx


0x0000023d12ec4b2b: test    ecx,ecx

0x0000023d12ec4b2d: jnl     23d12ec4b14h ; jump if `ecx` was not less-than `0`

safeAbsFast(C2,4 級):


0x000001d89e8a4b20: mov     ecx,dword ptr [r9+rdi*4+10h]


0x000001d89e8a4b25: cmp     ecx,80000000h

0x000001d89e8a4b2b: je      1d89e8a4b66h ; jump if `ecx` was equal to `2147483648`


0x000001d89e8a4b2d: mov     r11d,ecx

0x000001d89e8a4b30: neg     r11d

0x000001d89e8a4b33: test    ecx,ecx

0x000001d89e8a4b35: cmovl   ecx,r11d


0x000001d89e8a4b39: add     eax,ecx

0x000001d89e8a4b3b: inc     edi


0x000001d89e8a4b3d: cmp     edi,989680h

0x000001d89e8a4b43: jl      1d89e8a4b20h ; jump if `edi` was less than `10_000_000`

從上面我們可以看出,safeAbsSlow比 具有更多的條件跳轉safeAbsFast。


這尤其是因為Math.abs內聯到的實現safeAbsFast沒有條件跳轉:


0x000001d89e8a4b2d: mov     r11d,ecx

0x000001d89e8a4b30: neg     r11d

0x000001d89e8a4b33: test    ecx,ecx

0x000001d89e8a4b35: cmovl   ecx,r11d

因此,與數據集同時具有分散在數組中的正值和負值時的版本slow相比,該  版本中的分支未命中次數要多得多。normal以下是使用 Linux 分析器收集的相應統計信息perf:


Benchmark                          Mode  Cnt          Score         Error  Units

safeAbsFast                        avgt   10    9611659.726 ± 1429082.431  ns/op

safeAbsFast:branch-misses          avgt            2869.853                 #/op

safeAbsFast:branches               avgt        12492918.020                 #/op

safeAbsFast:cycles                 avgt        28212203.936                 #/op

safeAbsFast:instructions           avgt        92352048.153                 #/op

safeAbsSlow                        avgt   10   44524180.366 ± 6324887.086  ns/op

safeAbsSlow:branch-misses          avgt         5006493.144                 #/op

safeAbsSlow:branches               avgt        17496069.911                 #/op

safeAbsSlow:cycles                 avgt       126413171.674                 #/op

safeAbsSlow:instructions           avgt        67549877.558                 #/op

相反,這是排序數據集的結果:


Benchmark                          Mode  Cnt         Score         Error  Units

safeAbsFast                        avgt   10   9026800.584 ±  528992.157  ns/op

safeAbsFast:branch-misses          avgt           2785.463                 #/op

safeAbsFast:branches               avgt       12474751.905                 #/op

safeAbsFast:cycles                 avgt       27379727.603                 #/op

safeAbsFast:instructions           avgt       92418075.715                 #/op

safeAbsSlow                        avgt   10   6981828.374 ± 2375480.834  ns/op

safeAbsSlow:branch-misses          avgt           2801.022                 #/op

safeAbsSlow:branches               avgt       17496585.992                 #/op

safeAbsSlow:cycles                 avgt       19478382.113                 #/op

safeAbsSlow:instructions           avgt       67589946.278                 #/op

當數據集排序時,以前的slow版本變得更快(在這種情況下,代價高昂的分支未命中被最小化)。


環境:


openjdk version "12-internal" 2019-03-19

OpenJDK Runtime Environment (slowdebug build 12-internal+0-adhoc.jdk12)

OpenJDK 64-Bit Server VM (slowdebug build 12-internal+0-adhoc.jdk12, mixed mode)


查看完整回答
反對 回復 2023-08-04
  • 1 回答
  • 0 關注
  • 199 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號