Выделить память устройства CUDA для облака точек с увеличением размера (количество точек)

Я пишу программу, в которой мне нужно:

  • сделать тест на каждом пикселе изображения
  • если результат теста TRUE, я должен добавить точку в облако точек
  • если результат теста FALSE, ничего не делать

Я уже написал рабочий код на стороне процессора C++. Теперь мне нужно ускорить его с помощью CUDA. Моя идея состояла в том, чтобы сделать некоторый блок/поток (думаю, по одному потоку на пиксель) выполнять тест параллельно и, если результат теста ИСТИНЕН, создать поток для добавления точки в облако.

Вот моя проблема: Как я могу выделить место в памяти устройства для облака точек (используя cudaMalloc или подобное), если я заранее не знаю количество точек, которые я буду вставлять в облако?

Должен ли я выделять фиксированный объем памяти, а затем увеличивать его каждый раз, когда облако точек достигает предельного размера? Или есть способ "динамически" выделить память?


person dbovo89    schedule 22.04.2016    source источник
comment
Я хотел прокомментировать, но это было слишком долго, посмотрите мой ответ, чтобы увидеть, как динамически выделять из ядер. Но это не на 100% то, что вы хотите, так как каждый раз он будет размещаться в разных массивах.   -  person Taro    schedule 22.04.2016


Ответы (2)


Когда вы выделяете память на устройстве, вы можете сделать это с помощью двух вызовов API: один — это malloc, описанный Таро, но он ограничен некоторым внутренним пределом драйвера (по умолчанию 8 МБ), который можно увеличить, установив соответствующий параметр. ограничение с помощью cudaDeviceSetLimit с параметром cudaLimitMallocHeapSize.

В качестве альтернативы вы можете использовать cudaMalloc в ядре, как это метод API хоста и устройства.

В обоих случаях наблюдение Таро остается в силе: вы будете выделять новый другой буфер, как это, кстати, было бы на процессоре. Следовательно, использование одного буфера может привести к необходимости копирования данных. Обратите внимание, что cudaMemcpy не является методом API устройства, поэтому вам может потребоваться написать свой собственный.

Насколько мне известно, в API CUDA нет такой вещи, как realloc.

Возвращаясь к исходной проблеме, вы можете захотеть реализовать свой алгоритм в три этапа: на первом этапе будет подсчитываться количество необходимых вам выборок, на втором этапе будет выделяться массив данных, а на третьем этапе будет передаваться массив данных. Чтобы реализовать это, вы можете использовать атомарные функции для увеличения некоторого int, который подсчитывает количество выборок.

person Florent DUGUET    schedule 22.04.2016
comment
Идея реализации в три этапа кажется интересной и позволит избежать выделения буфера большего, чем необходимо (как в случае с предложенным мной обходным путем). Думаю, @dbovo89 стоит попробовать :) - person Taro; 22.04.2016

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

Да, вы можете динамически выделять память из ядер. Вы можете вызывать функции malloc() и free() внутри ваших ядер для динамического выделения и освобождения памяти во время вычислений, как объяснено в разделе B-16 руководства CUDA 7.5 Programming Руководство :

__global__ void mallocTest()
{
    size_t size = 123;
    char* ptr = (char*)malloc(size);
    memset(ptr, 0, size);
    printf("Thread %d got pointer: %p\n", threadIdx.x, ptr);
    free(ptr);
}

int main()
{
    // Set a heap size of 128 megabytes. Note that this must
    // be done before any kernel is launched.
    cudaDeviceSetLimit(cudaLimitMallocHeapSize, 128*1024*1024);
    mallocTest<<<1, 5>>>();
    cudaDeviceSynchronize();
    return 0;
}

(Вам потребуется вычислительная мощность 2.x или выше)

Но при этом вы выделяете новый и другой буфер в памяти, вы не заставляете свой предыдущий - и выделенный хостом - буфер "расти", как динамический контейнер ЦП (вектор, список и т. д.). ).

Я думаю, вы должны установить постоянную настройку максимального размера вашего массива, затем выделить максимальный размер и заставить ваше ядро ​​увеличивать «действительно используемый размер» в этом максимальном буфере. Если вы делаете это, не забудьте сделать это приращение атомарным/синхронизированным, чтобы подсчитывать каждое приращение от каждого параллельного потока.

person Taro    schedule 22.04.2016