c++ - 性能报告显示此函数 "__memset_avx2_unaligned_erms"有开销。这是否意味着内存未对齐?

标签 c++ profiling avx perf avx2

我正在尝试使用 perf 工具分析我的 C++ 代码。实现包含带有 SSE/AVX/AVX2 指令的代码。除此之外,代码还使用 -O3 -mavx2 -march=native 标志进行编译。我相信 __memset_avx2_unaligned_erms 函数是 memset 的 libc 实现。 perf 表明这个函数有相当大的开销。函数名称表示内存未对齐,但是在代码中我使用 GCC 内置宏 __attribute__((aligned (x))) 显式对齐内存显着的开销以及为什么调用未对齐的版本,尽管内存是显式对齐的?

我已将示例报告作为图片附上。 enter image description here

最佳答案

不,它没有。 这意味着 glibc 在该硬件上选择的 memset 策略不会尝试在小规模情况下完全避免对齐访问。 (glibc 在动态链接器符号解析时选择一个 memset 实现,因此它在第一次调用后得到运行时调度而没有额外的开销。)

如果您的缓冲区实际上是对齐的并且大小是 vector 宽度的倍数,那么所有访问都将对齐并且基本上没有开销。 (将 vmovdqu 与恰好在运行时对齐的指针一起使用完全等同于所有支持 AVX 的 CPU 上的 vmovdqa。)

对于大型缓冲区,它仍会在主循环之前对齐指针,以防它未对齐,与仅适用于 32 字节的实现相比,需要一些额外的指令对齐的指针。 (但看起来它使用了 rep stosb 而没有对齐指针,如果它根本就不会指向 rep stosb。)

gcc+glibc 没有特殊版本的 memset,只能用对齐的指针调用。 (或用于不同对齐保证的多个特殊版本)。 GLIBC 的 AVX2 未对齐实现适用于对齐和未对齐的输入。


它在 glibc/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S 中定义,它定义了几个宏(比如将 vector 大小定义为 32)然后 #includes "memset-vec-unaligned-erms.S" .

源码中的注释是这样说的:

/* memset is implemented as:
   1. Use overlapping store to avoid branch.
   2. If size is less than VEC, use integer register stores.
   3. If size is from VEC_SIZE to 2 * VEC_SIZE, use 2 VEC stores.
   4. If size is from 2 * VEC_SIZE to 4 * VEC_SIZE, use 4 VEC stores.
   5. If size is more to 4 * VEC_SIZE, align to 4 * VEC_SIZE with
      4 VEC stores and store 4 * VEC at a time until done.  */

主循环之前的实际对齐是在一些 vmovdqu vector 存储之后完成的(如果用于实际对齐的数据则没有惩罚:https://agner.org/optimize/):

L(loop_start):
    leaq        (VEC_SIZE * 4)(%rdi), %rcx   # rcx = input pointer + 4*VEC_SIZE
    VMOVU        %VEC(0), (%rdi)            # store the first vector
    andq        $-(VEC_SIZE * 4), %rcx      # align the pointer
    ...  some more vector stores
    ...  and stuff, including storing the last few vectors I think
    addq        %rdi, %rdx                  # size += start, giving an end-pointer
    andq        $-(VEC_SIZE * 4), %rdx      # align the end-pointer

L(loop):                                       # THE MAIN LOOP
    VMOVA        %VEC(0), (%rcx)               # vmovdqa = alignment required
    VMOVA        %VEC(0), VEC_SIZE(%rcx)
    VMOVA        %VEC(0), (VEC_SIZE * 2)(%rcx)
    VMOVA        %VEC(0), (VEC_SIZE * 3)(%rcx)
    addq        $(VEC_SIZE * 4), %rcx
    cmpq        %rcx, %rdx
    jne        L(loop)

所以当 VEC_SIZE = 32 时,它会将指针对齐 128。这太过分了;缓存行是 64 字节,实际上只要与 vector 宽度对齐就可以了。

它还有一个使用 rep stos 的阈值,如果启用并且缓冲区大小 > 2kiB,在具有 ERMSB 的 CPU 上。 (Enhanced REP MOVSB for memcpy)。

关于c++ - 性能报告显示此函数 "__memset_avx2_unaligned_erms"有开销。这是否意味着内存未对齐?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51614543/

相关文章:

c++ - AVX2:AVX 寄存器中 8 位元素上的 BitScanReverse 或 CountLeadingZeros

sse - AVX2:U8绝对差

c++ - pybind11 返回 numpy 对象数组

c# - 反转数学函数

c++ - 可以在重载运算符中使用访问器方法吗?

c - 使用 dtrace 分析 C 代码

java - NetBeans Profiler - 未显示实时结果

performance - 如何使用 QEMU 进行分析?

c++ - 可变参数计数函数

c++ - md5 矢量化 sse* && avx