| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2404 人关注过本帖
标题:【转载】在物理内存中测试内存复制函数的小程序 SSE优化内存复制是假的!!!( ...
只看楼主 加入收藏
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
结帖率:100%
收藏
 问题点数:0 回复次数:10 
【转载】在物理内存中测试内存复制函数的小程序 SSE优化内存复制是假的!!!(WIN32汇编)
原帖 http://www.

;************************************************************************
;By zklhp
;Email:zklhp#(#==@)    QQ:493165744
;版权所有 转载请保持完整
;************************************************************************

题目为嘛这么写呢 放我的结论给大家看看。。

经过测试 我得出的一点结论

1 对于内存复制来说 各种方法用时差别不大(只有百分之几)

2 所谓的MMX SSE2优化内存复制是不切实际的 因为经过测试提升很小 有时反而慢

3 movsd 和 movsd 区别不大(和我预计的不一样 原因不明)

4 大内存情况下 movsb性能稍好(和我预计的不一样 原因不明)

5 对于效率相关(或者说是极端优化)的程序 尽量减少内存的使用是王道

6 一般写程序(当然不是用汇编啦。。) 用环境自带的内存复制函数性能就很好 比

如用C memcpy就是最优选择 因为会有优化 而 使用什么所谓的SSE加速 收益很小

当然 如果是特定情况下 优化提升的这百分之几很关键 也可以用嘛。。。。

程序+源码 下载

MemCopy_Test.zip (29.5 KB)


某次测试的结果 不好发图片 你们可以自己试

by zklhp   Email:zklhp#(#==@)  QQ:493165744
Usage:console 数据块长度(单位KB 即千字节) 循环次数
例如 console 10240 100 则分配10MB内存循环100次供测试
善意的提醒:测试程序强制性不高 数据块大小太大太小都不好 有可能出错的
注意:本程序需申请物理内存 需要锁定内存中页面的权限 如

AllocateUserPhysicalPages有1314错误则需启用
具体可以看MSDN:http://msdn.(中文的)
Allocated only 400000 pages.(1 page = 4096 bytes = 4 KB)
测试数据为两个 800000 KB的物理内存进行复制 结果如下:
***********************************************************
RtlMoveMemory           2446685 MicroSecond
memcpy                  2424361 MicroSecond
rep movsd               2424357 MicroSecond
rep movsb               2429301 MicroSecond
memcpy_sse2_align       2485165 MicroSecond
memcpyMMX               2511669 MicroSecond
SSE_Copy_16bytes_align  2476686 MicroSecond
***********************************************************
***********************************************************
RtlMoveMemory           2418823 MicroSecond
memcpy                  2429876 MicroSecond
rep movsd               2417805 MicroSecond
rep movsb               2415204 MicroSecond
memcpy_sse2_align       2478441 MicroSecond
memcpyMMX               2503898 MicroSecond
SSE_Copy_16bytes_align  2475844 MicroSecond
***********************************************************
***********************************************************
RtlMoveMemory           2414346 MicroSecond
memcpy                  2426489 MicroSecond
rep movsd               2420959 MicroSecond
rep movsb               2420464 MicroSecond
memcpy_sse2_align       2475373 MicroSecond
memcpyMMX               2507619 MicroSecond
SSE_Copy_16bytes_align  2475526 MicroSecond
***********************************************************
***********************************************************
RtlMoveMemory           2425497 MicroSecond
memcpy                  2417941 MicroSecond
rep movsd               2434072 MicroSecond
rep movsb               2413697 MicroSecond
memcpy_sse2_align       2474931 MicroSecond
memcpyMMX               2512142 MicroSecond
SSE_Copy_16bytes_align  2476819 MicroSecond
***********************************************************
***********************************************************
RtlMoveMemory           2418599 MicroSecond
memcpy                  2418517 MicroSecond
rep movsd               2413637 MicroSecond
rep movsb               2429412 MicroSecond
memcpy_sse2_align       2476802 MicroSecond
memcpyMMX               2505525 MicroSecond
SSE_Copy_16bytes_align  2480774 MicroSecond
***********************************************************
平均用时(整除的 不精确)依次为:
2424790 MicroSecond
2423436 MicroSecond
2422166 MicroSecond
2421615 MicroSecond
2478142 MicroSecond
2508170 MicroSecond
2477129 MicroSecond

1.6G的结果哦 我只有2G内存。。

关于AWE 可以看windows核心编程或MSDN相关章节 我把MSDN里面的例子代码打包了

这个AWE 我觉得挺靠谱(我尝试申请很大的物理内存 发现实际给的和任务管理器显

示的可用物理内存大小差不多 当然这个有待研究)

老规矩 欢迎板砖

[ 本帖最后由 zklhp 于 2011-5-15 20:34 编辑 ]
搜索更多相关主题的帖子: 版权所有 
2011-05-15 20:29
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
代码 依次是主程序 优化函数的 和罗云彬大大的

程序代码:

;*************************************************************************
;By zklhp
;Email:zklhp#(#==@)    QQ:493165744
;版权所有 转载请保持完整
;*************************************************************************

;MASMPlus 代码模板 - 控制台程序

.686
.MMX
.XMM
.model flat, stdcall
option casemap :none

include windows.inc
include user32.inc
include kernel32.inc
include advapi32.inc
include masm32.inc
include gdi32.inc

includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib advapi32.lib
includelib masm32.lib
includelib msvcrt.lib


include macro.asm

include _CmdLine.asm
include memcpy_sse2_align.asm

;C库函数挺好的
sscanf proto C hFile_IN:DWORD,lpszFormat_IN:DWORD,var_OUT:VARARG
memcpy proto C :DWORD,:DWORD,:DWORD

FUNCNUMBERS equ 7

.data?
    dwBufLen                dd ?
    dwTimes                dd ?
    dwPages                dd ?
    lpPages                dd ?
    lpMemReserved        dd ?
    lpBufSrc                dd ?
    lpBufDst                dd ?
    szBuf                    db 256 dup(?)
   
    time1 LARGE_INTEGER <>
    time2 LARGE_INTEGER <>
   
    times    LARGE_INTEGER FUNCNUMBERS dup(<>)
   
    sSysInfo SYSTEM_INFO <>
   
.CODE

;提权函数 不知道哪搞的
_EnablePrivilege proc szPriv:DWORD, bFlags:DWORD
   
    LOCAL hToken:DWORD
    LOCAL tkp:TOKEN_PRIVILEGES
   
    invoke GetCurrentProcess
    mov edx, eax
    invoke OpenProcessToken, edx, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr hToken
    mov ecx,szPriv
    invoke LookupPrivilegeValue, NULL, ecx, addr tkp.Privileges.Luid
    mov tkp.PrivilegeCount, 1
    xor eax, eax
    .if bFlags
        mov eax, SE_PRIVILEGE_ENABLED
    .endif
    mov tkp.Privileges.Attributes, eax
    invoke AdjustTokenPrivileges, hToken, FALSE, addr tkp, 0, 0, 0
    push eax
    invoke CloseHandle, hToken
    pop eax
    ret
   
_EnablePrivilege endp

;还可以自行补充类似的代码
;_lpDst _lpSrc 对应目的和源地址 _dwLen 单位字节
;这里面写的函数有些是已知或默认数据对齐的 和那些库函数比好像不公平 不过这个例子更多的是探讨大内存复制的情况 所以可以忽略不计。。
_MemCopy1 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    invoke RtlMoveMemory,edi,esi,ebx
    ;**********************************************************
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('RtlMoveMemory',09h,09h)
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+0]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+0],MM0        ;记得这里要改!!!
   
    ret
