找回密码
 欢迎注册
楼主: G-Spider

[原创] 【日积月累】优化小技巧

[复制链接]
发表于 2010-12-14 16:45:59 | 显示全部楼层
sorry。 以上指令确实是SSE4指令集。属于SSE4.1。
刚才在发帖前,我试图从手边的文档中查出PMINUD属于那个指令集,但没有得到答案,猜想应该是SSE2指令集,就按此发帖了。楼上一提醒,遂google了一下,果然发现是SSE4指令。请参照http://en.wikipedia.org/wiki/SSE4
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-12-14 16:50:30 | 显示全部楼层
假如SSE2有此指令,HugeCalc里的部分汇编会更精简。
所以看到老兄的帖子才比较敏感,有点疑惑。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-14 17:04:33 | 显示全部楼层
G-Spider 发表于 2010-12-14 13:12

之前的可能有点小不公平,第一个ebx是内存变量,之后的两个ebx是寄存器变量,修改了下,还是要快一点。

结果(时间可能不稳定,大致趋势如此):
  1. Elapsed time:0.121000 s
  2. Elapsed time:0.100000 s
  3. Elapsed time:0.098000 s
  4. result=8
复制代码
测试代码:
  1. #include <stdio.h>
  2. #include <time.h>

  3. int main()
  4. {
  5.         int i,j,result;
  6.         double  t1,t2,t3;
  7.         //测试1#################
  8.         result=0;
  9.         j=2009;        
  10.         t1=clock();
  11.         for(i=0;i<99990000;i+=2,j-=10)
  12.         {
  13.               result = (i < j) ? 6 : 8;
  14.         }
  15.         printf("Elapsed time: %f s\n",(clock()-t1)/CLOCKS_PER_SEC);
  16.         //printf("result=%d\n",result);
  17.         //测试2#################
  18.         result=0;
  19.         j=2009;
  20.         t2=clock();
  21.         for(i=0;i<99990000;i+=2,j-=10)
  22.         {
  23.              __asm
  24.              {
  25.                 xor ebx, ebx               
  26.                 mov eax, i
  27.                 cmp eax, j
  28.                 setl bl                                                                          
  29.                 dec ebx                     
  30.                 and ebx, 2  
  31.                 add ebx, 6
  32.                 mov result,ebx                       
  33.              }
  34.         }
  35.         
  36.         printf("Elapsed time: %f s\n",(clock()-t2)/CLOCKS_PER_SEC);
  37.         //printf("result=%d\n",result);

  38.         
  39.         //测试3#################
  40.         result=0;
  41.         j=2009;
  42.         t3=clock();
  43.         for(i=0;i<99990000;i+=2,j-=10)
  44.         {
  45.              __asm
  46.              {
  47.                 xor ebx, ebx
  48.                 mov eax, i
  49.                 cmp eax, j
  50.                 setge bl                  
  51.                 lea ebx, [ebx*2+6]
  52.                 mov result,ebx                     
  53.              }
  54.         }
  55.         
  56.         printf("Elapsed time: %f s\n",(clock()-t3)/CLOCKS_PER_SEC);
  57.         printf("result=%d\n",result);
  58.         system("Pause");
  59.         return 0;
  60. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-14 17:57:09 | 显示全部楼层
6# liangbch
有时间我也来试试.....
1.int型
2.float型
3.double型
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-14 20:45:42 | 显示全部楼层
Intel优化文档部分翻译   By  G-Spider 2010-12-14  不妥之处,欢迎指正。

http://blog.csdn.net/G_Spider

Software Prefetch Scheduling Distance
软件预取调度的距离

Determining the ideal prefetch placement in the code depends on many architecturalparameters, including: the amount of memory to be prefetched, cache lookuplatency, system memory latency, and estimate of computation cycle. The ideal
distance for prefetching data is processor- and platform-dependent. If the distance is too short, the prefetch will not hide the latency of the fetch behind computation. Ifthe prefetch is too far ahead, prefetched data may be flushed out of the cache by the time it is required.

在代码中确定理想的预取位置取决于许多结构性参数,其中包括:将预取的存储量,缓存查找延迟,系统内存延迟,和运算周期的估计。理想
预取数据的距离是处理器和平台相关的。如果距离太短,预取将不能掩盖背后的提取计算延迟。如果预取是过于超前,有用的预取数据可能被刷出缓存。

Since prefetch distance is not a well-defined metric, for this discussion, we define a new term, prefetch scheduling distance (PSD), which is represented by the number of iterations. For large loops, prefetch scheduling distance can be set to 1 (that is, schedule prefetch instructions one iteration ahead). For small loop bodies (that is, loop iterations with little computation), the prefetch scheduling distance must be more than one iteration.

由于预取距离不是一个明确的指标,为了讨论,我们定义一个新的术语,预取调度距离(PSD),它是由迭代的次数反映。对于大循环,调度预取距离可设置为1(即,预取指令附在第一次迭代前)。对于小的循环体(即有很少的循环迭代计算),预取距离必须调度不止一次迭代。

A simplified equation to compute PSD is deduced from the mathematical model. For a simplified equation, complete mathematical model, and methodology of prefetch distance determination, see Appendix E, “Summary of Rules and Suggestions.”

关于计算PSD的一个简化公式可由数学模型推导出。对于简化方程,完整的数学模型和预取方法距离测定,见附录E,“规则和建议摘要”。

Example 7-3 illustrates the use of a prefetch within the loop body. The prefetch scheduling distance is set to 3, ESI is effectively the pointer to a line, EDX is the address of the data being referenced and XMM1-XMM4 are the data used in computation. Example 7-4 uses two independent cache lines of data per iteration. The PSD would need to be increased/decreased if more/less than two cache lines are used per iteration.

例7-3说明了一个预取在循环体内的使用。预取调度距离(PSD)设置为3,ESI是有效的数据基指,EDX是数据的参考地址,XMM1 - XMM4存放计算中使用的数据。示例7-4每次迭代使用两个独立的数据高速缓存行。如果每次迭代使用多于/小于两个缓存行,PSD需要增加/减少。

例 7-3. 预取调度距离
top_loop:
prefetchnta [edx + esi + 128*3]
prefetchnta [edx*4 + esi + 128*3]
......
......
movaps xmm1, [edx + esi]
movaps xmm2, [edx*4 + esi]
movaps xmm3, [edx + esi + 16]
movaps xmm4, [edx*4 + esi + 16]
......
......
add esi, 128
cmp esi, ecx
jl top_loop
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-22 12:09:45 | 显示全部楼层
之前也看了些快速memcpy()的实现,经过亲自尝试,是乎都不尽人意......今又看到一兄台的文章,我笑了...

http://blog.csdn.net/OJOE/archive/2010/08/18/5819921.aspx

难道果真如这位兄台所说的:"使用MMS/SSE内存技术对memcpy的性能优化空间不太大,而且在执行初期,优化的性能甚至比不上未优化的性能。"

还有一些:
真的能成就30-70% faster 的提升?
Courtesy of William Chan and Google. 30-70% faster than memcpy in Microsoft Visual Studio 2005.
  1. void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size_t)
  2. {
  3.     __asm
  4.        {
  5.            mov esi, src;         //src pointer
  6.            mov edi, dest;        //dest pointer      
  7.            mov ebx, size_t;      //ebx is our counter      
  8.            shr ebx, 7;           //divide by 128 (8 * 128bit registers)
  9.                   
  10.        loop_copy:      
  11.             prefetchnta 128[ESI]; //SSE2 prefetch      
  12.             prefetchnta 160[ESI];      
  13.             prefetchnta 192[ESI];      
  14.             prefetchnta 224[ESI];
  15.                     
  16.             movdqa xmm0, 0[ESI]; //move data from src to registers      
  17.             movdqa xmm1, 16[ESI];      
  18.             movdqa xmm2, 32[ESI];      
  19.             movdqa xmm3, 48[ESI];      
  20.             movdqa xmm4, 64[ESI];      
  21.             movdqa xmm5, 80[ESI];      
  22.             movdqa xmm6, 96[ESI];      
  23.             movdqa xmm7, 112[ESI];
  24.                     
  25.             movntdq 0[EDI], xmm0; //move data from registers to dest      
  26.             movntdq 16[EDI], xmm1;      
  27.             movntdq 32[EDI], xmm2;      
  28.             movntdq 48[EDI], xmm3;      
  29.             movntdq 64[EDI], xmm4;      
  30.             movntdq 80[EDI], xmm5;      
  31.             movntdq 96[EDI], xmm6;      
  32.             movntdq 112[EDI], xmm7;        
  33.             add esi, 128;      
  34.             add edi, 128;      
  35.             dec ebx;        
  36.             jnz loop_copy; //loop please
  37.                
  38.             loop_copy_end:   
  39.        }
  40. }
