【问题标题】:Vectorization: aligned and unaligned arrays矢量化:对齐和未对齐的数组
【发布时间】:2015-09-12 05:55:50
【问题描述】:

这个问题只是为了尝试对循环向量化有更多的了解,尤其是使用 OpenMP4。下面给出的代码生成“size”随机样本,然后从这些样本中,我们从位置“qpos”中提取“qsize”样本的“q”。然后程序在“samples”数组中找到“q”的位置。这是代码:

#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <mm_malloc.h>

// SIMD size in floats, assuming 1 float = 4 bytes
#define VEC_SIZE 8
#define ALIGN (VEC_SIZE*sizeof(float))

int main(int argc, char *argv[])
{
    if (argc!=4)
    {
        printf("Usage: %s <size> <qsize> <qpos>",argv[0]);
        exit(1);
    }
    int size = atoi(argv[1]);
    int qsize = atoi(argv[2]);
    int qpos = atoi(argv[3]);
    assert(qsize < size);
    assert((qpos < size - qsize) && (qpos >= 0));

    float *samples;
    float *q;

    samples = (float *) malloc(size*sizeof(float));
    q = (float *) _mm_malloc(size*sizeof(float),ALIGN);

    // Initialization
    // - Randomly filling the samples
    samples[0] = 0.0;
    for (int i = 1 ; i < size; i++) //LOOP1
        samples[i] = samples[i-1] + rand()/((float)RAND_MAX) - 0.5;

    // - Getting q from the samples
#pragma omp simd aligned(q:ALIGN)
    for (int i = 0; i < qsize; i++) //LOOP2
        q[i] = samples[qpos+i];

    // Finding the best match (since q is taken form the samples it self
    // the position of the best match must be qpos)
    float best_dist = FLT_MAX;
    int pos = -1;
    for (int i = 0; i < size - qsize; i++)//LOOP 3
    {
        float dist = 0;
#pragma omp simd aligned(q:ALIGN) reduction(+:dist)        
        for (int j = 0; j < qsize; j++)//LOOP4
            dist += (q[j] - samples[i+j]) * (q[j] - samples[i+j]);
        if (dist < best_dist)
        {
            best_dist = dist;
            pos = i;
        }
    }    
    assert(pos==qpos);
    printf("Done!\n");

    free(samples);
    _mm_free(q);
}

我正在使用 icc 15.0.0 和 gcc 4.9.2 使用以下命令进行编译:

icc vec-test.c -o icc-vec-test -std=c11 -qopt-report=3 -qopt-report-phase=vec -qopt-report-file=icc.vec -O3 -xHost -fopenmp
gcc vec-test.c -o gcc-vec-test -std=c11 -fopt-info-vec-missed-optimized=gcc.vec -O3 -march=native -fopenmp

'q' 使用 _mm_malloc() 对齐。对“样本”做同样的事情是没有意义的,因为最内层循环(LOOP4)总是会访问它的未对齐元素。

gcc 和 icc 都报告了 LOOP4 的矢量化(实际上,如果我们省略了 '#pragma omp simd',icc 会设法自动矢量化循环,而 gcc 拒绝这样做,但这只是一个额外的观察)。从矢量化报告看来,没有一个编译器生成剥离循环。我的问题:

1) 编译器如何处理“样本”未对齐的事实?

2) 这会对性能产生多大影响?

3) icc 对 LOOP2 进行矢量化没有问题。但是 gcc 不能:“注意:未矢量化:基本块中没有足够的数据引用”。有什么想法吗?

谢谢!

【问题讨论】:

  • 对齐不再像以前那么重要了。现代处理器处理未对齐访问的速度几乎与对齐访问一样快。
  • 为什么要对齐呢?如果您想要最大的性能,我想说对齐仍然很重要。
  • 我只是说编译器无论如何都会向量化,即使它没有对齐。 (对于最近的处理器)他们不会特意检查或特殊情况进行对齐。仅仅是因为未对齐的开销可能小于分支和特殊情况处理的开销。
  • @Mystical:好的,同意:-)

标签: c openmp vectorization


【解决方案1】:

以下是我在测试运行流包以测试可持续内存带宽时的一些经验。

1) 据我所知,英特尔编译器不会生成用于检查对齐的代码,它会使用 movdqu 的等价物来加载样本,movdqa 来加载 q

2) 这取决于内存带宽和可用触发器的比率。循环 4 只需要少量计算,我的猜测是,鉴于样本的大小和 q 很大,您当前在现代 HPC 上的程序将只是内存带宽限制,修复对齐并没有多大帮助。但是,如果您将核心数量限制为

3) 编译器不根据对齐来确定向量化,当由于数据依赖性导致向量化不安全时,编译器将拒绝向量化。我在 gcc 方面的经验很少,所以我无法为此提供任何建议。

供您参考,在运行时检查对齐并提供使用对齐加载和寄存器内移位的专用例程通常可以击败编译器生成的代码。您可以查看 Intel 的 L1 BLAS 例程,了解他们是如何做到这一点的。

【讨论】:

  • 感谢您的回答。我同意你对问题二的回答,但我的问题更多地是在这个方向上(我的问题不是很清楚,很抱歉):使用movdqu 而不是movdqa 的成本会有多高?或者一般来说,与执行相同操作但使用对齐内存的指令相比,使用指令从未对齐的内存中加载/存储的成本要高多少?对于问题3)我也同意你的观点,但我想知道“基本块中没有足够的数据引用”是什么意思
  • 2) 对于串行访问,惩罚可能很小,但如果您随机访问double 的大数组,您将更频繁地从缓存边界加载双精度,并且惩罚相当到一个额外的缓存行未命中。
猜你喜欢
  • 2012-07-23
  • 2016-09-28
  • 2020-10-26
  • 2021-12-30
  • 2010-11-07
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
相关资源
最近更新 更多