_MemCopy1 endp

_MemCopy2 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    invoke memcpy,edi,esi,ebx
    ;**********************************************************
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('memcpy',09h,09h,09h)
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+8]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+8],MM0        ;记得这里要改!!!
   
    ret
_MemCopy2 endp

_MemCopy3 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    mov ecx,ebx
    shr ecx,2
    rep movsd
    ;**********************************************************
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('rep movsd',09h,09h)
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+16]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+16],MM0        ;记得这里要改!!!
   
    ret
_MemCopy3 endp

_MemCopy4 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    mov ecx,ebx
    rep movsb
    ;**********************************************************961835
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('rep movsb',09h,09h)
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+24]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+24],MM0        ;记得这里要改!!!
   
    ret
_MemCopy4 endp

_MemCopy5 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    invoke memcpy_sse2_align,edi,esi,ebx
    ;**********************************************************
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('memcpy_sse2_align',09h)
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+32]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+32],MM0        ;记得这里要改!!!
   
    ret
_MemCopy5 endp

_MemCopy6 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    invoke memcpyMMX,edi,esi,ebx
    ;**********************************************************
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('memcpyMMX',09h,09h)
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+40]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+40],MM0        ;记得这里要改!!!
   
    ret
_MemCopy6 endp

_MemCopy7 proc uses ebx esi edi _lpDst,_lpSrc,_dwLen
   
    mov edi,_lpDst
    mov esi,_lpSrc
    mov ebx,_dwLen
    invoke QueryPerformanceCounter,offset time1
    ;**********************************************************
    invoke SSE_Copy_16bytes_align,edi,esi,ebx
    ;**********************************************************
    invoke QueryPerformanceCounter,offset time2
    invoke StdOut,CTXT('SSE_Copy_16bytes_align  ')
    mov ecx,time2.LowPart
    sub ecx,time1.LowPart
    mov ebx,ecx
    invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    lea esi,times
    movq MM0,QWORD ptr [esi+48]        ;记得这里要改!!!
    movd MM1,ebx
    paddq MM0,MM1
    movq QWORD ptr [esi+48],MM0        ;记得这里要改!!!
   
    ret
