免费注册 查看新帖 |

Chinaunix

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

[C] 我用C语言实现的memcpy算法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-04-30 12:55 |只看该作者 |倒序浏览
这是我的一个开源程序库的其中一个函数(http://gforge.osdn.net.cn/frs/?group_id=86
程序源码如下:

typedef  unsigned char  ylib_byte_t;
typedef  unsigned int   ylib_word_t;

enum YOUNG_LIBRARY_MEMORY_FUNCTION_CONSTANT
{
    /* 循环展开的次数 */
    OUTSPREAD = 16,

    /* 最大余数,先将其按位取反,再与整数 N 按位与,
     * 可得最接近 N 的 OUTSPREAD 的倍数 */
    RESIDUE = OUTSPREAD - 1
};

#define  CYCLE_OUTSPREAD( expression ) \
         expression;  expression;  expression;  expression; \
         expression;  expression;  expression;  expression; \
         expression;  expression;  expression;  expression; \
         expression;  expression;  expression;  expression;

    void* ylib_memcopy( void* dst, const void* src, size_t count )
    {
        ylib_byte_t *d, *s;
        ylib_word_t* dstword = (ylib_word_t*)dst;
        const ylib_word_t* srcword = (const ylib_word_t*)src;
        size_t tmp, word_count = count / sizeof(ylib_word_t);
        size_t word_outspread = word_count & ~((size_t)RESIDUE);

        /* 复制可被循环展开的机器字 */
        for( tmp = 0; tmp < word_outspread; tmp += OUTSPREAD )
        {
            CYCLE_OUTSPREAD( *dstword++ = *srcword++ )
        }

        /* 复制剩下的机器字 */
        for( ; tmp < word_count; ++tmp )
            *dstword++ = *srcword++;

        /* 复制剩下的字节 */
        d = (ylib_byte_t*)dstword;
        s = (ylib_byte_t*)srcword;
        for( tmp *= sizeof(ylib_word_t); tmp < count; ++tmp )
            *d++ = *s++;

        return dst;
    }

void test_memcpy(void)
{
    double sec;
    clock_t begin, end;
    int i, dst[10000];
    int src[10000];

    begin = clock();
    for( i = 0; i < 100000; ++i )
        ylib_memcopy( dst, src, sizeof(int) * 10000 );
    end = clock();
    sec = (double)(end - begin) / (double)CLOCKS_PER_SEC;
    printf( "\nylib_memcopy time = %f\n", sec );

    begin = clock();
    for( i = 0; i < 100000; ++i )
        memcpy( dst, src, sizeof(int) * 10000 );
    end = clock();
    sec = (double)(end - begin) / (double)CLOCKS_PER_SEC;
    printf( "\nmemcpy time = %f\n", sec );
}

比VC6.0的稍快(用默认的release设置编译): 1.078 VS 1.109
比VC7.1的慢大概1/4(用默认的release设置编译): 1.078 VS 0.813
比DEV-CPP4.9.9.2慢近一倍(-O2 优化) : 1.093 VS 0.532

[ 本帖最后由 phoneix 于 2007-4-30 12:57 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-04-30 12:58 |只看该作者
memcpy( dst, src, sizeof(int) * 10000 );

10000*4 == 39 K

很少需要一次这么多的复制,很少很少。

应该统计一下 你的10000编成10会怎么样,100又会如何。找到一个点和标准库的实现一样

论坛徽章:
0
3 [报告]
发表于 2007-04-30 13:00 |只看该作者
你这个也不会比memcpy快。

你有比较结果?

论坛徽章:
0
4 [报告]
发表于 2007-04-30 13:08 |只看该作者
#include<string.h>
#include<stdlib.h>
char buf1[4096*10];
char buf2[4096*10];
int main()
{
        int i = 0;
        while(i++ < 100000)
                memcpy(buf1,buf2,4096*10);
        exit(0);
}
gcc编译 P4 3.0 0.5秒

论坛徽章:
0
5 [报告]
发表于 2007-04-30 13:08 |只看该作者
效率与每次拷贝的大小有关。
你测试一下每次1, 4, 8, 16, 32, 64, 128...字节时效率如何。

论坛徽章:
0
6 [报告]
发表于 2007-04-30 13:10 |只看该作者
测试程序和结果
是memcpy速度的1/3多点。

其实你根本不应该写这样的程序。因为你是用C复制*dst = *src的循环,怎么能和优化为最快机器串操作指令比速度?


./a.out
src[AFFEC008], dst[A7FEB008], start :
4480000
1850000




  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <time.h>
  4. #include <stdlib.h>


  5. /*
  6. void *  mmcp(void*, const void*, size_t);

  7. void *  mmcp(void* dst, const void *src, size_t size)
  8. {
  9.         typedef struct {char bytes[size]; } buffer_t;

  10.         const buffer_t *psrc = (const buffer_t *)src;
  11.         buffer_t *pdst = (buffer_t *)dst;

  12.   *pdst = *psrc;

  13.   return dst;
  14. }
  15. */

  16. typedef  unsigned char  ylib_byte_t;
  17. typedef  unsigned int   ylib_word_t;

  18. enum YOUNG_LIBRARY_MEMORY_FUNCTION_CONSTANT
  19. {
  20.     OUTSPREAD = 16,
  21.     RESIDUE = OUTSPREAD - 1
  22. };

  23. #define  CYCLE_OUTSPREAD( expression ) \
  24.          expression;  expression;  expression;  expression; \
  25.          expression;  expression;  expression;  expression; \
  26.          expression;  expression;  expression;  expression; \
  27.          expression;  expression;  expression;  expression;

  28. void* mmcp( void* dst, const void* src, size_t count )
  29. {
  30.         ylib_byte_t *d, *s;
  31.         ylib_word_t* dstword = (ylib_word_t*)dst;
  32.         const ylib_word_t* srcword = (const ylib_word_t*)src;
  33.         size_t tmp, word_count = count / sizeof(ylib_word_t);
  34.         size_t word_outspread = word_count & ~((size_t)RESIDUE);

  35.         /* 赂麓脰驴杀禄循禄路展驴陋碌幕煤 */
  36.         for( tmp = 0; tmp < word_outspread; tmp += OUTSPREAD )
  37.         {
  38.             CYCLE_OUTSPREAD( *dstword++ = *srcword++ )
  39.         }

  40.         /* 赂麓脰剩脧碌幕煤 */
  41.         for( ; tmp < word_count; ++tmp )
  42.             *dstword++ = *srcword++;

  43.         /* 赂麓脰剩脧碌脛纸脷*/
  44.         d = (ylib_byte_t*)dstword;
  45.         s = (ylib_byte_t*)srcword;
  46.         for( tmp *= sizeof(ylib_word_t); tmp < count; ++tmp )
  47.             *d++ = *s++;

  48.         return dst;
  49. }



  50. int main(void)
  51. {
  52.         size_t size = 1024 * 1024 * 128;
  53.         size_t count = 30;
  54.         clock_t t;
  55.         int i;

  56.         char *src = (char *)malloc(size);
  57.         char *dst = (char *)malloc(size);

  58.         memcpy(dst, src, size);

  59.         printf("src[%08X], dst[%08X], start :\n", src, dst);

  60.         t = clock();
  61.         for (i = 0; i < count; i ++)
  62.                 mmcp(dst, src, size);
  63.         printf("%ld\n", clock() - t);

  64.         t = clock();
  65.         for (i = 0; i < count; i ++)
  66.                 memcpy(dst, src, size);
  67.         printf("%ld\n", clock() - t);

  68.         return 0;
  69. }


复制代码

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
7 [报告]
发表于 2007-04-30 13:12 |只看该作者
原帖由 思一克 于 2007-4-30 13:10 发表
测试程序和结果
是memcpy速度的1/3多点。

其实你根本不应该写这样的程序。因为你是用C复制*dst = *src的循环,怎么能和优化为最快机器串操作指令比速度?

对头,许多时候 memcpy 之类的操作直接就是用汇编实现的。

论坛徽章:
0
8 [报告]
发表于 2007-04-30 13:16 |只看该作者
重新修改了一下测试程序:
void test_memcpy(void)
{
    double sec;
    clock_t begin, end;
    int i;
    int dst[100];
    int src[100] = { 0 };

    begin = clock();
    for( i = 0; i < 1000000; ++i )
        memcpy( dst, src, sizeof(int) * 100 );
    end = clock();
    sec = (double)(end - begin) / (double)CLOCKS_PER_SEC;
    printf( "\nbegin = %ld, end = %ld, memcpy time = %f\n",
            begin, end, sec );

    begin = clock();
    for( i = 0; i < 1000000; ++i )
        ylib_memcopy( dst, src, sizeof(int) * 100 );
    end = clock();
    sec = (double)(end - begin) / (double)CLOCKS_PER_SEC;
    printf( "\nbegin = %ld, end = %ld, ylib_memcopy time = %f\n",
            begin, end, sec );
}

此时,我写的函数比DEV-CPP自带的memcpy快近一倍 : 0.063 VS 0.140
而和VC 6.0自带的memcpy相比却变成了: 0.093 VS 0.000
和VC 7.0自带的memcpy也类似: 0.078 VS 0.000

天壤之别啊!看来微软还是更务实一些,只对小数据优化,毕竟,小数据的复制还是用的多一些。

论坛徽章:
0
9 [报告]
发表于 2007-04-30 13:23 |只看该作者
你的程序,只能比没有用机器串操作指令的(而是用C写的)memcpy的库快。对于使用了用机器串操作指令的就没有优势了。

论坛徽章:
0
10 [报告]
发表于 2007-04-30 13:25 |只看该作者
回应楼上的各位,我没有说要取代标准库的memcpy,这个函数是我的程序库中的一个,
在我的程序库中通过一个宏来控制使用自定义的函数还是使用标准库的函数,它的使用是有前提的。
我的程序库是准备在嵌入式硬件的裸机上运行用的,有的硬件平台只有一个简单的GCC编译器的移植,
而没有标准库的移植,这个时候就可以使用这个函数替换memcpy保证程序库的正确编译。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP