Ручное развертывание петли с известным максимальным размером

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

uint point_color = 4278190080;
float point_percent = 1.0f;
float near_pixel_size = (...);
float far_pixel_size = (...);
float delta_pixel_size = far_pixel_size - near_pixel_size;
float3 near = (...);
float3 far = (...);
float3 direction = normalize(far - near);

point_position = (...) + 10;
for (size_t p = 0; p < point_count; p++, position += 4)
{
    float3 point = (float3)(point_list[point_position], point_list[point_position + 1], point_list[point_position + 2]);
    float projection = dot(point - near, direction);
    float3 projected = near + direction * projection;
    float rejection_length = distance(point, projected);
    float percent = projection / segment_length;
    float pixel_size = near_pixel_size + percent * delta_pixel_size;
    bool is_candidate = (pixel_size > rejection_length && point_percent > percent);
    point_color = (is_candidate ? (uint)point_list[point_position + 3] | 4278190080 : point_color);
    point_percent = (is_candidate ? percent : point_percent);
}

Этот код пытается найти в списке точку, ближайшую к отрезку линии между дальним и ближним, и присваивает ее цвет point_color и его "процентное расстояние" в point_percent. (Кстати, код вроде в порядке).

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

Я хотел бы развернуть этот цикл вручную, и я боюсь, что мне придется использовать много

value = (point_count < constant ? new_value : value)

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

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


person Izhido    schedule 10.04.2018    source источник


Ответы (1)


Большинство драйверов OpenCL (по крайней мере, с которыми я знаком) поддерживают использование #pragma unroll для развертывания циклов во время компиляции. Просто используйте его так:

#pragma unroll
for (int i = 0; i < 4; i++) {
    /* ... */
}

Фактически это то же самое, что развернуть его вручную, без каких-либо усилий. В вашем случае это, вероятно, будет выглядеть так:

if (pointCount == 1) {
    /* ... */
} else if (pointCount == 2) {
    #pragma unroll
    for (int i = 0; i < 2; i++) { /* ... */ }
} else if (pointCount == 3) { 
    #pragma unroll
    for (int i = 0; i < 3; i++) { /* ... */ }
}

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

Подробнее об этом можно прочитать здесь.

person apetranzilla    schedule 11.04.2018