使用 Neon 加速 memcpy 和 memset

1 简介

在现代计算机系统中,内存操作是常见且至关重要的任务。对于需要频繁进行数据传输和初始化的应用场景,memcpy和memset函数的性能显得尤为重要。Neon是ARM公司推出的一种SIMD(单指令多数据)指令集,能够大幅提升内存操作的效率。本文将深入探讨如何使用Neon指令集优化memcpy和memset函数的性能,以实现更快的内存操作。

2 代码实现

2.1 实现 memcpy 操作

这里参考了 nihui 在 opencv-mobile 中对 RKMPP 数据拷贝时做的优化

inline void LockzhinerMemoryCopy(void* dst, const void* src, size_t size) {
#if __ARM_NEON
  unsigned char* neon_dst = (unsigned char*)dst;
  const unsigned char* neon_src = (const unsigned char*)src;

  int nn = size / 64;
  size -= nn * 64;
  while (nn--) {
    __builtin_prefetch(neon_src + 64);
    uint8x16_t _p0 = vld1q_u8(neon_src);
    uint8x16_t _p1 = vld1q_u8(neon_src + 16);
    uint8x16_t _p2 = vld1q_u8(neon_src + 32);
    uint8x16_t _p3 = vld1q_u8(neon_src + 48);
    vst1q_u8(neon_dst, _p0);
    vst1q_u8(neon_dst + 16, _p1);
    vst1q_u8(neon_dst + 32, _p2);
    vst1q_u8(neon_dst + 48, _p3);
    neon_src += 64;
    neon_dst += 64;
  }
  if (size > 16) {
    uint8x16_t _p0 = vld1q_u8(neon_src);
    vst1q_u8(neon_dst, _p0);
    neon_src += 16;
    neon_dst += 16;
    size -= 16;
  }
  if (size > 8) {
    uint8x8_t _p0 = vld1_u8(neon_src);
    vst1_u8(neon_dst, _p0);
    neon_src += 8;
    neon_dst += 8;
    size -= 8;
  }
  while (size--) {
    *neon_dst++ = *neon_src++;
  }
#else
  memcpy(dst, src, size);
#endif
}

2.2 实现 memset 操作

参考 memcpy 我们很容易就能实现 memset

inline void LockzhinerMemorySet(void* dst, unsigned char value, size_t size) {
#if __ARM_NEON
  // NEON 优化部分
  unsigned char* neon_dst = (unsigned char*)dst;
  int nn = size / 64;
  size -= nn * 64;

  // 生成包含 16 个相同字节的 NEON 向量
  uint8x16_t neon_value = vdupq_n_u8(value);

  // 使用 NEON 指令进行批量内存填充
  while (nn--) {
    // 预取下一块数据,尽管在 memset 中这个可能影响较小
    __builtin_prefetch(neon_dst + 64);
    vst1q_u8(neon_dst, neon_value);
    vst1q_u8(neon_dst + 16, neon_value);
    vst1q_u8(neon_dst + 32, neon_value);
    vst1q_u8(neon_dst + 48, neon_value);
    neon_dst += 64;
  }

  // 处理剩余的字节
  while (size >= 16) {
    vst1q_u8(neon_dst, neon_value);
    neon_dst += 16;
    size -= 16;
  }
  while (size >= 8) {
    uint8x8_t neon_value8 = vdup_n_u8(value);
    vst1_u8(neon_dst, neon_value8);
    neon_dst += 8;
    size -= 8;
  }
  // 处理剩余不足 8 个字节的情况
  while (size--) {
    *neon_dst++ = value;
  }
#else
  // 如果不支持 NEON,使用标准的 memset
  memset(dst, value, size);
#endif
}

3 参考文档

posted @ 2024-12-01 20:50  Zheng-Bicheng  阅读(219)  评论(0编辑  收藏  举报