OpenCL: почему производительность так сильно отличается в этих двух случаях? - PullRequest
5 голосов
/ 07 октября 2011

Вот два куска кода из ядра 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;
}

Как я уже сказал, код несколько более сложен, чем этот (в циклах происходит много других вещей), но переменная "ничто" действительно перемещается от непосредственно до сразу после фигурной скобки.

Я очень плохо знаком с OpenCL и не могу понять, что происходит, тем более, как это исправить. Излишне говорить, что медленный случай - это то, что мне нужно в моей реализации. Я попытался возиться с адресными пространствами (все переменные здесь находятся в __private).

Я могу только представить, что по какой-то причине графический процессор выталкивает переменную «value1» в более медленную память, когда скобка закрывается. Это вероятное объяснение? Что я могу сделать?

Заранее спасибо!

ОБНОВЛЕНИЕ: Это также выполняется менее чем за одну секунду: (но с раскомментированием любой строки, оно возвращается к крайне медленной). Это без внесения каких-либо других изменений в циклы, а значение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 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 ]

4 голосов
/ 08 октября 2011

Какую реализацию вы используете? Я ожидаю, что "double nothing = value1;" должен быть устранен как мертвый код в любом случае любым разумным компилятором.

2 голосов
/ 08 октября 2011

Первый случай - всего один цикл (с оптимизацией компилятора) Но второй - это цикл с вложенным циклом. Это большая проблема. Много проверок глобальных / локальных переменных. (Уверены, что они закрытые? Вы объявили все это внутри ядра?)

Я рекомендую вам сохранить его как личную переменную (somenumber и somenumber2) перед началом цикла. Потому что таким образом вы будете каждый раз проверять личные данные. Как личный опыт, каждая переменная, используемая в качестве контрольного случая цикла OpenCL, должна быть закрытой. Это может сэкономить до 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;
}

EDIT: Кроме того, значение1 ДОЛЖНО быть кэшировано в частной памяти. (Как вы делали в своем последнем редактировании)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...