2009-11-11 473 views
29

我在做C中的圖像處理,需要在內存周圍複製大塊數據 - 源和目標不會重疊。非常快速的圖像處理memcpy?

什麼是在x86平臺上使用GCC(其中SSE,SSE2而不是SSE3可用)執行此操作的最快速方式?

我希望解決方案可以是裝配或使用GCC內部函數?

我發現下面的鏈接,但不知道是否這是最好的方式去它(筆者也表示有一些錯誤):http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm.x86/2006-02/msg00123.html

編輯:注意,副本是必要的,我不能避開不必複製數據(我可以解釋爲什麼,但我會饒你的解釋:))

+0

你能寫你的代碼,所以副本不是必需的嗎? – Ron 2009-11-11 13:44:27

+0

Ron,不,我不能:( – horseyguy 2009-11-11 13:47:32

+1

如果你能得到英特爾編譯器的保留,你可能有更好的機會將優化器轉換成矢量cpu指令 – 2009-11-11 13:54:05

回答

38

致謝William Chan和Google。比快的memcpy在Microsoft Visual Studio 2005

void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size) 
{ 

    __asm 
    { 
    mov esi, src; //src pointer 
    mov edi, dest; //dest pointer 

    mov ebx, size; //ebx is our counter 
    shr ebx, 7;  //divide by 128 (8 * 128bit registers) 


    loop_copy: 
     prefetchnta 128[ESI]; //SSE2 prefetch 
     prefetchnta 160[ESI]; 
     prefetchnta 192[ESI]; 
     prefetchnta 224[ESI]; 

     movdqa xmm0, 0[ESI]; //move data from src to registers 
     movdqa xmm1, 16[ESI]; 
     movdqa xmm2, 32[ESI]; 
     movdqa xmm3, 48[ESI]; 
     movdqa xmm4, 64[ESI]; 
     movdqa xmm5, 80[ESI]; 
     movdqa xmm6, 96[ESI]; 
     movdqa xmm7, 112[ESI]; 

     movntdq 0[EDI], xmm0; //move data from registers to dest 
     movntdq 16[EDI], xmm1; 
     movntdq 32[EDI], xmm2; 
     movntdq 48[EDI], xmm3; 
     movntdq 64[EDI], xmm4; 
     movntdq 80[EDI], xmm5; 
     movntdq 96[EDI], xmm6; 
     movntdq 112[EDI], xmm7; 

     add esi, 128; 
     add edi, 128; 
     dec ebx; 

     jnz loop_copy; //loop please 
    loop_copy_end: 
    } 
} 

您可以去優化它進一步根據您的具體情況,你可以做任何假設30-70%。

您可能還想查看memcpy源(memcpy.asm)並去除其特殊情況處理。有可能進一步優化!

+6

注意:此memcopy的性能將大大取決於要複製的數據量和緩存大小。例如,與普通movdqa相比,預取和非暫時移動可能會使性能下降,以適應較小(適合L2)的副本。 – 2009-11-11 14:39:23

+2

banister:不要忘了給他發郵件說你在你的項目中使用了他的代碼;)[http://williamchan.ca/portfolio/assembly/ssememcpy/source/viewsource.php?id=readme.txt] – ardsrk 2009-11-11 14:48:22

+3

我記得先閱讀AMD64手冊中的這段代碼。代碼在英特爾上並不是最佳的,它存在緩存銀行別名問題。 – hirschhornsalz 2009-11-29 10:33:59

2

如果您使用的是Windows,使用DirectX的API,這對於圖形處理特定GPU - 優化程序(它的速度有多快?你的CPU沒有被加載,當GPU咀嚼它的時候做一些其他的事情)。

如果您想成爲操作系統不可知論者,請嘗試OpenGL

不要搗鼓彙編程序,因爲它很有可能會慘敗於超過10年以上的精通圖書館軟件工程師。

+1

更快,我需要它在MEMORY中執行,也就是說,它不會發生在GPU上。 :)另外,我自己並不打算超越庫函數(因此爲什麼我在這裏問這個問題),但我確定有人在stackoverflow上,誰可以勝過libs :)另外,庫編寫者通常是受限制的通過可移植性要求 - 正如我所說我只關心x86平臺,所以可能進一步x86特定的優化。 – horseyguy 2009-11-11 14:12:02

+0

