Моя проблема заключается в следующем: у меня есть изображение, в котором я обнаруживаю некоторые интересные точки, используя GPU. Обнаружение представляет собой тяжеловесный тест с точки зрения обработки, однако только около 1 из 25 баллов проходят тест в среднем. Заключительным этапом алгоритма является составление списка точек. На CPU это будет реализовано как:Общая память мьютекса с CUDA - добавление к списку элементов
forall pixels x,y
{
if(test_this_pixel(x,y))
vector_of_coordinates.push_back(Vec2(x,y));
}
На графическом процессоре у меня есть каждый блок обработки CUDA 16x16 пикселей. Проблема в том, что мне нужно сделать что-то особенное, чтобы в конечном итоге иметь единый консолидированный список точек в глобальной памяти. В настоящий момент я пытаюсь создать локальный список точек в общей памяти на блок, который в конечном итоге будет записан в глобальную память. Я пытаюсь избежать отправки чего-либо обратно в CPU, потому что после этого есть несколько этапов CUDA.
Я ожидал, что могу использовать атомные операции для реализации функции push_back в общей памяти. Однако я не могу заставить это работать. Есть два вопроса. Первая неприятная проблема заключается в том, что я постоянно сталкиваюсь с следующим сбоем компилятора: «nvcc error:« ptxas »умер с статусом 0xC0000005 (ACCESS_VIOLATION)» при использовании атомных операций. Удар или промах, могу ли я что-то скомпилировать. Кто-нибудь знает, что вызывает это?
Следующая ядро будет воспроизвести ошибку:
__global__ void gpu_kernel(int w, int h, RtmPoint *pPoints, int *pCounts)
{
__shared__ unsigned int test;
atomicInc(&test, 1000);
}
Во-вторых, мой код, который включает в себя блокировку мьютекса на разделяемой памяти висит на GPU, и я не понимаю, почему:
__device__ void lock(unsigned int *pmutex)
{
while(atomicCAS(pmutex, 0, 1) != 0);
}
__device__ void unlock(unsigned int *pmutex)
{
atomicExch(pmutex, 0);
}
__global__ void gpu_kernel_non_max_suppress(int w, int h, RtmPoint *pPoints, int *pCounts)
{
__shared__ RtmPoint localPoints[64];
__shared__ int localCount;
__shared__ unsigned int mutex;
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
int threadid = threadIdx.y * blockDim.x + threadIdx.x;
int blockid = blockIdx.y * gridDim.x + blockIdx.x;
if(threadid==0)
{
localCount = 0;
mutex = 0;
}
__syncthreads();
if(x<w && y<h)
{
if(some_test_on_pixel(x,y))
{
RtmPoint point;
point.x = x;
point.y = y;
// this is a local push_back operation
lock(&mutex);
if(localCount<64) // we should never get >64 points per block
localPoints[localCount++] = point;
unlock(&mutex);
}
}
__syncthreads();
if(threadid==0)
pCounts[blockid] = localCount;
if(threadid<localCount)
pPoints[blockid * 64 + threadid] = localPoints[threadid];
}
В примере код в this site, автору удается успешно использовать атомные операции в общей памяти, поэтому я смущен тем, почему мой случай не работает. Если я прокомментирую блокировку и разблокировку строк, код будет работать нормально, но явно неправильно добавит в список.
Я был бы признателен за некоторые советы о том, почему эта проблема происходит, а также, возможно, если есть лучшее решение для достижения цели, поскольку я все равно обеспокоен проблемами производительности с использованием атомных операций или блокировок мьютексов.
Это очень интересно. Спасибо. – Robotbugs
Я просто попытался реализовать это, и одна вещь, которую я обнаружил, заключается в том, что функция сканирования неверна в строке: «temp [pout * n + thid] + = temp [pin * n + thid - offset];".На самом деле это должно быть «temp [pout * n + thid] = temp [pin * n + thid] + temp [pin * n + thid-offset];" – Robotbugs
OK Я реализовал в основном то, что у вас есть, я отправлю окончательный код позже. Большое спасибо. – Robotbugs