精華區beta C_and_CPP 關於我們 聯絡資訊
(繼前篇) 為了觀察幾個主流 C++ 編譯器的性能,在前一篇的 operator+ 的 兩種版本 X1, X2 之外,提出另一種基於 Expression Templates 優化技術所實作出的版本 Y,與 X1, X2 版本相互參照。 首先,引入一個中間層的 class template: Addition,它內部只保 有兩個 reference to const T 物件: template<typename T> struct Addition { T const &lhs; T const &rhs; Addition(T const &lhs, T const &rhs) : lhs(lhs), rhs(rhs) {} }; 接著,對任意型別 T,重載 operator+ 運算子,但注意它的回 傳值的型別並不是 T ,而是前述我們引入的 Addition<T> 中間層。 template<typename T> Addition<T> operator+(T const &lhs, T const &rhs) { return Addition<T>(lhs, rhs); } 最後,再利用 Addition<T> 和 operator+ 的重載功能,令 class Y 擁有和 class X 一致的操作介面。 struct Y { int val[1000]; Y &operator=(Addition<Y> const &add) { Y const &lhs = add.lhs; Y const &rhs = add.rhs; for (int i=0; i<1000; ++i) { val[i] = lhs.val[i] + rhs.val[i]; } return *this; } }; 如此一來,以下的寫法就可以被編譯器接受了: Y a, b, c; c = a + b; 實際的測試函式如下: void Test2() { for (int i=0; i<200000; ++i) // 執行 20 萬次加法運算 { Y a, b, c; c = a + b; } } 測試結果,平均執行效能:(時間單位 Ticks) X1 X2 Y VC6(D) 3390 2578 1875 VC6(R) 1250 750 500 g++3.4.2(D) 1984 1891 1563 BCC5.6.4(D) 1394 1594 1695 BCC5.6.4(R) 672 690 500 (註:在 VC6 中,前面的 class template Addition 實際上編不過, 必須自己改成 non-template 版本才行) 結果有兩個重點: 一、在 VC 和 g++ 上,使用 Expression Templates 的優化技術後,  效率明顯改進了許多。(也就是 Y 版本勝過兩種 X 版本) 二、但在 BCC(Debug版本) 上竟然是反過來,辛苦寫程式想幫編譯器  做優化,結果比沒做更慢!也因此我只好再編出 Release 版本出  來比較,這次終於發現 Y 版本比較快了。 當然,Y 版本不像 X 版本一樣,可以使用 s = a+b+c+d+... 這種寫 法,它基本上是利用 Addition 這個中間層,取得更多的資訊,讓編 譯器有機會做更加的優化動作。簡單說明如下: Y a, b, c; c = a + b; 在 Y &operator=(Addition<Y> const &add) 中,編譯器等於知道 a, b, c 這三個物件資訊,但在 X 版本中,不論是 operator= 或 operator+ 最多都只知道兩個物件資訊。 最後有幾個感想: 一、關於效能的問題,實際上和 Complier 實作技術有很大的關係。  我們只能避免那些很明顯的沒效率的用法(例出產生大量無用的暫  時物件),儘量寫出正確、清楚、簡潔、乾淨的程式碼,有些很細  節的部份,不轉成 asm 大概很難看出名堂。 二、優化的技術有很多,有的初看到真是令人大開眼界,也讓人覺得  C++ 真是無比的豐富。不過還是 MEC 的那句話,過早的優化其實是  不必要的。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.214.120
renderer:推 太神了 61.222.148.171 08/24
※ 編輯: cppOrz 來自: 59.120.214.120 (08/24 10:36)
godfat:還有這種用法喔 @@ 61.216.0.106 08/26