+1,因爲這是首要的建議 - 即使它不適用於欄杆的情況。 – peterchen 2009-11-12 18:54:03

+1

我不確定這是不錯的建議。典型的現代機器具有與CPU和GPU相同的內存帶寬。例如,許多流行的筆記本電腦都使用英特爾高清顯卡,它使用與CPU相同的內存。 CPU可能已經飽和內存總線。對於memcpy,我希望CPU或GPU具有類似的性能。 – 2013-08-15 11:17:40

3

如果特定於英特爾處理器,則可能從IPP獲益。如果你知道它可以使用Nvidia GPU運行,也許你可以使用CUDA - 在這兩種情況下,最好比優化memcpy()更寬 - 它們提供了在更高級別上改進算法的機會。但它們都依賴於特定的硬件。

6

截至-O1以上任何優化級別,GCC將使用內置的定義,功能,如memcpy - 用(爲你所提到的功能集-march=pentium4)右-march參數應該產生相當的最佳體系結構相關的內嵌代碼。

我會對它進行基準測試,看看會發生什麼。

6

由hapalibashi發佈的SSE代碼是要走的路。

如果你需要更多的性能,並且不要回避編寫設備驅動程序的漫長而曲折的道路:現在所有重要的平臺都有一個DMA控制器,它能夠更快地完成複製任務與CPU代碼並行可以。

這涉及到編寫驅動程序。由於存在安全風險,我不知道如何將這種功能暴露給用戶方。

然而,它可能是值得的(如果您需要性能),因爲地球上的任何代碼都無法超越專爲執行此類工作而設計的硬件。

+1

我剛剛發佈了一個討論RAM帶寬的答案。如果我說的是真的,那麼我不認爲DMA引擎可以超越CPU所能達到的效果。我錯過了什麼嗎? – 2013-08-15 11:02:25

5

這個問題現在四歲了,我有點驚訝沒有人提到內存帶寬。 CPU-Z報告我的機器有PC3-10700 RAM。 RAM的峯值帶寬(又稱傳輸速率,吞吐量等)爲10700 MBytes/sec。我的機器中的CPU是一個i5-2430M CPU,其峯值turbo頻率爲3 GHz。理論上講,使用無限快的CPU和我的RAM,memcpy可以在5300 MBytes/sec,即10700的一半,因爲memcpy必須讀取然後寫入RAM。 (編輯:v.oddou指出,這是一個簡單的近似)。另一方面,想象一下,我們擁有無限快速的RAM和逼真的CPU,我們可以實現什麼?以我的3 GHz CPU爲例。如果每個週期可以執行32位讀取和32位寫入,則它可以傳輸3e9 * 4 = 12000兆字節/秒。這似乎很容易達到現代CPU。我們已經可以看到CPU上運行的代碼並不是真正的瓶頸。這是現代機器具有數據緩存的原因之一。

當我們知道數據被緩存時,我們可以通過對memcpy進行基準測試來測量CPU的真正功能。準確地做這件事很費勁。我做了一個簡單的應用程序,它將隨機數寫入數組,將它們memcpy到另一個數組,然後檢查複製的數據。我瀏覽了調試器中的代碼,以確保聰明的編譯器沒有刪除副本。改變數組的大小會改變緩存的性能 - 小數組適合高速緩存,大數組不太適合。我得到了以下的結果:

  • 40 K字節數組:16000兆字節/秒
  • 400 K字節的數組:11000兆字節/秒
  • 4000 K字節陣列:3100兆字節/秒

顯然,我的CPU每個週期可以讀寫32位以上,因爲16000比我在理論上計算的12000多。這意味着CPU比我想象的更不是瓶頸。我使用Visual Studio 2005,並進入標準的memcpy實現,我可以看到它在我的機器上使用了movqda指令。我想這可以讀寫每個週期64位。

在我的機器上發佈的漂亮代碼hapalibashi達到了4200 MBytes /秒 - 比VS 2005實現速度快大約40%。我猜它更快,因爲它使用預取指令來提高緩存性能。

總之,在CPU上運行的代碼不是瓶頸,並且調優代碼只會做出很小的改進。

+0

你的思考過程很好。然而,你沒有考慮RAM的市場推廣數量,這是所有四通道抽取的數字,與1通道的速度並不相符。而且這也是公交前的速度,核心i7/opterons在numa模型中也存在管理費用。 – 2013-10-30 08:03:05