2013-05-22 51 views
1

考慮基於for循環以下範圍C++ 11克++,基於範圍和量化

for (T k : j) 
{ 
    ... 
} 

g++clang++優化標誌,可以加快經編譯的代碼?

我不是在談論任何for週期我只考慮這個新的C++ 11構造。

+0

由於基於範圍的循環是語法糖,也許你可以通過展開循環來嘗試。看到這個[問題](http://stackoverflow.com/questions/10678419/c-2011-range-based-loop-unrolling) –

+3

如何加快該循環將取決於什麼'...'位是。 –

+0

'T'是什麼類型?也許'(T&k:j)'可以加快速度。 –

回答

3

優化循環很少關於優化實際循環迭代代碼(在這種情況下爲for (T k : j)),但非常重要的是優化什麼是循環。

現在,因爲這是...在這種情況下,不可能說例如展開循環會有幫助,還是聲明函數內聯[或者簡單地移動它們以便編譯器可以看到它們並將它們內聯] ,使用自動矢量化,或者可能在循環內使用完全不同的算法。

在上述段落中稍微詳細的例子:

  1. 解開循環 - 主要做幾個循環迭代,而不必返回到循環的開始。當循環內容非常小時這是最有用的。在編譯器進行展開的地方有自動展開,或者你可以手動展開代碼,只需在每個循環迭代中執行四個項目,然後在每個循環變量中向前步進四個項目,或者在迭代過程中多次更新迭代器循環本身[但這當然意味着不使用基於範圍的for循環]。
  2. 內聯函數 - 編譯器將採用(通常很小的)函數並將它們放入循環本身,而不是進行調用。這節省了處理器在代碼中調用另一個地方並返回的時間。大多數編譯器只能這樣做對於那些在編譯過程中「看得見」的編譯器功能 - 所以源,必須爲在同一個源文件,或者是包含被編譯源文件中的頭文件。
  3. 自動向量化 - 使用SSE,MMX或AVX指令在一個指令處理多個數據項(例如一個SSE指令可以在一條指令中向另外四個float添加四個float值)。這比一次操作單個數據項更快(大多數情況下,由於嘗試將不同數據項合併,然後在計算完成時將其中的結果進行分類時會出現更多複雜情況,因此這種方法沒有任何好處)。
  4. 選擇不同的算法 - 通常有幾種方法可以解決特定的問題。根據你試圖達到的目標,任何類型的for-loop都可能不是正確的解決方案,或者循環內的代碼可能會使用更聰明的方式來計算/重新排列/無論如何 - 實現你需要的結果。

但是...太含糊不清了,說上面哪個解決方案可以改善你的代碼。

+0

一般而言,我想閱讀並瞭解更多關於這個主題的內容,實際上我通常在構造中使用這種類型來處理像vector和map這樣的標準容器,我也不確定如何打開MMX和SSE的用法,以及是否有可能影響某些緩存活動用於CPU優化。 – user2384250

+0

再次,這是一個非常廣泛的主題。 'gcc'(我相信MSVC)能夠自動轉換爲SSE指令,但要說服編譯器這是個好主意並不容易。它也取決於你對'vector'或'map'的內容所做的事情,以及組合多個元素並處理它們的開銷與收益之間的關係。在'map'的情況下,我認爲編譯器會發現很難做任何有意義的事情,因爲相互之間的元素不是(必然)在內存中。 「矢量」被定義爲具有連續的元素。 –

+0

以及我如何研究這些行爲,可以幫助我的主題是什麼?我的意思是應該有一個話題或一組話題與你正在說的話和這種優化有關,並且我想開始一些有趣的閱讀。 – user2384250

3

GCC documentation about auto-vectorization沒有提及基於範圍的for循環的任何內容。此外,它的代碼歸結爲:

{ 
    auto && __range = range_expression ; 
    for (auto __begin = begin_expr, 
       __end = end_expr; 
      __begin != __end; ++__begin) { 
     range_declaration = *__begin; 
     loop_statement 
    } 
} 

所以,從技術上來說,任何標誌幫助自動矢量化結構在這種定期for應自動向量化類似的基於範圍的for循環。我真的這樣做,編譯器只將基於範圍的for循環轉換爲常規的for循環,然後讓自動向量化在這些舊循環中完成它的工作。這意味着在任何情況下都不需要標誌來告訴編譯器自動矢量化基於範圍的for循環。


由於GCC的實施情況,問,這裏是在源代碼中描述什麼是真正的基於範圍的for循環中完成相關評論(您可以檢查實現文件parser.c,如果你想擁有看代碼):

/* Converts a range-based for-statement into a normal 
    for-statement, as per the definition. 

     for (RANGE_DECL : RANGE_EXPR) 
    BLOCK 

    should be equivalent to: 

     { 
    auto &&__range = RANGE_EXPR; 
    for (auto __begin = BEGIN_EXPR, end = END_EXPR; 
      __begin != __end; 
      ++__begin) 
     { 
      RANGE_DECL = *__begin; 
      BLOCK 
     } 
     } 

    If RANGE_EXPR is an array: 
    BEGIN_EXPR = __range 
    END_EXPR = __range + ARRAY_SIZE(__range) 
    Else if RANGE_EXPR has a member 'begin' or 'end': 
    BEGIN_EXPR = __range.begin() 
    END_EXPR = __range.end() 
    Else: 
    BEGIN_EXPR = begin(__range) 
    END_EXPR = end(__range); 

    If __range has a member 'begin' but not 'end', or vice versa, we must 
    still use the second alternative (it will surely fail, however). 
    When calling begin()/end() in the third alternative we must use 
    argument dependent lookup, but always considering 'std' as an associated 
    namespace. */ 

正如你所看到的,他們沒有什麼比標準實際描述的更多。

+0

I不要認爲標準實際上意味着說基於範圍的循環必須這樣看,我認爲關鍵是這是他們的行爲。 (該措辭有點混亂「在每種情況下,基於範圍的語句相當於 」[...]「) – Cubic

+0

這就是我的問題,gcc沒有提到它...... – user2384250