2016-06-29 2 views
0

Я пытаюсь преобразовать код C++ в код Cuda, и у меня есть следующий тройной вложенный цикл цикла, который заполнит массив для дальнейшего рендеринга OpenGL (я просто создаю массив вершин координат):Cuda triple inested for loop assignement

for(int z=0;z<263;z++) {      
     for(int y=0;y<170;y++) { 
      for(int x=0;x<170;x++) { 
       g_vertex_buffer_data_3[i]=(float)x+0.5f; 
       g_vertex_buffer_data_3[i+1]=(float)y+0.5f; 
       g_vertex_buffer_data_3[i+2]=-(float)z+0.5f; 
       i+=3;    
      } 
     } 
    } 

Я хотел бы получить более быстрые операции, поэтому я буду использовать Cuda для некоторых операций, подобных перечисленным выше. Я хочу создать один блок для каждой итерации самого внешнего цикла, и поскольку внутренние петли имеют итерации 170 * 170 = 28900 тотальных итераций, назначьте один поток для каждой самой внутренней итерации цикла. Я преобразовал C++ код в это (это просто небольшая программа, которая я сделал, чтобы понять, как использовать Cuda):

__global__ void mykernel(int k, float *buffer) { 
int idz=blockIdx.x; 
int idx=threadIdx.x; 
int idy=threadIdx.y; 

buffer[k]=idx+0.5; 
buffer[k+1]=idy+0.5; 
buffer[k+2]=idz+0.5; 
k+=3; 

} 

int main(void) { 
    int dim=3*170*170*263; 
    float* g_vertex_buffer_data_2 = new float[dim]; 
    float* g_vertex_buffer_data_3; 
    int i=0; 

    HANDLE_ERROR(cudaMalloc((void**)&g_vertex_buffer_data_3, sizeof(float)*dim)); 

    dim3 dimBlock(170, 170); 

    dim3 dimGrid(263); 

    mykernel<<<dimGrid, dimBlock>>>(i, g_vertex_buffer_data_3); 

    HANDLE_ERROR(cudaMemcpy(&g_vertex_buffer_data_2,g_vertex_buffer_data_3,sizeof(float)*dim,cudaMemcpyDeviceToHost)); 

    for(int j=0;j<100;j++){ 
    printf("g_vertex_buffer_data_2[%d]=%f\n",j,g_vertex_buffer_data_2[j]); 
    } 
    cudaFree(g_vertex_buffer_data_3); 

    return 0; 

} 

Попытка запустить его я получаю ошибку segmenation. Знаете ли вы, что я делаю неправильно? Я думаю, проблема в том, что threadIdx.x и threadIdx.y растут одновременно, хотя я бы хотел, чтобы threadIdx.x был внутренним, а threadIdx.y - внешним.

ответ

4

Существует много здесь не так, но источник Segfault это:

cudaMemcpy(&g_vertex_buffer_data_2,g_vertex_buffer_data_3, 
       sizeof(float)*dim,cudaMemcpyDeviceToHost); 

Вы либо хотите

cudaMemcpy(&g_vertex_buffer_data_2[0],g_vertex_buffer_data_3, 
       sizeof(float)*dim,cudaMemcpyDeviceToHost); 

или

cudaMemcpy(g_vertex_buffer_data_2,g_vertex_buffer_data_3, 
       sizeof(float)*dim,cudaMemcpyDeviceToHost); 

После того, как вы исправить, что вам что ядро ​​на самом деле никогда не запускается с недопустимой ошибкой запуска. Это связано с тем, что размер блока (170,170) является незаконным. CUDA имеет 1024 потока на каждый предел блока для всего текущего оборудования.

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

+0

Я отредактировал первое, спасибо! Теперь я попробую со вторым, я должен найти правильный способ установить количество блоков на сетку и потоки на каждый блок. Для моего тройного вложенного цикла я должен использовать threadsId и blockId в качестве индексов для g_vertex_buffer_data_3 или использовать разные индексы, которые я увеличиваю в каждом цикле? –

+0

Вместо того, чтобы работать с таким большим набором данных, вы можете начать с меньшего набора данных, чтобы исправить остальные проблемы, например: k + = 3 не выполняет то, что вы ожидаете, тест для переполнения буфера и g_vertex_buffer_data_2 протекает. После этого вы можете, например, разделяйте весь набор данных и вызывайте свое ядро ​​CUDA несколько раз, чтобы обойти ограничение HW. Но сначала получите логику правильно. –

+0

Спасибо большое! Как я могу сделать k + = 3 с CUDA? Я имею в виду, как я могу сказать Cuda, что делать k + = 3 в C++? –