簡體   English   中英

使用 SSE 加速浮點 5x5 矩陣 * 向量乘法

[英]Speed up float 5x5 matrix * vector multiplication with SSE

我需要每秒運行 240000 次矩陣向量乘法。 矩陣是 5x5 並且始終相同,而向量在每次迭代時都會發生變化。 數據類型是float 我正在考慮使用一些 SSE(或類似)指令。

  1. 我擔心算術運算的數量與涉及的 memory 運算的數量相比太少了。 你認為我能得到一些切實的(例如> 20%)改進嗎?

  2. 我需要英特爾編譯器嗎?

  3. 你能指出一些參考資料嗎?

向量、矩陣等的Eigen C++ 模板庫...

  • 針對小型固定大小矩陣(以及動態大小的矩陣)的優化代碼

  • 使用 SSE 優化的優化代碼

所以你應該試一試。

原則上,SSE 的加速可以是 4 倍(AVX 是 8 倍)。 讓我解釋。

讓我們稱您的固定 5x5 矩陣M 將 5D 向量的分量定義為 (x,y,z,w,t)。 現在從前四個向量形成一個 5x4 矩陣U。

U =
xxxx
yyyy
zzzz
wwww
tttt

接下來,做矩陣乘積MU = V 矩陣V包含M和前四個向量的乘積。 唯一的問題是,對於 SSE,我們需要讀取U的行,但在 memory 中, U存儲為xyzwtxyzwtxyzwtxyzwt ,因此我們必須將其轉置為xxxxyyyyzzzzwwwwtttt 這可以通過 SSE 中的洗牌/混合來完成。 一旦我們有了這種格式,矩陣乘積就非常有效。

而不是使用標量代碼進行 O(5x5x4) 操作,它只需要 O(5x5) 操作,即 4 倍加速。 使用 AVX,矩陣U將是 5x8,因此它不需要 O(5x5x8) 操作,它只需要 O(5x5),即 8 倍加速。

然而,矩陣V將采用xxxxyyyyzzzzwwwwtttt格式,因此根據應用程序,它可能必須轉換為xyzwtxyzwtxyzwtxyzwt格式。

對接下來的四個向量(AVX 為 8 個)重復此操作,依此類推,直到完成。

如果您可以控制向量,例如,如果您的應用程序動態生成向量,那么您可以以xxxxyyyyzzzzwwwwtttt格式生成它們並避免數組的轉置。 在這種情況下,您應該使用 SSE 獲得 4 倍的加速,使用 AVX 獲得 8 倍的加速。 如果您將此與線程(例如 OpenMP)結合使用,您的加速應該接近 16 倍(假設四個物理內核)與 SSE。 我認為這是你可以用 SSE 做的最好的事情。

編輯:由於指令級並行性 (ILP),您可以獲得另一個 2 倍的加速,因此 SSE 的加速可以在四個核心 (64x AVX) 的情況下提高 32 倍,並且由於 FMA3,Haswell 的加速可以再次提高 2 倍。

我建議使用英特爾 IPP 並抽象出對技術的依賴

如果您使用的是 GCC,請注意 -O3 選項將啟用自動矢量化,這將在許多情況下自動生成 SSE 或 AVX 指令。 一般來說,如果你只是把它寫成一個簡單的for循環,GCC 會將它向量化。 有關詳細信息,請參閱http://gcc.gnu.org/projects/tree-ssa/vectorization.html

這應該很容易,尤其是當您使用 Core 2 或更高版本時:您需要 5* _mm_dp_ps 、一個_mm_mul_ps 、兩個_mm_add_ps 、一個普通乘法,以及一些隨機播放、加載和存儲(如果矩陣是固定的,您可以保留大部分都在 SSE 寄存器中,如果您不需要它們用於其他任何事情)。

至於 memory 帶寬:我們說的是 2.4 兆字節的向量,而 memory 的帶寬是個位數千兆字節每秒。

對向量有什么了解? 由於矩陣是固定的,並且如果向量可以采用的值數量有限,那么我建議您預先計算計算並使用表格查找來訪問它們。

以循環換取 memory 的經典優化技術...

我建議查看優化的 BLAS 庫,例如 Intel MKL 或 AMD ACML。 根據您的描述,我假設您將在SGEMV 2 級矩陣向量例程之后執行y = A*x樣式操作。

如果你真的想自己實現一些東西,使用(可用的) SSE..SSE4AVX指令集在某些情況下可以提供顯着的性能改進,盡管這正是一個好的 BLAS 庫要做的事情。 您還需要仔細考慮緩存友好的數據訪問模式。

我不知道這是否適用於您的情況,但是您可以一次對向量的“塊”進行操作嗎? 因此,您可以對[y1 y2... yn] = A * [x1 x2... xn]的塊進行操作,而不是重復執行y = A*x樣式的操作。 如果是這樣,這意味着您可以使用優化的矩陣矩陣例程,例如SGEMM 由於數據訪問模式,這可能比重復調用SGEMV更有效。 如果是我,我會嘗試沿着這條路走 go ......

希望這可以幫助。

如果您事先知道向量(例如,一次完成所有 240k),那么通過並行化循環比通過 SSE 獲得更好的加速。 如果您已經邁出了這一步,或者您不是一下子了解所有這些,那么 SSE 可能會帶來很大的好處。

如果 memory 是連續的,那么不要太擔心 memory 操作。 如果你有一個鏈表或其他東西,那么你就有麻煩了,但它應該能夠跟上而沒有太多問題。

5x5 是一個有趣的大小,但您可以在一條 SSE 指令中至少執行 4 次翻轉,並嘗試減少算術開銷。 您不需要英特爾編譯器,但它可能會更好,我聽說過關於它如何使用算術代碼更好的傳說。 Visual Studio 具有處理 SSE2 的內在函數,我認為最多 SSE4 取決於您的需要。 當然,你必須自己滾動它。 抓住圖書館可能是這里的明智之舉。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM