c++;amp:复合类型,for循环,在GPU上声明 我正在用C++ AMP做仿真代码。我有以下问题,无法找到一个明确的答案。希望有人能帮忙。实际上,它们是相互关联的

c++;amp:复合类型,for循环,在GPU上声明 我正在用C++ AMP做仿真代码。我有以下问题,无法找到一个明确的答案。希望有人能帮忙。实际上,它们是相互关联的,c++,c++-amp,C++,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,

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

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();
类示例
{
双x;
双y;
很好;
};
载体A;
//将某个值向后推
双M[3];
数组_视图ar(A.size(),A);
阵列视图m(3,m);
双t=1;
每个(ar.extent,[=](索引idx)限制(amp)的并行(U)
{
双a,b;//Q1
对于(int i=0;i 1)
ar[idx].good=0;//Q3
});
ar.synchronize();
Q1我们是否可以在并行_中为每个_进行声明,如本例所示?这些变量有GPU作用域吗?如果是这样,在GPU上,这些变量是否存储在公共内存空间中,或者对于GPU中的每个核心/线程,它都有自己的本地内存,以便所有计算不会相互影响?我们甚至可以使用数组或向量吗

Q2建议在每个并行\u中使用“for”循环?对此有何评论

Q3建议在每个并行_中使用“如果”,特别是如图所示,作为某个类的成员?如果有一些缺点,我会在parralel_外为每个检查

基本上,这个例子展示了我想做的事情:我想构建一个类,它将生成一个向量(很多)对象,它们将由一个矩阵更新。我想用C++ AMP加速计算。
我可能在这里包含了太多的问题,请评论其中的任何一个。感谢您的光临。

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

Q2:这个
for
循环没有问题,因为它在每个线程上运行完全相同。请记住,线程意味着分支,如果扭曲中的不同线程遵循不同的分支,这可能会导致扭曲发散。您可能希望手动展开此循环,或者编译器可能会为您执行此操作

Q3:通常,您应该避免在每个
并行\u中进行分支,因为这可能会导致扭曲发散。这里的循环非常糟糕,因为
((a+b)>1)
条件将有在每个扭曲上计算true和false的线程

另一件事,你应该考虑避免使用一个结构数组,<代码> AlayyVIEW 因为它导致内存访问模式不好。最好使用单独的数组来存储

x
y
good
。这将允许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();
}
#包括
结构样本
{
双x;
双y;
很好;
公众:
样本(双x,双y):x(x),y(y),好(真){
};
main()
{
数组A={sample(0.0000001,0.0),sample(1.0,1.0)};
双M[3]={1.0,1.5,2.0};
数组_视图ar(A.size(),A);
阵列视图m(3,m);
双t=1;
每个(ar.extent,[=](concurrency::index idx)限制(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;
//警告:单精度!
ar[idx].good=!concurrency::fast\u math::signbit(ar[idx].x+ar[idx].y-1.0);
});
ar.synchronize();
}

在外部作用域中将
a
作为
array\u视图
,并在并行作用域中将其重新声明为
double
,这着实令人困惑。谢谢,@acraig5075。编辑。你对每一个机构的平行声明有何评论?事实上,我想在并行_中为每个_声明一个数组,因为在我的计算中,向量的每个元素的矩阵都是不同的。非常感谢您的回答和建议。特别是Q1,GPU内存模式真的让我很困惑。我读了你的书(C++AMP),了解到类数组的效率较低。但是一个类可以将不同类型的数据保存在一起,因此使用起来更简单。如果性能不可接受,我会将它们展开为不同的向量。我理解像if这样的分支会拖累性能,但我真的想标记一些项目,然后将它们从向量中删除。有什么建议或例子吗?