Мое ядро ​​OpenCL медленнее работает на более быстром оборудовании. Но почему?

Поскольку я заканчивал кодирование моего проекта для многоядерного класса программирования, я придумал что-то действительно странное, с которым я хотел обсудить с вами.

Нам было предложено создать любую программу, которая продемонстрировала бы значительное улучшение в программировании для многоядерной платформы. Я решил попробовать что-то на графическом процессоре, чтобы попробовать OpenCL. Ive выбрал матричную задачу свертки, так как Im хорошо знаком с ней (Ive распараллеливал ее раньше с помощью open_mpi с большим ускорением для больших изображений).

Итак, вот, я выбираю большой GIF файл (2.5 MB) [2816X2112], и я запускаю последовательную версию (исходный код), и я получаю в среднем 15,3 секунды.

Затем я запускаю новую версию OpenCL, которую я только что написал на моей MBP-интегрированной GeForce 9400M, и я получаю в среднем 1,26 секунды. Пока все хорошо, его ускорение 12X!

Но теперь я зашел в свою панель энергосбережения, чтобы включить "Графический режим производительности". Этот режим отключает GeForce 9400M и включает Geforce 9600M GT в моей системе. Apple говорит, что эта карта в два раза быстрее встроенной.

Угадайте, что мое время, использующее графическую карту kick-ass, составляет в среднем 3,2 секунды... Мой 9600M GT кажется более чем в два раза медленнее, чем 9400M.

Для тех из вас, кто настроен на OpenCL, я копирую все данные в удаленные буферы перед запуском, поэтому фактическое вычисление не требует округления к главному RAM. Кроме того, я разрешаю OpenCL определять оптимальную локальную работу, поскольку Ive читает, что они сделали довольно хорошую реализацию при вычислении этого параметра.

У кого есть ключ?

edit: полный исходный код с make файлами здесь http://www.mathieusavard.info/convolution.zip

cd gimage
make
cd ../clconvolute
make
put a large input.gif in clconvolute and run it to see results

Ответ 1

9400M интегрирован в ваш контроллер памяти, тогда как 9600M GT - это дискретная карта, которая подключается к вашему контроллеру памяти через шину PCI-e. Это означает, что при передаче памяти на 9400M он просто выделяет ее в системную память. 9600M, с другой стороны, отправляет данные по PCI-e в выделенную графическую память на карте. Эта передача - это то, что делает ваш тест медленнее.

Если вы хотите сравнить производительность двух видеокарт, вы должны использовать функцию профилирования OpenCL вместо используемой вами функции часов.

cl_int clGetEventProfilingInfo (cl_event event, cl_profiling_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)

Передайте функцию событие, которое было создано, когда вы запустили ядро ​​и передали ему CL_PROFILING_COMMAND_START для второго аргумента, чтобы получить начальную точку ядра в наносекундах и CL_PROFILING_COMMAND_END, чтобы получить конечную точку ядра. Обязательно используйте эту команду ПОСЛЕ завершения выполнения ядра (события сохраняют свои значения до тех пор, пока они не выйдут из области видимости.) Вы также можете получить время, необходимое для передачи данных на устройство, применив эту функцию к событиям из очереди в буфер. Вот пример:

        TRACE("Invoking the Kernel")
    cl::vector<cl::Event> matMultiplyEvent;
    cl::NDRange gIndex(32,64);
    cl::NDRange lIndex(16,16);

    err = queueList["GPU"]->enqueueNDRangeKernel(
                                                 matrixMultiplicationKernel, 
                                                 NULL, 
                                                 gIndex, 
                                                 lIndex, 
                                                 &bufferEvent,
                                                 matMultiplyEvent);
    checkErr(err, "Invoke Kernel");


    TRACE("Reading device data into array");
    err = queueList["GPU"]->enqueueReadBuffer(thirdBuff, 
                                              CL_TRUE,
                                              0,
                                              (matSize)*sizeof(float),
                                              testC,
                                              &matMultiplyEvent,
                                              bufferEvent);
    checkErr(err, "Read Buffer");
    matMultiplyEvent[0].wait();
    for (int i = 0; i < matSize; i++) {
        if (i%64 == 0) {
            std::cout << "\n";
        }
        std::cout << testC[i] << "\t";
    }
    long transferBackStart = bufferEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_START>();
    long transferBackEnd = bufferEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_END>();
    double transferBackSeconds = 1.0e-9 * (double)(transferBackEnd- transferBackStart);

    long matrixStart = matMultiplyEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_START>();
    long matrixEnd = matMultiplyEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_END>();
    double dSeconds = 1.0e-9 * (double)(matrixEnd - matrixStart);

В этом примере используется оболочка С++, но концепция должна быть одинаковой.

