关于memset的实现

zhengr 2003-06-22 11:22:23
我需要一个32bit的memset,简单地可以
void memset(int *pMem, int value, int size)
{
while (size--)
{
*pMem++ = value;
}
}
但是这样看起来做的加法和比较次数太多,可以这样优化
{
switch (size & 7L)
{
case 1: *pMem++ = value;
case 2: *pMem++ = value;
case 3: *pMem++ = value;
case 4: *pMem++ = value;
case 5: *pMem++ = value;
case 6: *pMem++ = value;
case 7: *pMem++ = value;
}
size = (size >> 3);
while (size--)
{
pMem[0] = value;
pMem[1] = value;
pMem[2] = value;
pMem[3] = value;
pMem[4] = value;
pMem[5] = value;
pMem[6] = value;
pMem[7] = value;
pMem += 8;
}
}
我用vc6编译,禁止优化,后一种实现的确会快不少。
但是一旦打开速度优化,却是第一种实现快,而且和vc自带的
libc里面的memset速度接近
哪位兄台知道标准库里的memset是如何实现的?
难不成它也是用第一种土法,然后依赖编译器优化一下?
...全文
942 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
zteliubin 2003-06-22
  • 打赏
  • 举报
回复
关注ing...
感觉比较难写,搂主写得不错。
能否直接嵌入汇编代码!可以参考编译器优化后的结果。
zhangyan_qd 2003-06-22
  • 打赏
  • 举报
回复
真正的memset是用的汇编的串指令。
wingfiring 2003-06-22
  • 打赏
  • 举报
回复
我看到过用你的“土法”的实现,具体在那里记不太清楚了。在while循环中,如果你的size不在循环体内修改,则可以进行优化。如果真的追求效率,该函数完全可以用汇编实现,一两条指令而已。
晨星 2003-06-22
  • 打赏
  • 举报
回复
关注,up。
zhengr 2003-06-22
  • 打赏
  • 举报
回复
呵呵,其实我的本意是想探讨一下单纯用c语言写不优化,有没有更快的算法。
既然libc里面就是用汇编写的那就没有话说了。
xzygod 2003-06-22
  • 打赏
  • 举报
回复
memset 和这个原理差不多,看着改,汇编水平有限,高手多指教,这个函数在处理64字节块时和memcpy差不多,但块越大效果越好,一般都有2倍的效率(vtune测的)
//********************************************************************
// 方法名称:memcpy_intel
// 方法说明:为Intel CPU优化的memcpy操作,使用MMX指令
//
// 参数说明:
// dst:目的指针
// src:源指针
// nQWORDs:复制字节数,必须为64的倍数
//********************************************************************
__inline static void memcpy_intel(void *dst, const void *src, size_t nQWORDs)
{
size_t loopCount = nQWORDs / 64;

__asm
{
mov ebx,dst //目标数据地址
mov edx,src //源数据地址
mov ecx,loopCount //设置循环次数

LOOPBODY: //每次循环处理64个字节

movq mm0, [edx] //依次将每8字节数据放入mm0-mm7寄存器
movq mm1, [edx + 8]
movq mm2, [edx + 16]
movq mm3, [edx + 24]
movq mm4, [edx + 32]
movq mm5, [edx + 40]
movq mm6, [edx + 48]
movq mm7, [edx + 56]
add edx, 64 //源指针+64

movq qword ptr [ebx],mm0 //依次将mm0-mm7寄存器中的数据放入目标地址
movq qword ptr [ebx + 8],mm1
movq qword ptr [ebx + 16],mm2
movq qword ptr [ebx + 24],mm3
movq qword ptr [ebx + 32],mm4
movq qword ptr [ebx + 40],mm5
movq qword ptr [ebx + 48],mm6
movq qword ptr [ebx + 56],mm7
add ebx,64 //目标指针+64

dec ecx
jg LOOPBODY

emms //清除mmx状态
}
Cypher 2003-06-22
  • 打赏
  • 举报
回复
To zhjhe(穿过你的黑发的我的手)

真的吗?用户真正关心的是软件能不能做他们想要的事情,他们可不关心你用什么技术有没有有优化,如果要求你的软件在50ms中做出某种响应,但它却100ms才开始,那么不管你的软件结构什么的在优美,逻辑处理再正确,对于用户来说它是错的,不合格的。

我们遇到过中断中申请一块内存空间花了1ms,一直很奇怪,最好定位出是自己实现的内存分配函数中申请后自动清零。结果同样是自己实现的那个按字节写的memset消耗了过多的CPU时间。
zhjhe 2003-06-22
  • 打赏
  • 举报
回复
优化是万恶之源!
Cypher 2003-06-22
  • 打赏
  • 举报
回复
原型都写错了吧:
void *memset(void *, int, size_t);

它单个字节地写比较慢很重要的一点是32位CPU写一个字节还不如写4个字节快,因为读/写一个字节要做一些额外的处理。当然不是四字节就快,由于CPU读取时的特点,只有对齐的4字节才会快,如果是跨边界的,有可能访问4个字节CPU要从总线读取两次。

所以优化的关键就是这两点:对齐与4字节操作。有兴趣可以看一看Linux中的实现,下面是它在PowerPC上的实现(我加了一点简单的说明void *memset(void *p, int v, size_t sz):
.globl memset
memset:
rlwimi r4,r4,8,16,23
rlwimi r4,r4,16,0,15
addi r6,r3,-4
cmplwi 0,r5,4
blt 7f
stwu r4,4(r6)
beqlr
andi. r0,r6,3
add r5,r0,r5
subf r6,r0,r6
srwi r0,r5,2
mtctr r0
bdz 6f
1: stwu r4,4(r6)
bdnz 1b
6: andi. r5,r5,3
7: cmpwi 0,r5,0
beqlr
mtctr r5
addi r6,r6,3
8: stbu r4,1(r6)
bdnz 8b
blr

x86上的实现是一次4字节,这里是8字节,用了两个存储器。

知道了关键,完全可以用C/C++写一个优化的,虽然编译后代码不可能比得上汇编,但至少可以解决主要问题。对于大块内的处理优化后的差异还是比较明显的。
xzygod 2003-06-22
  • 打赏
  • 举报
回复
用simd指令优化,至少提高2倍性能

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