CSAPP 5 - 優化程序性能

CSAPP 5 - 優化程序性能

1. 概述

  1. 首當其衝的,還是要編寫出好的算法和數據結構,優化內部結構
  2. 其次纔是編寫出能讓編譯器 易優化的,高效的可執行代碼。這點在特定的機器上可能有着特定的不同的優化,但有一些基本的優化仍然是相同的。
    1. 消除不必要的工作,讓代碼消耗時間在期望執行的任務上。包括消除或減少函數調用、條件測試、內存引用;同時熟悉處理器如何工作,利用反彙編知道它究竟如何執行操作,從而調整程序獲得最大的速度。
    2. 利用好處理器的指令級並行能力,同時執行多條指令

2. 利用好編譯器自身優化

gcc 就提供了不同優化級別的執行操作,利用 -O1 -O2 -O3 對程序進行不同級別的編譯器優化代碼。gcc 也在不斷的更新迭代,編譯器自身也在越來越強大。

基本編碼規範:(避免限制優化的因素,產生更高效的代碼)

消除連續的函數調用;避免不必要的內存引用

3. 消除循環的低效率,內存調用等

  • 展開循環,降低開銷
  • 實現指令級並行
  • 用功能性代碼重寫條件操作,使得編譯採用條件傳送
for (i=0; i<len; i++)
    if (s[i] >= 'A' && s[i]<= 'Z')
        s[i] -= ('A' - 'a');

函數調用不斷使用,極其低效

4. 理解現代處理器

現代處理器採用分支預測的技術,處理器會猜測是否會選擇分支,同時還預測分支的目標地址。這就讓true/false 很痛苦,因爲一旦預測失敗就會產生很大的代價。所以我們會盡可能的採用條件傳送(conditional move),而不是條件控制轉移。

條件控制轉移:等待代碼的條件結果,選擇合適的路徑

for (i=0;i<n;i++)
    if(a[i]>b[i]){
        long t = a[i];
        a[i] = b[i];
        b[i]=t;
    }

條件傳送:先將結果運行,再根據結果選擇最終的結果值

for (i=0;i<n;i++)
    if(a[i]>b[i]){
        long min =a[i] < b[i] ? a[i] : b[i];
        long max =a[i] < b[i] ? b[i] : a[i];
        a[i] = min;
        b[i] = max;
    }

防止寄存器溢出

當並行度 p 超過可用寄存器的數量,編譯器就會溢出,將一些臨時變量放在內存中,會降低運行速度

5. 利用代碼剖析程序,進行分析

Unix提供剖析程序GPROF可以進行代碼剖析分析

代碼剖析(Code profiling)
程序員在優化軟件性能時要注意應儘量優化軟件中被頻繁調用的部分,這樣才能對程序進行有效優化。使用真實的數據,精確的分析應用程序在時間上的花費的行爲就成爲_代碼剖析_。現在幾乎所有的開發平臺都支持代碼剖析,本文要介紹的是linux下針對c/c++的GNU的gprof代碼剖析工具。

PS:gprof不只能對c/c++,還可對Pascal和Fortran 77進行代碼剖析。

gprof
GNU gprof 是一款linux平臺上的程序分析軟件(unix也有prof)。藉助gprof可以獲得C/C++程序運行期間的統計數據,例如每個函數耗費的時間,函數被調用的次數以及各個函數相互之間的調用關係。gprof可以幫助我們找到程序運行的瓶頸,對佔據大量CPU時間的函數進行調優。

PS:gprof統計的只是用戶態CPU的佔用時間,不包括內核態的CPU時間。gprof對I/O瓶頸無能爲力,耗時甚久的I/O操作很可能只佔據極少的CPU時間。

如何使用gprof
gprof的使用很簡單,遵循以下步驟即可:

參考文檔:

https://sourceware.org/binutils/docs/gprof/index.html#Top

6. 小結

沒有一個編譯器能用好的算法代替低效率的算法,因此程序設計的內容纔是仍然是程序員主要關心的。我們應當養成良好的代碼風格,給後續的工作帶來便捷。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章