c++ amp:复合类型,for循环,GPU上的声明

Posted

技术标签:

【中文标题】c++ amp:复合类型,for循环,GPU上的声明【英文标题】:c++ amp: compound type, for loop, declaration on GPU 【发布时间】:2015-03-17 23:59:00 【问题描述】:

我正在使用 c++ amp 编写模拟代码。我有以下问题,无法为他们找到明确的答案。希望有人能帮忙。实际上,它们是相互关联的。

我写了一些这样的行并且它有效,我已经测试了结果,但我需要有人指出为什么它是对或错的。

class sample

    double x;
    double y;
    bool good;
;

vector<sample> A;

//push_back some values for A

double M[3];

array_view<sample,1> ar(A.size(),A);
array_view<double,1> m(3,M);

double t = 1;


parallel_for_each(ar.extent, [=](index<1> idx) restrict(amp)

    double a, b; // Q1
    for (int i=0;i<3;i++)  //Q2
    
        a += m[i]*ar[idx].x;
        b += m[i]*ar[idx].y;
    

    ar[idx].x = a;
    ar[idx].y = b;

    if ( (a+b) > 1 ) 
        ar[idx].good = 0; //Q3
);

ar.synchronize();

Q1 可以像本例那样在parallel_for_each 中进行声明吗?这些变量有 GPU 作用域吗?如果是这样,在GPU上,这些变量是存储在公共内存空间还是GPU中的每个核心/线程都有自己的本地内存,这样所有计算都不会相互影响?我们甚至可以为临时使用声明一个数组或向量吗?

Q2 是否建议在 parallel_for_each 中使用“for”循环?有什么相关的吗?

Q3 在parallel_for_each 中使用'if',特别是如这里所示,推荐作为某个类的成员?如果有一些缺点,我会在 parralel_for_each 之外进行检查。

基本上这个例子显示了我想要做的事情:我想构建一个类,它会生成一个向量(很多)对象,它们将由一个矩阵更新。我想用c++ amp来加速计算。

我可能在这里包含了太多问题,请对其中任何一个发表评论。先谢谢了。

【问题讨论】:

在外部范围内将a 作为array_view 并在parallel_for 范围内重新声明为double,这真是令人困惑。 谢谢,@acraig5075。已编辑。您对parallel_for_each 正文中的声明有什么意见吗?其实我想在parallel_for_each里面声明一个数组,因为在我的计算中,向量的每个元素的矩阵都会不同。 【参考方案1】:

Q1: ab 在线程范围内声明。每个线程都有自己的副本。与所有 C++ 变量一样,您应该初始化它们。是的,您可以在此处声明一个数组,但要小心分配大量的每个线程数据。 GPU 具有少量的每线程内存。这可能会限制 GPU 当前能够执行的线程数,从而导致占用率低和性能下降。

Q2:这个for 循环是OK-ish,因为它在每个线程上运行完全相同。请记住,线程意味着分支,如果经线中的不同线程遵循不同的分支,这可能会导致经线发散。您可能想要手动展开此循环,或者编译器可能会为您完成。

Q3:一般情况下,您应该避免在parallel_for_each 内进行分支,因为这会导致warp 发散。这里的循环非常糟糕,因为( (a+b) &gt; 1 ) 条件将有线程在每个warp 上评估真假。

您真正应该考虑的另一件事是避免使用结构数组array_view&lt;sample,1&gt;,因为它会导致糟糕的内存访问模式。最好使用单独的数组来存储xygood。这将允许 GPU 合并内存负载。

是的,类/结构更易于使用,但通常会影响性能。根据您的代码库从结构数组 (AoS) 移动到数组结构 (SoA) 的大小,以后可能会很痛苦。在运行时将 AoS 展开为 SoA 以在 GPU 上使用可能也值得避免,因为它需要大量内存副本,这反过来又是一个很大的性能损失。 AoS 工作正常,只需注意对(更大的)代码库可能的性能影响和长期影响。

因为您的循环是固定大小且非常小,您可能需要展开它。如果M 中的值是常量,那么您可能根本不应该将它们存储在全局数组中,而只需对它们进行硬编码。您还可以将if 条件替换为给出相同结果的函数。

示例如下。我没有测试过这个的性能。它可能更快,您应该对其进行基准测试,因为这些只是建议。

#include <amp_math.h>

struct sample

    double x;
    double y;
    bool good;
public:
    sample(double x, double y) : x(x), y(y), good(true)  
;

main()

    std::array<sample, 2> A =  sample(0.0000001, 0.0), sample(1.0, 1.0) ;
    double M[3] =  1.0, 1.5, 2.0 ;

    array_view<sample, 1> ar(A.size(), A);
    array_view<double, 1> m(3, M);

    double t = 1;

    parallel_for_each(ar.extent, [=](concurrency::index<1> idx) restrict(amp)
    
        ar[idx].x = m[0] * ar[idx].x + m[1] * ar[idx].x + m[2] * ar[idx].x;
        ar[idx].y = m[0] * ar[idx].y + m[1] * ar[idx].y + m[2] * ar[idx].y;

        // WARNING: Single precision!
        ar[idx].good = !concurrency::fast_math::signbit(ar[idx].x + ar[idx].y - 1.0);
    );

    ar.synchronize();

【讨论】:

非常感谢您的回答和建议。尤其是 Q1,GPU 内存模式真的让我很困惑。我读了你的书(C++ AMP)并了解到一组类的效率较低。但是一个类可以将不同类型的数据保存在一起,因此使用起来更简单。如果性能不可接受,我会将它们展开到不同的向量。我理解分支就像 if 会拖累性能,但我真的想标记一些项目并稍后从向量中删除它们。有什么建议或例子吗?

以上是关于c++ amp:复合类型,for循环,GPU上的声明的主要内容,如果未能解决你的问题,请参考以下文章

如何在布尔值(假和真)上编写“for”循环

复合类型

C++ 循环for 引用 for(string & : )

复合类型数组上的 SUM 和 GROUP BY

for 循环中的 C++ 参考

小白学习C++ 教程四C++逻辑运算符While循环和For 循环