作者cppOrz (cppOrz)
看板C_and_CPP
標題[心得] 關於 Expression Templates 的優化技術
時間Wed Aug 24 10:09:17 2005
(繼前篇)
為了觀察幾個主流 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