Мое ядро ​​OpenCL медленнее на более быстром оборудовании. Но почему? - PullRequest
11 голосов
/ 12 апреля 2010

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

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

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

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

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

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

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

У кого-нибудь есть подсказка?

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

Ответы [ 5 ]

10 голосов
/ 29 ноября 2010

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

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

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

2 голосов
/ 19 мая 2010

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

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

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

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

1 голос
/ 13 апреля 2010

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

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

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

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

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

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

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

http://www.macresearch.org/opencl

0 голосов
/ 10 марта 2011

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

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

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

...