gpt4 book ai didi

gcc - 在标量矩阵加法中使用 vaddss 代替 adds 有什么好处?

转载 作者:行者123 更新时间:2023-12-01 21:15:58 25 4
gpt4 key购买 nike

我已经实现了标量矩阵加法内核。

#include <stdio.h>
#include <time.h>
//#include <x86intrin.h>

//loops and iterations:
#define N 128
#define M N
#define NUM_LOOP 1000000


float __attribute__(( aligned(32))) A[N][M],
__attribute__(( aligned(32))) B[N][M],
__attribute__(( aligned(32))) C[N][M];

int main()
{
int w=0, i, j;
struct timespec tStart, tEnd;//used to record the processiing time
double tTotal , tBest=10000;//minimum of toltal time will asign to the best time
do{
clock_gettime(CLOCK_MONOTONIC,&tStart);

for( i=0;i<N;i++){
for(j=0;j<M;j++){
C[i][j]= A[i][j] + B[i][j];
}
}

clock_gettime(CLOCK_MONOTONIC,&tEnd);
tTotal = (tEnd.tv_sec - tStart.tv_sec);
tTotal += (tEnd.tv_nsec - tStart.tv_nsec) / 1000000000.0;
if(tTotal<tBest)
tBest=tTotal;
} while(w++ < NUM_LOOP);

printf(" The best time: %lf sec in %d repetition for %dX%d matrix\n",tBest,w, N, M);
return 0;
}

在本例中,我使用不同的编译器标志编译了程序,内循环的汇编输出如下:

gcc -O2 msse4.2:最佳时间:128X128 矩阵 406490 次重复中的 0.000024 秒

movss   xmm1, DWORD PTR A[rcx+rax]
addss xmm1, DWORD PTR B[rcx+rax]
movss DWORD PTR C[rcx+rax], xmm1

gcc -O2 -mavx:最佳时间:128X128 矩阵 1000001 次重复中的 0.000009 秒

vmovss  xmm1, DWORD PTR A[rcx+rax]
vaddss xmm1, xmm1, DWORD PTR B[rcx+rax]
vmovss DWORD PTR C[rcx+rax], xmm1

AVX版本gcc -O2 -mavx:

__m256 vec256;
for(i=0;i<N;i++){
for(j=0;j<M;j+=8){
vec256 = _mm256_add_ps( _mm256_load_ps(&A[i+1][j]) , _mm256_load_ps(&B[i+1][j]));
_mm256_store_ps(&C[i+1][j], vec256);
}
}

SSE版本gcc -O2 -sse4.2::

__m128 vec128;
for(i=0;i<N;i++){
for(j=0;j<M;j+=4){
vec128= _mm_add_ps( _mm_load_ps(&A[i][j]) , _mm_load_ps(&B[i][j]));
_mm_store_ps(&C[i][j], vec128);
}
}

在标量程序中,-mavx 相对于 msse4.2 的加速是 2.7 倍。我知道 avx 有效地改进了 ISA,这可能是因为这些改进。但是,当我在 AVXSSE 的内在函数中实现该程序时,速度提升了 3 倍。问题是:AVX 标量比 SSE 快 2.7 倍,当我对其进行矢量化时,速度提高了 3 倍(这个问题的矩阵大小为 128x128)。这有什么意义吗?在标量模式下使用 AVX 和 SSE 时,速度提高了 2.7 倍。但矢量化方法一定更好,因为我在 AVX 中处理 8 个元素,而在 SSE 中处理 4 个元素。根据 perf stat 报告,所有程序的缓存未命中率均低于 4.5%。

使用gcc -O2linux mintskylake

更新: 简而言之,Scalar-AVX 比 Scalar-SSE 快 2.7 倍,但 AVX-256 在矢量化时仅比 SSE-128 快 3 倍。我认为这可能是因为管道。在标量中,我有 3 个 vec-ALU,它们可能无法在矢量化模式下使用。我可能会比较苹果与橙子,而不是比较苹果与苹果,这可能是我无法理解原因的一点。

最佳答案

您所观察到的问题已得到解释 here 。在 Skylake 系统上,如果 AVX 寄存器的上半部分脏,则非 vex 编码的 SSE 操作对 AVX 寄存器的上半部分存在错误依赖性。就您而言,您的 glibc 2.23 版本似乎存在错误。在我的带有 Ubuntu 16.10 和 glibc 2.24 的 Skylake 系统上,我没有遇到这个问题。您可以使用

__asm__ __volatile__ ( "vzeroupper" : : : ); 

清理 AVX 寄存器的上半部分。我认为您不能使用诸如 _mm256_zeroupper 之类的内在函数来解决此问题,因为 GCC 会说它是 SSE 代码并且无法识别该内在函数。 -mvzeroupper 选项也不起作用,因为 GCC 再次认为它是 SSE 代码,并且不会发出 vzeroupper 指令。

顺便说一句,it's Microsoft's fault that the hardware has this problem .

<小时/>

更新:

Other people are apparently encountering this problem on Skylake 。在 printf 之后观察到,memsetclock_gettime

如果您的目标是将 128 位操作与 256 位操作进行比较,可以考虑使用 -mprefer-avx128 -mavx (这在 AMD 上特别有用)。但这样你就会比较 AVX256 与 AVX128,而不是 AVX256 与 SSE。 AVX128和SSE都使用128位运算,但它们的实现不同。如果您进行基准测试,您应该提及您使用的是哪一个。

关于gcc - 在标量矩阵加法中使用 vaddss 代替 adds 有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42324992/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com