【问题标题】:answer is not correct using icc compiler使用 icc 编译器的答案不正确
【发布时间】:2018-05-14 05:53:13
【问题描述】:

当我在mac上使用icc编译器时,我无法用gcc、clang等其他编译器得到相同的答案。 使用icc编译器,结果如下

0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00

期待的答案就在这里

1.000000e+00
2.000000e+00
3.000000e+00
4.000000e+00
2.500000e+01
3.000000e+01
3.500000e+01
4.000000e+01

我是这样编译的:

  • icc:icc test1.c -fopenmp -mavx -Wall
  • gcc:gcc test1.c -fopenmp -mavx -Wall
  • 叮当声:clang test1.c -fopenmp -mavx -Wall

我的代码如下:

#include "stdio.h"
#include "time.h"
#include "math.h"
#include "stdlib.h"
#include "omp.h"
#include "x86intrin.h"

void dd_m_dd(double *ahi, double *bhi, double *chi, int m, int n)
{

    int j;
    #pragma omp parallel
    {
        __m256d vahi,vbhi,vchi;
        #pragma omp for private(vahi,vbhi,vchi)
        for (j = 0; j < m*n; j+=4) {

            vbhi = _mm256_broadcast_sd(&bhi[j]);
            vahi = _mm256_load_pd(&ahi[j]);
            vchi = _mm256_load_pd(&chi[j]);

            vchi=vahi*vbhi;

            chi[j]=vchi[0];
            chi[j+1]=vchi[1];
            chi[j+2]=vchi[2];
            chi[j+3]=vchi[3];

        }
    }
}

int main(int argc, const char * argv[]){
    // Matrix Vector Product with DD

    // set variables
    int m;
    double* xhi;
    double* yhi;
    double* z;
    int i;

    m=(int)pow(2,3);
    // main program

    // set vector or matrix
    xhi=(double *)malloc(sizeof(double) * m*1);
    yhi=(double *)malloc(sizeof(double) * m*1);
    z=(double *)malloc(sizeof(double) * m*1);
    //preset
    for (i=0;i<m;i++) {
        xhi[i]=i+1;
        yhi[i]=i+1;
        z[i]=0;
    }

    dd_m_dd(xhi,yhi,z,m,1);

    for (i=0;i<m;i++) {
        printf("%e\n",z[i]);
    }

    free(xhi);
    free(yhi);
    free(z);
    return 0;
}

这里发生了什么?

【问题讨论】:

  • 在这里停止对旧 cppcon 视频的记忆,但我认为 icc 默认启用了-ffast-math。我不知道这是否会对您的示例起作用,但可能值得测试。
  • 我建议使用-march=native,而不仅仅是-mavx,来针对您的目标机器进行调优,而不是在针对通用进行调优的同时启用AVX。 (尤其是 gcc)。
  • vchi = _mm256_load_pd(&amp;chi[j]); 立即被vchi=vahi*vbhi; 覆盖,这看起来不对;您的意思是添加 += 而不是分配?

标签: gcc clang openmp avx icc


【解决方案1】:

我不习惯向量内在函数,但这对我来说看起来很可疑:

    chi[j]=vchi[0];
    chi[j+1]=vchi[1];
    chi[j+2]=vchi[2];
    chi[j+3]=vchi[3];

事实上,用看起来非常适合工作的函数替换它,即_mm256_store_pd() 似乎可以解决问题。

您的函数现在可能看起来像这样(还有一些样式修复)

void dd_m_dd(double *ahi, double *bhi, double *chi, int m, int n) {

    #pragma omp parallel for
    for (int j = 0; j < m*n; j+=4) {

        __m256d vbhi = _mm256_broadcast_sd(&bhi[j]);
        __m256d vahi = _mm256_load_pd(&ahi[j]);

        __m256d vchi=vahi*vbhi;

        _mm256_store_pd( &chi[j], vchi );
    }
}

另一个问题是你没有强制你的指针正确对齐......像这样重写分配只是修复它:

double *xhi=(double *)aligned_alloc(256, sizeof(double) * m*1);
double *yhi=(double *)aligned_alloc(256, sizeof(double) * m*1);
double *z=(double *)aligned_alloc(256, sizeof(double) * m*1);

【讨论】:

  • 也可以vchi = _mm256_mul_pd(vahi,vdhi
  • @Zboson 是的,我在写答案时想知道这一点,但由于我对这些东西很陌生,所以我更喜欢坚持 OP 的原始方法。现在,出于好奇,我确实尝试了*_mm256_mul_pd(),结果编译器生成了完全相同的代码(这并不让我感到惊讶)。现在这两个哪个更好,IDK...
  • @Zboson:实现 GNU C 扩展的编译器根据 GNU C 原生向量定义 __m256d,因此 __m256d vchi=vahi*vbhi; 被很好地定义为垂直 SIMD 乘法 (vmulpd)。顺便说一句,Gilles:我们不知道chi 是对齐的,所以应该使用_mm256_storeu_pd。但同样,GNU C 原生向量扩展定义了 vchi[1] 语法来做 OP 所期望的。 (不保证它有效地编译了一个vmovupd完成的4个元素,但这并不能解释正确性问题。)
  • re: 哪个更好? * 运算符更具可读性,但不能移植到 MSVC,除非您使用像 Agner Fog 的 VCL 这样的包装库。它也会让你在整数向量方面遇到麻烦,因为它们是根据long long 定义的,所以你会得到paddq 或其他任何东西,无论它来自set1_epi8 还是set1_epi64。 Agner Fog 的 VCL 对整数向量的不同元素宽度有不同的类型,所以你可以在那里使用v1 + v2v1 * v2agner.org/optimize/#vectorclass.
  • @PeterCordes,我个人尽可能尝试使用所有向量扩展或所有内在函数。在 OP 的情况下,如果指针是 32 字节对齐的,则 ICC 只需要广播内在函数(但不需要 GCC 或 Clang stackoverflow.com/a/43801280/2542702)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-30
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-05
相关资源
最近更新 更多