2013-12-11 66 views
1

我正在將SSE2正弦和餘弦函數(來自Julien Pommier的sse_mathfun.h;基於CEPHES sinf函數)轉換爲使用AVX以接受8個浮點向量或4個雙精度值。將SSE代碼轉換爲AVX - 成本_mm256_and_ps

因此,Julien的函數sin_ps變爲sin_ps8(對於8個浮點數)和sin_pd4對於4個雙精度。 (此處「高級」編輯器無法接受我的代碼,因此請訪問http://arstechnica.com/civis/viewtopic.php?f=20&t=1227375查看它。)

在2011年Core2 i7 @ 2.7Ghz上運行的Mac OS X 10.6.8下使用clang 3.3進行測試,基準測試結果像這樣:

  • SINF .. - > 27.7百萬向量評估/第二過5.56e + 07 iters(標準,標量SINF()函數)

    sin_ps .. - > 41.0百萬矢量評估/秒,在 8.22e + 07 iters

    sin_pd4 .. - > 40.2百萬向量評估/第二過 8.06e + 07 iters

    sin_ps8的.. - > 2.5百萬向量評估/第二過 5.1E + 06 iters

sin_ps8的代價是非常可怕的,它似乎是由於使用了_mm256_castsi256_ps。實際上,註釋掉這行「poly_mask = _mm256_castsi256_ps(emmm2);」導致更正常的表現。 sin_pd4使用_mm_castsi128_pd,但它似乎不是(僅)在sin_ps8中咬住我的SSE和AVX指令的混合:當我通過2次調用_mm_castsi128_ps來模擬_mm256_castsi256_ps調用時,性能不會提高。 emm2和emm0是指向emmm2和emmm0的指針,都是v8si實例,因此(先驗)正確對齊32位邊界。

有關編譯代碼,請參見sse_mathfun.hsse_mathfun_test.c

有沒有(n簡單)的方法來避免我看到的懲罰?

+0

對遺漏的代碼真的很抱歉:預覽看起來不錯,但我的文本被拒絕發佈... – RJVB

+0

什麼是「Core2 i7」? – Mysticial

+0

Agner Fog的[優化表](http://www.agner.org/optimize/#manuals)顯示,無論參數大小,Ivy Bridge和Haswell上的ANDPS和VANDPS都有1個週期的延遲。此外,'_mm256_castsi256_ps'實際上並不會發出任何指令 - 純粹是在編譯器中,它是一種真正的類型轉換。你的問題可能在其他地方。 –

回答

1

將寄存器中的東西轉移到內存中通常不是一個好主意。每當你存儲一個指針時,你都會這樣做。

取而代之的是:

{ ALIGN32_BEG v4sf *yy ALIGN32_END = (v4sf*) &y; 
     emm2[0] = _mm_and_si128(_mm_add_epi32(_mm_cvttps_epi32(yy[0]), _v4si_pi32_1), _v4si_pi32_inv1), 
     emm2[1] = _mm_and_si128(_mm_add_epi32(_mm_cvttps_epi32(yy[1]), _v4si_pi32_1), _v4si_pi32_inv1); 
     yy[0] = _mm_cvtepi32_ps(emm2[0]), 
     yy[1] = _mm_cvtepi32_ps(emm2[1]); 
     } 

/* get the swap sign flag */ 
emm0[0] = _mm_slli_epi32(_mm_and_si128(emm2[0], _v4si_pi32_4), 29), 
emm0[1] = _mm_slli_epi32(_mm_and_si128(emm2[1], _v4si_pi32_4), 29); 

/* get the polynom selection mask 
there is one polynom for 0 <= x <= Pi/4 
and another one for Pi/4<x<=Pi/2 

Both branches will be computed. 
*/ 
emm2[0] = _mm_cmpeq_epi32(_mm_and_si128(emm2[0], _v4si_pi32_2), _mm_setzero_si128()), 
emm2[1] = _mm_cmpeq_epi32(_mm_and_si128(emm2[1], _v4si_pi32_2), _mm_setzero_si128()); 

((v4sf*)&poly_mask)[0] = _mm_castsi128_ps(emm2[0]); 
((v4sf*)&poly_mask)[1] = _mm_castsi128_ps(emm2[1]); 
swap_sign_bit = _mm256_castsi256_ps(emmm0); 

嘗試這樣:

__m128i emm2a = _mm_and_si128(_mm_add_epi32(_mm256_castps256_ps128(y), _v4si_pi32_1), _v4si_pi32_inv1); 
__m128i emm2b = _mm_and_si128(_mm_add_epi32(_mm256_extractf128_ps(y, 1), _v4si_pi32_1), _v4si_pi32_inv1); 

y = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_cvtepi32_ps(emm2a)), _mm_cvtepi32_ps(emm2b), 1); 

/* get the swap sign flag */ 
__m128i emm0a = _mm_slli_epi32(_mm_and_si128(emm2a, _v4si_pi32_4), 29), 
__m128i emm0b = _mm_slli_epi32(_mm_and_si128(emm2b, _v4si_pi32_4), 29); 

swap_sign_bit = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(emm0a), emm0b, 1)); 

/* get the polynom selection mask 
there is one polynom for 0 <= x <= Pi/4 
and another one for Pi/4<x<=Pi/2 

Both branches will be computed. 
*/ 
emm2a = _mm_cmpeq_epi32(_mm_and_si128(emm2a, _v4si_pi32_2), _mm_setzero_si128()), 
emm2b = _mm_cmpeq_epi32(_mm_and_si128(emm2b, _v4si_pi32_2), _mm_setzero_si128()); 

poly_mask = _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(emm2a), emm2b, 1)); 

正如評論所說,cast內在純粹編譯時和不發出指令。

+0

回覆:投入內在因素:的確如此。我比較了純_mm * _cast * _ps內在函數,它們都是*快*。 所以我有SSE2整數代碼和兩個AVX轉換,如果我取消了兩個轉換(或者確實是一個特定的轉換,IIRC計算poly_mask),那麼性能會突然增加。我必須小心解釋,因爲sse_mathfun_test將緩衝函數結果存儲到其操作數中以避免循環展開(性能可能會超過頂端;)),但仍然表明我正在因轉換而被擊中。 – RJVB

+0

對齊問題,加載/存儲延遲,我對彙編編碼的知識太少,但我已經看到Apple的Shark工具提供的足夠反饋來懷疑類似的情況正在發生。 (不,鯊魚不幫我在這裏,我的版本顯然不知道AVX呢。) 事實上,我的CPU還沒有AVX2呢,可悲的是。 – RJVB

+0

是否刪除內存使用像我這裏做的幫助? –

1

也許你可以將你的代碼與已經有效的Julien Pommier SSE數學函數的AVX擴展進行比較?

http://software-lisc.fbk.eu/avx_mathfun/

這個代碼在GCC但不是MSVC並且只支持浮點數(的float8),但我認爲你可以很容易地擴展它使用雙打(double4)爲好。您的sin函數的快速比較表明它們除了SSE2整數部分外非常相似。

+0

我記得我必須做一些工作才能在MSVC下編譯sse_mathfun.h,我想大概是用AVX版本做同樣的事情。我老實說,還沒有到處去看看是否有人做了這項工作,部分原因是我確實是在做這個練習。 也就是說,使用臨時聯合和「標量指針」代替使用指向允許以__m128 [2]方式訪問該變量的__m256實例的指針的方式進行轉換真的有好處嗎?如果鑄造實際上只進行編譯時,沒有對齊調整,那麼應該沒有區別。 – RJVB

+0

另外,我嘗試使用包含__m256和__m128 [2]的聯合...但gcc和clang都對此不屑一顧。無論如何,當我做這個快速比較,我有一個明顯的印象,即真正不同的整數部分是AVX2 ... 猜猜最簡單的事情就是去時間avx_sse_mathfun.h :) – RJVB