复制代码
还有这个: 试了一下,似乎在intel上没有得到它所说的完美的性能提升,不过想法很好,应该取自:amd资料.
内存拷贝的优化方法
http://www.freegames.com.cn/school/383/2007/27312.html
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-23 12:09:01 | 显示全部楼层
经过测试发现,对于存拷贝,只有当数据量较大时,以M为单位的数据量时,SSE系列滴指令才突显优势。
Intel(R) Core (TM) 2 Duo CPU E8500 3.16GHz
测试151,885KB
_fast_memcpy9  (SSE)计算用时:
52 ms
49 ms
50 ms
49 ms
52 ms
_fast_memcpy1 (movsd)计算用时:
73 ms
71 ms
73 ms
72 ms
74 ms
---------------------------
测试63KB
_fast_memcpy9 (SSE)计算用时:
24 us
10 us
10 us
10 us
10 us
_fast_memcpy1 (movsd)计算用时:
6 us
6 us
6 us
6 us
6 us
--------------------------------
代码:
  1. ;ml  /c /coff memcpyTest.asm  
  2. ;link /subsystem:console memcpyTest.obj  ;5329 15044
  3. ;************************************************************
  4. .686p
  5. .XMM

  6. .model flat,stdcall
  7. option casemap:none

  8. include windows.inc
  9. include user32.inc
  10. include kernel32.inc
  11. include msvcrt.inc

  12. includelib user32.lib
  13. includelib kernel32.lib  
  14. includelib msvcrt.lib

  15. .data
  16. dwlm            dd      1000000 ;1000是毫秒为单位,1000000则是微秒为单位
  17. fmt             db      '计算用时:',0dh,0ah,0
  18. fmt1            db      '%6lld us',0dh,0ah,0

  19. ;szFileName      db     'xinyu.mkv',0    ;151,885KB 原文件
  20. ;szOutName       db     'output.mkv',0   ;输出文件;

  21. szFileName      db      'test.jpg',0    ;63KB   请以微秒为单位 原文件
  22. szOutName       db      'output.jpg',0   ;输出文件

  23. szPause         db      'Pause',0

  24. .data?
  25. hHandle         dd      ?
  26. hHandle1        dd      ?
  27. lpInputBuf      dd      ?
  28. lpOutputBuf     dd      ?
  29. dwStrlen        dd      ?
  30. lpNumberOfBytes dd      ?

  31. dwOldProcessP   dd      ?
  32. dwOldThreadP    dd      ?


  33. ;-------------------------------------
  34. dqTickCounter1  dq      ?
  35. dqTickCounter2  dq      ?
  36. dqFreq          dq      ?
  37. dqTime          dq      ?

  38. .code
  39. ;*************************************
  40. _fast_memcpy1   proc lpdst,lpsrc,dwlen

  41.         ;%define param esp+8+4
  42.         ;%define src param+0
  43.         ;%define dst param+4
  44.         ;%define len param+8
  45.         push esi
  46.         push edi

  47.         mov esi, lpsrc  ; source array
  48.         mov edi, lpdst  ; destination array
  49.         mov ecx, dwlen
  50.         shr ecx, 2      ; convert to DWORD count

  51.         rep movsd
  52.         pop edi
  53.         pop esi
  54.         xor     eax,eax
  55.         ret
  56. _fast_memcpy1   endp

  57. ;***************************************
  58. _fast_memcpy9  proc lpdst,lpsrc,dwlen
  59.         
  60.            mov esi, lpsrc;         //src pointer
  61.            mov edi, lpdst;        //dest pointer      
  62.            mov ebx, dwlen;      //ebx is our counter      
  63.            shr ebx, 7;           //divide by 128 (8 * 128bit registers)
  64.        ALIGN 8               
  65.        loop_copy:      
  66.             prefetchnta 128[ESI]; //SSE2 prefetch      
  67.             prefetchnta 160[ESI];      
  68.             prefetchnta 192[ESI];      
  69.             prefetchnta 224[ESI];
  70.                     
  71.             movdqa xmm0, 0[ESI]; //move data from src to registers      
  72.             movdqa xmm1, 16[ESI];      
  73.             movdqa xmm2, 32[ESI];      
  74.             movdqa xmm3, 48[ESI];      
  75.             movdqa xmm4, 64[ESI];      
  76.             movdqa xmm5, 80[ESI];      
  77.             movdqa xmm6, 96[ESI];      
  78.             movdqa xmm7, 112[ESI];
  79.                     
  80.             movntdq 0[EDI], xmm0; //move data from registers to dest      
  81.             movntdq 16[EDI], xmm1;      
  82.             movntdq 32[EDI], xmm2;      
  83.             movntdq 48[EDI], xmm3;      
  84.             movntdq 64[EDI], xmm4;      
  85.             movntdq 80[EDI], xmm5;      
  86.             movntdq 96[EDI], xmm6;      
  87.             movntdq 112[EDI], xmm7;        
  88.             add esi, 128;      
  89.             add edi, 128;      
  90.             dec ebx;        
  91.             jnz loop_copy; //loop please


  92.         xor eax,eax
  93.         ret
  94. _fast_memcpy9   endp


  95. ;*****************************************************
  96. start:
  97.         invoke  CreateFile,offset szFileName,GENERIC_READ,FILE_SHARE_READ,\
  98.                 NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
  99.         .if     eax == INVALID_HANDLE_VALUE
  100.                 invoke MessageBox,NULL,0,0,0
  101.         .endif
  102.         mov     hHandle,eax
  103.         
  104.         invoke  GetFileSize,eax,NULL
  105.         mov     dwStrlen,eax
  106.         add     eax,16
  107.         invoke  crt_malloc,eax
  108.         mov     lpInputBuf,eax
  109.         mov     edx,lpInputBuf
  110.         and     eax,0fh
  111.         jz      Good1
  112.         xor     eax,edx
  113.         add     eax,10h
  114.         mov     lpInputBuf,eax
  115.         
  116. Good1:

  117.         invoke  RtlZeroMemory,lpInputBuf,dwStrlen
  118.         invoke  ReadFile,hHandle,lpInputBuf,dwStrlen,offset lpNumberOfBytes,NULL
  119.         
  120.         mov     eax,dwStrlen
  121.         add     eax,16
  122.         invoke  crt_malloc,eax
  123.         mov     lpOutputBuf,eax
  124.         mov     edx,lpOutputBuf
  125.         and     eax,0fh
  126.         jz      Good2
  127.         xor     eax,edx
  128.         add     eax,10h
  129.         mov     lpOutputBuf,eax
  130. Good2:        
  131.         invoke  RtlZeroMemory,lpOutputBuf,dwStrlen

  132. ;----------------------------------------------------
  133.         invoke  crt_printf,offset fmt
  134.         mov     ecx,5   ;测试5次
  135. .while  ecx!=0
  136.         push  ecx
  137.         
  138.         invoke  GetCurrentProcess
  139.         invoke  GetPriorityClass,eax
  140.         mov     dwOldProcessP,eax
  141.         
  142.         invoke  GetCurrentThread
  143.         invoke  GetThreadPriority,eax
  144.         mov     dwOldThreadP,eax
  145.         
  146.         invoke  GetCurrentProcess
  147.         invoke  SetPriorityClass,eax,REALTIME_PRIORITY_CLASS
  148.         invoke  GetCurrentThread
  149.         invoke  SetThreadPriority,eax,THREAD_PRIORITY_TIME_CRITICAL
  150.         ;--------------------------------------------------
  151.         
  152.         invoke  QueryPerformanceCounter,addr dqTickCounter1
  153.         ;时间测试
  154.         ;invoke  _fast_memcpy1,lpOutputBuf,lpInputBuf,dwStrlen            
  155.         invoke  _fast_memcpy9,lpOutputBuf,lpInputBuf,dwStrlen  
  156.         ;测试结束
  157.         invoke  QueryPerformanceCounter,addr dqTickCounter2
  158.         invoke  QueryPerformanceFrequency,addr  dqFreq
  159.         mov     eax,dword ptr dqTickCounter1
  160.         mov     edx,dword ptr dqTickCounter1[4]      
  161.         sub     dword ptr dqTickCounter2,eax
  162.         sub     dword ptr dqTickCounter2[4],edx
  163.          
  164.         ;----------------------------------------------------   
  165.         ;优先级还原
  166.         invoke  GetCurrentThread
  167.         invoke  SetThreadPriority,eax,dwOldThreadP
  168.         
  169.         invoke  GetCurrentProcess
  170.         invoke  SetPriorityClass,eax, dwOldProcessP
  171.         
  172.             
  173.         finit
  174.         fild    dqFreq
  175.         fild    dqTickCounter2
  176.         fimul   dwlm
  177.         fdivr
  178.         fistp   dqTime  ;dqTime中的64位值就是时间间隔(以微秒为单位)
  179.         ;---------------------------------------------------
  180.         
  181. ;----------------------------------------------------      
  182.         invoke  crt_printf,offset fmt1,dqTime

  183.         pop      ecx
  184.         dec      ecx
  185. .endw
  186.         
  187.         ;输出copy文件        
  188.         invoke  CreateFile,offset szOutName,GENERIC_WRITE,FILE_SHARE_READ,\
  189.                 NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
  190.         .if     eax == INVALID_HANDLE_VALUE
  191.                 invoke MessageBox,NULL,0,0,0
  192.         .endif
  193.         mov     hHandle1,eax
  194.         invoke  WriteFile,eax,lpOutputBuf,dwStrlen,offset lpNumberOfBytes,NULL
  195.         
  196.         invoke  CloseHandle,hHandle
  197.         invoke  CloseHandle,hHandle1
  198.         
  199.         invoke  crt_system,offset szPause
  200.         invoke ExitProcess,0

  201. end start
  202.         
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-12-24 10:18:17 | 显示全部楼层
关于 memcpy 函数的优化,在intel 的官方文档
Intel @ 64 and IA-32 Architectures Optimization Reference Manual (更新日期:2009-11月)第7.7.2.4 Optimizing Memory Copy Routines 部分,能找出多种优化方式的代码。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-24 12:52:39 | 显示全部楼层
18# liangbch
嗯,看过。难于对细节的把握。
The memory copy algorithm can be optimized using the Streaming SIMD Extensions
with these considerations:
Alignment of data
Proper layout of pages in memory
Cache size
Interaction of the transaction lookaside buffer (TLB) with memory accesses
Combining prefetch and streaming-store instructions.

