memcpy:GCC或实施优化?

时间:2019-06-18 09:32:08

标签: c gcc optimization memcpy

关于为自定义引导程序和内核编写自己的memcpy函数,我决定研究编写可在对齐边界上复制内存的良好且可能快速的实现的各个方面(例如,在视频模式下滚动,屏幕上的每一行都从对齐的边界开始),但对于大型(> 1 MB)和未对齐的结构也是如此。

我的问题是,由于我的编译器GCC确实支持多种优化选项(通过启用单个选项或使用O2O3等), 我需要实现实际的memcpy函数到什么级别的优化,以便在复制时达到最佳效果以及GCC优化标志?

我当前的实现如下:

static void *memcpy_unaligned(void *dst, const void *src, size_t len)
{
    size_t i;
    unsigned char *d = (unsigned char *)dst;
    unsigned char *s = (unsigned char *)src;

    for (i = 0; i < len; i++)
        d[i] = s[i];

    return dst; 
}

static void *memcpy_aligned16(void *dst, const void *src, size_t len)
{
    size_t i;
    uint16_t *d = (uint16_t *)dst;
    uint16_t *s = (uint16_t *)src;

    for (i = 0; i < ((len) & (~1)); i += 2)
        d[i] = s[i];

    for ( ; i < len; i++)
        ((unsigned char *)d)[i] = ((unsigned char *)s)[i];

    return dst;
}

static void *memcpy_aligned32(void *dst, const void *src, size_t len)
{
    size_t i;
    uint32_t *d = (uint32_t *)dst;
    uint32_t *s = (uint32_t *)src;

    for (i = 0; i < ((len) & (~3)); i += 4)
        d[i] = s[i];

    for ( ; i < len; i++)
        ((unsigned char *)d)[i] = ((unsigned char *)s)[i];

    return dst;
}

static void *memcpy_aligned(void *dst, const void *src, size_t len)
{
    /* Are dst and src aligned on a 4-byte boundary? */
    if (ALIGNED(dst, src, 4))
        return memcpy_aligned32(dst, src, len);

    /* Are dst and src aligned on a 2-byte boundary? */
    if (ALIGNED(dst, src, 2))
        return memcpy_aligned16(dst, src, len);

    return memcpy_unaligned(dst, src, len);
}

void* memcpy(void *dst, const void *src, size_t len)
{
    return memcpy_aligned(dst, src, len);
}

检查dstsrc指针是否仅在前三个字节或前三个字节的奇数边界处对齐也很有用,以便首先进行单字节复制,然后进行通过worddword复制?

1 个答案:

答案 0 :(得分:0)

  

检查dst和src指针是否仅在前三个字节或前三个字节的奇数边界处对齐,以便首先进行单字节复制,然后进行单词和dword复制,这是否也有用?

针对此类问题进行性能分析,但首先要正确使用该功能。

OP的代码存在功能错误。

  • OP原始代码增加索引的速度太快
  • 注意:(len)和(〜3)可能会错误地掩盖罕见的非2补码

使用restrict进行其他优化。注意:当缓冲区重叠时,memcpy()是UB。

static void *memcpy_aligned32(void * restrict dst, const void *restrict src, size_t len) {
  size_t i;
  // Casts not needed.  Do not cast away const-ness
  uint32_t *d = dst;
  const uint32_t *s = src;  

  size_t l4 = len/4;
  for (i = 0; i < l4; i++) {
    d[i] = s[i];
  }

  i *= 4;
  for ( ; i < len; i++) {
    ((unsigned char *)d)[i] = ((unsigned char *)s)[i]; // I'd use `uint8_t*` for symmetry
  }  

  return dst;
}

可能还会出现其他AA问题。