AVX mat4 inv 实现比 SSE 慢

Posted

技术标签:

【中文标题】AVX mat4 inv 实现比 SSE 慢【英文标题】:AVX mat4 inv implementation is slower than SSE 【发布时间】:2018-10-29 09:41:17 【问题描述】:

我在 SSE2 和 AVX 中实现了 4x4 矩阵求逆。两者都比简单的实现更快。但如果启用了 AVX (-mavx),则 SSE2 实现比手动 AVX 实现运行得更快。似乎编译器使我的 SSE2 实现对 AVX 更加友好:(

在我的 AVX 实现中,乘法更少,加法更少……所以我希望 AVX 可能比 SSE 更快。也许像_mm256_permute2f128_ps_mm256_permutevar_ps/_mm256_permute_ps 这样的指令会使 AVX 变慢?我没有尝试将 SSE/XMM 寄存器加载到 AVX/YMM 寄存器。

如何让我的 AVX 实施比 SSE 更快?

我的 CPU:Intel(R) Core(TM) i7-3615QM CPU @ 2.30GHz(Ivy Bridge)

Plain with -O3      : 0.045853 secs
SSE2  with -O3      : 0.026021 secs
SSE2  with -O3 -mavx: 0.024336 secs
AVX1  with -O3 -mavx: 0.031798 secs

Updated (See bottom of question) all have -O3 -mavx flags:
AVX1 (reduced div)  : 0.027666 secs
AVX1 (using rcp_ps) : 0.023205 secs
SSE2 (using rcp_ps) : 0.021969 secs

初始矩阵:

Matrix (float4x4):
    |0.0714    -0.6589  0.7488  2.0000|
    |0.9446     0.2857  0.1613  4.0000|
    |-0.3202    0.6958  0.6429  6.0000|
    |0.0000     0.0000  0.0000  1.0000|

测试代码:

start = clock();

for (int i = 0; i < 1000000; i++) 
  glm_mat4_inv_sse2(m, m);

  // glm_mat4_inv_avx(m, m);
  // glm_mat4_inv(m, m)


end   = clock();
total = (float)(end - start) / CLOCKS_PER_SEC;
printf("%f secs\n\n", total);

实现:

图书馆:http://github.com/recp/cglm

SSE 实施:https://gist.github.com/recp/690025c955c2e69a91e3a60a13768dee

AVX 实现:https://gist.github.com/recp/8ccc5ad0d19f5516de55f9bf7b5045b2

SSE2 实现输出(使用godbolt;选项-O3):

glm_mat4_inv_sse2:
        movaps  xmm8, XMMWORD PTR [rdi+32]
        movaps  xmm2, XMMWORD PTR [rdi+16]
        movaps  xmm5, XMMWORD PTR [rdi+48]
        movaps  xmm6, XMMWORD PTR [rdi]
        movaps  xmm4, xmm8
        movaps  xmm13, xmm8
        movaps  xmm11, xmm8
        shufps  xmm11, xmm2, 170
        shufps  xmm4, xmm5, 238
        movaps  xmm3, xmm11
        movaps  xmm1, xmm8
        pshufd  xmm12, xmm4, 127
        shufps  xmm13, xmm2, 255
        movaps  xmm0, xmm13
        movaps  xmm9, xmm8
        pshufd  xmm4, xmm4, 42
        shufps  xmm9, xmm2, 85
        shufps  xmm1, xmm5, 153
        movaps  xmm7, xmm9
        mulps   xmm0, xmm4
        pshufd  xmm10, xmm1, 42
        movaps  xmm1, xmm11
        shufps  xmm5, xmm8, 0
        mulps   xmm3, xmm12
        pshufd  xmm5, xmm5, 128
        mulps   xmm7, xmm12
        mulps   xmm1, xmm10
        subps   xmm3, xmm0
        movaps  xmm0, xmm13
        mulps   xmm0, xmm10
        mulps   xmm13, xmm5
        subps   xmm7, xmm0
        movaps  xmm0, xmm9
        mulps   xmm0, xmm4
        subps   xmm0, xmm1
        movaps  xmm1, xmm8
        movaps  xmm8, xmm11
        shufps  xmm1, xmm2, 0
        mulps   xmm8, xmm5
        movaps  xmm11, xmm7
        mulps   xmm4, xmm1
        mulps   xmm5, xmm9
        movaps  xmm9, xmm2
        mulps   xmm12, xmm1
        shufps  xmm9, xmm6, 85
        pshufd  xmm9, xmm9, 168
        mulps   xmm1, xmm10
        movaps  xmm10, xmm2
        shufps  xmm10, xmm6, 0
        pshufd  xmm10, xmm10, 168
        subps   xmm4, xmm8
        mulps   xmm7, xmm10
        movaps  xmm8, xmm2
        shufps  xmm2, xmm6, 255
        shufps  xmm8, xmm6, 170
        pshufd  xmm8, xmm8, 168
        pshufd  xmm2, xmm2, 168
        mulps   xmm11, xmm8
        subps   xmm12, xmm13
        movaps  xmm13, XMMWORD PTR .LC0[rip]
        subps   xmm1, xmm5
        movaps  xmm5, xmm3
        mulps   xmm5, xmm9
        mulps   xmm3, xmm10
        subps   xmm5, xmm11
        movaps  xmm11, xmm0
        mulps   xmm11, xmm2
        mulps   xmm0, xmm10
        addps   xmm5, xmm11
        movaps  xmm11, xmm12
        mulps   xmm11, xmm8
        mulps   xmm12, xmm9
        xorps   xmm5, xmm13
        subps   xmm3, xmm11
        movaps  xmm11, xmm4
        mulps   xmm4, xmm9
        subps   xmm7, xmm12
        mulps   xmm11, xmm2
        mulps   xmm2, xmm1
        mulps   xmm1, xmm8
        subps   xmm0, xmm4
        addps   xmm3, xmm11
        movaps  xmm11, XMMWORD PTR .LC1[rip]
        addps   xmm2, xmm7
        addps   xmm0, xmm1
        movaps  xmm1, xmm5
        xorps   xmm3, xmm11
        xorps   xmm2, xmm13
        shufps  xmm1, xmm3, 0
        xorps   xmm0, xmm11
        movaps  xmm4, xmm2
        shufps  xmm4, xmm0, 0
        shufps  xmm1, xmm4, 136
        mulps   xmm1, xmm6
        pshufd  xmm4, xmm1, 27
        addps   xmm1, xmm4
        pshufd  xmm4, xmm1, 65
        addps   xmm1, xmm4
        movaps  xmm4, XMMWORD PTR .LC2[rip]
        divps   xmm4, xmm1
        mulps   xmm5, xmm4
        mulps   xmm3, xmm4
        mulps   xmm2, xmm4
        mulps   xmm0, xmm4
        movaps  XMMWORD PTR [rsi], xmm5
        movaps  XMMWORD PTR [rsi+16], xmm3
        movaps  XMMWORD PTR [rsi+32], xmm2
        movaps  XMMWORD PTR [rsi+48], xmm0
        ret
.LC0:
        .long   0
        .long   2147483648
        .long   0
        .long   2147483648
.LC1:
        .long   2147483648
        .long   0
        .long   2147483648
        .long   0
.LC2:
        .long   1065353216
        .long   1065353216
        .long   1065353216
        .long   1065353216

SSE2 实现(启用 AVX)输出(使用 Godbolt;选项 -O3 -mavx):

glm_mat4_inv_sse2:
        vmovaps xmm9, XMMWORD PTR [rdi+32]
        vmovaps xmm6, XMMWORD PTR [rdi+48]
        vmovaps xmm2, XMMWORD PTR [rdi+16]
        vmovaps xmm7, XMMWORD PTR [rdi]
        vshufps xmm5, xmm9, xmm6, 238
        vpshufd xmm13, xmm5, 127
        vpshufd xmm5, xmm5, 42
        vshufps xmm1, xmm9, xmm6, 153
        vshufps xmm11, xmm9, xmm2, 170
        vshufps xmm12, xmm9, xmm2, 255
        vmulps  xmm3, xmm11, xmm13
        vpshufd xmm1, xmm1, 42
        vmulps  xmm0, xmm12, xmm5
        vshufps xmm10, xmm9, xmm2, 85
        vshufps xmm6, xmm6, xmm9, 0
        vpshufd xmm6, xmm6, 128
        vmulps  xmm8, xmm10, xmm13
        vmulps  xmm4, xmm10, xmm5
        vsubps  xmm3, xmm3, xmm0
        vmulps  xmm0, xmm12, xmm1
        vsubps  xmm8, xmm8, xmm0
        vmulps  xmm0, xmm11, xmm1
        vsubps  xmm4, xmm4, xmm0
        vshufps xmm0, xmm9, xmm2, 0
        vmulps  xmm9, xmm12, xmm6
        vmulps  xmm13, xmm0, xmm13
        vmulps  xmm5, xmm0, xmm5
        vmulps  xmm0, xmm0, xmm1
        vsubps  xmm12, xmm13, xmm9
        vmulps  xmm9, xmm11, xmm6
        vmovaps xmm13, XMMWORD PTR .LC0[rip]
        vmulps  xmm6, xmm10, xmm6
        vshufps xmm10, xmm2, xmm7, 85
        vpshufd xmm10, xmm10, 168
        vsubps  xmm5, xmm5, xmm9
        vshufps xmm9, xmm2, xmm7, 170
        vpshufd xmm9, xmm9, 168
        vsubps  xmm1, xmm0, xmm6
        vmulps  xmm11, xmm8, xmm9
        vshufps xmm0, xmm2, xmm7, 0
        vshufps xmm2, xmm2, xmm7, 255
        vmulps  xmm6, xmm3, xmm10
        vpshufd xmm2, xmm2, 168
        vpshufd xmm0, xmm0, 168
        vmulps  xmm3, xmm3, xmm0
        vmulps  xmm8, xmm8, xmm0
        vmulps  xmm0, xmm4, xmm0
        vsubps  xmm6, xmm6, xmm11
        vmulps  xmm11, xmm4, xmm2
        vaddps  xmm6, xmm6, xmm11
        vmulps  xmm11, xmm12, xmm9
        vmulps  xmm12, xmm12, xmm10
        vxorps  xmm6, xmm6, xmm13
        vsubps  xmm3, xmm3, xmm11
        vmulps  xmm11, xmm5, xmm2
        vmulps  xmm5, xmm5, xmm10
        vsubps  xmm8, xmm8, xmm12
        vmulps  xmm2, xmm1, xmm2
        vmulps  xmm1, xmm1, xmm9
        vaddps  xmm3, xmm3, xmm11
        vmovaps xmm11, XMMWORD PTR .LC1[rip]
        vsubps  xmm0, xmm0, xmm5
        vaddps  xmm2, xmm8, xmm2
        vxorps  xmm3, xmm3, xmm11
        vaddps  xmm0, xmm0, xmm1
        vshufps xmm1, xmm6, xmm3, 0
        vxorps  xmm2, xmm2, xmm13
        vxorps  xmm0, xmm0, xmm11
        vshufps xmm4, xmm2, xmm0, 0
        vshufps xmm1, xmm1, xmm4, 136
        vmulps  xmm1, xmm1, xmm7
        vpshufd xmm4, xmm1, 27
        vaddps  xmm1, xmm1, xmm4
        vpshufd xmm4, xmm1, 65
        vaddps  xmm1, xmm1, xmm4
        vmovaps xmm4, XMMWORD PTR .LC2[rip]
        vdivps  xmm1, xmm4, xmm1
        vmulps  xmm6, xmm6, xmm1
        vmulps  xmm3, xmm3, xmm1
        vmulps  xmm2, xmm2, xmm1
        vmulps  xmm1, xmm0, xmm1
        vmovaps XMMWORD PTR [rsi], xmm6
        vmovaps XMMWORD PTR [rsi+16], xmm3
        vmovaps XMMWORD PTR [rsi+32], xmm2
        vmovaps XMMWORD PTR [rsi+48], xmm1
        ret
.LC0:
        .long   0
        .long   2147483648
        .long   0
        .long   2147483648
.LC1:
        .long   2147483648
        .long   0
        .long   2147483648
        .long   0
.LC2:
        .long   1065353216
        .long   1065353216
        .long   1065353216
        .long   1065353216

AVX 实现输出(使用godbolt;选项-O3 -mavx):

glm_mat4_inv_avx:
        vmovaps ymm3, YMMWORD PTR [rdi]
        vmovaps ymm1, YMMWORD PTR [rdi+32]
        vmovdqa ymm2, YMMWORD PTR .LC1[rip]
        vmovdqa ymm0, YMMWORD PTR .LC0[rip]
        vperm2f128      ymm6, ymm3, ymm3, 3
        vperm2f128      ymm5, ymm1, ymm1, 0
        vperm2f128      ymm1, ymm1, ymm1, 17
        vmovdqa ymm10, YMMWORD PTR .LC4[rip]
        vpermilps       ymm9, ymm5, ymm0
        vpermilps       ymm7, ymm1, ymm2
        vperm2f128      ymm8, ymm6, ymm6, 0
        vpermilps       ymm1, ymm1, ymm0
        vpermilps       ymm5, ymm5, ymm2
        vpermilps       ymm0, ymm8, ymm0
        vmulps  ymm4, ymm7, ymm9
        vpermilps       ymm8, ymm8, ymm2
        vpermilps       ymm11, ymm6, 1
        vmulps  ymm2, ymm5, ymm1
        vmulps  ymm7, ymm0, ymm7
        vmulps  ymm1, ymm8, ymm1
        vmulps  ymm0, ymm0, ymm5
        vmulps  ymm5, ymm8, ymm9
        vmovdqa ymm9, YMMWORD PTR .LC3[rip]
        vmovdqa ymm8, YMMWORD PTR .LC2[rip]
        vsubps  ymm4, ymm4, ymm2
        vsubps  ymm7, ymm7, ymm1
        vperm2f128      ymm2, ymm4, ymm4, 0
        vperm2f128      ymm4, ymm4, ymm4, 17
        vshufps ymm1, ymm2, ymm4, 77
        vpermilps       ymm1, ymm1, ymm9
        vsubps  ymm5, ymm0, ymm5
        vpermilps       ymm0, ymm2, ymm8
        vmulps  ymm0, ymm0, ymm11
        vperm2f128      ymm1, ymm1, ymm2, 0
        vshufps ymm2, ymm2, ymm4, 74
        vpermilps       ymm4, ymm6, 90
        vmulps  ymm1, ymm1, ymm4
        vpermilps       ymm2, ymm2, ymm10
        vpermilps       ymm6, ymm6, 191
        vmovaps ymm11, YMMWORD PTR .LC5[rip]
        vperm2f128      ymm2, ymm2, ymm2, 0
        vperm2f128      ymm4, ymm3, ymm3, 0
        vpermilps       ymm12, ymm4, YMMWORD PTR .LC7[rip]
        vmulps  ymm2, ymm2, ymm6
        vinsertf128     ymm6, ymm7, xmm5, 1
        vperm2f128      ymm5, ymm7, ymm5, 49
        vshufps ymm7, ymm6, ymm5, 77
        vpermilps       ymm9, ymm7, ymm9
        vsubps  ymm0, ymm0, ymm1
        vpermilps       ymm1, ymm4, YMMWORD PTR .LC6[rip]
        vpermilps       ymm4, ymm4, YMMWORD PTR .LC8[rip]
        vaddps  ymm2, ymm0, ymm2
        vpermilps       ymm0, ymm6, ymm8
        vshufps ymm6, ymm6, ymm5, 74
        vpermilps       ymm6, ymm6, ymm10
        vmulps  ymm1, ymm1, ymm0
        vmulps  ymm0, ymm12, ymm9
        vmulps  ymm6, ymm4, ymm6
        vxorps  ymm2, ymm2, ymm11
        vdpps   ymm3, ymm3, ymm2, 255
        vsubps  ymm0, ymm1, ymm0
        vdivps  ymm2, ymm2, ymm3
        vaddps  ymm0, ymm0, ymm6
        vxorps  ymm0, ymm0, ymm11
        vdivps  ymm0, ymm0, ymm3
        vperm2f128      ymm5, ymm2, ymm2, 3
        vshufps ymm1, ymm2, ymm5, 68
        vshufps ymm2, ymm2, ymm5, 238
        vperm2f128      ymm4, ymm0, ymm0, 3
        vshufps ymm6, ymm0, ymm4, 68
        vshufps ymm0, ymm0, ymm4, 238
        vshufps ymm3, ymm1, ymm6, 136
        vshufps ymm1, ymm1, ymm6, 221
        vinsertf128     ymm1, ymm3, xmm1, 1
        vshufps ymm3, ymm2, ymm0, 136
        vshufps ymm0, ymm2, ymm0, 221
        vinsertf128     ymm0, ymm3, xmm0, 1
        vmovaps YMMWORD PTR [rsi], ymm1
        vmovaps YMMWORD PTR [rsi+32], ymm0
        vzeroupper
        ret
.LC0:
        .long   2
        .long   1
        .long   1
        .long   0
        .long   0
        .long   0
        .long   0
        .long   0
.LC1:
        .long   3
        .long   3
        .long   2
        .long   3
        .long   2
        .long   1
        .long   1
        .long   1
.LC2:
        .long   0
        .long   0
        .long   1
        .long   2
        .long   0
        .long   0
        .long   1
        .long   2
.LC3:
        .long   0
        .long   1
        .long   1
        .long   2
        .long   0
        .long   1
        .long   1
        .long   2
.LC4:
        .long   0
        .long   2
        .long   3
        .long   3
        .long   0
        .long   2
        .long   3
        .long   3
.LC5:
        .long   0
        .long   2147483648
        .long   0
        .long   2147483648
        .long   2147483648
        .long   0
        .long   2147483648
        .long   0
.LC6:
        .long   1
        .long   0
        .long   0
        .long   0
        .long   1
        .long   0
        .long   0
        .long   0
.LC7:
        .long   2
        .long   2
        .long   1
        .long   1
        .long   2
        .long   2
        .long   1
        .long   1
.LC8:
        .long   3
        .long   3
        .long   3
        .long   2
        .long   3
        .long   3
        .long   3
        .long   2

编辑

我在 macOS 上使用 Xcode(版本 10.0 (10A255))(在 MacBook Pro(Retina,2012 年中)15')上使用 -O3 优化选项构建和运行测试。它用 clang 编译测试代码。我在 Godbolt 中使用 GCC 8.2 来查看 asm(对此感到抱歉),但汇编输出似乎相似。

我通过启用 cglm 选项启用了 shuffd:CGLM_USE_INT_DOMAIN。我在查看 asm 时忘记禁用它。

#ifdef CGLM_USE_INT_DOMAIN
#  define glmm_shuff1(xmm, z, y, x, w)                                        \
     _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xmm),                \
                                        _MM_SHUFFLE(z, y, x, w)))
