OpenCL:为什么这两种情况之间的性能差异如此之大?

时间:2011-10-07 15:48:33

标签: performance opencl

这是我正在研究的OpenCL内核的两段代码;它们显示出截然不同的运行时间。

代码相当复杂,所以我简化了它。

此版本在一秒钟内运行:

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;
    }
}

此版本需要大约38秒才能运行:

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;
}

正如我所说的,代码比这更复杂(循环中还有很多其他的东西),但是变量“nothing”确实从紧接着之后移动到紧跟在括号之后。

我是OpenCL的新手,我无法弄清楚发生了什么,更不用说如何修复它了。毋庸置疑,缓慢的情况实际上是我在实施中所需要的。我试过搞乱地址空间(这里的所有变量都在__private中)。

我只能想象,由于某些原因,当支架关闭时,GPU正在将变量“value1”推入较慢的内存中。这可能是一个解释吗?我该怎么办?

提前致谢!

更新:这也在不到一秒的时间内运行:(但如果没有注释任何一行,它将恢复到极端缓慢)。这不会对循环进行任何其他更改,并且value1仍然在与之前相同的位置声明。

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;
}

更新2:代码实际上嵌套在另一个这样的循环中,声明为value1如下所示:

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;
    }
}

移动宣布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;
    }
}

看来OpenCL是一件非常棘手的艺术品!我仍然不明白发生了什么,但至少我知道如何解决它现在!

2 个答案:

答案 0 :(得分:4)

您使用的是什么实现?我希望“double nothing = value1;”在任何情况下由任何合理的编译器作为死代码被删除。

答案 1 :(得分:2)

第一种情况只是一个循环(使用编译器优化) 但第二个是带有嵌套循环的循环。这是一个大问题。大量的全局/局部变量检查。(确定它们是私有的?你在内核中声明了所有内容?)

我建议你在开始循环之前保存为私有变量(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;
}

编辑: 此外,value1应该缓存在私有内存中。 (正如您在上次编辑中所做的那样)