性能優化:編譯器優化選項 -O2/-O3 究竟有多強大?

来源:https://www.cnblogs.com/tengzijian/p/18075365
-Advertisement-
Play Games

之前的“性能優化的一般策略及方法”一文中介紹了多種性能優化的方法。根據以往的項目經驗,開啟編譯器優化選項可能是立竿見影、成本最低、效果最好的方式了。 這麼說可能還不夠直觀,舉個真實的例子:我所參與的自動駕駛的項目中,無需修改任何代碼,僅僅增加一個 -O2 選項,進程整體的 CPU loading 可 ...


之前的“性能優化的一般策略及方法”一文中介紹了多種性能優化的方法。根據以往的項目經驗,開啟編譯器優化選項可能是立竿見影、成本最低、效果最好的方式了。

這麼說可能還不夠直觀,舉個真實的例子:我所參與的自動駕駛的項目中,無需修改任何代碼,僅僅增加一個 -O2 選項,進程整體的 CPU loading 可以從 50% 降到 30% 左右,某些關鍵函數的執行時間可以從 1700us 降低到 700us 左右。

編譯器能優化能力遠比你想象中的強大!往後翻翻附錄,看看那些多到讓人眼花的優化選項你就知道,很多的人工優化都是不必要的,編譯器會做得更快,更好,更安全!人工優化,不僅會降低代碼的可讀性和可維護性,而且非常容易引入 bug!

實際上,不管是 -O2 還是 -O3,都是一組優化選項的集合,要知道具體做了什麼,可以通過 gcc/g++ 的 -c -Q --help=optimizers 參數

例如我用的 aarch64-unknown-nto-qnx7.1.0-g++ 編譯器,如果想知道加了 -O2 之後開啟了哪些優化項,可以通過以下 3 條命令:

$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q -O2 --help=optimizers > /tmp/O2-opts
$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q --help=optimizers > /tmp/O-opts
$ diff /tmp/O2-opts /tmp/O-opts | grep enabled
<   -fdevirtualize                              [enabled]
<   -finline-functions-called-once              [enabled]
<   -finline-small-functions                    [enabled]
<   -foptimize-strlen                           [enabled]
<   -freorder-blocks                            [enabled]
<   -freorder-functions                         [enabled]
<   -ftree-switch-conversion                    [enabled]
<   -ftree-tail-merge                           [enabled]
...

隨便看了幾個,就足以感受到編譯器優化選項的強大:

  • finline-xxx:內聯函數,以避免函數調用開銷。順便提一句:代碼中的 inline 關鍵字只是一個對編譯器的提示,編譯器會根據具體情況作出最佳的選擇,無論是否有 inline 關鍵字
  • fdevirtualize:嘗試把虛函數調用轉換為直接調用,以避免虛函數導致的額外開銷
  • freorder-blocks:對函數中的代碼塊重新排序,以減少分支數、提高代碼局部性
  • freorder-functions:對對象中函數重新排序,以提升代碼局部性:把經常執行的函數放到 ".text.hot" 節,不常執行的函數放到 ".text.unlikely" 節
    ...

完整的優化項很多,具體每個選項的確切解釋需要查看編譯器手冊。

小結

  1. 如果性能不理想,先檢查是否開啟了編譯器優化選項。這可能是最快、最有效的手段了。
  2. 編譯器能優化能力遠比你想象中的強大!
  3. 不要在沒有開啟優化選項的時候就開始盲目改代碼,很多都是徒勞,甚至降低性能、引入 bug:編譯器優化會做得更快、更安全
  4. 如果開了優化選項,你的程式出現問題,不要懷疑編譯器,大概率是因為你的代碼不規範,使用了 C/C++ “未定義”行為導致的
  5. 需要註意,在汽車領域中,對優化選項有一定的限制,比如我的項目中,編譯器的 Safety Manual 明確說明瞭最大隻支持 -O2 的優化等級

附錄

授人以漁

關於這個問題,我第一開始想到的是問 ChatGPT,但是得到的結果並不滿意。然後想到的是 RTFM!

man gcc

線上版本:https://manpages.org/gcc

搜索關鍵字 /optimiz,很快就找到了我要的答案:

gcc 支持的優化選項

 Optimization Options
           -faggressive-loop-optimizations -falign-functions[=n[:m:[n2[:m2]]]] -falign-jumps[=n[:m:[n2[:m2]]]] -falign-labels[=n[:m:[n2[:m2]]]]
           -falign-loops[=n[:m:[n2[:m2]]]] -fno-allocation-dce -fallow-store-data-races -fassociative-math  -fauto-profile  -fauto-profile[=path]
           -fauto-inc-dec  -fbranch-probabilities -fcaller-saves -fcombine-stack-adjustments  -fconserve-stack -fcompare-elim  -fcprop-registers
           -fcrossjumping -fcse-follow-jumps  -fcse-skip-blocks  -fcx-fortran-rules -fcx-limited-range -fdata-sections  -fdce  -fdelayed-branch
           -fdelete-null-pointer-checks  -fdevirtualize  -fdevirtualize-speculatively -fdevirtualize-at-ltrans  -fdse -fearly-inlining  -fipa-sra
           -fexpensive-optimizations  -ffat-lto-objects -ffast-math  -ffinite-math-only  -ffloat-store  -fexcess-precision=style -ffinite-loops
           -fforward-propagate  -ffp-contract=style  -ffunction-sections -fgcse  -fgcse-after-reload  -fgcse-las  -fgcse-lm  -fgraphite-identity
           -fgcse-sm  -fhoist-adjacent-loads  -fif-conversion -fif-conversion2  -findirect-inlining -finline-functions  -finline-functions-called-once
           -finline-limit=n -finline-small-functions -fipa-modref -fipa-cp  -fipa-cp-clone -fipa-bit-cp  -fipa-vrp  -fipa-pta  -fipa-profile
           -fipa-pure-const -fipa-reference  -fipa-reference-addressable -fipa-stack-alignment  -fipa-icf  -fira-algorithm=algorithm
           -flive-patching=level -fira-region=region  -fira-hoist-pressure -fira-loop-pressure  -fno-ira-share-save-slots -fno-ira-share-spill-slots
           -fisolate-erroneous-paths-dereference  -fisolate-erroneous-paths-attribute -fivopts  -fkeep-inline-functions  -fkeep-static-functions
           -fkeep-static-consts  -flimit-function-alignment  -flive-range-shrinkage -floop-block  -floop-interchange  -floop-strip-mine
           -floop-unroll-and-jam  -floop-nest-optimize -floop-parallelize-all  -flra-remat  -flto  -flto-compression-level -flto-partition=alg
           -fmerge-all-constants -fmerge-constants  -fmodulo-sched  -fmodulo-sched-allow-regmoves -fmove-loop-invariants  -fno-branch-count-reg
           -fno-defer-pop  -fno-fp-int-builtin-inexact  -fno-function-cse -fno-guess-branch-probability  -fno-inline  -fno-math-errno  -fno-peephole
           -fno-peephole2  -fno-printf-return-value  -fno-sched-interblock -fno-sched-spec  -fno-signed-zeros -fno-toplevel-reorder  -fno-trapping-math
           -fno-zero-initialized-in-bss -fomit-frame-pointer  -foptimize-sibling-calls -fpartial-inlining  -fpeel-loops  -fpredictive-commoning
           -fprefetch-loop-arrays -fprofile-correction -fprofile-use  -fprofile-use=path -fprofile-partial-training -fprofile-values
           -fprofile-reorder-functions -freciprocal-math  -free  -frename-registers  -freorder-blocks -freorder-blocks-algorithm=algorithm
           -freorder-blocks-and-partition  -freorder-functions -frerun-cse-after-loop  -freschedule-modulo-scheduled-loops -frounding-math
           -fsave-optimization-record -fsched2-use-superblocks  -fsched-pressure -fsched-spec-load  -fsched-spec-load-dangerous
           -fsched-stalled-insns-dep[=n]  -fsched-stalled-insns[=n] -fsched-group-heuristic  -fsched-critical-path-heuristic -fsched-spec-insn-heuristic
           -fsched-rank-heuristic -fsched-last-insn-heuristic  -fsched-dep-count-heuristic -fschedule-fusion -fschedule-insns  -fschedule-insns2
           -fsection-anchors -fselective-scheduling  -fselective-scheduling2 -fsel-sched-pipelining  -fsel-sched-pipelining-outer-loops
           -fsemantic-interposition  -fshrink-wrap  -fshrink-wrap-separate -fsignaling-nans -fsingle-precision-constant  -fsplit-ivs-in-unroller
           -fsplit-loops -fsplit-paths -fsplit-wide-types  -fsplit-wide-types-early  -fssa-backprop  -fssa-phiopt -fstdarg-opt  -fstore-merging
           -fstrict-aliasing -fthread-jumps  -ftracer  -ftree-bit-ccp -ftree-builtin-call-dce  -ftree-ccp  -ftree-ch -ftree-coalesce-vars
           -ftree-copy-prop  -ftree-dce  -ftree-dominator-opts -ftree-dse  -ftree-forwprop  -ftree-fre  -fcode-hoisting -ftree-loop-if-convert
           -ftree-loop-im -ftree-phiprop  -ftree-loop-distribution  -ftree-loop-distribute-patterns -ftree-loop-ivcanon  -ftree-loop-linear
           -ftree-loop-optimize -ftree-loop-vectorize -ftree-parallelize-loops=n  -ftree-pre  -ftree-partial-pre  -ftree-pta -ftree-reassoc
           -ftree-scev-cprop  -ftree-sink  -ftree-slsr  -ftree-sra -ftree-switch-conversion  -ftree-tail-merge -ftree-ter  -ftree-vectorize  -ftree-vrp
           -funconstrained-commons -funit-at-a-time  -funroll-all-loops  -funroll-loops -funsafe-math-optimizations  -funswitch-loops -fipa-ra
           -fvariable-expansion-in-unroller  -fvect-cost-model  -fvpt -fweb  -fwhole-program  -fwpa  -fuse-linker-plugin -fzero-call-used-regs --param
           name=value -O  -O0  -O1  -O2  -O3  -Os  -Ofast  -Og

aarch64-unknown-nto-qnx7.1.0-g++ 加 -O2 相較於預設不加 -O2 增加的優化選項(完整列表)

$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q -O2 --help=optimizers > /tmp/O2-opts
$ aarch64-unknown-nto-qnx7.1.0-g++ -c -Q --help=optimizers > /tmp/O-opts
$ diff /tmp/O2-opts /tmp/O-opts | grep enabled
<   -falign-labels                              [enabled]
<   -fbranch-count-reg                          [enabled]
<   -fcaller-saves                              [enabled]
<   -fcode-hoisting                             [enabled]
<   -fcombine-stack-adjustments                 [enabled]
<   -fcompare-elim                              [enabled]
<   -fcprop-registers                           [enabled]
<   -fcrossjumping                              [enabled]
<   -fcse-follow-jumps                          [enabled]
<   -fdefer-pop                                 [enabled]
<   -fdevirtualize                              [enabled]
<   -fdevirtualize-speculatively                [enabled]
<   -fexpensive-optimizations                   [enabled]
<   -fforward-propagate                         [enabled]
<   -fgcse                                      [enabled]
<   -fguess-branch-probability                  [enabled]
<   -fhoist-adjacent-loads                      [enabled]
<   -fif-conversion                             [enabled]
<   -fif-conversion2                            [enabled]
<   -findirect-inlining                         [enabled]
<   -finline-functions-called-once              [enabled]
<   -finline-small-functions                    [enabled]
<   -fipa-bit-cp                                [enabled]
<   -fipa-cp                                    [enabled]
<   -fipa-icf                                   [enabled]
<   -fipa-icf-functions                         [enabled]
<   -fipa-icf-variables                         [enabled]
<   -fipa-profile                               [enabled]
<   -fipa-pure-const                            [enabled]
<   -fipa-ra                                    [enabled]
<   -fipa-reference                             [enabled]
<   -fipa-sra                                   [enabled]
<   -fipa-vrp                                   [enabled]
<   -fisolate-erroneous-paths-dereference       [enabled]
<   -flra-remat                                 [enabled]
<   -fmove-loop-invariants                      [enabled]
<   -foptimize-sibling-calls                    [enabled]
<   -foptimize-strlen                           [enabled]
<   -fpartial-inlining                          [enabled]
<   -fpeephole2                                 [enabled]
<   -freorder-blocks                            [enabled]
<   -freorder-functions                         [enabled]
<   -frerun-cse-after-loop                      [enabled]
<   -fsched-pressure                            [enabled]
<   -fschedule-insns                            [enabled]
<   -fschedule-insns2                           [enabled]
<   -fsection-anchors                           [enabled]
<   -fshrink-wrap                               [enabled]
<   -fsplit-wide-types                          [enabled]
<   -fssa-phiopt                                [enabled]
<   -fstore-merging                             [enabled]
<   -fstrict-aliasing                           [enabled]
<   -fthread-jumps                              [enabled]
<   -ftree-bit-ccp                              [enabled]
<   -ftree-builtin-call-dce                     [enabled]
<   -ftree-ccp                                  [enabled]
<   -ftree-ch                                   [enabled]
<   -ftree-coalesce-vars                        [enabled]
<   -ftree-copy-prop                            [enabled]
<   -ftree-dce                                  [enabled]
<   -ftree-dominator-opts                       [enabled]
<   -ftree-dse                                  [enabled]
<   -ftree-fre                                  [enabled]
<   -ftree-pre                                  [enabled]
<   -ftree-pta                                  [enabled]
<   -ftree-sink                                 [enabled]
<   -ftree-slsr                                 [enabled]
<   -ftree-sra                                  [enabled]
<   -ftree-switch-conversion                    [enabled]
<   -ftree-tail-merge                           [enabled]
<   -ftree-ter                                  [enabled]
<   -ftree-vrp                                  [enabled]