#else
#  define glmm_shuff1(xmm, z, y, x, w)                                        \
     _mm_shuffle_ps(xmm, xmm, _MM_SHUFFLE(z, y, x, w))
#endif

整个测试代码(标题除外):

#include <cglm/cglm.h>

#include <sys/time.h>
#include <time.h>

int
main(int argc, const char * argv[]) 
  CGLM_ALIGN(32) mat4 m = GLM_MAT4_IDENTITY_INIT;

  double start, end, total;

  /* generate invertible matrix */
  glm_translate(m, (vec3)1,2,3);
  glm_rotate(m, M_PI_2, (vec3)1,2,3);
  glm_translate(m, (vec3)1,2,3);

  glm_mat4_print(m, stderr);

  start = clock();

  for (int i = 0; i < 1000000; i++) 
    glm_mat4_inv_sse2(m, m);

    // glm_mat4_inv_avx(m, m);
    // glm_mat4_inv(m, m);
  

  end   = clock();
  total = (float)(end - start) / CLOCKS_PER_SEC;

  printf("%f secs\n\n", total);

  glm_mat4_print(m, stderr);

编辑 2:

我通过乘法减少了一个除法(1 set_ps + 1 div_ps + 2 mul_ps 似乎比 2 div_ps 好):

旧版本:

r1 = _mm256_div_ps(r1, y4);
r2 = _mm256_div_ps(r2, y4);

新版本(SSE2版本是这样划分的):

y5 = _mm256_div_ps(_mm256_set1_ps(1.0f), y4);
r1 = _mm256_mul_ps(r1, y5);
r2 = _mm256_mul_ps(r2, y5);

新版本(快速版本):

y5 = _mm256_rcp_ps(y4);
r1 = _mm256_mul_ps(r1, y5);
r2 = _mm256_mul_ps(r2, y5);

现在它比以前更好,但仍不比 Ivy Bridge CPU 上的 SSE 快。我更新了测试结果。

【问题讨论】:

rcpps 的精度非常低,比如只有 12 位。如果这足够了,那就太好了。但通常它与 Newton-Raphson 迭代一起使用,几乎可以翻倍。如果分频器执行单元的吞吐量是一个瓶颈,那么这可能是一个胜利,否则divps 是一个具有高延迟的单个 uop,但除非非完全流水线化的 FP 分频器已经很忙,否则这不是吞吐量问题。 (不过,它只有 128 位宽,所以 256 位除法的吞吐量只有一半,这与其他 ALU 的东西不同。Floating point division vs floating point multiplication If that's enough, then great 是可选的。 glm_mat4_inv() 使用 1/div + mul,glm_mat4_inv_fast() 使用 rcpps 提高速度,但精度较低/精度较低,由用户选择。我想我应该理解“吞吐量与延迟”,我将它添加到我的 TODO 中。其实我试过理解,但似乎还不够:( 是的,计算 1/x 一次,然后乘以两次是好的,无论您使用 divps 还是 rcpps。回复:吞吐量与延迟:相关What considerations go into predicting latency for operations on modern superscalar processors and how can I calculate them by hand?。同样相关的是,标题不好的How does a single thread run on multiple cores?,还有Why does mulss take only 3 cycles on Haswell, different from Agner's instruction tables? @PeterCordes 非常感谢您提供宝贵的 cmets 和链接/资源。我稍后会阅读所有内容。 【参考方案1】:

您的 CPU 是 Intel IvyBridge。

Sandybridge / IvyBridge 在不同的端口上具有每时钟 1 次 mul 和增加吞吐量,因此它们不会相互竞争。

但对于 256 位随机播放和所有 FP 随机播放(甚至 128 位 shufps),每个时钟的随机播放吞吐量只有 1 个。 但是,对于整数混洗,它具有每时钟 2 次的吞吐量,我注意到您的编译器使用 pshufd 作为 FP 指令之间的复制和混洗。 SSE2,尤其是在 VEX 编码不可用的情况下(因此它通过替换 movaps xmm0, xmm1 / shufps xmm0, xmm0, 65 或其他方式来保存 movaps。)即使 AVX 可用,您的编译器也会这样做,所以它可以 em> 使用过vshufps xmm0, xmm1,xmm1, 65,但要么是出于微架构的原因巧妙地选择了vpshufd,要么它很幸运,或者它的启发式/指令成本模型是考虑到这一点而设计的。 (我怀疑这是clang,但您没有在问题中说或显示您编译的C源代码)。

在 Haswell 及更高版本(支持 AVX2 以及因此每个整数 shuffle 的 256 位版本)中,所有 shuffle 只能在端口 5 上运行。但在仅支持 AVX1 的 IvB 中,只有 FP shuffle 达到 256位。整数 shuffle 始终只有 128 位,并且可以在端口 1 或端口 5 上运行,因为这两个端口上都有 128 位的 shuffle 执行单元。 (https://agner.org/optimize/)


我没有详细查看 asm,因为它很长,但如果使用更宽的向量来节省加法/乘法的成本,那么它会更慢。

因为你所有的洗牌都变成了 FP 洗牌,所以它们只在端口 5 上运行,而不是利用端口 1。我怀疑有太多的洗牌,它是一个瓶颈与端口 0(FP 乘法)或端口 1( FP 添加)。

顺便说一句,Haswell 和后来的有两个 FMA 单元,在 p0 和 p1 上各一个,所以乘法的吞吐量是原来的两倍。 Skylake 和后来的 FMA 单元也在这些 FMA 单元上运行 FP add,因此它们每个时钟都有 2 个吞吐量。 (如果您可以有效地使用实际的 FMA 指令,您可以完成两倍的工作。)

此外,您的基准测试是在测试延迟,而不是吞吐量,因为相同的 m 是输入和输出。但是,可能有足够的指令级并行性来限制 shuffle 吞吐量。

vperm2f128vinsertf128 这样的通道交叉洗牌在 IvB 上有 2 个周期延迟,而在通道内洗牌(包括所有 128 位洗牌)只有一个周期延迟。英特尔的指南声称一个不同的数字 IIRC,但 2 个周期是 Agner Fog 在实践中在依赖链中发现的实际测量值。 (这可能是 1 个周期 + 某种旁路延迟)。在 Haswell 及更高版本上,车道交叉洗牌是 3 个周期延迟。 Why are some Haswell AVX latencies advertised by Intel as 3x slower than Sandy Bridge?

还相关:Do 128bit cross lane operations in AVX512 give better performance? 您有时可以使用未对齐的负载减少混洗量,该负载在有用的点切成 128 位一半,然后使用通道内混洗。这可能对 AVX1 有用,因为它缺少 vpermps 或其他粒度小于 128 位的车道交叉洗牌。

【讨论】:

很好的答案!我在问题的底部添加了更多细节,在测试中使用 clang 时我使用 GCC 来查看 asm,对此感到抱歉。 是否可以在另一个端口(例如整数域)上使用_mm256_permutevar_ps_mm256_shuffle_ps 以使其更快(我将查看英特尔内部指南)?你有什么建议,我应该保留 AVX 版本还是应该放弃它并在未来使用 SSE 版本? @recp:不,对于任何 256 位随机播放,没有任何英特尔 CPU 的每时钟吞吐量优于 1。快速 128 位随机播放是 Nehalem 通过 IvB 的一项功能。构建宽的 shuffle 单元需要花费大量晶体管,英特尔削减了 Haswell 的 shuffle 硬件。 @recp:如果可能,您应该在 Haswell 和/或 Skylake 上进行基准测试。我没有尝试手动或使用 IACA (What is IACA and how do I use it?) 对您的代码进行静态分析,以查看哪个具有更多的总洗牌,但如果它们在 Haswell 上的速度大致相同,则使用 IvB 上最快的.或者,Haswell 的 AVX2 + FMA 版本可能会通过车道交叉 256 位 shuffle 为您提供加速,但请确保您尝试将 FMA 与 AVX2 分开添加,以防 FMA + 128 位 shuffle 是最好的。这在 Ryzen 上可能真的很好。 我认为我现在找不到 Haswell 或 Skylake :( 我稍后会尝试检查 IACA。我的 CPU (IvB) 不支持 AVX2 或 FMA :( 这就是为什么我目前只实现了 AVX1。升级我的 Macbook 后,我将实现新的 CPU 功能。

以上是关于AVX mat4 inv 实现比 SSE 慢的主要内容,如果未能解决你的问题,请参考以下文章

Lanczos SSE/AVX 实施

SSE / AVX 对齐内存上的 valarray

为啥 SSE 和 AVX 具有相同的效率?

MSVC /arch:[指令集] - SSE3、AVX、AVX2

是否所有支持 AVX2 的 CPU 也支持 SSE4.2 和 AVX?

AVX vs. SSE:期望看到更大的加速