2015-11-01 118 views
6

不幸的是我有一個AMD打樁機的CPU,這似乎有問題,AVX指令:強制AVX內在使用SSE指令,而不是

內存與256位AVX寄存器寫入格外緩慢。測得的吞吐量比以前的型號(推土機)慢5 - 6倍,比兩個128位寫慢8 - 9倍。

根據我自己的經驗,我發現mm256內在函數比mm128慢得多,我假設它是因爲上述原因。

雖然我確實想編寫最新的指令集AVX,但仍然能夠以合理的速度在我的機器上測試構建。有沒有辦法強制mm256 intrinsics使用SSE指令呢?我正在使用VS 2015.

如果沒有簡單的方法,那麼困難的方法。將<immintrin.h>替換爲一個自定義標題,其中包含我自己的可以編碼爲使用SSE的內部函數的定義?不知道這是多麼合理,如果可能,我會在完成這項工作之前選擇更簡單的方法。

+0

我不認爲有。他們不會爲一個特定的處理器檢修他們的編譯器。 (只有Piledriver有這個bug。) – Mysticial

+0

當你引用某些東西時,你應該給一個參考。是的,這有一個解決方案。 Agner霧的矢量類。使用'Vec8f'等AVX矢量,並用'-D__SSE4_2__ -D__XOP__'進行編譯。 –

+0

你使用256位實際上比較慢嗎?你有沒有對齊問題? –

回答

6

使用Agner Fog的Vector Class Library並將其添加到Visual Studio的命令行:-D__SSE4_2__ -D__XOP__

然後使用AVX大小的矢量,例如Vec8f用於八個浮點數。如果在沒有啓用AVX的情況下編譯,它將使用文件vectorf256e.h,該文件用兩個SSE寄存器模擬AVX。例如從Vec256feVec8f繼承它開始像這樣:

class Vec256fe { 
protected: 
    __m128 y0;       // low half 
    __m128 y1;       // high half 

如果用/arch:AVX -D__XOP__編譯VCL將改爲使用文件vectorf256.h和一個AVX寄存器。然後,只有編譯器切換更改,您的代碼才能用於AVX和SSE。如果您不想使用XOP請不要使用-D__XOP__


正如彼得·柯德斯在他的回答中指出,如果你的目標僅僅是爲了避免256位加載/存儲,那麼你可能還是要VEX編碼指令(雖然目前還不清楚這將使除差異一些特殊情況)。你可以做到這一點與Vector類這樣

Vec8f a; 
Vec4f lo = a.get_low(); // a is a Vec8f type 
Vec4f hi = a.get_high(); 
lo.store(&b[0]);   // b is a float array 
hi.store(&b[4]); 

然後用/arch:AVX -D__XOP__編譯。

另一種選擇是是使用Vecnf,然後做

//foo.cpp 
#include "vectorclass.h" 
#if SIMDWIDTH == 4 
typedef Vec4f Vecnf; 
#else 
typedef Vec8f Vecnf; 
#endif 

和編譯這樣

cl /O2 /DSIMDWIDTH=4      foo.cpp /Fofoo_sse 
cl /O2 /DSIMDWIDTH=4 /arch:AVX /D__XOP__ foo.cpp /Fofoo_avx128 
cl /O2 /DSIMDWIDTH=8 /arch:AVX   foo.cpp /Fofoo_avx256 

這將創建三個可執行文件與一個源文件的源文件。而不是鏈接它們,你可以用/c來編譯它們,並且它們構成一個CPU調度器。我用XOP與avx128,因爲我認爲除了在AMD上使用avx128是沒有充分理由的。

+0

我想知道我怎麼能做到相反。將'__m256'推入Vector Class Library中的'Vec8fe'。是的,這沒有意義,但我需要這種情況。 – Royi

+0

@羅伊你爲什麼需要這種情況?如果你有__m256這意味着你已經編譯AVX,然後VCL將使用'Vec8f'而不是'Vec8fe'。 –

+0

因爲在某些情況下,我想在我的系統中使用2個不同的代碼。一個用於SSE,一個用於AVX。 VCL的問題只能處理其中的一個問題。我希望我可以強制它使用'Vec8f'的AVX和'Vec4f'的SSE。 – Royi

3

你不想使用SSE指令。你想要的是將256b存儲區作爲兩個獨立的128b存儲區完成,仍然使用VEX編碼的128b指令。即128b AVX vmovups


GCC有-mavx256-split-unaligned-load...-store選項(作爲-march=sandybridge部分啓用例如,想必也爲推土機家族(-march=bdver2是打樁機)。當編譯器知道內存這並不解決問題對準,雖然。


您可以覆蓋正常256B店鋪內在與像

// maybe enable this for all BD family CPUs? 

#if defined(__bdver2) | defined(PILEDRIVER) | defined(SPLIT_256b_STORES) 
    #define _mm256_storeu_ps(addr, data) do{ \ 
     _mm_storeu_ps(((float*)(addr)) + 0, _mm256_extractf128_ps((data),0)); \ 
     _mm_storeu_ps(((float*)(addr)) + 4, _mm256_extractf128_ps((data),1)); \ 
    }while(0) 
#endif 

gcc定義__bdver2(推土機版本2)爲Piledriver(-march=bdver2)。

您可以對(對齊)_mm256_store_ps執行相同的操作,或者只是始終使用未對齊的內部函數。

編譯器將_mm256_extractf128(data,0)優化爲簡單的演員表。即它應該只是編譯成

vmovups  [rdi], xmm0   ; if data is in xmm0 and addr is in rdi 
vextractf128 [rdi+16], xmm0, 1 

然而,testing on godbolt shows that gcc and clang are dumb,並提取到寄存器和然後店。 ICC正確地生成雙指令序列。

+0

由於AMD AVX基本上在硬件上作爲SSE仿真,所以使用非VEX編碼指令有什麼問題?我能想到的唯一優點是使用AVX指令,但是分割加載/存儲的操作是在指令緩存中使用更少的寄存器和更少的指令。 –

+0

我想因爲未對齊的加載不能被摺疊爲非VEX編碼指令,這是使用VEX編碼指令的原因之一。 –

+0

@Zboson:是的,根據我讀過的內容(例如Agner Fog),在AMD上使用256b向量通常沒有什麼優勢。具有VEX編碼指令的128b向量通常是最好的選擇。這個答案有助於使用Piledriver機器開發/調試AVX軟件。您可以使用256b內在函數,而不必考慮256b存儲性能問題。因此,如果您使用'_mm_ *'128b內在函數編寫代碼,但是希望Intel硬件的速度更快,那麼您將在Piledriver上獲得相同的速度。 –