2015-09-20 72 views
9

我試圖使用System.Numerics.Vector(T)矢量化算法並利用CPU的SIMD操作。但是,我的矢量實現比我原來的實現要慢很多。有沒有使用可能沒有記錄的矢量的技巧?這裏的具體用處是試圖加快Xors的kb數據。使用矢量<T> SIMD在通用Windows平臺

不幸的是,我幾乎可以找到的所有文檔都基於RyuJIT的預發佈版本,我不知道有多少材料可移植到.NET Native。

當我一個Vector XOR操作過程中檢查拆卸,它表明:

00007FFB040A9C10 xor   eax,eax 
00007FFB040A9C12 mov   qword ptr [rcx],rax 
00007FFB040A9C15 mov   qword ptr [rcx+8],rax 
00007FFB040A9C19 mov   rax,qword ptr [r8] 
00007FFB040A9C1C xor   rax,qword ptr [rdx] 
00007FFB040A9C1F mov   qword ptr [rcx],rax 
00007FFB040A9C22 mov   rax,qword ptr [r8+8] 
00007FFB040A9C26 xor   rax,qword ptr [rdx+8] 
00007FFB040A9C2A mov   qword ptr [rcx+8],rax 
00007FFB040A9C2E mov   rax,rcx 

爲什麼它不使用這個XMM寄存器和SIMD指令?奇怪的是,SIMD指令是爲我沒有明確向量化的代碼版本生成的,但它們從未被執行,而是支持常規寄存器和指令。

我確保我使用Release,x64,Optimize代碼啓用。我看到了與x86編譯類似的行爲。我在機器級別上有點新手,所以它有可能出現這種情況,我沒有正確理解。

框架版本是4.6,Vector.IsHardwareAccelerated在運行時爲false。

更新:「編譯與.NET Native工具鏈」是罪魁禍首。啓用它會導致Vector.IsHardwareAccelerated == false;禁用它會導致Vector.IsHardwareAccelerated == true。我已經確認,當禁用.NET Native時,編譯器正在使用ymm寄存器生成AVX指令。這導致了這個問題......爲什麼在.NET Native中未啓用SIMD?有什麼方法可以改變它?

更新Tangent:我發現auto-SSE向量化數組代碼沒有被執行的原因是編譯器插入了一條指令,看看數組的起始位置是否在較低的地址而不是數組中的最後一個元素,如果是,則只使用正常的寄存器。我認爲這肯定是編譯器中的一個bug,因爲按照慣例,數組的起始位置應該總是比最後一個元素的地址低一些。它是測試每個操作數數組的內存地址的一組指令的一部分,我認爲要確保它們不重疊。我提起了微軟連接錯誤報告此:https://connect.microsoft.com/VisualStudio/feedback/details/1831117

+0

這是什麼框架版本?硬件加速是否被報告爲「真實」? – usr

+0

Framework版本4.6和IsHardwareAccelerated返回false。 –

+0

'爲什麼在.NET Native中未啓用SIMD?'我只能冒險猜測:SIMD是由JIT(即時編譯器,即在運行時IL代碼轉換爲本地代碼的東西)處理的。 .NET native通過創建一個純粹的本地程序集(無需翻譯)完全繞過JIT。我想他們根本沒有在.NET本地工具鏈中實現SIMD支持。因爲他們還沒有時間,或者因爲.NET本地可以用來創建在沒有SIMD寄存器 –

回答

9

我聯繫了微軟,誰張貼的聯繫地址爲.NET原生的問題和疑慮:https://msdn.microsoft.com/en-us/vstudio/dotnetnative.aspx

我的問題被提到伊恩·比爾曼,首席軟件工程在微軟代碼生成和優化技術團隊經理:

目前.NET本機不優化System.Numerics庫 並依賴於默認庫實現。這可能(讀取:將 可能)導致使用System.Numerics編寫的代碼在.NET本機中不能很好地執行 ,因爲它會針對其他CLR實現。

雖然這很不幸,但是.NET Native支持使用上面提到的C++優化的自動矢量化 。 當前發貨。NET Native編譯器支持x86和x64上的 自動矢量化和ARM上的NEON ISA中的SSE2 ISA。

他還提到他們希望從C++編譯器中引入能夠根據運行時檢測指令集生成所有向量指令(AVX,SSE等)和分支。然後他建議如果指令的使用非常關鍵,那麼可以使用C++構建組件,該組件可以訪問編譯器內在函數(大概是這種分支功能?),然後輕鬆地與其餘的C#應用​​程序接口。

至於跳過的SSE2指令,我所需要做的就是讓它編譯成正確的指令,就是用「a^= b」代替循環的「a = a^b」。由於它們應該是等同的表達式,看起來它是一個錯誤,但幸運的是有一個解決方法。

+0

非常有趣/有用的信息,感謝您的跟進! –

+1

謝謝你回來。這不是我正在尋找的東西,但卻讓人着迷。 Kudo爲我們其他人跟進。 – EndsOfInvention