2010-06-29 196 views
8

我遇到了一個奇怪的問題。我工作的一種算法是由大量的計算這樣32位與64位浮點性能

q = x(0)*y(0)*z(0) + x(1)*y(1)*z(1) + ... 

其中總和的長度爲4和7

之間

原來的計算都使用64位精度完成的。對於實驗,我嘗試對x,y,z輸入值使用32位精度(以便計算使用32位執行),並將最終結果存儲爲64位值(直接轉換)。我希望32位性能更好(緩存大小, SIMD大小等),但令我驚訝的是,性能沒有差別,甚至可能會減少。

有問題的架構是Intel 64,Linux和GCC。兩個代碼似乎都使用SSE,並且這兩種情況下的數組都對齊到16字節的邊界。

爲什麼會這樣?到目前爲止,我的猜測是32位精度只能在前四個元素上使用SSE,其餘的都是通過施放開銷連續進行的。

+0

您已添加賞金 - 您對dsimcha的回答有什麼不喜歡的?也許值得嘗試一下最新的GCC或英特爾的編譯器http://software.intel.com/en-us/articles/non-commercial-software-download/,看看他們是否做得更好,編譯/矢量化。 – Rup 2010-07-06 16:56:16

+0

@Rup我喜歡他的回答,但也希望其他意見,所以我把一個賞金 – Anycorn 2010-07-06 19:12:21

回答

24

至少在x87上,所有內容都是以80位精度完成的。精確度只是確定這些位在內存中的存儲量。這是不同優化設置可以稍微改變結果的原因的一部分:它們將舍入數量從80位改爲32位或64位。

實際上,使用80位浮點(C和C++中的long double,D中的real)通常速度較慢,因爲沒有有效的方法來加載和存儲內存中的80位。 32位和64位通常同樣快,只要內存帶寬不是瓶頸,即無論如何一切都在緩存中。如果發生以下任一情況,64位可能會變慢:

  1. 內存帶寬是瓶頸。
  2. 64位數字在8字節邊界上沒有正確對齊。 32位數字只需要4字節對齊以獲得最佳效率,所以它們不那麼挑剔。一些編譯器(數字火星D編譯器浮現在腦海中)並不總是適合存儲在堆棧上的64位雙精度。這會導致加載一次所需的內存操作量的兩倍,實際上導致與正確對齊的64位浮點數或32位浮點數相比,性能下降了約2倍。

就SIMD優化而言,應該注意的是,大多數編譯器在自動矢量化代碼上都很糟糕。如果您不想直接用匯編語言編寫代碼,那麼利用這些指令的最好方法就是使用類似陣列的操作,例如在D中可用,並按照SSE指令來實現。同樣,在C或C++中,你可能想要使用一個高級函數庫,這些函數是經過SSE優化的,儘管我不知道這是一個好的例子,因爲我主要用D編程。

+4

「x87」 - 略好於那些舊的x86處理器。 :-) – Thanatos 2010-07-10 01:57:06

+4

http://en.wikipedia.org/wiki/X87 – Adam 2010-07-10 02:20:47

0

這可能是因爲你的處理器仍然會進行64位計數,然後修整數字。有一些CPU標誌,你可以改變,但我不記得...

0

首先檢查產生的ASM。它可能不是你所期望的。

也可以嘗試寫它作爲一個循環:

typedef float fp; 
fp q = 0 
for(int i = 0; i < N; i++) 
    q += x[i]*y[i]*z[i] 

一些編譯器可能會注意到的循環,而不是展開的形式。

最後,您的代碼使用()而不是[]。如果你的代碼正在進行大量的函數調用(12到21),那麼這將消耗FP成本,甚至一起去除fp計算也沒有多大區別。插入OTOH可能。

+0

謝謝,實際上'q()'是宏直接轉換爲原始指針訪問 – Anycorn 2010-07-10 02:21:26

+0

@aaa:那麼如果有任何數學,它可能仍然是一個很大的比例。另外,我不知道編譯器如何處理混合FP和其他內容。這可能足以阻止它使用矢量操作。 – BCS 2010-07-10 16:04:56