Mar*_*tin 5 x86 assembly gcc sse avx
我已经实现了标量矩阵加法内核。
#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;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我使用不同的编译器标志编译了程序,内部循环的汇编输出如下:
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
上交所版本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);
}
}
Run Code Online (Sandbox Code Playgroud)
-mavx在标量程序中, over的加速比msse4.2是 2.7 倍。我知道avxISA 得到了有效的改进,这可能是因为这些改进。但是当我在两者的内在函数中实现该程序时AVX,SSE加速率为 3 倍。问题是:AVX 标量比 SSE 快 2.7 倍,当我对其进行矢量化时,速度提高了 3 倍(这个问题的矩阵大小为 128x128)。这有什么意义吗?在标量模式下使用 AVX 和 SSE 时,速度提高了 2.7 倍。但矢量化方法一定更好,因为我在 AVX 中处理 8 个元素,而在 SSE 中处理 4 个元素。据报告,所有程序的缓存未命中率均低于 4.5% perf stat。
使用gcc -O2,linux mint,skylake
更新:简而言之,Scalar-AVX 比 Scalar-SSE 快 2.7 倍,但 AVX-256 在矢量化时仅比 SSE-128 快 3 倍。我认为这可能是因为管道。在标量中,我有 3 个vec-ALU可能无法在矢量化模式下使用。我可能会比较苹果与橙子,而不是比较苹果与苹果,这可能是我无法理解原因的一点。
这里解释了您所观察到的问题。在 Skylake 系统上,如果 AVX 寄存器的上半部分脏,则非 vex 编码的 SSE 操作对 AVX 寄存器的上半部分存在错误依赖性。就您而言,您的 glibc 2.23 版本似乎存在错误。在我的带有 Ubuntu 16.10 和 glibc 2.24 的 Skylake 系统上,我没有遇到这个问题。您可以使用
__asm__ __volatile__ ( "vzeroupper" : : : );
Run Code Online (Sandbox Code Playgroud)
清理 AVX 寄存器的上半部分。我不认为你可以使用内在函数来_mm256_zeroupper解决这个问题,因为 GCC 会说它是 SSE 代码并且无法识别内在函数。这些选项-mvzeroupper也不起作用,因为 GCC 再次认为它是 SSE 代码并且不会发出指令vzeroupper。
顺便说一句,硬件出现这个问题是微软的错。
更新:
其他人显然在 Skylake 上遇到了这个问题。printf在、memset、 和后观察到了这一点clock_gettime。
如果您的目标是将 128 位操作与 256 位操作进行比较,可以考虑使用-mprefer-avx128 -mavx(这在 AMD 上特别有用)。但这样你就会比较 AVX256 与 AVX128,而不是 AVX256 与 SSE。AVX128和SSE都使用128位运算,但它们的实现不同。如果你进行基准测试,你应该提及你使用的是哪一个。
| 归档时间: |
|
| 查看次数: |
1971 次 |
| 最近记录: |