Performance OpenCL:为什么这两种情况下的性能差异如此之大?
下面是我正在处理的OpenCL内核中的两段代码;它们显示了截然不同的运行时间 代码相当复杂,所以我已经简化了 此版本在1秒内运行:Performance OpenCL:为什么这两种情况下的性能差异如此之大?,performance,opencl,Performance,Opencl,下面是我正在处理的OpenCL内核中的两段代码;它们显示了截然不同的运行时间 代码相当复杂,所以我已经简化了 此版本在1秒内运行: for (int ii=0; ii<someNumber;ii++) { for (int jj=0; ii<someNumber2;jj++) { value1 = value2 + value3; value1 = value1 * someFunction(a,b,c); double
for (int ii=0; ii<someNumber;ii++)
{
for (int jj=0; ii<someNumber2;jj++)
{
value1 = value2 + value3;
value1 = value1 * someFunction(a,b,c);
double nothing = value1;
}
}
在声明value1
的位置移动也会让我们回到快速案例:
for (int kk=0; kk<someNumber3;kk++)
{
double value1=0;
for (int ii=0; ii<someNumber;ii++)
{
for (int jj=0; ii<someNumber2;jj++)
{
value1 = value2 + value3;
value1 = value1 * someFunction(a,b,c);
}
double nothing = value1;
}
}
for(int kk=0;kk第一种情况只是一个循环(通过编译器优化)
但是第二个是一个带有嵌套循环的循环。这是一个大问题。大量检查全局/局部变量。(确定它们是私有的吗?你在内核中声明了所有这些?)
我建议您在开始循环之前将其另存为私有变量(somenumber和somenumber2),因为这样您每次都将使用私有数据进行检查。
作为个人经验,用作OpenCL循环检查用例的每个var都必须是私有的。
这可以节省多达80%的全局内存访问(特别是当循环非常短或简单时)
例如,这应该可以快速工作:
int c_somenumber = someNumber;
for (int ii=0; ii<c_someNumber;ii++)
{
int c_somenumber2 = someNumber2;
for (int jj=0; ii<c_someNumber2;jj++)
{
value1 = value2 + value3;
value1 = value1 * someFunction(a,b,c);
}
double nothing = value1;
}
int c_somenumber=somenumber;
对于(int ii=0;ii您使用的是什么实现?我希望“double nothing=value1;”在任何情况下都可以被任何合理的编译器作为死代码删除。这很奇怪。你确定需要使用较慢的版本吗?从这些代码片段中看,它们在功能上完全相同。感谢你的回答。是的,我确定,但你是对的,我给出的示例在功能上完全相同。内括号中的代码应该有+=。根据这些代码片段,我看不出第二个工作单元速度较慢的任何原因。我猜移动分配肯定会有副作用,例如增加分支(一个工作单元执行如果,下一个工作单元执行否则),这确实会减慢GPU的速度。此外,我知道你说过所有的VAR都是\uu private
,但是如果你完全与全局内存同步,你可能会破坏对内存的联合访问。优化OpenCL内存访问可能很棘手:只是抛出一些想法而已。:)这给了我很多思考的空间。我已经用一些可能更清晰的东西更新了我的问题。代码没有if
s。我怀疑这会成为一个凝聚的问题。多亏了你的帖子,我想我已经发现了问题。在案例1(我问题的第一个框)中,我认为编译器通过“消除为死代码”内部循环。在案例2中,它意识到内部循环外部需要变量value1
,因此它运行它。函数someFunction(a、b、c)
非常慢,因此这会导致速度减慢。仅供参考,该实现是AMD的Linux SDK。感谢大家的帮助!您的意思是因为value1未使用,编译器优化了对someFunction的调用。如何确保someFunction没有副作用?因为“nothing”未使用。我不是说value1。@vocaro我不确定,但这是我能找到的最好的解释。它实际上是一个非常简单的函数,它对内存的影响非常大(我自己实现的稀疏矩阵访问).我对编译器一无所知,但由于它实际上只是一个复杂的反引用,也许编译器会注意到?当然,它可能是完全不同的东西,但我不知道是什么!是的,所有内容都保存为私有。请参阅我对该问题的解释,作为对其他答案的评论!
double value1=0;
for (int kk=0; kk<someNumber3;kk++)
{
for (int ii=0; ii<someNumber;ii++)
{
for (int jj=0; ii<someNumber2;jj++)
{
value1 = value2 + value3;
value1 = value1 * someFunction(a,b,c);
}
double nothing = value1;
}
}
for (int kk=0; kk<someNumber3;kk++)
{
double value1=0;
for (int ii=0; ii<someNumber;ii++)
{
for (int jj=0; ii<someNumber2;jj++)
{
value1 = value2 + value3;
value1 = value1 * someFunction(a,b,c);
}
double nothing = value1;
}
}
int c_somenumber = someNumber;
for (int ii=0; ii<c_someNumber;ii++)
{
int c_somenumber2 = someNumber2;
for (int jj=0; ii<c_someNumber2;jj++)
{
value1 = value2 + value3;
value1 = value1 * someFunction(a,b,c);
}
double nothing = value1;
}