Comments 13
А может подскажете, почему собственно первый запуск так долго работал? Я правильно понимаю, что всегда первая инициализация ядра куды проходит с задержкой?
0
Вы правы. Дело в том, что я не упомянул о контекстах CUDA: это некоторый аналог процесса на CPU — каждый контекст имеет свое собственное адресное пространство, а каждый CPU поток работает только с одним CUDA контекстом в конкретный момент времени. Собственно, первая инициализация происходит с задержкой изза ленивого создания контекста.
+1
Это еще что, мы гоняли некую вычислительную программу на серверах, так там первая инициализация могла выполняться секунд 10. Это к тому, что надо строить свой код так, чтобы такая инициализация была ровно одна.
0
здорово, продолжайте, изучал курс, но скомпилированная и переведенная информация всегда лучше
0
Если вы приводите в тексте конкретное время расчета задачи в миллисекундах, то наверное нужно обязательно указать также аппаратную и программную конфигурацию машины на которой эти расчеты были выполнены, а еще размер тестовых данных.
0
Спасибо за замечания — добавил аппаратную конфигурацию и размер тестовых данных в эту статью, учту для следующих. А какую именно программную конфигурацию следует указать — компилятор, версии OpenMP и CUDA?
0
Есть замечательное свойство фильтра Гаусса — вместо расчета один раз окном 9x9 можно применить последовательно 4 раза фильтр Гаусса с окном 3x3 и получить тот же результат (если конечно не учитывать ошибки округления).
Как не сложно подсчитать в первом случае будет порядка 81 операций сложения и умножения, а во втором только 36.
Зато второй вариант хуже параллелится и более требователен к пропускной способности памяти (ну и конечно гораздо менее показателен в плане прироста производительности GPU по сравнению с CPU).
Для сравнения результаты работы Гауссова фильтра размера 3x3 для RGB картинки на CPU (i7-4770).
Scalar — 0.853 ms, SSE2 — 0.132 ms, AVX2 — 0.069 ms.
Для корректности сравнения нужно умножить результаты на 4:
Scalar — 3.4 ms, SSE2 — 0.53 ms, AVX2 — 0.28 ms.
По итогу — код на CPU фактически в 10 раз быстрее кода на GPU и это даже без учета необходимости копирования данных. Тут к стати отдельный вопрос почему автор не ипользует ::cudaMallocHost для аллокации памяти на хосте. Это на порядок повысит скорость копирования данных на устройство.
Как не сложно подсчитать в первом случае будет порядка 81 операций сложения и умножения, а во втором только 36.
Зато второй вариант хуже параллелится и более требователен к пропускной способности памяти (ну и конечно гораздо менее показателен в плане прироста производительности GPU по сравнению с CPU).
Для сравнения результаты работы Гауссова фильтра размера 3x3 для RGB картинки на CPU (i7-4770).
Scalar — 0.853 ms, SSE2 — 0.132 ms, AVX2 — 0.069 ms.
Для корректности сравнения нужно умножить результаты на 4:
Scalar — 3.4 ms, SSE2 — 0.53 ms, AVX2 — 0.28 ms.
По итогу — код на CPU фактически в 10 раз быстрее кода на GPU и это даже без учета необходимости копирования данных. Тут к стати отдельный вопрос почему автор не ипользует ::cudaMallocHost для аллокации памяти на хосте. Это на порядок повысит скорость копирования данных на устройство.
0
Тут к стати отдельный вопрос почему автор не ипользует ::cudaMallocHost для аллокации памяти на хосте. Это на порядок повысит скорость копирования данных на устройство.
Про pinned memory будет рассказано в следующих частях.
Есть замечательное свойство фильтра Гаусса — вместо расчета один раз окном 9x9 можно применить последовательно 4 раза фильтр Гаусса с окном 3x3 и получить тот же результат (если конечно не учитывать ошибки округления).
Тут Вы, по-моему, ошиблись. Википедия говорит, что применение нескольких, последовательных фильтров с радиусами R1,...,RN эквивалентно применению единого фильтра с радиусом R=sqrt(R12+...+RN2). Так что применение 4-х фильтров с радиусом 3 эквивалентно применению фильтра с радиусом R=sqrt(4*9)=6, а не 9 — нужно применить фильтр с радиусом 3 девять раз, чтобы это было эквивалентно применению фильтра с радиусом 9 один раз.
А в общем — вы сравниваете оптимизированный код на CPU с неоптимизированным кодом на GPU — несколько некорректно, не находите?) Все таки приведенный код на GPU еще тоже есть куда оптимизировать — переместить веса фильтра в константную память, пиксели входного изображения в shared memory, обрабатывать несколько пикселей каждым потоком и т.д. Но я согласен, что и этот пример возможно будет рассчитываться быстрее на CPU, хотя все равно думаю, что для больших изображений GPU вариант должен выигрывать. Для интереса — не могли бы Вы подправить свой вариант, чтобы он выполнял маленький фильтр правильное количество раз, и прогнать его на этом изображении — а я оптимизирую код на GPU, и проверю его время?
0
Нет. Я правильно подсчитал — можете проверить:
применение фильтра 3х3 два раза подряд приводит к увеличению окна на один пиксел в каждую сторону, соответственно на 2 пикселя всего. 3x3 + 3x3 = 5x5. и т.д.
применение фильтра 3х3 два раза подряд приводит к увеличению окна на один пиксел в каждую сторону, соответственно на 2 пикселя всего. 3x3 + 3x3 = 5x5. и т.д.
0
Sign up to leave a comment.
Параллельное программирование с CUDA. Часть 2: Аппаратное обеспечение GPU и шаблоны параллельной коммуникации