免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 11870 | 回复: 25
打印 上一主题 下一主题

我的memcpy还是不如标准库的厉害 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-12-28 17:36 |只看该作者 |倒序浏览

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <memory.h>

  4. #ifdef WIN32
  5.     #include <windows.h>
  6. #else
  7.     #include<sys/time.h>
  8.     #include<unistd.h>
  9. #endif

  10. double get_time_ms()
  11. {
  12. #ifdef WIN32
  13.     return (double)GetTickCount();
  14. #else
  15.     struct timeval tv;
  16.     struct timezone tz;
  17.     gettimeofday (&tv , &tz);
  18.     return tv.tv_sec * 1000 + tv.tv_usec / 1000 ;
  19. #endif
  20. }

  21. //这是微软公开的crt src文件夹内的源代码:
  22. void * memcpy_1 (void * dst, void * src , size_t n)
  23. {
  24.     void * ret = dst;
  25.     while (n--) {
  26.             *(char *)dst = *(char *)src;
  27.             dst = (char *)dst + 1;
  28.             src = (char *)src + 1;
  29.     }
  30.     return ret;
  31. }


  32. //这是我写的,按照最近流行的优化方式做的
  33. void * memcpy_2 (void * dst, void * src , size_t n)
  34. {
  35.     void * ret = dst;
  36.     size_t l = n>>2;
  37.     while (l--) {
  38.         *(size_t *)dst = *(size_t *)src;
  39.         dst = (size_t *)dst + 1;
  40.         src = (size_t *)src + 1;
  41.     }
  42.     l = n & 3;
  43.     while (l--) {
  44.         *(char *)dst = *(char *)src;
  45.         dst = (char *)dst + 1;
  46.         src = (char *)src + 1;
  47.     }
  48.     return ret;
  49. }

  50. void main(int argc, char ** argv)
  51. {
  52.     const int cstMemSize = 0x2FFFFFF;

  53.     if(argc<2)
  54.     {
  55.         printf("请输入参数 [ 0 | 1 | 2 | 3] ");
  56.         return ;
  57.     }

  58.     char * str  = (char*)malloc(cstMemSize);
  59.     char * str2 = (char*)malloc(cstMemSize+16);

  60.     size_t t1 = get_time_ms();

  61.     switch(argv[1][0])
  62.     {
  63.         case '0': memcpy(str, str2, cstMemSize );
  64.             break;
  65.         case '1': memcpy_1(str, str2, cstMemSize );
  66.             break;
  67.         case '2': memcpy_2(str, str2, cstMemSize );
  68.             break;
  69.         case '3': memcpy_2(str, str2+1, cstMemSize );  //考虑字节不对齐的情况
  70.             break;
  71.     }
  72.    
  73.    
  74.     double t2 = get_time_ms();
  75.     free(str);
  76.     free(str2);
  77.     printf("memset_%c %f\n", argv[1][0] ,t2-t1);

  78. }
复制代码


在windows xp/vc6环境下:

结果发现memcpy_1是最慢的,当然,这是串操作,当然很慢;
但是直接调用memcpy函数是最快的,这大概是微软在vc链接程序时做的优化.
而上面memcpy_2的效果一般般,比memcpy_1快,但是不如直接调用memcpy快.


在gcc/freebsd环境下,如果未加优化参数-O2,case '3'的情况速度更慢.我怀疑可能是字节不对齐带来的恶果.
不过,当开启了-O2后,4个case的测试时间差不多了.但是还是gcc自己的memset函数最快.

我现在怀疑,象(int *)这样的奇技淫巧如果使用不当,带来的效果不明显,还不如不用.现实情况是复杂的,编译器比我考虑的多的多.

论坛徽章:
0
2 [报告]
发表于 2006-12-28 17:45 |只看该作者
一般memcpy都是用废编写的呢
你怎么可能快得过它

论坛徽章:
0
3 [报告]
发表于 2006-12-28 17:48 |只看该作者
估计是人家使用了更优化的指令.

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
4 [报告]
发表于 2006-12-28 18:25 |只看该作者
呵呵,下面的代码,UV管道都计算的异常精确,通过判断是否支持sse等高级操作来加快效率。
当然效率极高。
补充一句:这是来自微软的代码,一个朋友给我的,似乎是VS 2007里面的。

  1.        page    ,132
  2.         title   memcpy - Copy source memory bytes to destination
  3. ;***
  4. ;memcpy.asm - contains memcpy and memmove routines
  5. ;
  6. ;       Copyright (c) Microsoft Corporation. All rights reserved.
  7. ;
  8. ;Purpose:
  9. ;       memcpy() copies a source memory buffer to a destination buffer.
  10. ;       Overlapping buffers are not treated specially, so propogation may occur.
  11. ;       memmove() copies a source memory buffer to a destination buffer.
  12. ;       Overlapping buffers are treated specially, to avoid propogation.
  13. ;
  14. ;*******************************************************************************

  15.         .xlist
  16.         include cruntime.inc
  17.         .list

  18. M_EXIT  macro
  19.         ret                     ; _cdecl return
  20.         endm    ; M_EXIT

  21.         CODESEG
  22.     extrn   _VEC_memcpy:near
  23.     extrn   __sse2_available:dword

  24. page
  25. ;***
  26. ;memcpy - Copy source buffer to destination buffer
  27. ;
  28. ;Purpose:
  29. ;       memcpy() copies a source memory buffer to a destination memory buffer.
  30. ;       This routine does NOT recognize overlapping buffers, and thus can lead
  31. ;       to propogation.
  32. ;       For cases where propogation must be avoided, memmove() must be used.
  33. ;
  34. ;       Algorithm:
  35. ;
  36. ;           Same as memmove. See Below
  37. ;
  38. ;
  39. ;memmove - Copy source buffer to destination buffer
  40. ;
  41. ;Purpose:
  42. ;       memmove() copies a source memory buffer to a destination memory buffer.
  43. ;       This routine recognize overlapping buffers to avoid propogation.
  44. ;       For cases where propogation is not a problem, memcpy() can be used.
  45. ;
  46. ;   Algorithm:
  47. ;
  48. ;       void * memmove(void * dst, void * src, size_t count)
  49. ;       {
  50. ;               void * ret = dst;
  51. ;
  52. ;               if (dst <= src || dst >= (src + count)) {
  53. ;                       /*
  54. ;                        * Non-Overlapping Buffers
  55. ;                        * copy from lower addresses to higher addresses
  56. ;                        */
  57. ;                       while (count--)
  58. ;                               *dst++ = *src++;
  59. ;                       }
  60. ;               else {
  61. ;                       /*
  62. ;                        * Overlapping Buffers
  63. ;                        * copy from higher addresses to lower addresses
  64. ;                        */
  65. ;                       dst += count - 1;
  66. ;                       src += count - 1;
  67. ;
  68. ;                       while (count--)
  69. ;                               *dst-- = *src--;
  70. ;                       }
  71. ;
  72. ;               return(ret);
  73. ;       }
  74. ;
  75. ;
  76. ;Entry:
  77. ;       void *dst = pointer to destination buffer
  78. ;       const void *src = pointer to source buffer
  79. ;       size_t count = number of bytes to copy
  80. ;
  81. ;Exit:
  82. ;       Returns a pointer to the destination buffer in AX/DX:AX
  83. ;
  84. ;Uses:
  85. ;       CX, DX
  86. ;
  87. ;Exceptions:
  88. ;*******************************************************************************
复制代码

后续

[ 本帖最后由 gvim 于 2006-12-28 18:34 编辑 ]

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
5 [报告]
发表于 2006-12-28 18:26 |只看该作者
接上


  1. ifdef MEM_MOVE
  2.         _MEM_     equ <memmove>
  3. else  ; MEM_MOVE
  4.         _MEM_     equ <memcpy>
  5. endif  ; MEM_MOVE

  6. %       public  _MEM_
  7. _MEM_   proc \
  8.         dst:ptr byte, \
  9.         src:ptr byte, \
  10.         count:IWORD

  11.               ; destination pointer
  12.               ; source pointer
  13.               ; number of bytes to copy

  14. ;       push    ebp             ;U - save old frame pointer
  15. ;       mov     ebp, esp        ;V - set new frame pointer

  16.         push    edi             ;U - save edi
  17.         push    esi             ;V - save esi

  18.         mov     esi,[src]       ;U - esi = source
  19.         mov     ecx,[count]     ;V - ecx = number of bytes to move

  20.         mov     edi,[dst]       ;U - edi = dest

  21. ;
  22. ; Check for overlapping buffers:
  23. ;       If (dst <= src) Or (dst >= src + Count) Then
  24. ;               Do normal (Upwards) Copy
  25. ;       Else
  26. ;               Do Downwards Copy to avoid propagation
  27. ;

  28.         mov     eax,ecx         ;V - eax = byte count...

  29.         mov     edx,ecx         ;U - edx = byte count...
  30.         add     eax,esi         ;V - eax = point past source end

  31.         cmp     edi,esi         ;U - dst <= src ?
  32.         jbe     short CopyUp    ;V - yes, copy toward higher addresses

  33.         cmp     edi,eax         ;U - dst < (src + count) ?
  34.         jb      CopyDown        ;V - yes, copy toward lower addresses

  35. ;
  36. ; Copy toward higher addresses.
  37. ;
  38. CopyUp:
  39. ;
  40. ; First, see if we can use a "fast" copy SSE2 routine
  41.         ; block size greater than min threshold?
  42.         cmp     ecx,0100h
  43.         jb      Dword_align
  44.         ; SSE2 supported?
  45.         cmp     DWORD PTR __sse2_available,0
  46.         je      Dword_align
  47.         ; alignments equal?
  48.         push    edi
  49.         push    esi
  50.         and     edi,15
  51.         and     esi,15
  52.         cmp     edi,esi
  53.         pop     esi
  54.         pop     edi
  55.         jne     Dword_align

  56.         ; do fast SSE2 copy, params already on stack
  57.         pop     esi
  58.         pop     edi
  59.         pop     ebp
  60.         jmp     _VEC_memcpy
  61.         ; no return
  62. ;
  63. ; The algorithm for forward moves is to align the destination to a dword
  64. ; boundary and so we can move dwords with an aligned destination.  This
  65. ; occurs in 3 steps.
  66. ;
  67. ;   - move x = ((4 - Dest & 3) & 3) bytes
  68. ;   - move y = ((L-x) >> 2) dwords
  69. ;   - move (L - x - y*4) bytes
  70. ;

  71. Dword_align:
  72.         test    edi,11b         ;U - destination dword aligned?
  73.         jnz     short CopyLeadUp ;V - if we are not dword aligned already, align

  74.         shr     ecx,2           ;U - shift down to dword count
  75.         and     edx,11b         ;V - trailing byte count

  76.         cmp     ecx,8           ;U - test if small enough for unwind copy
  77.         jb      short CopyUnwindUp ;V - if so, then jump

  78.         rep     movsd           ;N - move all of our dwords

  79.         jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

  80. ;
  81. ; Code to do optimal memory copies for non-dword-aligned destinations.
  82. ;

  83. ; The following length check is done for two reasons:
  84. ;
  85. ;    1. to ensure that the actual move length is greater than any possiale
  86. ;       alignment move, and
  87. ;
  88. ;    2. to skip the multiple move logic for small moves where it would
  89. ;       be faster to move the bytes with one instruction.
  90. ;

  91.         align   @WordSize
  92. CopyLeadUp:

  93.         mov     eax,edi         ;U - get destination offset
  94.         mov     edx,11b         ;V - prepare for mask

  95.         sub     ecx,4           ;U - check for really short string - sub for adjust
  96.         jb      short ByteCopyUp ;V - branch to just copy bytes

  97.         and     eax,11b         ;U - get offset within first dword
  98.         add     ecx,eax         ;V - update size after leading bytes copied

  99.         jmp     dword ptr LeadUpVec[eax*4-4] ;N - process leading bytes

  100.         align   @WordSize
  101. ByteCopyUp:
  102.         jmp     dword ptr TrailUpVec[ecx*4+16] ;N - process just bytes

  103.         align   @WordSize
  104. CopyUnwindUp:
  105.         jmp     dword ptr UnwindUpVec[ecx*4] ;N - unwind dword copy

  106.         align   @WordSize
  107. LeadUpVec       dd      LeadUp1, LeadUp2, LeadUp3

  108.         align   @WordSize
  109. LeadUp1:
  110.         and     edx,ecx         ;U - trailing byte count
  111.         mov     al,[esi]        ;V - get first byte from source

  112.         mov     [edi],al        ;U - write second byte to destination
  113.         mov     al,[esi+1]      ;V - get second byte from source

  114.         mov     [edi+1],al      ;U - write second byte to destination
  115.         mov     al,[esi+2]      ;V - get third byte from source

  116.         shr     ecx,2           ;U - shift down to dword count
  117.         mov     [edi+2],al      ;V - write third byte to destination

  118.         add     esi,3           ;U - advance source pointer
  119.         add     edi,3           ;V - advance destination pointer

  120.         cmp     ecx,8           ;U - test if small enough for unwind copy
  121.         jb      short CopyUnwindUp ;V - if so, then jump

  122.         rep     movsd           ;N - move all of our dwords

  123.         jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

  124.         align   @WordSize
  125. LeadUp2:
  126.         and     edx,ecx         ;U - trailing byte count
  127.         mov     al,[esi]        ;V - get first byte from source

  128.         mov     [edi],al        ;U - write second byte to destination
  129.         mov     al,[esi+1]      ;V - get second byte from source

  130.         shr     ecx,2           ;U - shift down to dword count
  131.         mov     [edi+1],al      ;V - write second byte to destination

  132.         add     esi,2           ;U - advance source pointer
  133.         add     edi,2           ;V - advance destination pointer

  134.         cmp     ecx,8           ;U - test if small enough for unwind copy
  135.         jb      short CopyUnwindUp ;V - if so, then jump

  136.         rep     movsd           ;N - move all of our dwords

  137.         jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

  138.         align   @WordSize
  139. LeadUp3:
  140.         and     edx,ecx         ;U - trailing byte count
  141.         mov     al,[esi]        ;V - get first byte from source

  142.         mov     [edi],al        ;U - write second byte to destination
  143.         add     esi,1           ;V - advance source pointer

  144.         shr     ecx,2           ;U - shift down to dword count
  145.         add     edi,1           ;V - advance destination pointer

  146.         cmp     ecx,8           ;U - test if small enough for unwind copy
  147.         jb      short CopyUnwindUp ;V - if so, then jump

  148.         rep     movsd           ;N - move all of our dwords

  149.         jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

  150.         align   @WordSize
  151. UnwindUpVec     dd      UnwindUp0, UnwindUp1, UnwindUp2, UnwindUp3
  152.                 dd      UnwindUp4, UnwindUp5, UnwindUp6, UnwindUp7

  153. UnwindUp7:
  154.         mov     eax,[esi+ecx*4-28] ;U - get dword from source
  155.                                    ;V - spare
  156.         mov     [edi+ecx*4-28],eax ;U - put dword into destination
  157. UnwindUp6:
  158.         mov     eax,[esi+ecx*4-24] ;U(entry)/V(not) - get dword from source
  159.                                    ;V(entry) - spare
  160.         mov     [edi+ecx*4-24],eax ;U - put dword into destination
  161. UnwindUp5:
  162.         mov     eax,[esi+ecx*4-20] ;U(entry)/V(not) - get dword from source
  163.                                    ;V(entry) - spare
  164.         mov     [edi+ecx*4-20],eax ;U - put dword into destination
  165. UnwindUp4:
  166.         mov     eax,[esi+ecx*4-16] ;U(entry)/V(not) - get dword from source
  167.                                    ;V(entry) - spare
  168.         mov     [edi+ecx*4-16],eax ;U - put dword into destination
  169. UnwindUp3:
  170.         mov     eax,[esi+ecx*4-12] ;U(entry)/V(not) - get dword from source
  171.                                    ;V(entry) - spare
  172.         mov     [edi+ecx*4-12],eax ;U - put dword into destination
  173. UnwindUp2:
  174.         mov     eax,[esi+ecx*4-8] ;U(entry)/V(not) - get dword from source
  175.                                   ;V(entry) - spare
  176.         mov     [edi+ecx*4-8],eax ;U - put dword into destination
  177. UnwindUp1:
  178.         mov     eax,[esi+ecx*4-4] ;U(entry)/V(not) - get dword from source
  179.                                   ;V(entry) - spare
  180.         mov     [edi+ecx*4-4],eax ;U - put dword into destination

  181.         lea     eax,[ecx*4]     ;V - compute update for pointer

  182.         add     esi,eax         ;U - update source pointer
  183.         add     edi,eax         ;V - update destination pointer
  184. UnwindUp0:
  185.         jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

  186. ;-----------------------------------------------------------------------------

  187.         align   @WordSize
  188. TrailUpVec      dd      TrailUp0, TrailUp1, TrailUp2, TrailUp3

  189.         align   @WordSize
  190. TrailUp0:
  191.         mov     eax,[dst]       ;U - return pointer to destination
  192.         pop     esi             ;V - restore esi
  193.         pop     edi             ;U - restore edi
  194.                                 ;V - spare
  195.         M_EXIT

  196.         align   @WordSize
  197. TrailUp1:
  198.         mov     al,[esi]        ;U - get byte from source
  199.                                 ;V - spare
  200.         mov     [edi],al        ;U - put byte in destination
  201.         mov     eax,[dst]       ;V - return pointer to destination
  202.         pop     esi             ;U - restore esi
  203.         pop     edi             ;V - restore edi
  204.         M_EXIT

  205.         align   @WordSize
  206. TrailUp2:
  207.         mov     al,[esi]        ;U - get first byte from source
  208.                                 ;V - spare
  209.         mov     [edi],al        ;U - put first byte into destination
  210.         mov     al,[esi+1]      ;V - get second byte from source
  211.         mov     [edi+1],al      ;U - put second byte into destination
  212.         mov     eax,[dst]       ;V - return pointer to destination
  213.         pop     esi             ;U - restore esi
  214.         pop     edi             ;V - restore edi
  215.         M_EXIT

  216.         align   @WordSize
  217. TrailUp3:
  218.         mov     al,[esi]        ;U - get first byte from source
  219.                                 ;V - spare
  220.         mov     [edi],al        ;U - put first byte into destination
  221.         mov     al,[esi+1]      ;V - get second byte from source
  222.         mov     [edi+1],al      ;U - put second byte into destination
  223.         mov     al,[esi+2]      ;V - get third byte from source
  224.         mov     [edi+2],al      ;U - put third byte into destination
  225.         mov     eax,[dst]       ;V - return pointer to destination
  226.         pop     esi             ;U - restore esi
  227.         pop     edi             ;V - restore edi
  228.         M_EXIT

  229. ;-----------------------------------------------------------------------------
  230. ;-----------------------------------------------------------------------------
  231. ;-----------------------------------------------------------------------------

  232. ;
  233. ; Copy down to avoid propogation in overlapping buffers.
  234. ;
  235.         align   @WordSize
  236. CopyDown:
  237.         lea     esi,[esi+ecx-4] ;U - point to 4 bytes before src buffer end
  238.         lea     edi,[edi+ecx-4] ;V - point to 4 bytes before dest buffer end
  239. ;
  240. ; See if the destination start is dword aligned
  241. ;

  242.         test    edi,11b         ;U - test if dword aligned
  243.         jnz     short CopyLeadDown ;V - if not, jump

  244.         shr     ecx,2           ;U - shift down to dword count
  245.         and     edx,11b         ;V - trailing byte count

  246.         cmp     ecx,8           ;U - test if small enough for unwind copy
  247.         jb      short CopyUnwindDown ;V - if so, then jump

  248.         std                     ;N - set direction flag
  249.         rep     movsd           ;N - move all of our dwords
  250.         cld                     ;N - clear direction flag back

  251.         jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

  252.         align   @WordSize
  253. CopyUnwindDown:
  254.         neg     ecx             ;U - negate dword count for table merging
  255.                                 ;V - spare

  256.         jmp     dword ptr UnwindDownVec[ecx*4+28] ;N - unwind copy

  257.         align   @WordSize
  258. CopyLeadDown:

  259.         mov     eax,edi         ;U - get destination offset
  260.         mov     edx,11b         ;V - prepare for mask

  261.         cmp     ecx,4           ;U - check for really short string
  262.         jb      short ByteCopyDown ;V - branch to just copy bytes

  263.         and     eax,11b         ;U - get offset within first dword
  264.         sub     ecx,eax         ;U - to update size after lead copied

  265.         jmp     dword ptr LeadDownVec[eax*4-4] ;N - process leading bytes

  266.         align   @WordSize
  267. ByteCopyDown:
  268.         jmp     dword ptr TrailDownVec[ecx*4] ;N - process just bytes

  269.         align   @WordSize
  270. LeadDownVec     dd      LeadDown1, LeadDown2, LeadDown3

  271.         align   @WordSize
  272. LeadDown1:
  273.         mov     al,[esi+3]      ;U - load first byte
  274.         and     edx,ecx         ;V - trailing byte count

  275.         mov     [edi+3],al      ;U - write out first byte
  276.         sub     esi,1           ;V - point to last src dword

  277.         shr     ecx,2           ;U - shift down to dword count
  278.         sub     edi,1           ;V - point to last dest dword

  279.         cmp     ecx,8           ;U - test if small enough for unwind copy
  280.         jb      short CopyUnwindDown ;V - if so, then jump

  281.         std                     ;N - set direction flag
  282.         rep     movsd           ;N - move all of our dwords
  283.         cld                     ;N - clear direction flag

  284.         jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

  285.         align   @WordSize
  286. LeadDown2:
  287.         mov     al,[esi+3]      ;U - load first byte
  288.         and     edx,ecx         ;V - trailing byte count

  289.         mov     [edi+3],al      ;U - write out first byte
  290.         mov     al,[esi+2]      ;V - get second byte from source

  291.         shr     ecx,2           ;U - shift down to dword count
  292.         mov     [edi+2],al      ;V - write second byte to destination

  293.         sub     esi,2           ;U - point to last src dword
  294.         sub     edi,2           ;V - point to last dest dword

  295.         cmp     ecx,8           ;U - test if small enough for unwind copy
  296.         jb      short CopyUnwindDown ;V - if so, then jump

  297.         std                     ;N - set direction flag
  298.         rep     movsd           ;N - move all of our dwords
  299.         cld                     ;N - clear direction flag

  300.         jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

  301.         align   @WordSize
  302. LeadDown3:
  303.         mov     al,[esi+3]      ;U - load first byte
  304.         and     edx,ecx         ;V - trailing byte count

  305.         mov     [edi+3],al      ;U - write out first byte
  306.         mov     al,[esi+2]      ;V - get second byte from source

  307.         mov     [edi+2],al      ;U - write second byte to destination
  308.         mov     al,[esi+1]      ;V - get third byte from source

  309.         shr     ecx,2           ;U - shift down to dword count
  310.         mov     [edi+1],al      ;V - write third byte to destination

  311.         sub     esi,3           ;U - point to last src dword
  312.         sub     edi,3           ;V - point to last dest dword

  313.         cmp     ecx,8           ;U - test if small enough for unwind copy
  314.         jb      CopyUnwindDown  ;V - if so, then jump

  315.         std                     ;N - set direction flag
  316.         rep     movsd           ;N - move all of our dwords
  317.         cld                     ;N - clear direction flag

  318.         jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

  319. ;------------------------------------------------------------------

  320.         align   @WordSize
  321. UnwindDownVec   dd      UnwindDown7, UnwindDown6, UnwindDown5, UnwindDown4
  322.                 dd      UnwindDown3, UnwindDown2, UnwindDown1, UnwindDown0

  323. UnwindDown7:
  324.         mov     eax,[esi+ecx*4+28] ;U - get dword from source
  325.                                    ;V - spare
  326.         mov     [edi+ecx*4+28],eax ;U - put dword into destination
  327. UnwindDown6:
  328.         mov     eax,[esi+ecx*4+24] ;U(entry)/V(not) - get dword from source
  329.                                    ;V(entry) - spare
  330.         mov     [edi+ecx*4+24],eax ;U - put dword into destination
  331. UnwindDown5:
  332.         mov     eax,[esi+ecx*4+20] ;U(entry)/V(not) - get dword from source
  333.                                    ;V(entry) - spare
  334.         mov     [edi+ecx*4+20],eax ;U - put dword into destination
  335. UnwindDown4:
  336.         mov     eax,[esi+ecx*4+16] ;U(entry)/V(not) - get dword from source
  337.                                    ;V(entry) - spare
  338.         mov     [edi+ecx*4+16],eax ;U - put dword into destination
  339. UnwindDown3:
  340.         mov     eax,[esi+ecx*4+12] ;U(entry)/V(not) - get dword from source
  341.                                    ;V(entry) - spare
  342.         mov     [edi+ecx*4+12],eax ;U - put dword into destination
  343. UnwindDown2:
  344.         mov     eax,[esi+ecx*4+8] ;U(entry)/V(not) - get dword from source
  345.                                    ;V(entry) - spare
  346.         mov     [edi+ecx*4+8],eax ;U - put dword into destination
  347. UnwindDown1:
  348.         mov     eax,[esi+ecx*4+4] ;U(entry)/V(not) - get dword from source
  349.                                   ;V(entry) - spare
  350.         mov     [edi+ecx*4+4],eax ;U - put dword into destination

  351.         lea     eax,[ecx*4]     ;V - compute update for pointer

  352.         add     esi,eax         ;U - update source pointer
  353.         add     edi,eax         ;V - update destination pointer
  354. UnwindDown0:
  355.         jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

  356. ;-----------------------------------------------------------------------------

  357.         align   @WordSize
  358. TrailDownVec    dd      TrailDown0, TrailDown1, TrailDown2, TrailDown3

  359.         align   @WordSize
  360. TrailDown0:
  361.         mov     eax,[dst]       ;U - return pointer to destination
  362.                                 ;V - spare
  363.         pop     esi             ;U - restore esi
  364.         pop     edi             ;V - restore edi
  365.         M_EXIT

  366.         align   @WordSize
  367. TrailDown1:
  368.         mov     al,[esi+3]      ;U - get byte from source
  369.                                 ;V - spare
  370.         mov     [edi+3],al      ;U - put byte in destination
  371.         mov     eax,[dst]       ;V - return pointer to destination
  372.         pop     esi             ;U - restore esi
  373.         pop     edi             ;V - restore edi
  374.         M_EXIT

  375.         align   @WordSize
  376. TrailDown2:
  377.         mov     al,[esi+3]      ;U - get first byte from source
  378.                                 ;V - spare
  379.         mov     [edi+3],al      ;U - put first byte into destination
  380.         mov     al,[esi+2]      ;V - get second byte from source
  381.         mov     [edi+2],al      ;U - put second byte into destination
  382.         mov     eax,[dst]       ;V - return pointer to destination
  383.         pop     esi             ;U - restore esi
  384.         pop     edi             ;V - restore edi
  385.         M_EXIT

  386.         align   @WordSize
  387. TrailDown3:
  388.         mov     al,[esi+3]      ;U - get first byte from source
  389.                                 ;V - spare
  390.         mov     [edi+3],al      ;U - put first byte into destination
  391.         mov     al,[esi+2]      ;V - get second byte from source
  392.         mov     [edi+2],al      ;U - put second byte into destination
  393.         mov     al,[esi+1]      ;V - get third byte from source
  394.         mov     [edi+1],al      ;U - put third byte into destination
  395.         mov     eax,[dst]       ;V - return pointer to destination
  396.         pop     esi             ;U - restore esi
  397.         pop     edi             ;V - restore edi
  398.         M_EXIT

  399. _MEM_   endp
  400.         end
复制代码

论坛徽章:
0
6 [报告]
发表于 2006-12-28 18:32 |只看该作者
  1. /*      $NetBSD: bcopy.c,v 1.6 1997/07/13 20:24:12 christos Exp $       */
  2. ...
  3. /*
  4. * Copy a block of memory, handling overlap.
  5. * This is the routine that actually implements
  6. * (the portable versions of) bcopy, memcpy, and memmove.
  7. */
  8. #ifdef MEMCOPY
  9. void *
  10. memcpy(dst0, src0, length)
  11. #else
  12. #ifdef MEMMOVE
  13. void *
  14. memmove(dst0, src0, length)
  15. #else
  16. void
  17. bcopy(src0, dst0, length)
  18. #endif
  19. #endif
  20.         void *dst0;
  21.         const void *src0;
  22.         register size_t length;
  23. {
  24.         register char *dst = dst0;
  25.         register const char *src = src0;
  26.         register size_t t;

  27.         if (length == 0 || dst == src)          /* nothing to do */
  28.                 goto done;

  29.         /*
  30.          * Macros: loop-t-times; and loop-t-times, t>0
  31.          */
  32. #define TLOOP(s) if (t) TLOOP1(s)
  33. #define TLOOP1(s) do { s; } while (--t)

  34.         if ((unsigned long)dst < (unsigned long)src) {
  35.                 /*
  36.                  * Copy forward.
  37.                  */
  38.                 t = (long)src;  /* only need low bits */
  39.                 if ((t | (long)dst) & wmask) {
  40.                         /*
  41.                          * Try to align operands.  This cannot be done
  42.                          * unless the low bits match.
  43.                          */
  44.                         if ((t ^ (long)dst) & wmask || length < wsize)
  45.                                 t = length;
  46.                         else
  47.                                 t = wsize - (t & wmask);
  48.                         length -= t;
  49.                         TLOOP1(*dst++ = *src++);
  50.                 }
  51.                 /*
  52.                  * Copy whole words, then mop up any trailing bytes.
  53.                  */
  54.                 t = length / wsize;
  55.                 TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
  56.                 t = length & wmask;
  57.                 TLOOP(*dst++ = *src++);
  58.         } else {
  59.                 /*
  60.                  * Copy backwards.  Otherwise essentially the same.
  61.                  * Alignment works as before, except that it takes
  62.                  * (t&wmask) bytes to align, not wsize-(t&wmask).
  63.                  */
  64.                 src += length;
  65.                 dst += length;
  66.                 t = (long)src;
  67.                 if ((t | (long)dst) & wmask) {
  68.                         if ((t ^ (long)dst) & wmask || length <= wsize)
  69.                                 t = length;
  70.                         else
  71.                                 t &= wmask;
  72.                         length -= t;
  73.                         TLOOP1(*--dst = *--src);
  74.                 }
  75.                 t = length / wsize;
  76.                 TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
  77.                 t = length & wmask;
  78.                 TLOOP(*--dst = *--src);
  79.         }
  80. done:
  81. #if defined(MEMCOPY) || defined(MEMMOVE)
  82.         return (dst0);
  83. #else
  84.         return;
  85. #endif
复制代码

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
7 [报告]
发表于 2006-12-28 18:37 |只看该作者
原帖由 langue 于 2006-12-28 18:32 发表
[code]/*      $NetBSD: bcopy.c,v 1.6 1997/07/13 20:24:12 christos Exp $       */
...
/*
* Copy a block of memory, handling overlap.
* This is the routine that actually implements
* (the por ...


NetBSD的代码注重跨平台,首先需要在他所支持的平台上都能编译,其次才是效率。
MS的代码注重效率,只需要在i386上,自然可以强力优化,比如优化UV流水线、借助SSE指令等,移植性为0
两种设计,很有意思。

评分

参与人数 1可用积分 +4 收起 理由
langue + 4

查看全部评分

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
8 [报告]
发表于 2006-12-28 19:17 |只看该作者

论坛徽章:
0
9 [报告]
发表于 2006-12-28 22:36 |只看该作者
这个算法用C写,不知编译器会怎样生成代码,倒不如直接用汇编
不考虑其它条件的话:
#define do_mem_copy(dest, src, size)                        \
        __asm__ __volatile__ ("movl %0, %%edi; movl %1, %%esi;                \
                movl %2, %%ecx; movl %%ecx, %%eax;        \
                shr $2, %%ecx; rep movsl;                \
                movl %%eax, %%ecx; andl $3, %%ecx;        \
                rep movsb"                                \
                :                                        \
                : "r" (dest), "r" (src), "r" (size)        \
        );


再看看 sun 在 Solaris 的实现:

        ENTRY(memcpy)
        movl        %edi,%edx        / save register variables
        pushl        %esi
        movl        8(%esp),%edi        / %edi = dest address
        movl        12(%esp),%esi        / %esi = source address
        movl        16(%esp),%ecx        / %ecx = length of string
        movl        %edi,%eax        / return value from the call

        shrl        $2,%ecx                / %ecx = number of words to move
        rep ; smovl                / move the words

        movl        16(%esp),%ecx        / %ecx = number of bytes to move
        andl        $0x3,%ecx        / %ecx = number of bytes left to move
        rep ; smovb                / move the bytes

        popl        %esi                / restore register variables
        movl        %edx,%edi
        ret
        SET_SIZE(memcpy)

论坛徽章:
0
10 [报告]
发表于 2006-12-28 23:26 |只看该作者
原帖由 gvim 于 2006-12-28 18:37 发表


NetBSD的代码注重跨平台,首先需要在他所支持的平台上都能编译,其次才是效率。
MS的代码注重效率,只需要在i386上,自然可以强力优化,比如优化UV流水线、借助SSE指令等,移植性为0
两种设计,很有意思。


确实是有趣的问题。

不过NetBSD也可以这么做,首先调查在哪些平台上用得比较多,然后针对这些平台上:
#ifdef _I686_
...
使用UV流水线
#ifdef _MMX_
使用mmx...
#ifdef _SSE_
使用sse...
...

不过代码就太不美观了。。。不可取,呵呵
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP