尋找更快的記憶體拷貝方式

來源:互聯網
上載者:User

搜到這樣一篇文章【http://hi.baidu.com/_kouu/blog/item/c9761112ff2eca0b5baf5342.html】

比memcpy更快的記憶體拷貝2009-07-09 22:14

偶然間看到一個叫xmemcpy的工具,用做記憶體拷貝。號稱在拷貝120位元組以內時,比glibc提供的memcpy快10倍,並且有實驗資料。

這讓人感覺很詫異。一直以來都覺得memcpy是很高效的。相比於strcpy等函數的逐位元組拷貝,memcpy
是按照機器字長逐字進行拷貝的,一個字等於4(32位機)或8(64位機)個位元組。CPU存取一個位元組和存取一個字一樣,都是在一條指令、一個記憶體周期內
完成的。顯然,按字拷貝效率更高。

那麼,這個xmemcpy是靠什麼來實現比memcpy“快10倍”的呢?
看了一下xmemcpy的實現,原來它速度快的根據是:“小記憶體的拷貝,使用等號直接賦值比memcpy快得多”。
這下就更納悶了,記憶體拷貝不就是把一塊記憶體一部分一部分地拷貝到另一塊記憶體去嗎?難道逐字拷貝還有效能提升的空間?

寫了一段代碼:


}#include <stdio.h><br />#define TESTSIZE 128<br />struct node {<br />char buf[TESTSIZE];<br />};<br />void main()<br />{<br />char src[TESTSIZE] = {0};<br />char dst[TESTSIZE];<br />*(struct node*)dst = *(struct node*)src;<br />}
 


然後反組譯碼:

......<br />00000000004004a8 <main>:<br />4004a8: 55 push %rbp<br />4004a9: 48 89 e5 mov %rsp,%rbp<br />4004ac: 48 81 ec 00 01 00 00 sub $0x100,%rsp<br />4004b3: 48 8d 7d 80 lea 0xffffffffffffff80(%rbp),%rdi<br />4004b7: ba 80 00 00 00 mov $0x80,%edx<br />4004bc: be 00 00 00 00 mov $0x0,%esi<br />4004c1: e8 1a ff ff ff callq 4003e0 <memset@plt><br />4004c6: 48 8b 45 80 mov 0xffffffffffffff80(%rbp),%rax<br />4004ca: 48 89 85 00 ff ff ff mov %rax,0xffffffffffffff00(%rbp)<br />4004d1: 48 8b 45 88 mov 0xffffffffffffff88(%rbp),%rax<br />......<br />400564: 48 89 85 70 ff ff ff mov %rax,0xffffffffffffff70(%rbp)<br />40056b: 48 8b 45 f8 mov 0xfffffffffffffff8(%rbp),%rax<br />40056f: 48 89 85 78 ff ff ff mov %rax,0xffffffffffffff78(%rbp)<br />400576: c9 leaveq<br />400577: c3 retq<br />400578: 90 nop<br />......

再將libc反組譯碼,並找到memcpy的實現,以作比較:

......<br />0006b400 <memcpy>:<br />6b400: 8b 4c 24 0c mov 0xc(%esp),%ecx<br />6b404: 89 f8 mov %edi,%eax<br />6b406: 8b 7c 24 04 mov 0x4(%esp),%edi<br />6b40a: 89 f2 mov %esi,%edx<br />6b40c: 8b 74 24 08 mov 0x8(%esp),%esi<br />6b410: fc cld<br />6b411: d1 e9 shr %ecx<br />6b413: 73 01 jae 6b416 <memcpy+0x16><br />6b415: a4 movsb %ds:(%esi),%es:(%edi)<br />6b416: d1 e9 shr %ecx<br />6b418: 73 02 jae 6b41c <memcpy+0x1c><br />6b41a: 66 a5 movsw %ds:(%esi),%es:(%edi)<br />6b41c: f3 a5 repz movsl %ds:(%esi),%es:(%edi)<br />6b41e: 89 c7 mov %eax,%edi<br />6b420: 89 d6 mov %edx,%esi<br />6b422: 8b 44 24 04 mov 0x4(%esp),%eax<br />6b426: c3 ret<br />6b427: 90 nop<br />......

原來兩者都是通過逐字拷貝來實現的。但是“等號賦值”被編譯器翻譯成一連串的MOV指令,而memcpy則是一個迴圈。“等號賦值”比memcpy快,並不是快在拷貝方式上,而是快在程式流程上。
(另外,測試發現,“等號賦值”的長度必須小於等於128,並且是機器字長的倍數,才會被編譯成連續MOV形式,否則會被編譯成調用memcpy。當然,具體怎麼做是編譯器決定的。)

而為什麼同樣是按機器字長拷貝,連續的MOV指令就要比迴圈MOV快呢?
在迴圈方式下,每一次MOV過後,需要:1、判斷是否拷貝完成;2、跳轉以便繼續拷貝。
每拷貝一個字長,CPU就需要多執行以上兩個動作。

迴圈除了增加了判斷和跳轉指令以外,對於CPU處理流水產生的影響也是不可不計的。CPU將指令的執行分為若干個階段,組成一條指令處理流水線,這樣就能實現在一個CPU刻度完成一條指令,使得CPU的運算速度得以提升。
指令流水只能按照單一的指令路徑來執行,如果出現分支(判斷+跳轉),流水就沒法處理了。
為了緩解分支對於流水的影響,CPU可能會採取一定的分支預測策略。但是分支預測不一定就能成功,如果失敗,其損失比不預測還大。

所以,迴圈還是比較浪費的。如果效率要求很高,很多情況下,我們需要把迴圈展開(比如在本例中,每次迴圈拷貝N個位元組),以避免判斷與跳轉佔用大量的CPU時間。
這算是一種以空間換時間的做法。
GCC就有自動將迴圈展開的編譯選項(如
:-funroll-loops)。

但是,迴圈展開也是應該有個度的,並不是越展開越好(即使不考慮對空間的浪費)。因為CPU的快速執行很依賴於cache,如果cache不命中,CPU
將浪費不少的刻度在等待記憶體上(記憶體的速度一般比CPU低一個數量級)。而小段迴圈結構就比較有利於cache命中,因為重複執行的一段代碼很容易被
硬體放在cache中,這就是代碼局部性帶來的好處。而過度的迴圈展開就打破了代碼的局部性,所以xmemcpy一開始就提到拷貝120位元組以內。如果要
拷貝的位元組更多,則全部展開成連續的MOV指令的做法未必會很高效。



綜上所述,“等號賦值”之所以比memcpy快,就是因為它省略了CPU對於判斷與跳轉的處理,消除了分支對CPU流水的影響。而這一切都是通過適度展開記憶體拷貝的迴圈來實現的。

 

還有人說 strcpy 比 memcpy 要快

【http://wenda.tianya.cn/wenda/thread?tid=444a79853b705fe2】

memcpy strcpy哪個更快
匿名提問


2008-10-16 11:24:02

很奇怪,strcpy比memcpy快不少,在vc下strcpy 主要用的是通用算術寄存器EAX,EDX,也是基於機器字長的copymemcpy 主要用的是EDI,ESI,基於機器字長的copy,而且還有可能使用SSE2加速。 我個人開始總覺得應該memcpy快,因為可以成批傳送,而strcpy必須檢查是否到了串結束。但是實際測試的結果是,mempcy要慢很多今天測試一下哪個更快。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.