似乎movaps快一些,指令滴顺序也有影响....,指令体8字节对齐没有发现影响。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-24 22:13:05 | 显示全部楼层
17# G-Spider
有bug 更正(精确拷贝到字节),顺便加上硬预取方式,对于小字节量拷贝用movsd过渡。
测试平台:
cpu-26661.PNG
测试32.1 MB文件存拷贝:
_fast_memcpy1 (movsd)
33 ms
_fast_memcpy9  (SSE 系列)
23 ms
_block_prefetch  (硬预取 block_size 8KB)
22 ms
代码:
  1. ;************************************************************
  2. ;-==-: fast_memcpyTest  By G-Spider @2010
  3. ;-==-: ml  /c /coff memcpyTest.asm  
  4. ;-==-: link /subsystem:console memcpyTest.obj
  5. ;************************************************************
  6. .686p
  7. .XMM

  8. .model flat,stdcall
  9. option casemap:none

  10. include windows.inc
  11. include user32.inc
  12. include kernel32.inc
  13. include msvcrt.inc

  14. includelib user32.lib
  15. includelib kernel32.lib  
  16. includelib msvcrt.lib

  17. BLOCK_SIZE     equ  8192

  18. .data
  19. dwlm            dd      1000 ;1000是毫秒为单位,1000000则是微秒为单位
  20. fmt             db      '计算用时:',0dh,0ah,0
  21. fmt1            db      '%6lld ms',0dh,0ah,0

  22. szFileName      db      'xinyu.avi',0    ;32,954KB   原文件
  23. szOutName       db      'output.avi',0   ;输出文件;

  24. ;szFileName      db     'test.png',0    ;63KB   请以微秒为单位 原文件
  25. ;szOutName       db     'output.png',0   ;输出文件

  26. szPause         db      'Pause',0

  27. .data?
  28. hHandle         dd      ?
  29. hHandle1        dd      ?
  30. lpInputBuf      dd      ?
  31. lpOutputBuf     dd      ?
  32. dwStrlen        dd      ?
  33. lpNumberOfBytes dd      ?

  34. dwOldProcessP   dd      ?
  35. dwOldThreadP    dd      ?


  36. ;-------------------------------------
  37. dqTickCounter1  dq      ?
  38. dqTickCounter2  dq      ?
  39. dqFreq          dq      ?
  40. dqTime          dq      ?

  41. .code
  42. ;*************************************
  43. _fast_memcpy1   proc lpdst,lpsrc,dwlen

  44.         ;%define param esp+8+4
  45.         ;%define src param+0
  46.         ;%define dst param+4
  47.         ;%define len param+8

  48.         mov esi, lpsrc  ; source array
  49.         mov edi, lpdst  ; destination array
  50.         mov ecx, dwlen
  51.         mov eax,ecx
  52.         and eax,3
  53.         shr ecx, 2      ; convert to DWORD count
  54.         test ecx,ecx
  55.         jz   A000
  56.         rep movsd
  57. A000:
  58.         test eax,eax
  59.         jz A001
  60.         mov ecx,eax
  61.         rep movsb
  62. A001:       
  63.         xor eax,eax
  64.         ret
  65. _fast_memcpy1   endp

  66. ;***************************************
  67. _fast_memcpy9  proc lpdst,lpsrc,dwlen
  68.         
  69.            mov esi, lpsrc        ;src pointer
  70.            mov edi, lpdst        ;dest pointer      
  71.            mov ebx, dwlen        ;ebx is our counter
  72.            mov ecx, ebx
  73.            and ecx, 07fh         ;剩余的<128字节
  74.            shr ebx, 7                ;divide by 128 (8 * 128bit registers)
  75.            
  76.            test ebx,ebx
  77.            jz  A000
  78.            
  79.        ALIGN 16               
  80.        loop_copy:      
  81.             prefetchnta 128[ESI]; SSE2 prefetch      
  82.             prefetchnta 160[ESI];      
  83.             prefetchnta 192[ESI];      
  84.             prefetchnta 224[ESI];
  85.                     
  86.             movdqa xmm0, 0[ESI]        ; move data from src to registers      
  87.             movdqa xmm1, 16[ESI];      
  88.             movdqa xmm2, 32[ESI];      
  89.             movdqa xmm3, 48[ESI];      
  90.             movdqa xmm4, 64[ESI];      
  91.             movdqa xmm5, 80[ESI];      
  92.             movdqa xmm6, 96[ESI];      
  93.             movdqa xmm7, 112[ESI];
  94.                     
  95.             movntdq 0[EDI], xmm0 ; move data from registers to dest      
  96.             movntdq 16[EDI], xmm1;      
  97.             movntdq 32[EDI], xmm2;      
  98.             movntdq 48[EDI], xmm3;      
  99.             movntdq 64[EDI], xmm4;      
  100.             movntdq 80[EDI], xmm5;      
  101.             movntdq 96[EDI], xmm6;      
  102.             movntdq 112[EDI], xmm7;        
  103.             add esi, 128;      
  104.             add edi, 128;      
  105.             dec ebx;        
  106.             jnz loop_copy; //loop please
  107.             sfence
  108.         align 16   
  109.         A000:       
  110.                 mov eax, ecx
  111.                 and eax, 3
  112.                           
  113.                 shr ecx, 2      ; co[local]1[/local]nvert to DWORD count
  114.                 test ecx,ecx
  115.                 jz short A001
  116.                 rep movsd
  117.         A001:
  118.                 test eax,eax
  119.                 jz   A002
  120.                 mov  ecx,eax
  121.                 rep  movsb
  122.                
  123.         A002:       
  124.                 xor eax,eax
  125.                 ret

  126. _fast_memcpy9   endp



  127. _block_prefetch   proc lpdst,lpsrc,dwlen

  128.         mov  edi, lpdst
  129.         mov  esi, lpsrc
  130.         mov  eax, dwlen
  131.         mov  edx, eax
  132.         and  eax, (BLOCK_SIZE-1) ;4096-1=0fffh ;8192-1=1fffh;16*1024-1=3fffh
  133.        
  134.         and  edx, 0ffffe000h     ;与 BLOCK_SIZE有关
  135.         test edx,edx
  136.         jz  A000

  137.         align 16
  138. main_loop:
  139.         xor ecx,ecx
  140.         align 16
  141. prefetch_loop:
  142.         movaps xmm0, [esi+ecx]
  143.         movaps xmm0, [esi+ecx+64]
  144.         add ecx,128
  145.         cmp ecx,BLOCK_SIZE
  146.         jne prefetch_loop
  147.        
  148.         xor ecx,ecx
  149.         align 16
  150.         cpy_loop:
  151.         movdqa xmm0,[esi+ecx]
  152.         movdqa xmm1,[esi+ecx+16]
  153.         movdqa xmm2,[esi+ecx+32]
  154.         movdqa xmm3,[esi+ecx+48]
  155.         movdqa xmm4,[esi+ecx+64]
  156.         movdqa xmm5,[esi+ecx+16+64]
  157.         movdqa xmm6,[esi+ecx+32+64]
  158.         movdqa xmm7,[esi+ecx+48+64]
  159.        
  160.         movntdq [edi+ecx],xmm0
  161.         movntdq [edi+ecx+16],xmm1
  162.         movntdq [edi+ecx+32],xmm2
  163.         movntdq [edi+ecx+48],xmm3
  164.         movntdq [edi+ecx+64],xmm4
  165.         movntdq [edi+ecx+80],xmm5
  166.         movntdq [edi+ecx+96],xmm6
  167.         movntdq [edi+ecx+112],xmm7
  168.         add ecx,128
  169.         cmp ecx,BLOCK_SIZE
  170.         jne cpy_loop
  171.        
  172.         add esi,ecx
  173.         add edi,ecx
  174.         sub edx,ecx
  175.         jnz main_loop
  176.        
  177.         sfence
  178. align 16       
  179. A000:       
  180.         mov ecx, eax
  181.         and eax, 3
  182.                   
  183.         shr ecx, 2      ; convert to DWORD count
  184.         test ecx,ecx
  185.         jz short A001
  186.         rep movsd
  187. A001:
  188.         test eax,eax
  189.         jz   A002
  190.         mov  ecx,eax
  191.         rep  movsb
  192.        
  193. A002:       
  194.         xor eax,eax
  195.         ret

  196. _block_prefetch endp

  197. ;*****************************************************
  198. start:
  199.         invoke  CreateFile,offset szFileName,GENERIC_READ,FILE_SHARE_READ,\
  200.                 NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
  201.         .if     eax == INVALID_HANDLE_VALUE
  202.                 invoke MessageBox,NULL,0,0,0
  203.         .endif
  204.         mov     hHandle,eax
  205.         
  206.         invoke  GetFileSize,eax,NULL
  207.         mov     dwStrlen,eax
  208.         add     eax,16
  209.         invoke  crt_malloc,eax
  210.         mov     lpInputBuf,eax
  211.         mov     edx,lpInputBuf
  212.         and     eax,0fh
  213.         jz      Good1
  214.         xor     eax,edx
  215.         add     eax,10h
  216.         mov     lpInputBuf,eax
  217.         
  218. Good1:

  219.         invoke  RtlZeroMemory,lpInputBuf,dwStrlen
  220.         invoke  ReadFile,hHandle,lpInputBuf,dwStrlen,offset lpNumberOfBytes,NULL
  221.         
  222.         mov     eax,dwStrlen
  223.         add     eax,16
  224.         invoke  crt_malloc,eax
  225.         mov     lpOutputBuf,eax
  226.         mov     edx,lpOutputBuf
  227.         and     eax,0fh
  228.         jz      Good2
  229.         xor     eax,edx
  230.         add     eax,10h
  231.         mov     lpOutputBuf,eax
  232. Good2:        
  233.         invoke  RtlZeroMemory,lpOutputBuf,dwStrlen

  234. ;----------------------------------------------------
  235.         invoke  crt_printf,offset fmt
  236.         mov     ecx,5   ;测试5次
  237. .while  ecx!=0
  238.         push  ecx
  239.         
  240.         invoke  GetCurrentProcess
  241.         invoke  GetPriorityClass,eax
  242.         mov     dwOldProcessP,eax
  243.         
  244.         invoke  GetCurrentThread
  245.         invoke  GetThreadPriority,eax
  246.         mov     dwOldThreadP,eax
  247.         
  248.         invoke  GetCurrentProcess
  249.         invoke  SetPriorityClass,eax,REALTIME_PRIORITY_CLASS
  250.         invoke  GetCurrentThread
  251.         invoke  SetThreadPriority,eax,THREAD_PRIORITY_TIME_CRITICAL
  252.         ;--------------------------------------------------
  253.         
  254.         invoke  QueryPerformanceCounter,addr dqTickCounter1
  255.         ;时间测试
  256.         ;invoke  _fast_memcpy1,lpOutputBuf,lpInputBuf,dwStrlen            
  257.         ;invoke  _fast_memcpy9,lpOutputBuf,lpInputBuf,dwStrlen
  258.         invoke  _block_prefetch,lpOutputBuf,lpInputBuf,dwStrlen
  259.         
  260.         ;测试结束
  261.         invoke  QueryPerformanceCounter,addr dqTickCounter2
  262.         invoke  QueryPerformanceFrequency,addr  dqFreq
  263.         mov     eax,dword ptr dqTickCounter1
  264.         mov     edx,dword ptr dqTickCounter1[4]      
  265.         sub     dword ptr dqTickCounter2,eax
  266.         sub     dword ptr dqTickCounter2[4],edx
  267.          
  268.         ;----------------------------------------------------   
  269.         ;优先级还原
  270.         invoke  GetCurrentThread
  271.         invoke  SetThreadPriority,eax,dwOldThreadP
  272.         
  273.         invoke  GetCurrentProcess
  274.         invoke  SetPriorityClass,eax, dwOldProcessP
  275.         
  276.             
  277.         finit
  278.         fild    dqFreq
  279.         fild    dqTickCounter2
  280.         fimul   dwlm
  281.         fdivr
  282.         fistp   dqTime  ;dqTime中的64位值就是时间间隔(以微秒为单位)
  283.         ;---------------------------------------------------
  284.             
  285.         invoke  crt_printf,offset fmt1,dqTime

  286.         pop      ecx
  287.         dec      ecx
  288. .endw
  289.         
  290.         ;输出copy文件        
  291.         invoke  CreateFile,offset szOutName,GENERIC_WRITE,FILE_SHARE_READ,\
  292.                 NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
  293.         .if     eax == INVALID_HANDLE_VALUE
  294.                 invoke MessageBox,NULL,0,0,0
  295.         .endif
  296.         mov     hHandle1,eax
  297.         invoke  WriteFile,eax,lpOutputBuf,dwStrlen,offset lpNumberOfBytes,NULL
  298.         
  299.         invoke  CloseHandle,hHandle
  300.         invoke  CloseHandle,hHandle1
  301.         
  302.         invoke  crt_system,offset szPause
  303.         invoke ExitProcess,0

  304. end start
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-4-26 04:43 , Processed in 0.047544 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表