系统相关
首页 > 系统相关> > c-性能报告显示此函数“ __memset_avx2_unaligned_erms”具有开销.这是否意味着内存未对齐?

c-性能报告显示此函数“ __memset_avx2_unaligned_erms”具有开销.这是否意味着内存未对齐?

作者:互联网

我正在尝试使用perf工具分析我的C代码.实现包含带有SSE / AVX / AVX2指令的代码.除此以外,还使用-O3 -mavx2 -march = native标志编译该代码.我相信__memset_avx2_unaligned_erms函数是memset的libc实现. perf表明此功能有相当大的开销.函数名称指示内存未对齐,但是在代码中,我使用GCC内置宏__attribute __((aligned(x)))显式对齐内存,这可能是此函数产生大量开销的原因,以及为什么未对齐的版本尽管显式对齐内存却被称为?

我已将样本报告附加为picture.enter image description here

解决方法:

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

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

对于大型缓冲区,如果不对齐,它仍会在主循环之前对齐指针,这要花一些额外的指令,而对于仅适用于32字节对齐指针的实现来说,代价是. (但是,如果要完全使用rep stosb,则看起来它使用rep stosb而不对齐指针.)

gcc glibc没有仅通过对齐的指针调用的memset的特殊版本. (或针对不同对齐保证的多个特殊版本). GLIBC的AVX2不对齐实现对于对齐和不对齐输入都可以很好地工作.

它是在glibc/sysdeps/x86_64/multiarch/memset-avx2-unaligned-erms.S中定义的,它定义了几个宏(例如将矢量大小定义为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向量存储之后完成的(如果对实际上对齐的数据使用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个字节,实际上只对齐向量宽度就可以了.

如果启用并且缓冲区大小为&gt ;,它也具有使用代表的阈值.在具有ERMSB的CPU上为2kiB. (Enhanced REP MOVSB for memcpy).

标签:c,avx,perf,avx2,profiling
来源: https://codeday.me/bug/20191013/1908165.html