_MemCopy7 endp


START:
   
    invoke StdOut,CTXT("by zklhp   Email:zklhp#(#==@)  QQ:493165744",0dh,0ah)
    invoke StdOut,CTXT('Usage:')
    invoke _argv,0,offset szBuf,sizeof szBuf
    invoke StdOut,offset szBuf
    invoke StdOut,CTXT(' 数据块长度(单位KB 即千字节) 循环次数',0dh,0ah)
    invoke StdOut,CTXT('例如 console 10240 100 则分配10MB内存循环100次供测试',0dh,0ah)
    invoke StdOut,CTXT('善意的提醒:测试程序强制性不高 数据块太大太小都不好 有可能出错的',0dh,0ah)
    invoke StdOut,CTXT('注意:本程序需申请物理内存 需要锁定内存中页面的权限 如AllocateUserPhysicalPages有1314错误则需启用',0dh,0ah)
    invoke StdOut,CTXT('具体可以看MSDN:http://msdn.(中文的)',0dh,0ah)
   
    invoke _argc
    .if eax != 3
        invoke ExitProcess,-1
    .endif
   
    invoke _argv,1,offset szBuf,sizeof szBuf
    invoke sscanf,offset szBuf,CTXT('%d'),offset dwBufLen
    shl dwBufLen,10    ;单位字节
    invoke _argv,2,offset szBuf,sizeof szBuf
    invoke sscanf,offset szBuf,CTXT('%d'),offset dwTimes
   
    invoke GetSystemInfo,offset sSysInfo
    mov ecx,sSysInfo.dwPageSize
    mov eax,dwBufLen
    xor edx,edx
    div ecx
    mov dwPages,eax
    mov ebx,eax
    shl ebx,2
   
    invoke _EnablePrivilege,CTXT('SeLockMemoryPrivilege'),TRUE
   
    invoke VirtualAlloc,NULL,ebx,MEM_RESERVE or MEM_COMMIT,PAGE_EXECUTE_READWRITE        ;记得VirtualFree
    .if eax != NULL
        mov lpPages,eax
    .endif
   
    ;以下照抄MSDN里AWE例子程序
    invoke GetCurrentProcess
    mov ecx,eax
    invoke AllocateUserPhysicalPages,ecx,offset dwPages,lpPages
   
    .if eax != TRUE
        invoke GetLastError
        invoke wsprintf,offset szBuf,CTXT('AllocateUserPhysicalPages fail,GetLastError()=%d',0dh,0ah),eax
        invoke StdOut,offset szBuf
        invoke ExitProcess,-1
    .endif
   
    invoke wsprintf,offset szBuf,CTXT('Allocated only %d pages.(1 page = 4096 bytes = 4 KB)',0dh,0ah),dwPages
    invoke StdOut,offset szBuf
   
    invoke VirtualAlloc,NULL,dwBufLen,MEM_RESERVE or MEM_PHYSICAL,PAGE_READWRITE
   
    .if eax == 0
        invoke StdOut,CTXT('Cannot reserve memory.',0dh,0ah)
        invoke ExitProcess,-1
    .endif
    mov lpMemReserved,eax
   
    invoke MapUserPhysicalPages,lpMemReserved,dwPages,lpPages
   
    .if eax != TRUE
        invoke GetLastError
        invoke wsprintf,offset szBuf,CTXT('MapUserPhysicalPages fail,GetLastError()=%d',0dh,0ah),eax
        invoke StdOut,offset szBuf
        invoke ExitProcess,-1
    .endif
   
    ;到这里分配好了 分配的内存分两半 一半源一半目的
    ;根据页个数来的 也就是对齐到4K 如果是奇数就按少的来
    mov eax,lpMemReserved
    mov lpBufSrc,eax
    mov eax,dwPages
    shr eax,1
    mov ecx,sSysInfo.dwPageSize
    mul ecx
    mov ebx,eax        ;字节数 为分配内存的一半
    ;不会特别大。。
    add eax,lpMemReserved
    mov lpBufDst,eax
   
    ;可用可不用
    ;invoke RtlZeroMemory,lpMemReserved,ebx
    mov ecx,ebx
    shr ecx,10
    invoke wsprintf,offset szBuf,CTXT('测试数据为两个 %d KB的物理内存进行复制 结果如下:',0dh,0ah),ecx
    invoke StdOut,offset szBuf
   
    invoke RtlZeroMemory,offset times,FUNCNUMBERS * 8
   
    xor esi,esi
    .while esi < dwTimes
        ;开始调用测试函数
        invoke StdOut,CTXT('***********************************************************',0dh,0ah)
        invoke _MemCopy1,lpBufDst,lpBufSrc,ebx
        invoke _MemCopy2,lpBufDst,lpBufSrc,ebx
        invoke _MemCopy3,lpBufDst,lpBufSrc,ebx
        invoke _MemCopy4,lpBufDst,lpBufSrc,ebx
        invoke _MemCopy5,lpBufDst,lpBufSrc,ebx
        invoke _MemCopy6,lpBufDst,lpBufSrc,ebx
        invoke _MemCopy7,lpBufDst,lpBufSrc,ebx
        invoke StdOut,CTXT('***********************************************************',0dh,0ah)
        inc esi
    .endw
   
    invoke StdOut,CTXT('平均用时(整除的 不精确)依次为:',0dh,0ah)
   
    xor esi,esi
    lea edi,times
    .while esi < FUNCNUMBERS
       
        mov eax,[edi]
        mov edx,[edi+4]
        mov ecx,dwTimes
        div ecx
       
        invoke wsprintf,offset szBuf,CTXT('%d MicroSecond',0dh,0ah),eax
        invoke StdOut,offset szBuf
       
        add edi,8
        inc esi
    .endw
   
    ;释放物理内存
    invoke MapUserPhysicalPages,lpMemReserved,dwPages,NULL
   
    .if eax != TRUE
        invoke GetLastError
        invoke wsprintf,offset szBuf,CTXT('MapUserPhysicalPages fail,GetLastError()=%d',0dh,0ah),eax
        invoke ExitProcess,-1
    .endif
   
    invoke GetCurrentProcess
    mov ecx,eax
    invoke FreeUserPhysicalPages,ecx,offset dwPages,lpPages
   
    .if eax != TRUE
        invoke GetLastError
        invoke wsprintf,offset szBuf,CTXT('FreeUserPhysicalPages fail,GetLastError()=%d',0dh,0ah),eax
        invoke ExitProcess,-1
    .endif
   
    invoke VirtualFree,lpMemReserved,0,MEM_RELEASE
   
    invoke VirtualFree,lpPages,0,MEM_RELEASE
   
    invoke ExitProcess,0
   
end START



程序代码:

;前两个是网上找的 后面的一个用SSE2的是为了测试SSE对内存复制而定制的 和用movsb movsd的例子一样没有什么实际用处
.code
ALIGN 16
memcpy_sse2_align proc uses esi edi lpDst:DWORD,lpSrc:DWORD,nSize:DWORD
   
    mov edi,lpDst    ;dst
    mov esi,lpSrc    ;src
    mov ecx,nSize    ;count
    mov eax,ecx
    and eax,15        ; save the 16 unaligned bits
    shr ecx,04H       ; save num of double qua_dword

    cmp ecx,1         ;if so few , move it as Byte
    jg nextt
    jmp normal_copy2
nextt: 
    push esi          ;save addr of src
    push edi
    and esi,15        ;see if the src and dst addr can align
    and edi,15

    cmp esi,edi
    jne normal_mmx    ;if can't align use normal movdqu func
    xor edx,edx
    mov edx,16     
    sub edx,esi       ;(16-low 16 bit of addr) get the num of up_moving Bytes
    cmp eax,edx       ;if the low 16 bits is too small,we must borrow from aligned bits;
    jg not_add_sse2   ;now ignore eax == edx which makes eax = 0, we must deal with it before loop_down   
    add eax,16
    dec ecx
not_add_sse2:
    sub eax,edx       ;    eax maybe zero!
    pop edi
    pop esi           ;now edx keep up_moving Byte count; eax keeps down_moving Byte count;
    push ecx
loop_up_sse2:           ;we must move some bytes  before aligned_moving
    mov ecx,edx
    rep movsb
    pop ecx
loop_fast_sse2:         ;fast moving using movdqa
    movdqa XMM1,[esi]
    lea esi,[esi + 16]
    movdqa [edi],XMM1
    lea edi,[edi + 16]
    dec ecx
    jnz loop_fast_sse2

    cmp eax, 0 
    jne loop_down_sse2
    jmp done_align

loop_down_sse2:
    mov ecx,eax
    rep movsb
    jmp dword ptr done_align ; done all
normal_mmx:
    and esi,7
    and edi,7
    cmp esi,edi
    jne normal_dword
    xor edx,edx
    mov edx,8     
    sub edx,esi          ;(8-low 8 bit of addr) get the num of up_moving Bytes
    and eax,7
    cmp eax,edx          ;if the low 16 bits is too small,we must borrow from aligned bits;
    jg not_add_mmx       ;now ignore eax == edx which makes eax = 0, we must deal with it before loop_down   
    add eax,16
    dec ecx
not_add_mmx:
    sub eax,edx          ;    eax maybe zero!
    pop edi
    pop esi              ;now edx keep up_moving Byte count; eax keeps down_moving Byte count; ecx keeps fast_moving double qua_dword count
    push ecx             ;backup fast count
loop_up_mmx:               ;we must move some bytes  before aligned_moving
    mov ecx,edx
    rep movsb
    pop ecx
loop_fast_mmx:             ;fast moving using movdqa
    movq MM1,[esi]
    movq MM2,[esi + 8]
    lea esi,[esi + 16]
    movq [edi],MM1
    movq [edi + 8],MM2
    lea edi,[edi + 16]
    dec ecx
    jnz loop_fast_mmx

    cmp eax, 0
    jne loop_down_mmx 
    jmp done_align
loop_down_mmx:
    mov ecx,eax
    rep movsb
    jmp done_align; done all

normal_dword:
    and esi,3
    and edi,3
    cmp esi,edi
    jne normal_word
    xor edx,edx
    mov edx,4     
    sub edx,esi          ;(16-low 16 bit of addr) get the num of up_moving Bytes
    and eax,3
    shl ecx,2            ; transform it to be count of dword;
    cmp eax,edx          ;if the low 16 bits is too small,we must borrow from aligned bits;
    jg not_add_dword     ;now ignore eax == edx which makes eax = 0, we must deal with it before loop_down   
    add eax,4
    dec ecx
not_add_dword:

    sub eax,edx       ;    eax maybe zero!
    pop edi
    pop esi          ;now edx keep up_moving Byte count; eax keeps down_moving Byte count; ecx keeps fast_moving double qua_dword count
    push ecx;
loop_up_dword:               ;we must move some bytes  before aligned_moving
    mov ecx,edx
    rep movsb
    pop ecx
loop_fast_dword:            ;fast moving using movdqa
    rep movsd
    cmp eax, 0 
    je done_align
loop_down_dword:
    mov ecx,eax
    rep movsb
    jmp done_align; done all
normal_word:
    pop edi;here we deal with addr_unaligned moving;
    pop esi
loop_unalign:
loop_in:
    movq MM1,[esi]          ;the reason not use "rep movsd" or "movdqu" is that doing the same thing movq is the fastest when addr is unaligned
    movq MM2,[esi + 8]
    lea esi,[esi + 16]
    movq [edi],MM1
    movq [edi + 8],MM2
    lea edi,[edi + 16]
    dec ecx
    jnz loop_in
normal_copy2:
    shl ecx, 4
    add eax,ecx
    cmp eax,0
    je done_align
normal_loop2:
    mov ecx,eax
    rep movsb
done_align:
    ret
memcpy_sse2_align endp

memcpyMMX proc uses ebx esi edi dest,src,nCopySize
   
    mov ecx,nCopySize
    mov ebx,ecx
    and ebx,03fh
    shr ecx,6
    mov edi,dest
    mov esi,src
    cmp edi,esi
    jz mmM2
    jb mmM3
    ;if the memory block is to be moved forward,we start at the end of the block.
    ;if the memory block is to be moved backward,we start at the head of the block.
    mov eax,nCopySize
    lea esi,[esi+eax]
    lea edi,[edi+eax]
mmM4:
    or ecx,ecx
    jz mmM5
mmM6:
    movq MM0,[esi-8]
    movq MM1,[esi-10h]
    movq MM2,[esi-18h]
    movq MM3,[esi-20h]
    movq MM4,[esi-28h]
    movq MM5,[esi-30h]
    movq MM6,[esi-38h]
    movq MM7,[esi-40h]
    movq [edi-40h],MM7
    movq [edi-38h],MM6
    movq [edi-30h],MM5
    movq [edi-28h],MM4
    movq [edi-20h],MM3
    movq [edi-18h],MM2
    movq [edi-10h],MM1
    movq [edi-8],MM0
    sub esi,40h
    sub edi,40h
    loop mmM6
mmM5:
    mov ecx,ebx
    or ecx,ecx
    jz mmM2
    std
    dec esi
    dec edi
    rep movsb
    jmp mmM2
mmM3:
    or ecx,ecx
    jz mmM1
mmM:
    movq MM0,[esi]
    movq MM1,[esi+8]
    movq MM2,[esi+16]
    movq MM3,[esi+24]
    movq MM4,[esi+32]
    movq MM5,[esi+40]
    movq MM6,[esi+48]
    movq MM7,[esi+56]
    movq [edi+56],MM7
    movq [edi+48],MM6
    movq [edi+40],MM5
    movq [edi+32],MM4
    movq [edi+24],MM3
    movq [edi+16],MM2
    movq [edi+8],MM1
    movq [edi],MM0
    add esi,64
    add edi,64
    loop mmM
mmM1:
    mov ecx,ebx
    or ecx,ecx
    jz mmM2
    cld
    rep movsb
mmM2:
    ;emms
   
    ret
memcpyMMX endp

SSE_Copy_16bytes_align proc uses esi edi lpDst:DWORD,lpSrc:DWORD,nSize:DWORD
   
    mov ecx,nSize
    shr ecx,4
    @@:
    movdqa XMM1,[esi]
    add esi,16
    movdqa [edi],XMM1
    add edi,16
    dec ecx
    jnz @B
   
    ret
SSE_Copy_16bytes_align endp



程序代码:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming >
; by 罗云彬, http://asm.
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; _CmdLine.asm
; 命令行参数分析的通用子程序
; 功能:
; _argc ---> 对命令行参数进行数量统计
; _argv ---> 取某个命令行参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CHAR_BLANK    equ    20h    ;定义空格
CHAR_DELI    equ    '"'    ;定义分隔符
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 取命令行参数个数 (arg count)
; 参数个数必定大于等于 1, 参数 1 为当前执行文件名
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
_argc proc
        local    @dwArgc

        pushad
        mov    @dwArgc,0
        invoke    GetCommandLine
        mov    esi,eax
        cld
_argc_loop:
;********************************************************************
; 忽略参数之间的空格
;********************************************************************
        lodsb
        or    al,al
        jz    _argc_end
        cmp    al,CHAR_BLANK
        jz    _argc_loop
;********************************************************************
; 一个参数开始
;********************************************************************
        dec    esi
        inc    @dwArgc
_argc_loop1:
        lodsb
        or    al,al
        jz    _argc_end
        cmp    al,CHAR_BLANK
        jz    _argc_loop        ;参数结束
        cmp    al,CHAR_DELI
        jnz    _argc_loop1        ;继续处理参数内容
;********************************************************************
; 如果一个参数中的一部分有空格,则用 " " 包括
;********************************************************************
        @@:
        lodsb
        or    al,al
        jz    _argc_end
        cmp    al,CHAR_DELI
        jnz    @B
        jmp    _argc_loop1
_argc_end:
        popad
        mov    eax,@dwArgc
        ret

_argc        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 取指定位置的命令行参数
;  argv 0 = 执行文件名
;  argv 1 = 参数1 ...
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_argv        proc    _dwArgv,_lpReturn,_dwSize
        local    @dwArgv,@dwFlag

        pushad
        inc    _dwArgv
        mov    @dwArgv,0
        mov    edi,_lpReturn

        invoke    GetCommandLine
        mov    esi,eax
        cld
_argv_loop:
;********************************************************************
; 忽略参数之间的空格
;********************************************************************
        lodsb
        or    al,al
        jz    _argv_end
        cmp    al,CHAR_BLANK
        jz    _argv_loop
;********************************************************************
; 一个参数开始
; 如果和要求的参数符合,则开始复制到返回缓冲区
;********************************************************************
        dec    esi
        inc    @dwArgv
        mov    @dwFlag,FALSE
        mov    eax,_dwArgv
        cmp    eax,@dwArgv
        jnz    @F
        mov    @dwFlag,TRUE
        @@:
_argv_loop1:
        lodsb
        or    al,al
        jz    _argv_end
        cmp    al,CHAR_BLANK
        jz    _argv_loop        ;参数结束
        cmp    al,CHAR_DELI
        jz    _argv_loop2
        cmp    _dwSize,1
        jle    @F
        cmp    @dwFlag,TRUE
        jne    @F
        stosb
        dec    _dwSize
        @@:
        jmp    _argv_loop1        ;继续处理参数内容

_argv_loop2:
        lodsb
        or    al,al
        jz    _argv_end
        cmp    al,CHAR_DELI
        jz    _argv_loop1
        cmp    _dwSize,1
        jle    @F
        cmp    @dwFlag,TRUE
        jne    @F
        stosb
        dec    _dwSize
        @@:
        jmp    _argv_loop2
_argv_end:
        xor    al,al
        stosb
        popad
        ret

_argv        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


2011-05-15 20:32
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
自己顶 顺便吐槽一下论坛的访问速度和稳定性 反正在我这很感觉差。。。
2011-05-15 20:33
zaixuexi
Rank: 12Rank: 12Rank: 12
来 自:上海
等 级:火箭侠
威 望:8
帖 子:858
专家分:3233
注 册:2010-12-1
收藏
得分:0 
支持下zklp

技术问题,请不要以短消息方式提问
2011-05-15 20:49
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
以下是引用zaixuexi在2011-5-15 20:49:51的发言:

支持下zklp

谢谢!

欢迎批评
2011-05-15 20:53
zaixuexi
Rank: 12Rank: 12Rank: 12
来 自:上海
等 级:火箭侠
威 望:8
帖 子:858
专家分:3233
注 册:2010-12-1
收藏
得分:0 
写的很干净清楚,看着就很舒服,我准备打印下来学习

技术问题,请不要以短消息方式提问
2011-05-17 17:39
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
以下是引用zaixuexi在2011-5-17 17:39:58的发言:

写的很干净清楚,看着就很舒服,我准备打印下来学习

风格越好的代码 打印起来越废纸。。。
2011-05-17 22:08
Alar30
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:10
帖 子:988
专家分:1627
注 册:2009-9-8
收藏
得分:0 
长了一点
先收藏之
等手上的事儿忙完了再看哈。。
2011-05-18 15:17
xiaomarn
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:5
帖 子:348
专家分:2026
注 册:2009-3-18
收藏
得分:0 
好东西,收藏下先!

2011-05-18 20:03
hellovfp
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:禁止访问
威 望:30
帖 子:2976
专家分:7697
注 册:2009-7-21
收藏
得分:0 
有道理,MMX有提速的作用,SSE的可能就有点怀疑了。

我们都在路上。。。。。
2011-06-09 13:35
快速回复:【转载】在物理内存中测试内存复制函数的小程序 SSE优化内存复制是假的 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.064534 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved