Время вычислений OpenCL намного больше, чем у CPU - PullRequest
0 голосов
/ 22 ноября 2011

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

Код для основного: http://pastebin.com/i4A6kPfn, и для ядра: http://pastebin.com/Wefrqifh Я начинаю измерять время после возвращения segmentPunten(segmentArray, begin, eind);, и я заканчиваю измерение времени после последнего clEnqueueReadBuffer.

Время вычислений на Nvidia GT440 составляет 38,6 секунды, на GT555M 35,5, на Athlon II X4 5,6 секунды и на Intel P8600 6 секунд.

Может кто-нибудь объяснить мне это? Почему время вычислений так велико, и какие решения для этого есть?

Что он должен делать: (короткая версия), чтобы вычислить, какую шумовую нагрузку создает проходящий мимо самолет.

длинная версия: есть несколько точек наблюдения (OP), которые являются точками, в которых звук измеряется с самолета, который проходит мимо. Маршрут полета сегментируется на 10 000 сегментов, это делается с помощью функции plotPunten. Двойной цикл for в главном дает ОП координату. Есть два ядра. Первый рассчитывает расстояние от одного OP до одного сегмента. Затем он сохраняется в массиве «afstanden». Второе ядро ​​вычисляет звуковую нагрузку в OP из всех сегментов.

Ответы [ 3 ]

3 голосов
/ 23 ноября 2011

Просто взглянув на ваше ядро, я вижу это:

kernel void SEL(global const float *afstanden, global double *totaalSEL, 
    const int aantalSegmenten)
{
    // ... 
    for(i = 0; i < aantalSegmenten; i++) {
        double distance = afstanden[threadID * aantalSegmenten + i];
        // ...
    }
    // ...
}

Похоже, aantalSegmenten устанавливается на 1000. У вас есть цикл в каждом ядро, которое обращается к глобальной памяти 1000 раз. Не сканируя код, Я предполагаю, что многие из этих доступов перекрываются при рассмотрении вашего вычисление в целом. Это тот случай? Будет ли доступ к двум рабочим элементам одинаковым глобальная память? Если это так, вы увидите потенциально огромную победу на GPU переписывает ваш алгоритм, чтобы разделить работу так, чтобы вы могли прочитать из определенной глобальной памяти только один раз, сохраняя ее в локальной памяти. После этого, каждый рабочий элемент в рабочей группе, которому требуется это местоположение, может быстро прочитать его.

Кроме того, спецификация CL позволяет вам опустить ведущий __ в CL такие ключевые слова, как global и kernel. Я не думаю, что многие новички в CL понимают что.

1 голос
/ 26 ноября 2011

Прежде чем продолжить оптимизацию, вы должны сначала понять, что занимает все это время. Это ядро ​​компилирует, передает данные или выполняет ядро?

Как уже упоминалось выше, вы можете избавиться от компиляции ядра, кэшируя результаты. Я полагаю, что некоторые реализации OpenCL (по крайней мере, Apple) уже делают это автоматически. С другими, вам может понадобиться выполнить кэширование вручную. Вот инструкции по кешированию.

Если узким местом производительности является само ядро, вы, вероятно, сможете значительно ускорить процесс, если по-разному организовать поиск в массиве afstanden. В настоящее время, когда блок потоков выполняет чтение из памяти, адреса распределяются по памяти, что является реальным фактором снижения производительности графического процессора. В идеале вы хотели бы индексировать массив с помощью чего-то вроде afstanden[ndx*NUM_THREADS + threadID], что обеспечило бы доступ из рабочей группы для загрузки непрерывного блока памяти. Это на намного быстрее, чем текущий случайный поиск в памяти.

0 голосов
/ 24 ноября 2011

Прежде всего, вы измеряете не время вычислений, а целое ядро, читающее / компилирующее / выполняющее mumbo-jumbo. Чтобы провести справедливое сравнение, измерьте время вычислений из первой «нестатической» части вашей программы. (Например, между первым clSetKernelArgs и последним clEnqueueReadBuffer.)

Если время выполнения все еще слишком велико, вы можете использовать какой-либо профиль (например, VisualProfiler от NVidia) и прочитать руководство по OpenCL Best Practices, которое включено в документацию по CUDA Toolkit.

К исходному времени выполнения ядра. Подумайте (и оцените), что вам действительно требуется двойная точность для ваших вычислений, потому что вычисления двойной точности искусственно замедляются на картах NVidia потребительского уровня.

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