相同的AVX指令集代码Intel Core与AMD Ryzen性能差距巨大

2024-02-16

我想使用AVX指令集来加速从8通道图像到8通道图像的卷积运算。我使用 3x3 卷积核。我的代码如下:

        const float* kptr = kernels;
        const float* bptr = biases;

        __m256 _out0 = _mm256_loadu_ps(bptr);
        __m256 _out1 = _mm256_setzero_ps();
        __m256 _out2 = _mm256_setzero_ps();

        for (int i = 0; i < 8; i ++)
        {
            const __m256 _r00 = _mm256_broadcast_ss(tl + i);
            const __m256 _r01 = _mm256_broadcast_ss(tc + i);
            const __m256 _r02 = _mm256_broadcast_ss(tr + i);
            const __m256 _r03 = _mm256_broadcast_ss(ml + i);
            const __m256 _r04 = _mm256_broadcast_ss(mc + i);
            const __m256 _r05 = _mm256_broadcast_ss(mr + i);
            const __m256 _r06 = _mm256_broadcast_ss(bl + i);
            const __m256 _r07 = _mm256_broadcast_ss(bc + i);
            const __m256 _r08 = _mm256_broadcast_ss(br + i);

            const __m256 _k00 = _mm256_loadu_ps(kptr + i * 72);
            const __m256 _k01 = _mm256_loadu_ps(kptr + i * 72 + 8);
            const __m256 _k02 = _mm256_loadu_ps(kptr + i * 72 + 16);
            const __m256 _k03 = _mm256_loadu_ps(kptr + i * 72 + 24);
            const __m256 _k04 = _mm256_loadu_ps(kptr + i * 72 + 32);
            const __m256 _k05 = _mm256_loadu_ps(kptr + i * 72 + 40);
            const __m256 _k06 = _mm256_loadu_ps(kptr + i * 72 + 48);
            const __m256 _k07 = _mm256_loadu_ps(kptr + i * 72 + 56);
            const __m256 _k08 = _mm256_loadu_ps(kptr + i * 72 + 64);

            _out0 = _mm256_fmadd_ps(_r00, _k00, _out0);
            _out1 = _mm256_fmadd_ps(_r01, _k01, _out1);
            _out2 = _mm256_fmadd_ps(_r02, _k02, _out2);
            _out0 = _mm256_fmadd_ps(_r03, _k03, _out0);
            _out1 = _mm256_fmadd_ps(_r04, _k04, _out1);
            _out2 = _mm256_fmadd_ps(_r05, _k05, _out2);
            _out0 = _mm256_fmadd_ps(_r06, _k06, _out0);
            _out1 = _mm256_fmadd_ps(_r07, _k07, _out1);
            _out2 = _mm256_fmadd_ps(_r08, _k08, _out2);
        }
        _out0 = _mm256_max_ps(_mm256_add_ps(_out0, _mm256_add_ps(_out1, _out2)), _mm256_setzero_ps());

        _mm256_storeu_ps(outMat, _out0);

在 Ryzen 上,这非常有效。在R5 2600和R5 3500U上测试,经过编译器优化,与普通C++代码相比,我可以获得2-4倍的性能提升。但在 Intel Core CPU 上,经过编译器优化,它甚至比普通 C++ 代码慢 50%,在 i7 8750H 和 i3 4170 上进行了测试。实际上,在这种情况下,3500U 比 i7 8750H 快 4 倍。

我对此很困惑。我发现Intel CPU中最耗时的指令是fmadd指令,但是用等效的avx指令替换fmadd后仍然没有任何改善。

我也考虑过寄存器数量的限制,但在尝试减少__mm256变量的数量后,情况可能会变得更糟。

编译器和参数都是一样的,我用msvc2019编译的,甚至用了同样的二进制文件。

权重的内存布局(kptr) 是 CHWB,输入图像像素(tl to br)是 BHWC。

测试过程中我注意到,同样场景下,i7 8750h是满载,而2600则在35%左右,性能是前者的8倍。

有什么建议么?

我没有找到很好的方法来反汇编MSVC编译的二进制文件,所以我在Linux下编译它并用GDB反汇编。这是我使用 GDB 反汇编得到的结果:

-g -fopenmp -lpthread -mavx2 -mfma -O3

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
898       return *(__m256_u *)__P;
   0x00007fffff710967 <+135>:   vxorps %xmm1,%xmm1,%xmm1
   0x00007fffff71096b <+139>:   lea    0x4(,%r13,4),%r13
   0x00007fffff710973 <+147>:   lea    0x4(,%rdi,4),%rdi
   0x00007fffff71097b <+155>:   vmovaps %ymm1,%ymm3
   0x00007fffff71097f <+159>:   mov    (%rax),%r10
   0x00007fffff710982 <+162>:   mov    0x10(%r9),%rax
   0x00007fffff710986 <+166>:   lea    0x4(,%rsi,4),%rsi
   0x00007fffff71098e <+174>:   lea    (%r11,%rdi,1),%rbx
   0x00007fffff710992 <+178>:   lea    (%r11,%rsi,1),%r12
   0x00007fffff710996 <+182>:   lea    (%rdx,%rsi,1),%r9
   0x00007fffff71099a <+186>:   add    %r13,%r11
   0x00007fffff71099d <+189>:   add    %rcx,%rsi
   0x00007fffff7109a0 <+192>:   mov    (%rax),%rax
   0x00007fffff7109a3 <+195>:   vmovups (%r10),%xmm7
   0x00007fffff7109a8 <+200>:   vinsertf128 $0x1,0x10(%r10),%ymm7,%ymm0

/home/tianzer/Anime4KCPP/Anime4KCore/src/CPUCNNProcessor.cpp:
390             for (int i = 0; i < 8; i += 2)
=> 0x00007fffff7109af <+207>:   lea    (%rdx,%rdi,1),%r10
   0x00007fffff7109b3 <+211>:   add    %r13,%rdx
   0x00007fffff7109b6 <+214>:   add    %rcx,%rdi
   0x00007fffff7109b9 <+217>:   add    %r13,%rcx
   0x00007fffff7109bc <+220>:   lea    0x900(%rax),%r13

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
735       return (__m256) __builtin_ia32_vbroadcastss256 (__X);
   0x00007fffff7109c3 <+227>:   vbroadcastss -0x4(%rbx),%ymm11
   0x00007fffff7109c9 <+233>:   vmovups (%rax),%xmm5
   0x00007fffff7109cd <+237>:   add    $0x8,%rbx
   0x00007fffff7109d1 <+241>:   add    $0x240,%rax
   0x00007fffff7109d7 <+247>:   vbroadcastss -0x4(%r11),%ymm6
   0x00007fffff7109dd <+253>:   vbroadcastss -0x4(%r9),%ymm8
   0x00007fffff7109e3 <+259>:   add    $0x8,%r12
   0x00007fffff7109e7 <+263>:   add    $0x8,%r11
   0x00007fffff7109eb <+267>:   vbroadcastss -0x4(%rdx),%ymm7
   0x00007fffff7109f1 <+273>:   vbroadcastss -0x4(%rsi),%ymm4
   0x00007fffff7109f7 <+279>:   add    $0x8,%r10
   0x00007fffff7109fb <+283>:   add    $0x8,%r9
   0x00007fffff7109ff <+287>:   vbroadcastss -0xc(%r12),%ymm10
   0x00007fffff710a06 <+294>:   vbroadcastss -0xc(%r10),%ymm9
   0x00007fffff710a0c <+300>:   add    $0x8,%rdx
   0x00007fffff710a10 <+304>:   add    $0x8,%rdi
   0x00007fffff710a14 <+308>:   vbroadcastss -0x4(%rcx),%ymm2
   0x00007fffff710a1a <+314>:   vbroadcastss -0xc(%rdi),%ymm12

/usr/lib/gcc/x86_64-linux-gnu/9/include/fmaintrin.h:
65        return (__m256)__builtin_ia32_vfmaddps256 ((__v8sf)__A, (__v8sf)__B,
   0x00007fffff710a20 <+320>:   add    $0x8,%rsi
   0x00007fffff710a24 <+324>:   add    $0x8,%rcx
   0x00007fffff710a28 <+328>:   vinsertf128 $0x1,-0x230(%rax),%ymm5,%ymm5
   0x00007fffff710a32 <+338>:   vfmadd231ps %ymm5,%ymm11,%ymm0
   0x00007fffff710a37 <+343>:   vmovups -0x220(%rax),%xmm5
   0x00007fffff710a3f <+351>:   vinsertf128 $0x1,-0x210(%rax),%ymm5,%ymm5
   0x00007fffff710a49 <+361>:   vfmadd231ps %ymm5,%ymm10,%ymm3
   0x00007fffff710a4e <+366>:   vmovups -0x200(%rax),%xmm5
   0x00007fffff710a56 <+374>:   vinsertf128 $0x1,-0x1f0(%rax),%ymm5,%ymm5
   0x00007fffff710a60 <+384>:   vfmadd231ps %ymm5,%ymm6,%ymm1
   0x00007fffff710a65 <+389>:   vmovups -0x1e0(%rax),%xmm6
   0x00007fffff710a6d <+397>:   vinsertf128 $0x1,-0x1d0(%rax),%ymm6,%ymm11
   0x00007fffff710a77 <+407>:   vmovups -0x1c0(%rax),%xmm6
   0x00007fffff710a7f <+415>:   vinsertf128 $0x1,-0x1b0(%rax),%ymm6,%ymm10
   0x00007fffff710a89 <+425>:   vfmadd132ps %ymm11,%ymm0,%ymm9
   0x00007fffff710a8e <+430>:   vfmadd132ps %ymm10,%ymm3,%ymm8
   0x00007fffff710a93 <+435>:   vmovups -0x1a0(%rax),%xmm3
   0x00007fffff710a9b <+443>:   vinsertf128 $0x1,-0x190(%rax),%ymm3,%ymm6
   0x00007fffff710aa5 <+453>:   vfmadd132ps %ymm6,%ymm1,%ymm7
   0x00007fffff710aaa <+458>:   vmovups -0x180(%rax),%xmm1
   0x00007fffff710ab2 <+466>:   vinsertf128 $0x1,-0x170(%rax),%ymm1,%ymm5
   0x00007fffff710abc <+476>:   vmovups -0x160(%rax),%xmm1
   0x00007fffff710ac4 <+484>:   vinsertf128 $0x1,-0x150(%rax),%ymm1,%ymm3
   0x00007fffff710ace <+494>:   vfmadd132ps %ymm5,%ymm9,%ymm12
   0x00007fffff710ad3 <+499>:   vbroadcastss -0x8(%r11),%ymm1
   0x00007fffff710ad9 <+505>:   vbroadcastss -0x8(%r10),%ymm5
   0x00007fffff710adf <+511>:   vfmadd132ps %ymm3,%ymm8,%ymm4
   0x00007fffff710ae4 <+516>:   vbroadcastss -0x8(%r12),%ymm3
   0x00007fffff710aeb <+523>:   vmovaps %ymm12,%ymm11
   0x00007fffff710af0 <+528>:   vmovaps %ymm4,%ymm10
   0x00007fffff710af4 <+532>:   vmovups -0x140(%rax),%xmm4
   0x00007fffff710afc <+540>:   vinsertf128 $0x1,-0x130(%rax),%ymm4,%ymm0
   0x00007fffff710b06 <+550>:   vbroadcastss -0x8(%r9),%ymm4
   0x00007fffff710b0c <+556>:   vfmadd132ps %ymm0,%ymm7,%ymm2
   0x00007fffff710b11 <+561>:   vbroadcastss -0x8(%rbx),%ymm0
   0x00007fffff710b17 <+567>:   vmovaps %ymm2,%ymm6

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
735       return (__m256) __builtin_ia32_vbroadcastss256 (__X);
   0x00007fffff710b1b <+571>:   vbroadcastss -0x8(%rdx),%ymm2
   0x00007fffff710b21 <+577>:   vbroadcastss -0x8(%rsi),%ymm8
   0x00007fffff710b27 <+583>:   vmovups -0x120(%rax),%xmm13
   0x00007fffff710b2f <+591>:   vmovups -0x100(%rax),%xmm14
   0x00007fffff710b37 <+599>:   vinsertf128 $0x1,-0x110(%rax),%ymm13,%ymm12
   0x00007fffff710b41 <+609>:   vmovups -0xe0(%rax),%xmm15
   0x00007fffff710b49 <+617>:   vbroadcastss -0x8(%rdi),%ymm9
   0x00007fffff710b4f <+623>:   vbroadcastss -0x8(%rcx),%ymm7

/usr/lib/gcc/x86_64-linux-gnu/9/include/fmaintrin.h:
65        return (__m256)__builtin_ia32_vfmaddps256 ((__v8sf)__A, (__v8sf)__B,
   0x00007fffff710b55 <+629>:   vfmadd132ps %ymm12,%ymm11,%ymm0
   0x00007fffff710b5a <+634>:   vinsertf128 $0x1,-0xf0(%rax),%ymm14,%ymm11
   0x00007fffff710b64 <+644>:   vfmadd132ps %ymm11,%ymm10,%ymm3
   0x00007fffff710b69 <+649>:   vinsertf128 $0x1,-0xd0(%rax),%ymm15,%ymm10
   0x00007fffff710b73 <+659>:   vfmadd132ps %ymm10,%ymm6,%ymm1
   0x00007fffff710b78 <+664>:   vmovups -0xc0(%rax),%xmm6
   0x00007fffff710b80 <+672>:   vinsertf128 $0x1,-0xb0(%rax),%ymm6,%ymm6
   0x00007fffff710b8a <+682>:   vfmadd132ps %ymm6,%ymm0,%ymm5
   0x00007fffff710b8f <+687>:   vmovups -0xa0(%rax),%xmm6
   0x00007fffff710b97 <+695>:   vinsertf128 $0x1,-0x90(%rax),%ymm6,%ymm0
   0x00007fffff710ba1 <+705>:   vfmadd132ps %ymm0,%ymm3,%ymm4
   0x00007fffff710ba6 <+710>:   vmovups -0x80(%rax),%xmm3
   0x00007fffff710bab <+715>:   vmovaps %ymm9,%ymm0
   0x00007fffff710baf <+719>:   vinsertf128 $0x1,-0x70(%rax),%ymm3,%ymm6
   0x00007fffff710bb6 <+726>:   vmovups -0x40(%rax),%xmm3
   0x00007fffff710bbb <+731>:   vinsertf128 $0x1,-0x30(%rax),%ymm3,%ymm3
   0x00007fffff710bc2 <+738>:   vfmadd132ps %ymm6,%ymm1,%ymm2
   0x00007fffff710bc7 <+743>:   vmovups -0x60(%rax),%xmm1
   0x00007fffff710bcc <+748>:   vinsertf128 $0x1,-0x50(%rax),%ymm1,%ymm6
   0x00007fffff710bd3 <+755>:   vfmadd132ps %ymm6,%ymm5,%ymm0
   0x00007fffff710bd8 <+760>:   vfmadd132ps %ymm8,%ymm4,%ymm3
   0x00007fffff710bdd <+765>:   vmovups -0x20(%rax),%xmm4
   0x00007fffff710be2 <+770>:   vinsertf128 $0x1,-0x10(%rax),%ymm4,%ymm1
   0x00007fffff710be9 <+777>:   vfmadd132ps %ymm7,%ymm2,%ymm1

/home/tianzer/Anime4KCPP/Anime4KCore/src/CPUCNNProcessor.cpp:
390             for (int i = 0; i < 8; i += 2)
   0x00007fffff710bee <+782>:   cmp    %rax,%r13
   0x00007fffff710bf1 <+785>:   jne    0x7fffff7109c3 <std::_Function_handler<void(int, int, float*, float*), Anime4KCPP::CPU::CNNProcessor::conv8To8(const FP*, const FP*, cv::Mat&)::<lambda(int, int, Anime4KCPP::CPU::ChanFP, Anime4KCPP::CPU::LineFP)> >::_M_invoke(const std::_Any_data &, int &&, int &&, float *&&, float *&&)+227>

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
1230      return __extension__ (__m256){ 0.0, 0.0, 0.0, 0.0,
   0x00007fffff710bf7 <+791>:   vaddps %ymm3,%ymm0,%ymm0
   0x00007fffff710bfb <+795>:   vaddps %ymm1,%ymm0,%ymm0
   0x00007fffff710bff <+799>:   vxorps %xmm1,%xmm1,%xmm1
   0x00007fffff710c03 <+803>:   vmaxps %ymm1,%ymm0,%ymm0

904       *(__m256_u *)__P = __A;
   0x00007fffff710c07 <+807>:   vmovups %xmm0,(%r8)
   0x00007fffff710c0c <+812>:   vextractf128 $0x1,%ymm0,0x10(%r8)
   0x00007fffff710c13 <+819>:   vzeroupper
   0x00007fffff710c16 <+822>:   pop    %rbx
   0x00007fffff710c17 <+823>:   pop    %r12
   0x00007fffff710c19 <+825>:   pop    %r13
   0x00007fffff710c1b <+827>:   pop    %rbp
   0x00007fffff710c1c <+828>:   retq

如果我使用 -march=native 来构建:-g -fopenmp -lpthread -march=native -O3

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
898       return *(__m256_u *)__P;
   0x00007fffff711596 <+134>:   vxorps %xmm1,%xmm1,%xmm1
   0x00007fffff71159a <+138>:   lea    0x4(,%r10,4),%r13
   0x00007fffff7115a2 <+146>:   lea    0x4(,%rdi,4),%rdi
   0x00007fffff7115aa <+154>:   vmovaps %ymm1,%ymm2
   0x00007fffff7115ae <+158>:   mov    (%rax),%rax
   0x00007fffff7115b1 <+161>:   lea    0x4(,%rsi,4),%rsi
   0x00007fffff7115b9 <+169>:   lea    (%r11,%rdi,1),%rbx
   0x00007fffff7115bd <+173>:   lea    (%r11,%rsi,1),%r12
   0x00007fffff7115c1 <+177>:   lea    (%rdx,%rdi,1),%r10
   0x00007fffff7115c5 <+181>:   add    %r13,%r11
   0x00007fffff7115c8 <+184>:   add    %rcx,%rdi
   0x00007fffff7115cb <+187>:   vmovups (%rax),%ymm0

/home/tianzer/Anime4KCPP/Anime4KCore/src/CPUCNNProcessor.cpp:
390             for (int i = 0; i < 8; i += 2)
=> 0x00007fffff7115cf <+191>:   mov    0x10(%r9),%rax
   0x00007fffff7115d3 <+195>:   lea    (%rdx,%rsi,1),%r9
   0x00007fffff7115d7 <+199>:   add    %r13,%rdx
   0x00007fffff7115da <+202>:   add    %rcx,%rsi
   0x00007fffff7115dd <+205>:   add    %r13,%rcx
   0x00007fffff7115e0 <+208>:   mov    (%rax),%rax
   0x00007fffff7115e3 <+211>:   lea    0x900(%rax),%r13

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
735       return (__m256) __builtin_ia32_vbroadcastss256 (__X);
   0x00007fffff7115ea <+218>:   vbroadcastss -0x4(%r11),%ymm4
   0x00007fffff7115f0 <+224>:   vbroadcastss -0x4(%rbx),%ymm3
   0x00007fffff7115f6 <+230>:   add    $0x8,%r12
   0x00007fffff7115fa <+234>:   add    $0x240,%rax
   0x00007fffff711600 <+240>:   vbroadcastss -0x4(%r10),%ymm11
   0x00007fffff711606 <+246>:   vbroadcastss -0x4(%r9),%ymm10
   0x00007fffff71160c <+252>:   add    $0x8,%rbx
   0x00007fffff711610 <+256>:   add    $0x8,%r11
   0x00007fffff711614 <+260>:   vbroadcastss -0x4(%rdx),%ymm9
   0x00007fffff71161a <+266>:   vbroadcastss -0x4(%rdi),%ymm8
   0x00007fffff711620 <+272>:   add    $0x8,%r10
   0x00007fffff711624 <+276>:   add    $0x8,%r9
   0x00007fffff711628 <+280>:   vbroadcastss -0xc(%r12),%ymm5
   0x00007fffff71162f <+287>:   vbroadcastss -0x4(%rsi),%ymm7
   0x00007fffff711635 <+293>:   add    $0x8,%rdx
   0x00007fffff711639 <+297>:   add    $0x8,%rdi
   0x00007fffff71163d <+301>:   vbroadcastss -0x4(%rcx),%ymm6

/usr/lib/gcc/x86_64-linux-gnu/9/include/fmaintrin.h:
65        return (__m256)__builtin_ia32_vfmaddps256 ((__v8sf)__A, (__v8sf)__B,
   0x00007fffff711643 <+307>:   add    $0x8,%rsi
   0x00007fffff711647 <+311>:   add    $0x8,%rcx
   0x00007fffff71164b <+315>:   vfmadd132ps -0x240(%rax),%ymm0,%ymm3
   0x00007fffff711654 <+324>:   vbroadcastss -0x8(%r10),%ymm0
   0x00007fffff71165a <+330>:   vfmadd132ps -0x220(%rax),%ymm2,%ymm5
   0x00007fffff711663 <+339>:   vbroadcastss -0x8(%rsi),%ymm2
   0x00007fffff711669 <+345>:   vfmadd231ps -0x200(%rax),%ymm4,%ymm1
   0x00007fffff711672 <+354>:   vbroadcastss -0x8(%rdx),%ymm4
   0x00007fffff711678 <+360>:   vfmadd132ps -0x1e0(%rax),%ymm3,%ymm11
   0x00007fffff711681 <+369>:   vbroadcastss -0x8(%rcx),%ymm3
   0x00007fffff711687 <+375>:   vfmadd132ps -0x1c0(%rax),%ymm5,%ymm10
   0x00007fffff711690 <+384>:   vbroadcastss -0x8(%r9),%ymm5
   0x00007fffff711696 <+390>:   vfmadd132ps -0x1a0(%rax),%ymm1,%ymm9
   0x00007fffff71169f <+399>:   vbroadcastss -0x8(%rdi),%ymm1
   0x00007fffff7116a5 <+405>:   vfmadd231ps -0x180(%rax),%ymm8,%ymm11
   0x00007fffff7116ae <+414>:   vbroadcastss -0x8(%rbx),%ymm8
   0x00007fffff7116b4 <+420>:   vfmadd231ps -0x160(%rax),%ymm7,%ymm10
   0x00007fffff7116bd <+429>:   vbroadcastss -0x8(%r12),%ymm7
   0x00007fffff7116c4 <+436>:   vfmadd231ps -0x140(%rax),%ymm6,%ymm9

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
735       return (__m256) __builtin_ia32_vbroadcastss256 (__X);
   0x00007fffff7116cd <+445>:   vbroadcastss -0x8(%r11),%ymm6

/usr/lib/gcc/x86_64-linux-gnu/9/include/fmaintrin.h:
65        return (__m256)__builtin_ia32_vfmaddps256 ((__v8sf)__A, (__v8sf)__B,
   0x00007fffff7116d3 <+451>:   vfmadd132ps -0x120(%rax),%ymm11,%ymm8
   0x00007fffff7116dc <+460>:   vfmadd132ps -0x100(%rax),%ymm10,%ymm7
   0x00007fffff7116e5 <+469>:   vfmadd132ps -0xe0(%rax),%ymm9,%ymm6
   0x00007fffff7116ee <+478>:   vfmadd132ps -0xc0(%rax),%ymm8,%ymm0
   0x00007fffff7116f7 <+487>:   vfmadd132ps -0xa0(%rax),%ymm7,%ymm5
   0x00007fffff711700 <+496>:   vfmadd132ps -0x80(%rax),%ymm6,%ymm4
   0x00007fffff711706 <+502>:   vfmadd132ps -0x20(%rax),%ymm4,%ymm3
   0x00007fffff71170c <+508>:   vfmadd231ps -0x60(%rax),%ymm1,%ymm0
   0x00007fffff711712 <+514>:   vfmadd132ps -0x40(%rax),%ymm5,%ymm2
   0x00007fffff711718 <+520>:   vmovaps %ymm3,%ymm1

/home/tianzer/Anime4KCPP/Anime4KCore/src/CPUCNNProcessor.cpp:
390             for (int i = 0; i < 8; i += 2)
   0x00007fffff71171c <+524>:   cmp    %rax,%r13
   0x00007fffff71171f <+527>:   jne    0x7fffff7115ea <std::_Function_handler<void(int, int, float*, float*), Anime4KCPP::CPU::CNNProcessor::conv8To8(const FP*, const FP*, cv::Mat&)::<lambda(int, int, Anime4KCPP::CPU::ChanFP, Anime4KCPP::CPU::LineFP)> >::_M_invoke(const std::_Any_data &, int &&, int &&, float *&&, float *&&)+218>

/usr/lib/gcc/x86_64-linux-gnu/9/include/avxintrin.h:
1230      return __extension__ (__m256){ 0.0, 0.0, 0.0, 0.0,
   0x00007fffff711725 <+533>:   vaddps %ymm2,%ymm0,%ymm0
   0x00007fffff711729 <+537>:   vxorps %xmm1,%xmm1,%xmm1
   0x00007fffff71172d <+541>:   vaddps %ymm3,%ymm0,%ymm0
   0x00007fffff711731 <+545>:   vmaxps %ymm1,%ymm0,%ymm0

904       *(__m256_u *)__P = __A;
   0x00007fffff711735 <+549>:   vmovups %ymm0,(%r8)
   0x00007fffff71173a <+554>:   vzeroupper
   0x00007fffff71173d <+557>:   pop    %rbx
   0x00007fffff71173e <+558>:   pop    %r12
   0x00007fffff711740 <+560>:   pop    %r13
   0x00007fffff711742 <+562>:   pop    %rbp
   0x00007fffff711743 <+563>:   retq

Benchmark结果来自Intel i3 4170,分数是处理时间乘以一个因子的倒数,使用​​来自gcc的bin,与上面的反汇编一致。 MSVC 的结果几乎相同:

ordinary C++ code: 4.13368
-mavx2 -mfma: 2.51132
-march=native: 2.46779

我注意到在下面-march=native编译时,vfmadd231ps 直接从内存中获取操作数。是因为Intel的L2不够大吗? Ryzen 每个核心的 L2 是 Intel 的两倍。


如果我正确地阅读了代码,则第一次计算out0只需要_r00 and _k00, then out1需要_r01 and _k01,等等。那么,对于out0你需要_r03 and _k03,等等。

这是可识别的代码。我想是 GRU 神经网络?

不管怎样,诀窍是合并内存中的 9 个子矩阵,这样你就只有一个权重矩阵,然后只产生一个输出向量。如果你really需要将输出拆分为 3 个向量,您可以在后面的步骤中复制这些值,但这可能没有必要。即使副本是必要的,如果你可以将它与激活函数合并,它也相当便宜。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

相同的AVX指令集代码Intel Core与AMD Ryzen性能差距巨大 的相关文章

  • 如果.Net Core可以在Windows上运行,为什么不能在.Net Framework中引用.Net Core DLL?

    我明白为什么 Net Framework 可能会在 Net Core IE 中导致问题 因为不存在特定于 Windows 平台的 API 但是为什么不能直接引用 Net Core 作为 Net Framework 中的库呢 如果 Net C
  • 获取两个字符串之间的公共部分c# [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我需要的是获取两个单词之间的共同部分并获取差异 例子 场景1 word1 感言 word2 Test 将返回 公共部分Test 不同之
  • 捕获 foreach 条件中抛出的异常

    我有一个foreach在 foreach 本身的条件下循环期间中断的循环 有没有办法try catch抛出异常然后继续循环的项 这将运行几次 直到异常发生然后结束 try foreach b in bees exception is in
  • Guid 应包含 32 位数字和 4 个破折号

    我有一个包含 createuserwizard 控件的网站 创建帐户后 验证电子邮件及其验证 URL 将发送到用户的电子邮件地址 但是 当我进行测试运行时 单击电子邮件中的 URL 时 会出现以下错误 Guid should contain
  • 迭代列表的奇怪速度差异

    我创建了两个重复两个不同值的长列表 在第一个列表中 值交替出现 在第二个列表中 一个值出现在另一个值之前 a1 object object 10 6 a2 a1 2 a1 1 2 然后我迭代它们 不对它们执行任何操作 for in a1 p
  • C++11 函数局部静态 const 对象的线程安全初始化

    这个问题已在 C 98 上下文中提出 并在该上下文中得到回答 但没有明确说明有关 C 11 的内容 const some type create const thingy lock my lock some mutex static con
  • C# 创建数组的数组

    我正在尝试创建一个将使用重复数据的数组数组 如下所示 int list1 new int 4 1 2 3 4 int list2 new int 4 5 6 7 8 int list3 new int 4 1 3 2 1 int list4
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • UWP 无法在两个应用程序之间创建本地主机连接

    我正在尝试在两个 UWP 应用程序之间设置 TCP 连接 当服务器和客户端在同一个应用程序中运行时 它可以正常工作 但是 当我将服务器部分移动到一个应用程序并将客户端部分移动到另一个应用程序时 ConnectAsync 会引发异常 服务器未
  • 通过等待任务或访问其 Exception 属性都没有观察到任务的异常

    这些是我的任务 我应该如何修改它们以防止出现此错误 我检查了其他类似的线程 但我正在使用等待并继续 那么这个错误是怎么发生的呢 通过等待任务或访问其 Exception 属性都没有观察到任务的异常 结果 未观察到的异常被终结器线程重新抛出
  • 从匿名类型获取值

    我有一个方法如下 public void MyMethod object obj implement 我这样称呼它 MyMethod new myparam waoww 那么我该如何实施MyMethod 获取 myparam 值 Edit
  • C# 搜索目录中包含字符串的所有文件,然后返回该字符串

    使用用户在文本框中输入的内容 我想搜索目录中的哪个文件包含该文本 然后我想解析出信息 但我似乎找不到该字符串或至少返回信息 任何帮助将不胜感激 我当前的代码 private void btnSearchSerial Click object
  • 过期时自动重新填充缓存

    我当前缓存方法调用的结果 缓存代码遵循标准模式 如果存在 则使用缓存中的项目 否则计算结果 在返回之前将其缓存以供将来调用 我想保护客户端代码免受缓存未命中的影响 例如 当项目过期时 我正在考虑生成一个线程来等待缓存对象的生命周期 然后运行
  • Silverlight Datagrid:在对列进行排序时突出显示整个列

    我的 Silverlight 应用程序中有一个 DataGrid 我想在对该列进行排序时突出显示整个列 它在概念上与上一个问题类似 Silverlight DataGrid 突出显示整列 https stackoverflow com qu
  • 是否有一个 C++ 库可以从 PDF 文件中提取文本,例如 PDFBox for Java? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 去年 我使用 PDFBox 在 Java 中创建了一个应用程序来获取某些 PDF 文件中的原始文本 现在
  • 内核开发和 C++ [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 从我know https stackoverflow com questions 580292 what languages are windo
  • Fluent NHibernate 日期时间 UTC

    我想创建一个流畅的 nhibernate 映射来通过以下方式映射 DateTime 字段 保存时 保存 UTC 值 读取时 调整为本地时区值 实现此映射的最佳方法是什么 就我个人而言 我会将日期存储在 UTC 格式的对象中 然后在读 写时在
  • 同时从多个流中捕获、最佳方法以及如何减少 CPU 使用率

    我目前正在编写一个应用程序 该应用程序将捕获大量 RTSP 流 在我的例子中为 12 个 并将其显示在 QT 小部件上 当我超过大约 6 7 个流时 问题就会出现 CPU 使用率激增并且出现明显的卡顿 我认为它不是 QT 绘制函数的原因是因
  • 如何在 GCC 5 中处理双 ABI?

    我尝试了解如何克服 GCC 5 中引入的双重 ABI 的问题 但是 我没能做到 这是一个重现错误的非常简单的示例 我使用的GCC版本是5 2 如您所见 我的主要函数 在 main cpp 文件中 非常简单 main cpp include
  • 热重载时调用方法

    我正在使用 Visual Studio 2022 和 C 制作游戏 我想知道当您热重新加载应用程序 当它正在运行时 时是否可以触发一些代码 我基本上有 2 个名为 UnloadLevel 和 LoadLevel 的方法 我想在热重载时执行它

随机推荐