gpt4 book ai didi

c - Memcpy 实现的优化

转载 作者:行者123 更新时间:2023-12-02 14:49:17 24 4
gpt4 key购买 nike

下面是我在搜索优化的 memcpy 实现时获得的代码。
这是link

void *memcpy(void *dst, void const *src, size_t len) {
long *plDst = (long *)dst;
long const *plSrc = (long const *)src;

if (!(src & 0xFFFFFFFC) && !(dst & 0xFFFFFFFC)) {
while (len >= 4) {
*plDst++ = *plSrc++;
len -= 4;
}
}

char *pcDst = (char *)plDst;
char const *pcDst = (char const *)plSrc;

while (len--) {
*pcDst++ = *pcSrc++;
}

return (dst);
}

有人可以向我解释一下下面这行吗?

if (!(src & 0xFFFFFFFC) && !(dst & 0xFFFFFFFC))

这里他们想要检查srcdst地址是否与4字节边界对齐。为什么他们要使用 !,因为它每次都会使条件 false

其次,上述代码是否还有进一步优化的余地?

最佳答案

本文虽然讨论了一个有趣的主题,但未能提供正确的示例。发布的代码被称为 GNU 的 newlib 源代码。 GNU 项目和 newlib 团队都会惊讶地发现这个意想不到的收敛声明! newlib 不是一个 GNU 项目,它的大部分源代码都没有获得 GPL 许可。

这个优化memcpy实现是不可移植的、次优的并且在许多方面都是不正确的。

测试 if (!(src & 0xFFFFFFFC) && !(dst & 0xFFFFFFFC)) 尝试检测 srcdst地址在边界上对齐。由于多种原因,它很麻烦且不可移植,而且正如您所注意到的那样,它是完全错误的:

  • void *int的隐式转换是丑陋的并且是实现定义的。为了更好的可移植性,指针应转换为 (uintptr_t)
  • 0xFFFFFFFC 假定类型 long 为 4 个字节。这可能不正确,事实上,在 64 位 Linux 和 Mac 系统上,long 类型的长度是 8 字节。
  • src & 0xFFFFFFC 不是对齐检查,不太可能是 0,4 字节边界对齐的预期测试是 src & 3

此外,代码无法优化 srcdst 具有相同对齐方式但未在 long 边界上对齐的情况。

其他可能的改进包括展开循环、使用小值 len 的开关、将从 src 读取的字节组合到 long 中以一旦它在边界上对齐,就写入dst...

这是一个改进的替代方案:

#include <stdint.h>

void *memcpy(void *dst, void const *src, size_t len) {
unsigned char *pcDst = (unsigned char *)dst;
unsigned char const *pcSrc = (unsigned char const *)src;

if (len >= sizeof(long) * 2
&& ((uintptr_t)src & (sizeof(long) - 1)) == ((uintptr_t)dst & (sizeof(long) - 1))) {
while (((uintptr_t)pcSrc & (sizeof(long) - 1)) != 0) {
*pcDst++ = *pcSrc++;
len--;
}
long *plDst = (long *)pcDst;
long const *plSrc = (long const *)pcSrc;
/* manually unroll the loop */
while (len >= sizeof(long) * 4) {
plDst[0] = plSrc[0];
plDst[1] = plSrc[1];
plDst[2] = plSrc[2];
plDst[3] = plSrc[3];
plSrc += 4;
plDst += 4;
len -= sizeof(long) * 4;
}
while (len >= sizeof(long)) {
*plDst++ = *plSrc++;
len -= sizeof(long);
}
pcDst = (unsigned char *)plDst;
pcSrc = (unsigned char const *)plSrc;
}
while (len--) {
*pcDst++ = *pcSrc++;
}
return dst;
}

请注意,void * 的转换在 C 中是不必要的,但在 C++ 中是必需的。

在尝试优化代码以提高速度时,请记住以下一些要点:

  • 无需权衡正确性。即使在边界情况下也失败的快速代码是无用的。
  • 注意可移植性问题:依赖于类型大小和/或字节顺序的解决方案可能会产生可移植性问题。
  • 基准测试将告诉您哪些有效、哪些无效:您必须在各种测试用例上仔细计算各种替代方案的时间。
  • 不存在完美的解决方案:一种架构上较快的代码在另一种架构上可能会较慢,包括 future 的架构,这也是最有问题的。对不同架构进行基准测试。
  • 对抗复杂性:避免复杂的解决方案,这些解决方案不会带来实质性改进,它们的正确性更难以证明和维护。
  • memcpy 通常在汇编中进行优化,或者由现代编译器作为内置函数实现。

关于c - Memcpy 实现的优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51494787/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com