簡體   English   中英

x86匯編指令優化

[英]x86 assembly instructions optimisation

我正在嘗試在稱為數千次循環的循環中優化指令塊,這是我算法的瓶頸。

此代碼塊計算N個矩陣3x3(iA數組)與N個向量3(iV數組)的乘積,並將N個結果存儲在oV數組中。 (N不是固定值,通常在3000到15000之間)

矩陣和向量的每一行都是128位對齊的(4個浮點數)以利用SSE優化(忽略第4個浮點值)。

C ++代碼:

  __m128* ip = (__m128*)iV;
  __m128* op = (__m128*)oV;
  __m128* A = (__m128*)iA;

  __m128 res1, res2, res3;
  int i;

  for (i=0; i<N; i++)
  {
    res1 = _mm_dp_ps(*A++, *ip, 0x71);
    res2 = _mm_dp_ps(*A++, *ip, 0x72);
    res3 = _mm_dp_ps(*A++, *ip++, 0x74);

    *op++ = _mm_or_ps(res1, _mm_or_ps(res2, res3));
  }

編譯器生成以下指令:

000007FEE7DD4FE0  movaps      xmm2,xmmword ptr [rsi]               //move "ip" in register
000007FEE7DD4FE3  movaps      xmm1,xmmword ptr [rdi+10h]           //move second line of A in register
000007FEE7DD4FE7  movaps      xmm0,xmmword ptr [rdi+20h]           //move third line of A in register
000007FEE7DD4FEB  inc         r11d                                 //i++
000007FEE7DD4FEE  add         rbp,10h                              //op++
000007FEE7DD4FF2  add         rsi,10h                              //ip++
000007FEE7DD4FF6  dpps        xmm0,xmm2,74h                        //dot product of 3rd line of A against ip
000007FEE7DD4FFC  dpps        xmm1,xmm2,72h                        //dot product of 2nd line of A against ip
000007FEE7DD5002  orps        xmm0,xmm1                            //"merge" of the result of the two dot products
000007FEE7DD5005  movaps      xmm3,xmmword ptr [rdi]               //move first line of A in register
000007FEE7DD5008  add         rdi,30h                              //A+=3
000007FEE7DD500C  dpps        xmm3,xmm2,71h                        //dot product of 1st line of A against ip
000007FEE7DD5012  orps        xmm0,xmm3                            //"merge" of the result
000007FEE7DD5015  movaps      xmmword ptr [rbp-10h],xmm0           //move result in memory (op)
000007FEE7DD5019  cmp         r11d,dword ptr [rbx+28h]             //compare i
000007FEE7DD501D  jl          MyFunction+370h (7FEE7DD4FE0h)       //loop

我對底層優化不是很熟悉,所以問題是:如果我自己編寫匯編代碼,您是否看到一些可能的優化?

例如,如果我進行更改,它將運行得更快嗎:

add         rbp,10h
movaps      xmmword ptr [rbp-10h],xmm0

通過

movaps      xmmword ptr [rbp],xmm0
add         rbp,10h

我也讀過ADD指令比INC更快...

計算帶偏移量的間接地址(例如rbp-10 )非常便宜,因為在“有效地址計算”單元中存在用於此類計算的特殊硬件[我認為名稱不同,但是想不起來或擁有谷歌成功找到它的名字]。

但是,在add rbp,10h[rbp-10h]之間存在依賴關系,這可能會引起問題-但在這種特殊情況下,我對此表示懷疑。 在您的情況下, rbp-10與使用它之間有很長的距離,所以這不是問題。 編譯器可能把它放的太遠了,因為那時候它是“免費的”,因為處理器將等待數據從外部輸入到先前已讀取的xmm寄存器中。 換句話說,我們可以在循環開始時在讀取xmm0xmm1xmm2之間進行任何工作,並且使用xmm0xmm1xmm2dpps指令將是有益的,因為處理器將等待該數據“才能計算出dpps結果。

我已經完成了許多x86程序集優化,並且可以告訴您這是一次很棒的學習經歷。 它教會了我很多關於編譯器如何工作的知識,而我所學到的最大的一點是,編譯器通常很擅長於其工作。 我知道這是一個輕率的評論,但這是真的...

我還了解到,您所做的優化可以對一個處理器系列產生積極的影響,而對另一個處理器系列產生不利的影響。 諸如流水線,分支預測和處理器緩存之類的事情起着巨大的作用……因此,除非您針對的是非常具體的硬件配置,否則請注意有關所做改進的假設。

對於您關於重新排序添加以刪除rbp-10h偏移量的特定問題……看起來有明顯的改進,您必須閱讀說明手冊進行驗證,但我想-10h內存偏移量是為了在該說明中免費。 移動add可能會拋出流水線指令,並實際上導致時鍾周期損失。 您必須進行試驗。

您可以對上述代碼做一些改進。 通常,在更改值后使用值會導致處理器在等待結果時停頓。 所以這些行將招致罰款:

add         rbp,10h
movaps      xmmword ptr [rbp-10h],xmm0

但是在這兩行上方的代碼段中相隔很遠,所以這並不是真正的問題。 正如其他人已經說過的那樣, rbp-10h是“免費的”,因為地址計算硬件可以處理它。

您可以將movaps xmm3,xmmword ptr [rdi]向上移動一行,也可以重新排列其他幾行。

值得嗎?

沒有

您會很幸運地從中獲得任何真正的性能提升,因為您的算法是

<blink> memory bandwidth limited </blink>*

這意味着從RAM讀取數據到CPU所花費的時間大於CPU進行處理所花費的時間。 最糟糕的是,讀取內存地址可能涉及頁面錯誤和磁盤讀取。 prefetch指令也無濟於事,它稱為“流SIMD擴展”,因為它已優化為將數據流傳輸到CPU(內存接口可以處理四個獨立的IIRC流)。

如果您要對少量數據(可能是FFT)進行大量計算,則可以通過手工制作匯編程序獲得很多收益。 但是您的算法非常簡單,因此CPU在空閑時間等待數據到達。 如果您知道RAM的速度,則可以計算出該算法的最大吞吐量,並將其與當前實現的性能進行比較(盡管如此,您永遠不會達到最大理論吞吐量)。

您可以采取一些措施來最大程度地減少內存停頓,這是一個更高級別的更改,而不是擺弄單個指令(通常,優化算法可獲得更好的結果)。 最簡單的方法是對輸入數據進行雙緩沖。 將寄存器組分為兩組(可以在此處執行,因為您僅使用四個SIMD寄存器):

  load set 1
mainloop:
  load set 2
  do processing on set 1
  save set 1 result
  load set 1
  do processing on set 2
  save set 2 result
  goto mainloop

希望這給了你一些想法。 即使運行不快,它仍然是一個有趣的練習,您可以從中學到很多東西。

  • RIP閃爍。

暫無
暫無

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

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