c服務編譯耗時優化原理及實例
Ⅰ 17.緙栬瘧浼樺寲鎶鏈
娣卞叆鎺㈢儲錛氱紪璇戜紭鍖栨妧鏈鐨勯瓍鍔
鍦ㄧ紪璇戝櫒鐨勪笘鐣岄噷錛屽叕鍏卞瓙琛ㄨ揪寮忔秷闄ょ姽濡備竴浣嶇簿鏄庣殑綆楁湳瀹訛紝鍠勪簬璇嗗埆騫舵秷闄ら噸澶嶈$畻銆傚綋浠g爜鐗囨靛俰nt d=(c*b)*12+a+(a+b*c)涓錛岀紪璇戝櫒媧炲療鍒"cb"涓"bc"瀹為檯涓婃槸鍚屼竴琛ㄨ揪寮忥紝涓攂鍜宑鐨勫煎湪璁$畻榪囩▼涓淇濇寔涓嶅彉錛屽畠浼氳仾鏄庡湴灝嗚繖孌佃〃杈懼紡綆鍖栦負int d=E*12+a+(a+E)錛岃繖鏍鋒棦鑺傜渷浜嗚$畻璧勬簮錛屽張鎻愬崌浜嗘墽琛屾晥鐜囥
鏁扮粍杈圭晫媯鏌ユ秷闄ゅ垯鏄涓浣嶈︽儠鐨勫畧鍗鑰咃紝Java璇璦鍦ㄨ塊棶鏁扮粍鍏冪礌鏃惰嚜鍔ㄨ繘琛岃竟鐣屾鏌ワ紝紜淇漣鐨勫煎湪鏈夋晥鑼冨洿鍐咃紝闃叉㈣繍琛屾椂寮傚父銆傜紪璇戝櫒閫氳繃鍦ㄥ驚鐜鍓嶈繘琛屾鏌ワ紝紜淇濅簡浠g爜鐨勬g『鎬у拰鍙闈犳с
鏂規硶鍐呰仈錛氱紪璇戝櫒鐨勯瓟娉曟墜絎
鏂規硶鍐呰仈鏄緙栬瘧鍣ㄧ殑閲嶅ご鎴忥紝瀹冭兘娑堥櫎鏂規硶璋冪敤鐨勫紑閿錛屼負鍏朵粬浼樺寲鎻愪緵鍩虹煶銆侸ava涓錛屽彧鏈夌壒瀹氱被鍨嬬殑鏂規硶錛堢佹湁銆佸疄渚嬫瀯閫犲櫒銆佺埗綾繪柟娉曞拰闈欐佹柟娉曪級鏈夋満浼氬湪緙栬瘧鏈熻瑙f瀽銆傚逛簬鉶氭柟娉曪紝Java鉶氭嫙鏈洪氳繃綾誨瀷緇ф壙鍏崇郴鍒嗘瀽錛屽垽鏂鏂規硶鐗堟湰鐨勯夋嫨錛岃嫢鍙鏈変竴涓鐗堟湰錛屽嵆浣挎墽琛屸滃畧鎶ゅ唴鑱斺濓紝涔熼渶棰勭暀鈥滈冪敓闂ㄢ濄傚彧鏈夊綋閫冮稿垎鏋愮『淇濇柟娉曟帴鏀惰呬笉鍙橈紝鍐呰仈浼樺寲鎵嶈兘鎸佺畫鐢熸晥銆
閫冮稿垎鏋愶細瑙i攣鍐呭瓨浼樺寲鐨勭樺瘑
閫冮稿垎鏋愭槸鐜頒唬鉶氭嫙鏈虹殑鍓嶆部鎶鏈錛屽畠鍏蟲敞瀵硅薄鐨勫姩鎬佷綔鐢ㄥ煙銆傚硅薄濡傛灉涓嶄細閫冮稿埌鏂規硶鎴栫嚎紼嬩箣澶栵紝鍙榪涜屾爤涓婂垎閰嶏紝鍑忓皯鍨冨溇鍥炴敹鍘嬪姏錛涘悓姝ユ秷闄ゅ垯鍦ㄧ『瀹氬彉閲忎笉閫冮哥殑鎯呭喌涓嬶紝娑堥櫎涓嶅繀瑕佺殑綰跨▼鍚屾ワ紝鎻愬崌鎬ц兘銆傛爣閲忔浛鎹㈠垯閽堝硅仛鍚堥噺瀵硅薄錛屽皢鍏舵垚鍛樺彉閲忔媶鍒嗭紝鎮㈠嶄負鍘熷嬬被鍨嬶紝榪涗竴姝ヤ紭鍖栧唴瀛樹嬌鐢ㄣ
榪欎簺緙栬瘧浼樺寲鎶鏈錛屽傚悓緙栬瘧鍣ㄧ殑鏃犲艦鍙屾墜錛屾倓鐒舵彁鍗囦唬鐮佹晥鐜囷紝璁╃▼搴忚繍琛屾洿鍔犳祦鐣呫傚畠浠鐨勫瓨鍦錛屾彮紺轟簡緙栫▼璇璦鍜岃櫄鎷熸満璁捐¤呭規ц兘鐨勪笉鎳堣拷奼傦紝浠ュ強瀵圭粏鑺傜殑娣卞埢鐞嗚В銆
Ⅱ 現代C/C++編譯器有多智能
最近在搞C/C++代碼的性能優化,發現很多時候自以為的優化其實編譯器早就優化過了,得結合反匯編才能看出到底要做什麼樣的優化。
請熟悉編譯器的同學結合操作系統和硬體談一談現代c/c++編譯器到底有多智能吧。哪些書本上的優化方法其實早就過時了?
以及程序員做什麼會讓編譯器能更好的自動優化代碼?
舉個栗子:
1,循環展開,大部分編譯器設置flag後會自動展開;
2,順序SIMD優化,大部分編譯器設置flag後也會自動優化成SIMD指令;
3,減少中間變數,大部分編譯器會自動優化掉中間變數;
etc.
查看代碼對應的匯編:
Compiler Explorer
【以下解答】
舉個之前看過的例子:
int calc_hash(signed char *s){ static const int N = 100003; int ret = 1; while (*s) { ret = ret * 131 + *s; ++ s; } ret %= N; if (ret < 0) ret += N; //注意這句 return ret;}
【以下解答】
舉個簡單例子,一到一百求和
#include int sum() { int ret= 0; int i; for(i = 1; i <= 100; i++) ret+=i; return ret;}int main() { printf("%d\n", sum()); return 0;}
【以下解答】
話題太大,碼字花時間…
先放傳送門好了。
請看Google的C++編譯器組老大Chandler Carruth的演講。這個演講是從編譯器研發工程師的角度出發,以Clang/LLVM編譯C++為例,向一般C++程序員介紹理解編譯器優化的思維模型。它講解了C++編譯器會做的一些常見優化,而不會深入到LLVM具體是如何實現這些優化的,所以即使不懂編譯原理的C++程序員看這個演講也不會有壓力。
Understanding Compiler Optimization - Chandler Carruth - Opening Keynote Meeting C++ 2015
演示稿:https://meetingcpp.com/tl_files/mcpp/2015/talks/meetingcxx_2015-understanding_compiler_optimization_themed_.pdf
錄像:https://www.youtube.com/watch?v=FnGCDLhaxKU(打不開請自備工具…)
Agner Fog寫的優化手冊也永遠是值得參考的文檔。其中的C++優化手冊:
Optimizing software in C++ - An optimization guide for Windows, Linux and Mac platforms - Agner Fog
要稍微深入一點的話,GCC和LLVM的文檔其實都對各自的內部實現有不錯的介紹。
GCC:GNU Compiler Collection (GCC) Internals
LLVM:LLVM』s Analysis and Transform Passes
========================================
反模式(anti-patterns)
1. 為了「優化」而減少源碼中局部變數的個數
這可能是最沒用的手工「優化」了。特別是遇到在高級語言中「不用臨時變數來交換兩個變數」這種場景的時候。
看另一個問題有感:有什麼像a=a+b;b=a-b;a=a-b;這樣的演算法或者知識? - 編程
2. 為了「優化」而把應該傳值的參數改為傳引用
(待續…)
【以下解答】
推薦讀一讀這里的幾個文檔:
Software optimization resources. C++ and assembly. Windows, Linux, BSD, Mac OS X
其中第一篇:http://www.agner.org/optimize/optimizing_cpp.pdf
講解了C++不同領域的優化思路和問題,還有編譯器做了哪些優化,以及如何代碼配合編譯器優化。還有優化多線程、使用向量指令等的介紹,推薦看看。
感覺比較符合你的部分需求。
【以下解答】
一份比較老的slides:
http://www.fefe.de/source-code-optimization.pdf
【以下解答】
利用C++11的range-based for loop語法可以實現類似python里的range生成器,也就是實現一個range對象,使得
for(auto i : range(start, stop, step))
【以下解答】
我覺得都不用現代。。。。寄存器分配和指令調度最智能了
【以下解答】
每次編譯poco庫的時候我都覺得很為難GCC
【以下解答】
有些智能並不能保證代碼變換前後語義是等價的
【以下解答】
誒誒,我錯了各位,GCC是可以藉助 SSE 的 xmm 寄存器進行優化的,經 @RednaxelaFX 才知道應該添加 -march=native 選項。我以前不了解 -march 選項,去研究下再來補充為什麼加和不加區別這么大。
十分抱歉黑錯了。。。以後再找別的點來黑。
誤導大家了,實在抱歉。(??ˇ?ˇ??)
/*********以下是並不正確的原答案*********/
我是來黑 GCC的。
最近在搞編譯器相關的活,編譯OpenSSL的時候有一段這樣的代碼:
BN_ULONG a0,a1,a2,a3; // EmmetZC 註:BN_ULONG 其實就是 unsigned longa0=B[0]; a1=B[1]; a2=B[2]; a3=B[3];A[0]=a0; A[1]=a1; A[2]=a2; A[3]=a3;
【以下解答】
提示:找不到對象
【以下解答】
忍不住抖個機靈。
私以為正常寫代碼情況下編譯器就能優化,才叫智能編譯器。要程序員絞盡腦汁去考慮怎麼寫代碼能讓編譯器更好優化,甚至降低了可讀性,那就沒有起到透明屏蔽的作用。
智能編譯器應該是程序猿要較勁腦汁才能讓編譯器不優化。
理論上是這樣的。折疊我吧。
【以下解答】
編譯器智能到每次我都覺得自己很智障。
【以下解答】
雖然題主內容里是想問編譯器代碼性能優化方面的內容,但題目里既然說到編譯器的的智能,我就偏一下方向來說吧。
有什麼更能展示編譯器的強大和智能?
自然是c++的模版元編程
template meta programming
簡單解釋的話就是寫代碼的代碼,寫的還是c++,但能讓編譯器在編譯期間生成正常的c++代碼。
沒接觸過的話,是不是聽上去感覺就是宏替換的加強版?感覺不到它的強大呢?
只是簡單用的話,效果上這樣理解也沒什麼
但是一旦深入下去,尤其翻看大神寫的東西,這明明看著就是c++的代碼,但TM怎麼完全看不懂他在干什麼?後來才知道這其實完全是另外一個世界,可是明明是另外一個世界的東西但它又可以用來做很多正常c++能做的事....
什麼?你說它好像不能做這個,不能做那個,好像做不了太多東西,錯了,大錯特錯。就像你和高手考試都考了100分的故事一樣,雖然分數一樣,但你是努力努力再努力才得了滿分,而高手只是因為卷面分只有100分.....在元編程面前,只有想不到,沒有做不到。
再回頭看看其他答案,編譯器順手幫你求個和,丟棄下無用代碼,就已經被驚呼強大了,那模板元編程這種幾乎能在編譯期直接幫你「生成」包含復雜邏輯的c++代碼,甚至還能間接「執行」一些復雜邏輯,這樣的編譯器是不是算怪獸級的強大?
一個編譯器同時支持編譯語法相似但結果不同卻又關聯的兩種依賴語言,這個編譯器有多強大多智能?
寫的人思維都要轉換幾次,編譯器轉著圈嵌著套翻著番兒地編譯代碼的代碼也肯定是無比蛋疼的,你說它有多強大多智能?
一個代碼創造另外一個代碼,自己能按照相似的規則生成自己,是不是聽上去已經有人工智慧的發展趨勢了?
上帝說,要有光,於是有了光。
老子曰,一生二,二生三,三生萬物。
信c++,得永生!
===
FBI WARNING:模板元編程雖然很強大,但也有不少缺點,尤其對於大型項目,為了你以及身邊同事的身心健康,請務必適度且謹慎的使用。勿亂入坑,回頭是岸。
【以下解答】
c++11的auto自動類型推斷算么....
【以下解答】
智能到開不同級別的優化,程序行為會不同 2333
【以下解答】
這個取決於你的水平
Ⅲ Xcode 構建速度優化(一)衡量編譯時間
隨著項目不斷迭代,工程文件越來越多,引用的三方庫也越來越多,這些直接導致編譯時間的不斷增加,完整編譯一次項目動輒需要五分鍾以上時間,實在有些影響開發效率,是時候來一波提速了。
為編譯和構建提速,首先我們需要對速度有一個衡量標准:准確獲得構建用時
首先,我們需要定義要衡量和優化的內容。 有兩種選擇:
xcode默認情況下會跟蹤所有構建,我們可以通過更改xcode相關設置,來在活動查看器中顯示出構建時間,通過命令行:
每次編譯成功後,會在Successed之後顯示出所用時間:
Xcode Build Timing Summary是Xcode10中加入的用於查看獲取構建時間和發現用時瓶頸方面的最有利工具。 可以通過Proct->Perform Action->Build With Timing Summary來開啟:這樣在 Build Log 的末尾就會添加 Timing Summary Log。我們可以通過這個 log 看到哪個階段是耗時的,便於我們進行優化。
如上圖中: xib階段的編譯耗時明顯是比普通c文件要多的,意味著我們可以通過減少xib方式來優化提升速度
而c文件的編譯用時比總時間還要長,是因為c文件是並行編譯的
在命令行中同樣可以開啟這個功能:
常用的第三方工具有 BuildTimeAnalyzer 、 xcode-build-times-rendering 、 XCLogParser 。
BuildTimeAnalyzer可以統計可以得出某個文件的類型檢查時長,每個表達式的類型檢查時長。
xcode-build-times-rendering是一個Ruby編寫的第三方工具,可以方便地分別測量目標的構建時間並在圖表上顯示它們,使用gem安裝
接下來使用這個工具自帶命令配置項目
然後構建項目並生成報告:
這個工具使用上比較簡單,缺點是只能從宏觀上生成各個target編譯的整體圖標,無法詳細列出各個內部編譯明細
XCLogParser可以詳細列出各個Target和內部每個文件的編譯耗時,對我們分析編譯時間瓶頸非常有幫助,它的工作原理主要是做為解析器,通過解析xcode編譯生成的xcactivitylog日誌來記錄
安裝:
編譯項目後,進行安裝
安裝成功後通過命令:
會自動在當前目錄的 build/xclogparser/reports/ 路徑下生成報告,其中--project參數需要設置為待分析項目的名字,並注意當前在終端切換到希望寫入日誌的目錄。
報告截圖:
這個工具將作為我們後面分析提升編譯構建速度的主要使用工具。
經過我多次在不同時間段,不同電腦上不斷嘗試編譯,
我發現編譯耗時是一個比較玄的東西,及時在同一台電腦,同一個項目, 同一套環境配置下,編譯用時也會隨著電腦當前狀態(包括同時打開進程、散熱等等)上下大幅跳動,就像演算法時間復雜度一樣,有時候我們明明做了一些細微的優化,但是結果反而是編譯耗時增加了,這是很正常的事情
所以,衡量這個標准需要我們取多次試驗中的平均值作為參考。
Ⅳ c語言編譯原理是什麼
編譯共分為四個階段:預處理階段、編譯階段、匯編階段、鏈接階段。
1、預處理階段:
主要工作是將頭文件插入到所寫的代碼中,生成擴展名為「.i」的文件替換原來的擴展名為「.c」的文件,但是原來的文件仍然保留,只是執行過程中的實際文件發生了改變。(這里所說的替換並不是指原來的文件被刪除)
2、匯編階段:
插入匯編語言程序,將代碼翻譯成匯編語言。編譯器首先要檢查代碼的規范性、是否有語法錯誤等,以確定代碼的實際要做的工作,在檢查無誤後,編譯器把代碼翻譯成匯編語言,同時將擴展名為「.i」的文件翻譯成擴展名為「.s」的文件。
3、編譯階段:
將匯編語言翻譯成機器語言指令,並將指令打包封存成可重定位目標程序的格式,將擴展名為「.s」的文件翻譯成擴展名為「.o」的二進制文件。
4、鏈接階段:
在示例代碼中,改代碼文件調用了標准庫中printf函數。而printf函數的實際存儲位置是一個單獨編譯的目標文件(編譯的結果也是擴展名為「.o」的文件),所以此時主函數調用的時候,需要將該文件(即printf函數所在的編譯文件)與hello world文件整合到一起,此時鏈接器就可以大顯神通了,將兩個文件合並後生成一個可執行目標文件。
Ⅳ C 璇璦鐨勭紪璇戝櫒濡備綍浼樺寲錛
C璇璦緙栬瘧鍣ㄤ紭鍖栫殑鏂規硶鏈夊緢澶氾紝鍏朵腑涓浜涘寘鎷錛氬父閲忎紶鎾銆佸父閲忔姌鍙犮佸嚱鏁板唴鑱斻佸驚鐜灞曞紑銆佹諱唬鐮佹秷闄ゃ佸彉閲忕紦瀛樸佹寚閽堜紭鍖栫瓑絳 銆
榪欎簺鏂規硶鍙浠ュ府鍔╃紪璇戝櫒鍦ㄤ笉鏀瑰彉紼嬪簭閫昏緫鐨勬儏鍐典笅錛屾彁楂樼▼搴忕殑榪愯屾晥鐜囥備絾鏄錛岃繖浜涙柟娉曞苟涓嶆槸涓囪兘鐨勶紝鏈夋椂鍊欎細閫傚緱鍏跺弽錛屽艱嚧紼嬪簭榪愯屾晥鐜囬檷浣庛傚洜姝わ紝鍦ㄤ嬌鐢ㄨ繖浜涙柟娉曟椂錛岄渶瑕佹牴鎹鍏蜂綋鎯呭喌榪涜岄夋嫨鍜岃皟鏁淬
Ⅵ 提高c語言代碼效率
C語言7種提高效率
1、位運算替代乘除
位運算是C語言中的最小數據單元,移位運算或位處理基本上是每個MCU或者處理器的指令集中直接支持的所以C代碼編譯成匯編以後基本上簡單的幾條匯編指令即可完成運算。
然而對於乘除法CPU一般無法直接運行,當然現在高端的晶元一般支持FPU等等之類的處理,相對而言速度得到了顯著提升;但是大部分還是會比移位運算處理耗時,特別是有些編譯器直接把乘除法編譯成函數調用來處理。所以像n/8這樣的處理直接使用n>>3即可替代,這樣效率會更高。
2、變數的使用
使用全局變數相對局部變數效率更高,函數的局部變數一般處於函數內部,在調用過程中存在入棧與出棧野孝的情況,這樣就增加了函數調用的耗時,而全局變數直接訪問效率更高。當然全局變數是程序中要非常小心使用的,濫用全局變數的行為確實會增加系統各模塊之間的耦合,所以在程席中要規范全局的統一介面使用。
同時對於變數類型的使用也是大家需要注意的,數據類型不是越大越好,比如uint64_t的處理匯編生成代碼就相對比較多,執行效率一般比短數據類型要低,盡量選擇晶元相同位數的數據類型處理,當然大部分更小的數據長度也是合適的。
3、指針替代數組
相對數組索引,指針運算效率更快,數組是一片連續的內存空間,那麼通過指針移動進行數組數據的索引也是合適的。
比如我們遍歷數組array[i],任意一次的循環都需要對其進行下 「i」值的標記與計算,而當指針「p」位於array數組位置的時候,循環僅只需要對「p」進行增量的操作,這樣指針耗時會比數組訪問小很多。
4、演算法優化
一些數據的處理明明可以通過更加簡潔的演算法,可是沒脊侍大部分程序員非要以最傻瓜的方式進行運算,最容易理解的就是高斯求和,1~100累加,還是選擇高斯求和演算法,當然還有很多演算法有多種形式,各有優劣,根據自身需求進行合理選擇。特別是一些應用根本沒有必要用使用高精度耗時的數據處理演算法,選擇一些低精度快速的演算法更加合適。
5、優化分支語句
我們都知道if-else語句是最常用的分支語句,其特點就是逐一判斷,既然是判斷就會消耗時間,然而對於一些處理並不是每個分支都是均勻執行的,如果你把頻繁執行的相應分支放到後面,勢必就需要執行較多前面的逐一判斷,從而降低代碼執行效率。
所以我們要對各個分支的執行頻率進行評估,把最有可能執行的放在判斷語句前面執行。同樣對於分支語句多級嵌套的情況,我們需要把頻率性對較高的放到外層,頻率低的放內層,這樣減枯吵少不必要的外層判斷。
6、循環語句的優化
在系統的多重循環過程中,需要程序員將最長的循環內容設置在系統的最內層,同時需要將最短的循環內容設置在系統的最外層。
這樣,能夠有效提升CPU的運行效率,減少循環次數。另外,如果在系統的循環過程中需要進行邏輯判斷,且循環的次數相對較大,就需要將循環判斷從系統內部轉移到系統的外部。
7、無敵」 宏"的利用
宏在C語言中是靈活度非常高的語法特性,宏代碼片段的使用其代碼表現形式上與函數差異並不是很大,大夥有學習C++語言模板的經驗,應該會覺得兩者有頗多相似之處。
在對函數進行調用的過程中,需要通過棧對其進行儲存,而且CPU在函數調用的過程中還要做好對數據的恢復准備,有效進行出棧和進棧的操作。所以佔用CPU時間除了代碼本身之外,對函數進行調用也需要佔據一定的時間。而宏就能節省參數壓棧、返回參數、C語言call調用以及執行return的操作步驟,從而提高程序的運行效率。