Я довольно новичок в программировании ocl.Предотвращение вычисления дважды в opencl
У меня есть 2 миллиона полигонов (по четыре строки - для этих примеров - но это вариант), что мне нужно найти пересечение с 1000 эллипсами.
Мне нужно знать, который, если каждый эллипс пересекается хотя бы с одним из полигонов.
Для этого я создал буфер poylgons со всеми точками и буфером эллипсов.
Мой выходной буфер - это 1000 элементов int, равных 0 во всех элементах. и ядро установит 1 (когда найдет пересечение) в правом индексе в соответствии с индексом эллипса.
Я запустил ядро с глобальным - 2 dim, {2million, 1000}.
__kernel void polygonsIntersectsEllipses( __global const Point* pts,
__global const Ellipse* ellipses,
__global int* output)
{
int polygonIdx = get_global_id(0);
int ellipseIdx = get_global_id(1);
if (<<isIntersects>>) {
output[ellipseIdx] = 1;
}
}
Проблема заключается в том, что когда-то один из полигонов пересекает эллипс я не нужно вычислить остальную часть полигонов.
Я попытался проверить output[ellipseIdx] != 0
перед тестом на пересечение, но производительность не изменилась так сильно.
Я попытался сделать одномерное глобальное - давая 1000 (эллипсы), а в ядре пробегают миллионы полигонов и останавливаются, когда я его найду, но все равно не так сильно меняются.
Я делаю что-то неправильно? могу ли я ускорить эту операцию? любые подсказки?
EDIT
Используя наконечник от @Moises и делать исследования, выделяют я изменить свой код, чтобы запустить 2 миллиона раз, один размер. используя элементы групповой работы. изменил все мои структуры на нативные типы, пропустил работу модуля. И в основном, когда я мог копировать данные из глобальной в частную/локальную память, я это сделал.
Мой местный размер - мое устройство CL_DEVICE_MAX_WORK_GROUP_SIZE
, в моем CPU & gpu - 1024, поэтому за один проход я покрываю все свои 1000 эллипсов.
стороне хоста
size_t global = 1999872; // 2 million divided by 1024 - for the test
size_t local = 1024;
Мой код выглядеть как это сейчас
__kernel void polygonsIntersectsEllipses( __global const float4* pts,
__global const float4* ellipses,
int ellipseCount,
__local float4* localEllipses,
__global int* output)
{
// Saving the ellipses to local memory
int localId = get_local_id(0);
if (localId < eCount)
localEllipses[localId] = ellipses[localId];
barrier(CLK_LOCAL_MEM_FENCE);
// Saving the current polygon into private memory
int polygonIdx = get_global_id(0);
float2 private_pts[5];
for (int currPtsIdx = 0; currPtsIdx < 4; currPtsIdx++)
{
private_pts[currPtsIdx] = pts[polygonIdx * 4 + currPtsIdx];
}
// saving the last point as first so i will not use modulus for cycling, in the intersection algorithm
private_pts[4] = private_pts[0];
// Run over all the ellipse in the local memory including checking if already there is an output
for (int ellipseIdx = 0; ellipseIdx < ellipseCount && output[ellipseIdx] == 0; ++ellipseIdx) {
if (<<isIntersects Using localEllipses array and private_pts>>) {
output[ellipseIdx] = 1;
}
}
}
Результаты деятельности
CPU не так значительно улучшилось - 1,1 быстрее после изменения.
GPU - 6,5 раз быстрее (я очень рад)
Есть ли место я могу улучшить еще больше? Напоминание, когда один из полигонов пересекает эллипс, нам не нужно проверять остальную часть полигонов. Как мне это сделать ? мой трюк с запросом на выходное значение на самом деле не работает - показатели одинаковы с или без него
Если я создаю 2mil потоков и внутри я бег за эллипсы. Это не то же самое? Я все еще читаю то же самое 1000 эллипсов для каждого потока? И все еще, как я могу предотвратить проверку пересечения для того же эллипса, если он уже пересечен? –
Обновлено мое сообщение, используя ваш совет и другие исследования, которые я сделал –