Надеюсь, что это поможет.

Ответ 2

Я получаю те же результаты, и я не уверен, почему. Мое ядро ​​включает в себя очень минимальное копирование в/из (я предоставляю все необходимые данные для всех вызовов ядра и возвращаю только изображение 512x512). Это raytracer, поэтому работа ядра значительно перевешивает копию (400 + ms до 10ms). Тем не менее, 9600M GT примерно на 1,5x-2x медленнее.

Согласно списку nVidia, 9600M GT должен иметь 32 SP (в два раза больше 9400M). Предположительно, он тоже высказал больше.

В некоторых случаях 9600M GT работает быстрее, например. игры. См. Следующие ссылки: http://www.videocardbenchmark.net/video_lookup.php?cpu=GeForce+9600M+GT http://www.videocardbenchmark.net/video_lookup.php?cpu=GeForce+9600M+GT

Согласно ars technica:

Кроме того, интересный лакомый кусочек о реализации Snow Leopard выявляется в результате ранних тестов. Хотя Snow Leopard, похоже, не позволяет использовать два графических процессора или "на лету" GPU-коммутацию для компьютеров с использованием набора микросхем NVIDIA GeForce 9400M - ограничение, перенесенное с Leopard, - похоже, что ОС может одновременно использовать как ресурсы OpenCL. Таким образом, даже если на вашем MacBook Pro включен 9600M GT, если код OpenCL встречается в приложении, Snow Leopard может отправить этот код, который будет обрабатываться 16-гигабайтными ядрами, которые в значительной степени спятны в 9400M. Обратное утверждение неверно, хотя при запуске MacBook Pro с включенным 9400M 9600M GT полностью отключается, чтобы сэкономить электроэнергию и не может использоваться как ресурс OpenCL.

Это похоже на то, что мы видим. Кроме того, я устанавливаю контекст CL только на одном устройстве за раз.

В ars forums есть несколько предложений, что 9600M GT не поддерживает парные разряды, что объясняет эту проблему. Я могу попытаться написать синтетический тест, чтобы проверить эту гипотезу.

Ответ 3

Я столкнулся с той же проблемой, когда тестировал OpenCL на своем MacBook. Я считаю, потому что GeForce 9400M имеет более высокую скорость шины в основной памяти, чем GeForce 9600M GT. Таким образом, хотя GeForce 9600M GT обладает гораздо большей мощностью, чем GeForce 9400M, время, необходимое для копирования памяти на GPU, слишком велико, чтобы увидеть преимущество более мощного графического процессора в вашей ситуации. Это также может быть вызвано несоответствующими размерами рабочих групп.

Также я нашел этот сайт очень полезным в моем опыте OpenCL.

http://www.macresearch.org/opencl

Ответ 4

Производительность не единственная разница между GeForce 9400M и GeForce 9600M GT. Большой - это дискретный графический процессор. При этом возникает множество различий, среди которых следующее может оказать влияние:

  • тенденция драйверов для пакетной загрузки команд Память
  • не является однородной. GPU обычно получает доступ только к собственной памяти, а драйвер перемещает память вперед и назад по шине PCI-E.

Я уверен, что мне не хватает некоторых...

Вот несколько идей, которые вы можете попробовать:

  • избегать вызова clFinish. То, как вы называете это между загрузкой памяти и исполнением, заставляет драйвер выполнять больше работы, чем необходимо. Он останавливает GPU.
  • Профилируйте свой код, чтобы узнать, что занимает время. Я еще не знаю поддержки анализа производительности CL, но с вашими clFinish звонками он дает оценку 1-го порядка, просто измеряя процессорную сторону. Обратите внимание, что в целом трудно отличить то, что связано с задержкой и что связано с пропускной способностью.

Ответ 5

Я новичок в OpenCL, поэтому я могу быть немного наивным, но я сомневаюсь, что вам нужно было войти в панель энергосбережения, чтобы переключить устройство OpenCL. Я считаю, что вы выбираете устройство при настройке контекста OpenCL в своем коде.

Моя гипотеза: 1) Когда вы запускаете свой код, не отключая встроенный графический процессор, OpenCL выбирает ваш дискретный графический процессор в качестве вычислительного устройства. Ваш код работает на (быстром) дискретном графическом процессоре. 2) Когда вы сначала отключите встроенный графический процессор, вы вынуждаете загрузку графического интерфейса OS X на свою дискретную карту. Когда вы запускаете свой код, он запускается на дискретном графическом процессоре, но он поддерживает ваш графический интерфейс для ресурсов.

Этот ответ наступает через 11 месяцев после того, как был задан вопрос, но, надеюсь, он будет полезен кому-то...