本文作者:Zijian/TENG(微信公眾號:好記性如爛筆頭),轉載請註明原文鏈接:https://www.cnblogs.com/tengzijian/p/18075365
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • .NET Aspire Preview 4 is now available! Here's a summary of what's new in this preview release:.NET Aspire Preview 4 現已推出!以下是此預覽版中新增內容的摘要: Podman Supp ...
  • c#的lamba表達式 之前已經寫過一些關於委托還有事件的文章,今天就來介紹一下lambda表達式。 首先定義需要的函數以及委托 { public delegate void DoNothingDelegate(); public delegate void StudyDelegate(int id ...
  • 前言 作為開發人員,我們經常嚮應用程式添加新功能並修改當前的 Api。版本控制使我們能夠安全地添加新功能而不會造成中斷性變更。一個良好的 Api 版本控制策略可以清晰地傳達所做的更改,並允許使用現有 REST Api 的客戶端在準備好時才遷移或更新他們的應用程式到最新版本。 哪些行為可能會造成 Ap ...
  • ASP.NET Core 中的框架中發出大量診斷事件,包括當前請求進入請求完成事件,HttpClient發出收到與響應,EFCore查詢等等。 我們可以利用DiagnosticListener來選擇性地監聽這些事件,然後通過自己的方式組織這些日誌,實現無侵入的分散式跟蹤。 下麵我們通過Diagnos ...
  • 概述:C#中的Attribute(特性)為程式元素提供了靈活的元數據機制。除基礎應用外,可高級應用於自定義代碼生成、AOP等領域。通過示例展示了Attribute在AOP中的實際用途,以及如何通過反射機制獲取並執行與Attribute相關的邏輯。 在C#中,Attribute(特性)是一種用於為程式 ...
  • 概述:.NET中實現數字轉大寫金額可通過現有庫或自定義方法。自定義方法示例使用遞歸將數字分段轉換為中文大寫金額,處理了千、百、十、個位數。實際應用中可根據需求進一步擴展,例如處理小數部分或負數。 在.NET中,你可以使用以下方案之一來實現將數字轉成大寫金額: 使用現有庫: .NET框架中有一些庫已經 ...
  • (適用於.NET/.NET Core/.NET Framework)【目錄】0.前言1.第一個AOP程式2.Aspect橫切麵編程3.一個橫切麵程式攔截多個主程式4.多個橫切麵程式攔截一個主程式5.優勢總結6.展望 0.前言AOP(Aspect Oriented Programming)是“面向橫切 ...
  • 前幾天,點開自己的博客,看了一下 CYQ.Data V5系列 都有哪些文章,發現了一篇2019年寫的:CYQ.Data 對於分散式緩存Redis、MemCache高可用的改進及性能測試,於是點進去看了看。感覺文章中有些表述存有問題,,不過不是重點。 重點,看了裡面的測試結論,如果四五年過去了,CYQ... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...