memcpy的优化方案

前不久在腾讯面试的时候,被问到这点。面试官看我博客有一篇介绍标准库函数memcpy,然后问我怎么对标准库函数优化。当时现场没有啥思路,后来面试官让我从汇编角度想想,然后就有了思路。

 

标准库是逐个字节复制,代码如下。

 
void *memmove (void *dest, const void *src, size_t len)
{
  char *d = dest;
  const char *s = src;
  if (d < s)
    while (len--)
      *d++ = *s++;
  else
    {
      char *lasts = s + (len-1);
      char *lastd = d + (len-1);
      while (len--)
        *lastd-- = *lasts--;
    }
  return dest;
}

 标准库代码每次复制一个字节,效率确实有点低。CPU内部寄存器可能是8个字节长度。这表示我们每次最多可以复制8个,理论上提升8倍性能,具体要根据寄存器长度来看。当时给出的方案使用8字节复制,不足8字节则逐个字节复制。代码如下,考虑了地址重叠。

//优化版本
void *myMemmove2(void *dst, const void *src, size_t len)
{
    //8字节长度
	double *srcdb, *dstdb;
	char *srcch, *dstch;
	size_t times, left;

	times = len / 8;
	left = len % 8;
	
	if (!src || !dst)	return dst;

	//从前往后复制
	if (dst < src)
	{
		srcdb = (double *)src;
		dstdb = (double *)dst;
		
		while (times--)
		{
			*dstdb++ = *srcdb++;
			len-=8;
		}
		
		srcch = (char *)srcdb;
		dstch = (char *)dstdb;

		while (left--)
		{
			*dstch++ = *srcch++;
		}
	}
	//从后往前复制
	else if (dst > src)
	{
		if (times > 0)
		{
			dstdb = (double *)(dst+len-8);
			srcdb = (double *)(src+len-8);	
		}
		
		while(times--)
		{
			*dstdb = *srcdb;
			dstdb--;srcdb--;
		}
		
		if (len > 8 && left)
		{
			srcch = (char *)(srcdb+1)-1;
			dstch = (char *)(dstdb+1)-1;
			while(left--)
			{
				*dstch-- = *srcch--;
			}
		}
		else
		{
      		srcch = (char *)src + (len-1);
      		dstch = (char *)dst + (len-1);	
      		while (len--)
	 	       *dstch-- = *srcch--;
		}
	}
	
	return dst;
}

上述代码是优化的一种,其实还有优化的空间。比如,地址对齐问题。

如果地址不对齐,CPU可能需要取两次。因此,最好在进行复制之前进行字节对齐。有些方案就是先进行字节对齐再处理的。面试的时候,面试官提示了字节对齐问题,当时我的想法是,即便地址没对齐,CPU取两次值,然后进行裁剪拼接。也能够运行。不过,对于后面一点,即地址拼接,我不确定。字节对齐问题仅考虑了结构体所占大小这种。参考资料3里给出了内存对齐的相关资料,资料1给出了地址对齐的一种实现。

使用8字节对齐的方案,没有考虑地址对齐问题(编译器默认会分配对齐地址),进行了如下测试,分别使用未优化版本和优化版本对内存进行复制,两个函数各执行10000次,使用gprof进行性能统计,结果如下:

从上图可以看到,未优化版本每次调用耗费2.11ms,优化版本每次耗费0.28ms。因此,优化显然还是有效果。

参考资料:

1. 更快的memcpy (https://www.cnblogs.com/Leo_wl/p/3163057.html)

2. C/C++性能测试工具 GNU gprof (C/C++性能测试工具 GNU gprof - 书亚博园)

3. 内存对齐分配策略(含位域模式) (https://www.cnblogs.com/chaozhu/p/5600496.html)

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值