JVM常見概念之條件移動

問題

當我們有分支頻率數據時,有什么有趣的技巧可以做嗎?什么是條件移動?

基礎知識

如果您需要在來自一個分支的兩個結果之間進行選擇,那么您可以在 ISA 級別做兩件不同的事情。

首先,你可以創建一個分支:

    # %r = (%rCond == 1) ? $v1 : $v2cmp %rCond, $1jne Amov %r, $v1jmp EA: mov %r, $v2E:

其次,您可以執行依賴于比較結果的預測指令 。在 x86 中,這采用條件移動 (CMOV) 的形式,當選定條件成立時執行操作:

# %r = (%rCond == 1) ? $v1 : $v2mov %r, $v1      ; put $v1 to %rcmp %rCond, ...cmovne %r, $v2   ; put $v2 to %r if condition is false

執行條件移動的優點是它有時會生成更緊湊的代碼,就像在這個例子中一樣,并且它不會受到可能的分支預測錯誤懲罰。缺點是它需要在選擇返回哪一邊之前計算兩邊,這可能會花費過多的 CPU 周期,增加寄存器壓力等。在分支情況下,我們可以選擇在檢查條件后不計算內容。預測良好的分支將優于條件移動。

因此,是否執行條件移動的選擇在很大程度上取決于其成本預測。這就是分支分析可以幫助我們的地方:它可以說出哪些分支可能沒有被完美預測,因此適合 CMOV 替換。當然, 實際成本模型還包括我們正在處理的參數類型、兩個計算分支的相對深度等。

實驗

源碼-用例1

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class BranchFrequency {@Benchmarkpublic void fair() {doCall(true);doCall(false);}@CompilerControl(CompilerControl.Mode.DONT_INLINE)public int doCall(boolean condition) {if (condition) {return 1;} else {return 2;}}
}

執行結果

我們在每次調用時都會在分支之間進行切換,這意味著它的運行時配置文件在它們之間大約是 50%-50%。如果我們通過提供 -XX:ConditionalMoveLimit=0 來限制條件移動替換,那么我們就可以清楚地看到替換的發生。

# doCall, out of box variant4.36%  ...4ac: mov    $0x1,%r11d         ; move $1 -> %r113.24%  ...4b2: mov    $0x2,%eax          ; move $2 -> %res8.46%  ...4b7: test   %edx,%edx          ; test boolean0.02%  ...4b9: cmovne %r11d,%eax         ; if false, move %r11 -> %res7.88%  ...4bd: add    $0x10,%rsp         ; exit the method8.12%  ...4c1: pop    %rbp18.60%  ...4c2: cmp    0x340(%r15),%rsp...4c9: ja     ...4d00.14%  ...4cf: retq# doCall, CMOV conversion inhibited6.48%    ...cac: test   %edx,%edx         ; test boolean╭  ...cae: je     ...cc8│                                   ; if true...│  ...cb0: mov    $0x1,%eax         ; move $1 -> %res7.41% │↗ ...cb5: add    $0x10,%rsp        ; exit the method0.02% ││ ...cb9: pop    %rbp27.43% ││ ...cba: cmp    0x340(%r15),%rsp││ ...cc1: ja     ...ccf3.28% ││ ...cc7: retq││                                  ; if false...7.04% ↘│ ...cc8: mov    $0x2,%eax         ; move $2 -> %res0.02%  ╰ ...ccd: jmp    ...cb5            ; jump back

在此示例中,CMOV 版本的表現稍好一些:

Benchmark                              Mode  Cnt   Score    Error  Units# Branches
BranchFrequency.fair                   avgt   25   5.422 ±  0.026  ns/op
BranchFrequency.fair:L1-dcache-loads   avgt    5  12.078 ±  0.226   #/op
BranchFrequency.fair:L1-dcache-stores  avgt    5   5.037 ±  0.120   #/op
BranchFrequency.fair:branch-misses     avgt    5   0.001 ±  0.003   #/op
BranchFrequency.fair:branches          avgt    5  10.037 ±  0.216   #/op
BranchFrequency.fair:cycles            avgt    5  14.659 ±  0.285   #/op
BranchFrequency.fair:instructions      avgt    5  35.184 ±  0.559   #/op# CMOVs
BranchFrequency.fair                   avgt   25   4.799 ±  0.094  ns/op
BranchFrequency.fair:L1-dcache-loads   avgt    5  12.014 ±  0.329   #/op
BranchFrequency.fair:L1-dcache-stores  avgt    5   5.005 ±  0.167   #/op
BranchFrequency.fair:branch-misses     avgt    510??            #/op
BranchFrequency.fair:branches          avgt    5   7.054 ±  0.118   #/op
BranchFrequency.fair:cycles            avgt    5  12.964 ±  1.451   #/op
BranchFrequency.fair:instructions      avgt    5  36.285 ±  0.713   #/op

您可能認為這是因為 CMOV 沒有分支預測失誤懲罰,但這種解釋與計數器不一致。請注意,在兩種情況下,“分支失誤”幾乎為零。這是因為硬件分支預測器實際上可以記住一個短暫的分支歷史,而這種反復出現的分支對它們來說沒有任何問題。性能差異的實際原因是分支情況下的跳躍:我們在關鍵路徑上有一條額外的控制流指令。

源碼-用例2

