使用CUDA在GPU上进行图像处理的多线程

skm*_*skm -1 c++ multithreading

问题陈述: 我必须连续处理从相机捕获的8百万像素图像。上面必须有几种图像处理算法,例如颜色插值,颜色转换等。这些操作在CPU上将花费很长时间。因此,我决定使用CUDA内核在GPU上执行这些操作。我已经编写了可工作的CUDA内核用于颜色转换。但是我仍然需要进一步提高性能。

基本上有两个计算时间:

  1. source image从CPU 复制到GPU,反之亦然
  2. source imageGPU的处理

当图像从CPU复制到GPU时...。同样,当在GPU上处理图像时,其他任何事情都不会发生。

我的想法:我想进行多线程处理,以便节省时间。我想在GPU上进行前一张图像的处理时捕获下一张图像。并且,当GPU完成前一个图像的处理时,下一个图像已经在那里,可以将其从CPU传输到GPU。

我需要什么:我对多线程世界完全陌生。我正在看一些教程和其他一些东西,以了解更多有关它的信息。因此,我正在寻找有关适当步骤和适当逻辑的一些建议。

Rob*_*lla 5

我不确定您是否真的需要线程。CUDA能够允许主机和设备之间进行异步并发执行(无需使用多个CPU线程。)您要的是一种非常标准的“流水线”算法。它看起来像这样:

$ cat t832.cu
#include <stdio.h>

#define IMGSZ 8000000
// for this example, NUM_FRAMES must be less than 255
#define NUM_FRAMES 128
#define nTPB 256
#define nBLK 64


unsigned char cur_frame = 0;
unsigned char validated_frame = 0;


bool validate_image(unsigned char *img) {
  validated_frame++;
  for (int i = 0; i < IMGSZ; i++) if (img[i] != validated_frame) {printf("image validation failed at %d, was: %d, should be: %d\n",i, img[i], validated_frame); return false;}
  return true;
}

void CUDART_CB my_callback(cudaStream_t stream, cudaError_t status, void* data) {
    validate_image((unsigned char *)data);
}


bool capture_image(unsigned char *img){

  for (int i = 0; i < IMGSZ; i++) img[i] = cur_frame;
  if (++cur_frame == NUM_FRAMES) {cur_frame--; return true;}
  return false;
}

__global__ void img_proc_kernel(unsigned char *img){

  int idx = threadIdx.x + blockDim.x*blockIdx.x;
  while(idx < IMGSZ){
    img[idx]++;
    idx += gridDim.x*blockDim.x;}
}

int main(){

  // setup

  bool done = false;
  unsigned char *h_imgA, *h_imgB, *d_imgA, *d_imgB;
  size_t dsize = IMGSZ*sizeof(unsigned char);
  cudaHostAlloc(&h_imgA, dsize, cudaHostAllocDefault);
  cudaHostAlloc(&h_imgB, dsize, cudaHostAllocDefault);
  cudaMalloc(&d_imgA, dsize);
  cudaMalloc(&d_imgB, dsize);
  cudaStream_t st1, st2;
  cudaStreamCreate(&st1); cudaStreamCreate(&st2);
  unsigned char *cur = h_imgA;
  unsigned char *d_cur = d_imgA;
  unsigned char *nxt = h_imgB;
  unsigned char *d_nxt = d_imgB;
  cudaStream_t *curst = &st1;
  cudaStream_t *nxtst = &st2;


  done = capture_image(cur); // grabs a frame and puts it in cur
  // enter main loop
  while (!done){
    cudaMemcpyAsync(d_cur, cur, dsize, cudaMemcpyHostToDevice, *curst); // send frame to device
    img_proc_kernel<<<nBLK, nTPB, 0, *curst>>>(d_cur); // process frame
    cudaMemcpyAsync(cur, d_cur, dsize, cudaMemcpyDeviceToHost, *curst);
  // insert a cuda stream callback here to copy the cur frame to output
    cudaStreamAddCallback(*curst, &my_callback, (void *)cur, 0);
    cudaStreamSynchronize(*nxtst); // prevent overrun
    done = capture_image(nxt); // capture nxt image while GPU is processing cur
    unsigned char *tmp = cur;
    cur = nxt;
    nxt = tmp;   // ping - pong
    tmp = d_cur;
    d_cur = d_nxt;
    d_nxt = tmp;
    cudaStream_t *st_tmp = curst;
    curst = nxtst;
    nxtst = st_tmp;
    }
}
$ nvcc -o t832 t832.cu
$ cuda-memcheck ./t832
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
$
Run Code Online (Sandbox Code Playgroud)

有很多cuda示例代码可能也有帮助,例如simpleStreamsasyncAPIsimpleCallbacks

  • 请发布一个新问题。而且我没有可使用的openCV。那不是我可以使用的MCVE。如果您想了解这些概念,则不必将OpenCV引入其中。 (2认同)