cpp程式效能優化

2021-06-03 23:36:17 字數 3341 閱讀 6594

1.        重中之重 - 演算法優化:

程式效能優化最顯著的優化方法是演算法上的優化,演算法的優化對效能的提公升往往是乙個數量級的,例如排序,冒泡的時間複雜度為o(n^2),而快速排序的時間複雜度為o(nlog(n)),這種效能的提供是非常明顯的。

2.       消除冗餘的迴圈:

我們先看一下for迴圈生成的彙編**for (int n = 4, i = 0; i < n;  ++i){}

15     movl    $4, -4(%ebp) // n = 4

16     movl    $0, -8(%ebp) // i = 0

17     jmp .l2

18 .l3:

19     addl    $1, -8(%ebp) // ++i

20 .l2:

21     movl    -8(%ebp), %eax

22     cmpl    -4(%ebp), %eax // i - n

23     setl    %al                           

24     testb   %al, %al       

25     jne .l3             

從上面的彙編**中可以看出每次執行迴圈的時候都要執行19到25行這6彙編指令,因此減少迴圈可以提高程式效能。

例如上面的**可以寫成如下開形式:

for(int n = 4, i = 0; i < n; i += 2)

3.        減少過程函式呼叫:

我們知道程式中函式呼叫的開銷是非常大的,我們看一下簡單的函式呼叫的開銷:

int add ( int a , int b)

其彙編**如下:

5 _z3addii:

6 .lfb0:

7     .cfi_startproc

8     .cfi_personality 0x0,__gxx_personality_v0

9     pushl   %ebp

10     .cfi_def_cfa_offset 8

11     movl    %esp, %ebp

12     .cfi_offset 5, -8

13     .cfi_def_cfa_register 5

14     movl    12(%ebp), %eax //取b 

15     addl    %eax, 8(%ebp) // a += b

16     popl    %ebp

17     ret

從彙編**中可以看出函式呼叫的開銷是非常大的。

假設有乙個程式

const

int num = 100;

int getnum()

for (int i = 0; i < getnum(); ++i)

最優化的寫法是

int inum = getnum();

for (int i = 0; i < inum; ++i)

當然這種寫法的前提是getnum()的數值在執行for的時候是沒有變化的。

4. 消除不必要的儲存器引用 : 

void add(int * array , int len , int * res)

}其彙編**(去掉for)

19     movl    12(%ebp), %ebx // %ebx,存len的位址

20     movl    16(%ebp), %edx // %edx, 存*res的位址

21     movl    $0, (%edx)     // 寫mem

22     testl   %ebx, %ebx          

23     jle .l4

24     movl    $0, %eax      // i = 0;

25 .l3:

26     movl    (%esi,%eax,4), %ecx // 取array[i]

27     addl    %ecx, (%edx)             // +=,寫mem

28     addl    $1, %eax                    // 

29     cmpl    %ebx, %eax

30     jne .l3

從上面的彙編**分析中可以看出,每次for迴圈都進行了寫記憶體。我們知道讀寫記憶體是非常耗時的,因此可以對其進行優化。

void add(int * array , int len , int * res)

*res = sum;

}//彙編

53     movl    12(%ebp), %ecx

54     movl    $0, %eax

55     movl    $0, %edx // sum = 0

56     testl   %ecx, %ecx

57     jle .l8

58 .l11:

59     addl    (%ebx,%eax,4), %edx // sum += array[i];, 只寫暫存器

60     addl    $1, %eax

61     cmpl    %ecx, %eax

62     jne .l11

63 .l8:

64     movl    16(%ebp), %eax

優化後的**在迴圈中少了一次暫存器的讀寫。

注意上面的**是經過了-o選項優化的。

5.        增強流水線處理能力。

現在的處理器,每個核心在會有多個執行單元,相互之間採用流水線的執行方式,如果前後兩個操作沒有依賴關係,可以並行執行。

考慮乙個求和的for迴圈

int array[n]; 假設n為偶數

int sum = 0

for (int i = 0; i < n; ++i)

將其流水線化可以表示如下:

int sum1 = 0;

int sum2 = 0;

for (int i = 0; i < n; i += 2)

sum1 += sum2;

由於 sum1 += array[i];

sum2 += array[i + 1];

是沒有相互依賴的,因此可以流水線執行。 

6. cache對程式效能的影響

參看本人關於「矩陣乘積的並行」演算法的討論

7.       效能除錯工具:

gprof .

$ g++ program.cpp -o program -pg

$ ./program

$ gprof program;

注意一定要帶-pg引數 

優化程式效能

編寫高效程式需要兩個活動 第一,我們必須選擇一組最好的演算法和資料結構 第二,我們必須編寫出編譯器能夠有效優化以轉換成高效可執行 的源 這裡,我們主要講述後者。首先,我們討論一下為什麼要編寫高效程式。不難想象,如果本來要用 天執行完的程式,經過優化只需要 天就可執行完,這是一件多麼令人振奮的 事啊。...

優化程式效能

l 消除迴圈的低效率 n 對於迴圈中的過程呼叫盡量移出迴圈外,例如 nfor i 0 i strlen s i strlen 函式為線性增長 在字串長度很大時 很消耗系統資源 n 減少不必要的儲存器引用,將儲存器引用儲存在臨時變數中.l 處理器優化 即充分利用儲存器流水線操作的吞吐量 n 迴圈展開,...

優化程式效能

研究彙編 是理解編譯器以及產生的 會如何執行的最有效的手段之一。編譯器優化 的限制 1 程式設計中存在 儲存器別名使用 的問題。編譯器必須假設不同的指標可能指向儲存器中相同的位置。2 函式呼叫 簡略了。具體看書 基本的編碼原則 效能大幅度提公升 優化程式效能的一些方法 1 將除錯完的程式完成編譯器級...