@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class AdjustableBranchFreq {@Param("50")int percent;boolean[] arr;@Setup(Level.Iteration)public void setup() {final int SIZE = 100_000;final int Q = 1_000_000;final int THRESH = percent * Q / 100;arr = new boolean[SIZE];ThreadLocalRandom current = ThreadLocalRandom.current();for (int c = 0; c < SIZE; c++) {arr[c] = current.nextInt(Q) < THRESH;}// Avoid uncommon traps on both branches.doCall(true);doCall(false);}@Benchmarkpublic void test() {for (boolean cond : arr) {doCall(cond);}}@CompilerControl(CompilerControl.Mode.DONT_INLINE)public int doCall(boolean condition) {if (condition) {return 1;} else {return 2;}}
}

執行結果

使用不同的 percent 值和 -prof perfnorm JMH 分析器運行它將產生以下結果:
在這里插入圖片描述依據上圖,你可以清楚地看到幾件事:

  • 每個測試的分支數約為 5,而 CMOV 轉換將其降至 4。這與之前的反匯編轉儲相關:我們將測試中的一個分支轉換為 CMOV。另外 4 個分支來自測試基礎設施本身。
  • 如果沒有 CMOV,分支測試性能會受到影響,在 50% 的分支概率下會變得最差。這個峰值反映了硬件分支預測器幾乎完全混亂,因為它每次操作都會遇到大約 0.5 次分支失誤。這意味著分支預測器并不是一直猜錯(這太荒謬了!),而只是一半的時間猜錯。我推測基于歷史的預測器會放棄,讓靜態預測器選擇最近的分支,而我們只選擇了一半的時間。
  • 使用 CMOV 后,我們可以看到操作時間幾乎持平 。該圖表明 CMOV 成本模型對于此測試來說可能過于保守,并且切換得有點晚。這并不一定意味著它有錯誤,因為其他情況的表現很可能會有所不同。盡管如此,當進行 CMOV 轉換時,對分支情況的改進是巨大的。
  • 您可能會注意到,當分支預測準確率為 >97% 時,分支變體會低于 CMOV 中間平均值。當然,這又是測試、硬件、虛擬機特有的事情。

總結

分支分析允許在執行概率敏感指令選擇時做出或多或少明智的選擇。條件移動替換通常使用分支頻率信息來驅動替換。這再次強調了使用與真實數據類似的數據來預熱 JIT 編譯代碼的必要性,以便編譯器能夠針對特定情況進行有效優化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898889.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898889.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898889.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MANISKILL3:GPU 并行機器人模擬和渲染,用于通用的具身AI

本文介紹了一種名為ManiSkill3的機器人仿真系統&#xff0c;它采用了GPU并行化技術&#xff0c;并針對通用性進行了優化。該系統支持多種視覺輸入方式和異構模擬&#xff0c;能夠在物理場景中進行高效的仿真和渲染&#xff0c;達到比其他平臺更快的速度和更少的GPU內存使用量。…

計算機網絡高頻(三)UDP基礎

計算機網絡高頻(三)UDP基礎 1.UDP的頭部格式是什么樣的?? UDP 頭部具有以下字段: 源端口(Source Port):16 位字段,表示發送方的端口號。目標端口(Destination Port):16 位字段,表示接收方的端口號。長度(Length):16 位字段,表示 UDP 數據報(包括頭部和數據部…

微信小程序中使用Less樣式方法

在微信小程序中使用Less樣式&#xff0c;可以通過以下步驟實現。主要原理是借助Visual Studio Code&#xff08;VSCode&#xff09;的插件將Less文件自動編譯為小程序支持的.wxss文件&#xff0c;或通過微信開發者工具的擴展功能直接集成Less編譯環境。以下是具體方法&#xff…

Leetcode 刷題筆記 圖論part05

卡碼網 107 尋找存在的路徑 初識并查集 并查集功能&#xff1a; 尋找根節點&#xff0c;函數: find(int u)&#xff0c;也就是判斷這個節點的祖先節點是哪個將兩個節點接入到同一個集合&#xff0c;函數: join(int u, int v)&#xff0c;將兩個節點連在同一個根節點上判斷兩…

SpringBoot星之語明星周邊產品銷售網站設計與實現

在當今數字化時代&#xff0c;明星周邊產品的線上銷售已成為一種趨勢。幽絡源作為一站式綜合平臺&#xff0c;不僅提供免費源碼、網絡兼職資源&#xff0c;還分享各類技術教程。本文將詳細介紹基于SpringBoot的星之語明星周邊產品銷售網站的設計與實現&#xff0c;幫助開發者快…

怎樣對比找到兩個git倉庫的差異

怎樣對比找到兩個git倉庫的差異 陳拓 2024/12/24-2024/12/28 1. 概述 要比較兩個Git倉庫的差異&#xff0c;可以使用git diff命令。你需要先將兩個倉庫的克隆版本都檢出到本地&#xff0c;然后在對應的目錄中運行git diff命令。 下面我們以YDLIDAR ROS2驅動程序ydlidar_ros2…

C語言-裝飾器模式詳解與實踐 - LED控制系統

文章目錄 C語言裝飾器模式詳解與實踐 - LED控制系統1. 什么是裝飾器模式&#xff1f;2. 為什么需要裝飾器模式&#xff1f;3. 實際應用場景4. 代碼實現4.1 頭文件 (led_decorator.h)4.2 實現文件 (led_decorator.c)4.3 使用示例 (main.c) 5. 代碼分析5.1 關鍵設計點5.2 實現特點…

Go常見問題與回答(下)

文章目錄 1、通過指針變量 p 訪問其成員變量 name&#xff0c;有哪幾種方式&#xff1f;2、代碼&#xff0c;說出結果3、擴容提&#xff0c;代碼&#xff0c;說出結果4、指出下面這段代碼的錯誤之處5、是否通過編譯6、關于字符串連接&#xff0c;下面語法正確的是7、關于iota&a…

JVM 核心知識點總結

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;…

SQL中體會多對多

我們可以根據學生與課程多對多關系的數據庫模型&#xff0c;給出實際的表數據以及對應的查詢結果示例&#xff0c;會用到JOINLEFT JOIN兩種連接 1. 學生表&#xff08;students&#xff09; student_idstudent_name1張三2李四3王五 2. 課程表&#xff08;courses&#xff09…

ES如果要查10條數據需要從各個分片上各取多少條數據?

目錄 ES如果要查10條數據需要從各個分片上各取多少條數據? 簡單查詢(如 match_all 或 term 查詢) 深度分頁查詢(如 from + size 查詢) 聚合查詢 什么叫聚合查詢? 聚合查詢的基本結構 常見的聚合類型 聚合查詢的執行過程 聚合查詢的示例 聚合查詢的應用場景 注意…

人機交互自學引導

第1關&#xff1a;輸出“Hello World!” # 在下面一行補充代碼&#xff0c;輸出“Hello World!” print(Hello World!) 第2關&#xff1a;輸出“李白&#xff0c;你好&#xff01;” # 在下面補充代碼&#xff0c;在兩行中依次輸出“李白&#xff0c;你好&#xff01;”和“…

CentOS 7 更換 yum 源(阿里云)+ 擴展 epel 源

CentOS 7 更換 yum 源&#xff08;阿里云&#xff09; 擴展 epel 源 一、備份現有 yum 源二、下載 yum 源&#xff08;任選其一即可&#xff09;三、清理并生成緩存四、安裝 EPEL 擴展源&#xff08;根據需要下載&#xff09;五、驗證是否生效六、一鍵腳本&#xff08;阿里云源…

無人機與傳統巡檢優劣勢對比!

一、無人機巡檢的優勢 1. 高效性 覆蓋范圍廣&#xff1a;可快速掃描大范圍區域&#xff08;如電力線路、管道、農田等&#xff09;&#xff0c;尤其適合復雜地形&#xff08;山區、沼澤等&#xff09;。 速度快&#xff1a;飛行速度遠高于人工巡檢&#xff0c;縮短任務周期…

DrRacket是一款專為Scheme和Racket編程語言設計的集成開發環境(IDE)

DrRacket是一款專為Scheme和Racket編程語言設計的集成開發環境&#xff08;IDE&#xff09;&#xff0c;由瑞士蘇黎世聯邦理工學院開發。它不僅是初學者學習編程的理想工具&#xff0c;也適用于專業級開發?。 安裝DrRacket 請訪問https://download.racket-lang.org安裝Racke…

走進底層-Java中的IO流

Java中IO流 在Java編程中&#xff0c;IO流&#xff08;Input/Output Stream&#xff09;是非常重要的概念&#xff0c;它為程序的輸入和輸出操作提供了一套強大而靈活的機制。本文將詳細介紹Java中IO流的相關內容&#xff0c;包括其基本概念、分類以及常見類的使用示例。 一、…

【Tiny RDM】Redis客戶端工具

Tiny RDM Tiny RDM是一款現代化、輕量級、跨平臺的Redis客戶端&#xff0c;支持Mac、Windows和Linux&#xff0c;目前在Github上已有10kStar。 Github 項目地址&#xff1a; https://github.com/tiny-craft/tiny-rdm 功能特性 極度輕量&#xff0c;基于Webview2&#xff0c…

ctfshow REVERSE re2 萌新賽 內部賽 七夕杯 WP

目錄 re2 萌新賽 flag白給 簽退 數學不及格 內部賽 批量生產的偽劣產品 來一個派森 好好學習 天天向上 屏幕裂開了 七夕杯 逆向簽到 easy_magic re2 ida分析主函數&#xff0c;將flag.txt內容加密寫入enflag.txt 這是密鑰加密過程 標準rc4加密 簡單異或解…

【Linux】線程庫

一、線程庫管理 tid其實是一個地址 void* start(void* args) {const char* name (const char *)args;while(true){printf("我是新線程 %s &#xff0c;我的地址&#xff1a;0x%lx\n",name,pthread_self());sleep(1);}return nullptr; }int main() {pthread_t tid…

深入剖析 Android Compose 框架的自動動畫:AnimatedVisibility 與 AnimatedContent(二十四)

深入剖析 Android Compose 框架的自動動畫&#xff1a;AnimatedVisibility 與 AnimatedContent 引言 在 Android 應用開發中&#xff0c;動畫是提升用戶體驗的重要手段。它能夠讓界面元素的顯示與隱藏、狀態的切換變得更加自然和流暢&#xff0c;避免生硬的變化給用戶帶來不佳…