簡體   English   中英

GCC優化?

[英]GCC optimization?

我正在使用GCC 4.8.1。 我正在嘗試通過將其放入嵌套循環來對某些代碼的速度進行基准測試,如下例所示。 每當我這樣做時,它都會在最短的時間內執行(例如.02秒),並且執行-03或不進行任何優化,無論執行多少次迭代。 有什么原因嗎? 我確信它工作正常,因為值始終正確,並且如果我在循環中使用printf ,那么它將按預期運行。

int main()
{
    int i,j,k;
    int var;
    int big_num = 1000000;
    int x[1];

    for (i = 0;i<big_num;++i){
        for (j = 0;j<big_num;++j){
            for (k = 0;k<big_num;++k){
               // any short code fragment such as:
               var = i - j + k; 
               x[0] = var;
            }
        }
    }
    return 0;
}

對於您所編輯的問題,還不那么正確: 您的代碼聲明一個單元素數組 int x[1]; 並使用 x[1]作為界外索引(索引應小於1但非負,因此只能為0)訪問它; 這是典型的 未定義行為 ,編譯器可以通過發出任何代碼來合法地對其進行優化。

順便說一句, GCC 4.9 (在我的Debian / Sid / x86-64上) 正在 (正確地) 將您的代碼優化為一個空的main (因為沒有有用的計算發生); 您可以通過使用gcc -fverbose-asm -O2 -S進行編譯並查看生成的*.s匯編文件來進行檢查; 如果您真的對優化過程中的各種內部表示感到好奇,請使用-fdump-tree-all編譯; 您還可以更改編譯器的行為(或添加一些檢查步驟),例如通過使用MELT擴展它

通過替換x[0] = var;可以使您的計算有意義x[0] = var; x[0] += var; 並通過對x[0]產生副作用來結束main ,例如printf("%d\\n", x[0]); return x[0] != 0; 然后,編譯器可能會生成一個循環(它可能會在編譯時計算循環的結果,但我認為GCC不夠聰明)。

最后,典型的當前微處理器通常是亂序的和超標量的,因此每個周期執行一個以上的指令(時鍾頻率至少為2GHz)。 因此,它們每秒運行數十億個基本操作。 通常,您需要一個基准持續時間超過半秒(否則,測量結果就沒有足夠的意義),並且需要重復幾次基准。 因此,您需要對基准測試代碼進行編碼,其中執行了數百億個(即,超過10 10個 )基本C操作。 並且您需要該代碼有用(帶有副作用或在其他地方使用的結果計算),否則編譯器將通過刪除代碼進行優化。 同樣,基准測試代碼應該接受一些輸入(否則,編譯器可能會在編譯時進行大量計算)。 在您的情況下,您可以像這樣初始化bignum

int main (int argc, char**argv) {
  int big_num = (argc>1)?atoi(argv[1]):1000000;

您如何設置優化? 對我來說,它有效(big_num = 1000):

$ gcc -o x -O0 x.c && time ./x
./x  2.08s user 0.00s system 99% cpu 2.086 total
$ gcc -o x -O1 x.c && time ./x 
./x  0.31s user 0.00s system 99% cpu 0.309 total
$ gcc -o x -O2 x.c && time ./x  
./x  0.00s user 0.00s system 0% cpu 0.000 total

您的代碼實際上不執行任何操作。 GCC和大多數編譯器都很聰明。 它可以查看它,確定它沒有可見的效果並將其完全刪除。

您的代碼沒有副作用 :它不會通過網絡發送任何內容,也不會編寫文件,因此gcc會刪除該代碼。 現代的gcc版本具有-fdump-*選項,這些選項允許記錄編譯器的每個階段:

$ gcc -O2 -fdump-tree-all elide.c

之后,gcc將生成一堆輸出文件:

$ ls -1 | head
a.out
elide.c
elide.c.001t.tu
elide.c.003t.original
elide.c.004t.gimple
elide.c.007t.omplower
...

比較它們可能會揭示刪除代碼的階段。 就我而言(GCC 4.8.1),它是cddce階段。 從GCC源文件gcc/tree-ssa-dce.c

/* Dead code elimination.

References:

    Building an Optimizing Compiler,
    Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9.

    Advanced Compiler Design and Implementation,
    Steven Muchnick, Morgan Kaufmann, 1997, Section 18.10.

Dead-code elimination is the removal of statements which have no
impact on the program's output.  "Dead statements" have no impact
on the program's output, while "necessary statements" may have
impact on the output.

The algorithm consists of three phases:
1. Marking as necessary all statements known to be necessary,
    e.g. most function calls, writing a value to memory, etc;
2. Propagating necessary statements, e.g., the statements
    giving values to operands in necessary statements; and
3. Removing dead statements.  */

您可以通過將變量標記為volatile來顯式破壞優化器:

volatile int i,j,k;
volatile int var;
volatile int big_num = 1000000;
volatile int x[1];

volatile將告訴編譯器,寫入存儲單元有副作用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM