首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

linux中memecpy兑现

2013-07-04 
linux中memecpy实现1/*2 * arch/arm/boot/compressed/string.c3 *4 * Small subset of simple string rout

linux中memecpy实现
1/*
2 * arch/arm/boot/compressed/string.c
3 *
4 * Small subset of simple string routines
5 */
6
7#include <linux/string.h>
8
9void *memcpy(void *__dest, __const void *__src, size_t __n)
10{
11        int i = 0;
12        unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
13
14        for (i = __n >> 3; i > 0; i--) {
15                *d++ = *s++;
16                *d++ = *s++;
17                *d++ = *s++;
18                *d++ = *s++;
19                *d++ = *s++;
20                *d++ = *s++;
21                *d++ = *s++;
22                *d++ = *s++;
23        }
24
25        if (__n & 1 << 2) {
26                *d++ = *s++;
27                *d++ = *s++;
28                *d++ = *s++;
29                *d++ = *s++;
30        }
31
32        if (__n & 1 << 1) {
33                *d++ = *s++;
34                *d++ = *s++;
35        }
36
37        if (__n & 1)
38                *d++ = *s++;
39
40        return __dest;
41}


请问为什么采用这种实现方式,采用这种实现方式会提升效率么?为什么? memcpy 效率 arm
[解决办法]
减少for循环变量i递增和判断语句的开销。


------解决方案--------------------


循环展开优化,现在很多编译器可以自动做这一优化,不需要再这样写了。
[解决办法]

http://www.microsoft.com/visualstudio/chs/downloads#d-2010-express
点开Visual C++ 2010 Express下面的语言选‘简体中文’,再点立即安装


再参考Windows中memcpy实现:
C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\intel\memcpy.asm

[解决办法]

引用:
循环展开优化,现在很多编译器可以自动做这一优化,不需要再这样写了。
这样做还涉及内存对齐
不仅仅是循环展开优化 
不是很多编译器都能做到的
[解决办法]
引用:
Quote: 引用:

循环展开优化,现在很多编译器可以自动做这一优化,不需要再这样写了。
这样做还涉及内存对齐
不仅仅是循环展开优化 
不是很多编译器都能做到的


memcpy与内存对齐有什么关系?如果你是指处理字长的话,编译器比人脑擅长处理这种问题。
不手动把循环展开的原因还在于,由于具体机器不同,循环展开不一定是最优的代码,是否展开应该交给编译器去决定。

在x86机器上,串移动指令是比展开的循环更好的选择。

同时编译器也会自动处理字长问题。


  short src[100], dest[100];
    for( int i = 0; i < 100; ++ i )
    {
        dest[i] = src[i];
    }
 

在vs2008中,打开完全速度优化后,这段代码被编译为计数器为50的32位串移动指令。
而下面这段代码将会被编译为25次的循环,循环内部做了四组16位的内存读和内存写。不过好在它轮流使用ecx和edx寄存器,还可以在一定程度上把指令流水线的能力发挥出来

    short src[100], dest[100];
    for( int i = 0; i < 100; i += 4 )
    {
        dest[i] = src[i];
        dest[i+1] = src[i+1];
        dest[i+2] = src[i+2];
        dest[i+3] = src[i+3];
    }


编译结果:

0040102C  xor         eax,eax 
0040102E  mov         edi,edi 
00401030  movzx       ecx,word ptr [esp+eax+0D0h] 
00401038  movzx       edx,word ptr [esp+eax+0D2h] 
00401040  mov         word ptr [esp+eax+8],cx 
00401045  movzx       ecx,word ptr [esp+eax+0D4h] 
0040104D  mov         word ptr [esp+eax+0Ah],dx 
00401052  movzx       edx,word ptr [esp+eax+0D6h] 
0040105A  mov         word ptr [esp+eax+0Ch],cx 
0040105F  mov         word ptr [esp+eax+0Eh],dx 
00401064  add         eax,8 
00401067  cmp         eax,0C8h 
0040106C  jl          main+20h (401030h) 

而下面这段代码:更另人失望,很多指令都与前一指令相关,极大地阻碍了指令流水线的能力:

    short src[100], dest[100];
    short* psrc = src, *pdest=dest;


    for( int i = 0; i < 100; i += 4 )
    {
        *pdest ++ = *psrc++;
        *pdest ++ = *psrc++;
        *pdest ++ = *psrc++;
        *pdest ++ = *psrc++;
    }


编译结果:

00401030  movzx       esi,word ptr [ecx] 
00401033  mov         word ptr [eax],si 
00401036  movzx       esi,word ptr [ecx+2] 
0040103A  add         ecx,2 
0040103D  add         eax,2 
00401040  mov         word ptr [eax],si 
00401043  movzx       esi,word ptr [ecx+2] 
00401047  add         ecx,2 
0040104A  add         eax,2 
0040104D  mov         word ptr [eax],si 
00401050  movzx       esi,word ptr [ecx+2] 
00401054  add         ecx,2 
00401057  add         eax,2 
0040105A  mov         word ptr [eax],si 
0040105D  add         eax,2 
00401060  add         ecx,2 
00401063  sub         edx,1 
00401066  jne         main+20h (401030h) 


事实上,指令级优化是编译器的工作,我们没必要自己手工去完成——除非你再写汇编代码。我们只要做好算法级优化就可以了。

[解决办法]
memcpy是intrinsic,那个源码只是在非优化模式下的摆设。优化编译的时候memcpy的实现时编译器自己处理的。Haswell之前,x86上进行大数据块复制是肯定要用SIMD的。

热点排行