2013-11-25 1 views
1

Я увидел реализацию smallpt в OpenCL, и автор использует свои собственные типы векторов и макропроцессоры prepocessor в ядре.Использование собственного векторного типа в OpenCL кажется более быстрым

typedef struct { float x, y, z; } Vec; 

#define vinit(v, a, b, c) { (v).x = a; (v).y = b; (v).z = c; } 
#define vsmul(v, a, b) { float k = (a); vinit(v, k * (b).x, k * (b).y, k * (b).z) } 
#define vdot(a, b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z) 
#define vnorm(v) { float l = 1.f/sqrt(vdot(v, v)); vsmul(v, l, v); } 
and much more... 

Я проверил код и заменил определяемые пользователем типы векторов и операции стандартным встроенным типом float3. Я был удивлен, что оригинальная реализация автора была на 10 кадров быстрее, чем вариант со встроенным float3. После этого я немного протестировал ситуацию с Intel OpenCL Applications Kernel Builder и, похоже, подтвердил, что встроенные функции работают медленнее.

Любые идеи, почему? Поставщики рекомендуют типы встроенных типов:/

+0

На каком языке это? В C или C++ нет встроенного типа 'float3'. –

+0

Как выглядит ваш тестовый код? На каком оборудовании вы работаете? –

+0

Это OpenCL C на основе стандарта C99 для программирования GPGPU. Контрольный код состоял в том, чтобы просто выполнить некоторые базовые векторные операции более миллиона раз и сравнить их с пользовательской версией. (норма, крест, точка, добавить, mull, ...) Оборудование для тестирования было Intel i7-3630QM (Intel HD 4000 не работал в построителе ядра). И код smallpt работает на моем nvidia quadro gpu (NVS 5200M) И вот оригинальная реализация opptl smallpt opencl http://www.phoronix-test-suite.com/benchmark-files/SmallptGPU-v1.6pts-1. tar.bz2 – Erabong

ответ

2

Вектор, определяемый пользователем, является истинным 3-х элементным вектором, с использованием 3 поплавков. Однако вектор OpenCL float3 действительно используя float4 вектор, как можно видеть в cl_platform.h:

/* cl_float3 is identical in size, alignment and behavior to cl_float4. See section 6.1.5. */ 
typedef cl_float4 cl_float3; 

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

Но поскольку разработан компилятор OpenCL, теперь компилятор достаточно умен, чтобы внутренне векторизовать код пользователя. Иногда (я видел это и с другими ядрами, даже с моими собственными), лучше написать код в простых элементах и ​​позволить компилятору повторно векторизовать его, вместо того, чтобы использовать векторные типы по умолчанию. Итак, я рекомендую, чтобы, если вектор не упрощает задачу программирования и его легче читать (например, 2D-обработки и т. Д.), Не используйте в настоящее время векторы OpenCL.

Возможно, пользователь определил vector3, используя меньше регистров и меньше выливается. Или может быть, что для алгоритма лучше подходит другое векторное устройство, и компилятор может свободно изменять код в пользовательском векторном случае.

Проводящий анализ того, что происходит, должен выполняться с помощью скомпилированного кода PTX.

+0

Так много для улучшения удобочитаемости и согласованности. – Thomas

+0

Аппаратное обеспечение NVIDIA не является векторным оборудованием, поэтому компилятор сканирует все встроенные типы векторов. Кроме того, некоторые компиляторы, например, делают это, а затем повторно векторизовать свой код, поэтому несколько рабочих элементов образуют один путь выполнения. Другими словами, если 4 элемента работы соответствуют типу вектора SSE или AVX, тогда векторный код будет запускать сразу четыре рабочих элемента на одном ядре. Это не зависит от использования вами типов векторов в вашем коде. Аппаратное обеспечение предыдущего поколения AMD было векторизовано и использовало типы векторов OpenCL C, когда это было возможно. Их последнее оборудование является скалярным. – Dithermaster

+0

@ Dithermaster Да, я прочитал это в Руководстве по оптимизации AMD OpenCL. Итак, все, что вы считаете лучшим решением для решения этой проблемы, выполняете векторный код на всех платформах очень быстро, насколько это возможно. – Erabong

1

Добавление немного. Для графических процессоров NVIDIA (я не знаю о AMD) есть инструкции загрузки для 32 бит (LD.32), 64 бит (LD.64) и 128 бит (LD.128), но не 96-разрядная загрузка. Загрузка истинного float3 из DRAM реализована в виде двух отдельных инструкций - одного LD.32 и одного LD.64. Если вы загружаете последовательные float3 в последовательные потоки в warp, как и для float2, double или float4, вы фактически получаете доступ к данным с 96-битным шагом в двух отдельных инструкциях, что приводит к повторам. То же самое верно для инструкций магазина. Я бы предположил, что это причина выбора typedef для float4.

Смежные вопросы