用 C++ 实现 SIMD

Posted

技术标签:

【中文标题】用 C++ 实现 SIMD【英文标题】:implement SIMD in C++ 【发布时间】:2010-04-29 16:53:11 【问题描述】:

我正在编写一些代码,我正在尝试尽可能优化它,基本上让它在一定的时间限制下运行。

下面的调用...

static affinity_partitioner ap;
parallel_for(blocked_range<size_t>(0, T), LoopBody(score), ap);

...下面是执行的内容。

void operator()(const blocked_range<size_t> &r) const 

    int temp;
    int i;
    int j;
    size_t k;
    size_t begin = r.begin();
    size_t end = r.end();

    for(k = begin; k != end; ++k)  // for each trainee
        temp = 0;
        for(i = 0; i < N; ++i)  // for each sample
            int trr = trRating[k][i];
            int ei = E[i];              
            for(j = 0; j < ei; ++j)  // for each expert
                temp += delta(i, trr, exRating[j][i]);
            
                   
        myscore[k] = temp;
    

我正在使用英特尔的 TBB 来优化它。但我也一直在阅读有关 SIMD 和 SSE2 以及类似性质的内容。所以我的问题是,如何将变量 (i,j,k) 存储在寄存器中,以便 CPU 可以更快地访问它们?我认为答案与实现 SSE2 或它的一些变体有关,但我不知道该怎么做。有什么想法吗?

编辑:这将在 Linux 机器上运行,但我相信使用英特尔的编译器。如果有帮助,我必须在执行任何操作以确保编译器工作之前运行以下命令... source /opt/intel/Compiler/11.1/064/bin/intel64/iccvars_intel64.csh; source /opt/intel/tbb/2.2/bin/intel64/tbbvars.csh ...然后编译我做: icc -ltbb test.cxx -o test

如果没有简单的方法来实现 SSE2,有什么建议可以进一步优化代码吗?

谢谢, 赫里斯托

【问题讨论】:

编译器应该为你做这种事情。 @zdav:C++ 的语义排除了向量化,因为默认情况下指针可能是未对齐的或别名的。 ICC 允许您提供嵌入在代码中的提示,以帮助它更好地进行矢量化。当然,如果您无法控制所提供数据的对齐方式等,那么这将无济于事。 【参考方案1】:

您的问题代表了对正在发生的事情的一些困惑。 i,j,k 变量几乎肯定已经保存在寄存器中,假设您正在编译优化(您应该这样做 - 在您的 icc 调用中添加“-O2”)。

您可以使用 asm 块,但考虑到您已经在使用 ICC,更简单的方法是使用 SSE 内在函数。英特尔为他们提供的文档在这里 - http://www.intel.com/software/products/compilers/clin/docs/ug_cpp/comm1019.htm

看起来您可以对***循环进行 SIMD 化处理,但这在很大程度上取决于您的 delta 函数是什么。

【讨论】:

我无法控制 icc 调用。这是一个家庭作业,所以我能做的非常有限。我什至无法编辑完全可以优化的 delta 函数。我会摆弄 asm 块的想法。谢谢。 @Hristo:与 asm 块相比,Intrinsics 应该给您带来更少的麻烦。但是一定要研究自动矢量化。您应该能够找到 #pragma 模拟对命令行标志的控制的命令。【参考方案2】:

当您想在 C++ 模块中使用汇编语言时,您可以将其放在 asm 块中,并继续在块外使用您的变量名。您在asm 块中使用的汇编指令将指定正在对哪个寄存器等进行操作,但它们会因平台而异。

【讨论】:

【参考方案3】:

如果您使用 GCC,请参阅http://gcc.gnu.org/projects/tree-ssa/vectorization.html,了解如何帮助编译器自动矢量化您的代码和示例。

否则,您需要让我们知道您使用的是什么平台。

【讨论】:

这将在 Linux 机器上运行,但我相信使用英特尔的编译器。如果有帮助,我必须在执行任何操作以确保编译器工作之前运行以下命令... source /opt/intel/Compiler/11.1/064/bin/intel64/iccvars_intel64.csh; source /opt/intel/tbb/2.2/bin/intel64/tbbvars.csh ...然后编译我做:icc -ltbb test.cxx -o test advogato.org/article/871.html 很旧,但看起来很相关。 -xW -O2 -vec-report3。并查看man icc 并搜索vector【参考方案4】:

编译器应该为您执行此操作。例如,在 VC++ 中,您可以简单地打开 SSE2。

【讨论】:

SSE2 自动矢量化是 icpc 的默认选项,而 g++ 则是完全正常的选项。从您所展示的内容来看,它可能需要交换内部循环以及允许函数的内联扩展。对于关于显式 simd 的问题更是如此。为什么

以上是关于用 C++ 实现 SIMD的主要内容,如果未能解决你的问题,请参考以下文章

基于 SIMD 的算法实现的复杂性比较

为啥访问单个 SIMD 元素这么慢

是否有 SIMD 指令来实现批量数组内存索引映射?

为啥 C++ 标准库中没有 SIMD 功能?

在 CUDA 中使用 SIMD 实现位循环运算符

在具有两个元素的领域中利用 SIMD 实现 Peterson 和 Monico 的 Lanczos 算法