![]() |
#2
zklhp2011-05-15 20:32
代码 依次是主程序 优化函数的 和罗云彬大大的
![]() ;************************************************************************* ;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 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
;************************************************************************
;By zklhp
;Email:zklhp#(#==@) QQ:493165744
;版权所有 转载请保持完整
;************************************************************************
题目为嘛这么写呢 放我的结论给大家看看。。
经过测试 我得出的一点结论
1 对于内存复制来说 各种方法用时差别不大(只有百分之几)
2 所谓的MMX SSE2优化内存复制是不切实际的 因为经过测试提升很小 有时反而慢
3 movsd 和 movsd 区别不大(和我预计的不一样 原因不明)
4 大内存情况下 movsb性能稍好(和我预计的不一样 原因不明)
5 对于效率相关(或者说是极端优化)的程序 尽量减少内存的使用是王道
6 一般写程序(当然不是用汇编啦。。) 用环境自带的内存复制函数性能就很好 比
如用C memcpy就是最优选择 因为会有优化 而 使用什么所谓的SSE加速 收益很小
当然 如果是特定情况下 优化提升的这百分之几很关键 也可以用嘛。。。。
程序+源码 下载
只有本站会员才能查看附件,请 登录
某次测试的结果 不好发图片 你们可以自己试
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 编辑 ]