CUDA Mandelbrot集

CUDA Mandelbrot集,cuda,parallel-processing,gpu,Cuda,Parallel Processing,Gpu,这是一个连续的Mandelbrot集实现 void mandelbrot(PGMData *I) { float x0,y0,x,y,xtemp; int i,j; int color; int iter; int MAX_ITER=1000; for(i=0; i<I->height; i++) for(j=0; j<I->width; j++) { x0 =

这是一个连续的Mandelbrot集实现

 void mandelbrot(PGMData *I)
{
    float x0,y0,x,y,xtemp;
    int i,j;
    int color;
    int iter;
    int MAX_ITER=1000;  
    for(i=0; i<I->height; i++)
        for(j=0; j<I->width; j++)
        {
            x0 = (float)j/I->width*(float)3.5-(float)2.5; 
            y0 = (float)i/I->height*(float)2.0-(float)1.0;
            x = 0;
            y = 0;
            iter = 0;
            while((x*x-y*y <= 4) && (iter < MAX_ITER))
            { 
                xtemp = x*x-y*y+x0;
                y = 2*x*y+y0;
                x = xtemp;
                iter++;
            }
            color = (int)(iter/(float)MAX_ITER*(float)I->max_gray);
            I->image[i*I->width+j] = I->max_gray-color;
        }
}
整个GPU功能

void mandelbrotGPU(PGMData *I)
{
    int *pos = (int *)malloc(HEIGHT*WIDTH*sizeof(int));
    int *d_pgmData;

    cudaMalloc((void **)&d_pgmData, sizeof(int)*WIDTH*HEIGHT);


    cudaMemcpy(d_pgmData, pos ,HEIGHT*WIDTH*sizeof(int) ,cudaMemcpyHostToDevice);

    dim3 block_size(16, 16);
    dim3 grid_size((N)/block_size.x, (int) N / block_size.y);
    calc<<<grid_size,block_size>>>(d_pgmData);

    cudaMemcpy(pos,d_pgmData,HEIGHT*WIDTH*sizeof(int) ,cudaMemcpyDeviceToHost);
    cudaFree(d_pgmData);
    I->image = pos;
}
void mandelbrotGPU(PGMData*I)
{
int*pos=(int*)malloc(高度*宽度*尺寸(int));
int*d_pgmData;
Cudamaloc((空心**)和d_pgmData,尺寸(内部)*宽度*高度);
cudaMemcpy(数据、位置、高度*宽度*尺寸(整数)、cudaMemcpyHostToDevice);
dim3块尺寸(16,16);
dim3网格大小((N)/块大小.x,(int)N/块大小.y);
计算(d_pgmData);
cudaMemcpy(位置、数据、高度*宽度*尺寸(整数)、cudaMemcpyDeviceToHost);
cudaFree(d_pgmData);
I->image=pos;
}

问题是:要么是退回垃圾,要么是司机撞车。我真的很想得到一些建议,因为我真的被卡住了

只是一些想法:

  • 无需
    \uu syncthreads()
    。块中的线程彼此不通信
  • 无需为I_宽度和I_高度创建设备内存。您只需将它们作为值(而不是指针或引用)传入。您确实需要
    pos
    的设备内存
  • 您需要检查所有CUDA函数的返回值(例如,
    cudamaloc
    ),并确保一切正常
  • 当您启动内核时,您的程序可以在GPU完成之前返回。有些情况下,您需要明确等待完成;您可以在启动后调用
    cudaDeviceSynchronize()
    来完成此操作。在您的情况下,您不必这样做,因为CUDA memcpy将等待内核完成

  • 这肯定是不对的:

        dim3 grid_size((N)/block_size.x, (int) N / block_size.y);
    
    这会导致内核中的越界访问。您希望总共启动
    WIDTH
    x
    HEIGHT
    线程,图像中的每个像素对应一个线程。而是启动
    N
    /16 x
    N
    /16线程

    内核中似乎有一个线程检查行(它应该阻止错误线程的越界访问),但它的格式不正确:

    if(col > WIDTH || row > HEIGHT || idx > N) return;
    
    例如,这允许
    idx
    =
    N
    通过线程检查,但当由内核的最后一行写入时,这不是有效的内存位置:

    pos[idx] = color;
    
    您可以使用以下方法修复此线程检查:

    if(col >= WIDTH || row >= HEIGHT || idx >= N) return;
    
    其他一些评论:

    • 你什么都没做
    • 如果使用
      cuda memcheck

      • 以下是您的代码的工作版本(使用OpenCV):

        #包括“cuda_runtime.h”
        #包括“设备启动参数.h”
        #包括
        #包括
        #包括
        使用名称空间cv;
        使用名称空间std;
        #定义高度512//必须是块大小.y的倍数
        #定义宽度512//必须是块大小的倍数
        #定义最大ITER 10000
        void mandelbrotGPU(char*);
        __全局无效计算(字符*图像缓冲区);
        #定义cudaAssertSuccess(ans){cudaAssertSuccess((ans),_文件_,_行__)}
        内联void\u cudaAssertSuccess(cudaError\u t代码、char*文件、int行)
        {
        如果(代码!=cudaSuccess){
        fprintf(标准字符,“\u cudaAssertSuccess:%s%s%d\n”,cudaGetErrorString(代码),文件,行);
        出口(代码);
        }
        }
        int main(int argc,字符**argv)
        {
        IplImage*图像_输出=cvCreateImage(cvSize(宽度、高度)、IPL_深度_8U,1);
        mandelbrotGPU(图像输出->图像数据);
        cvShowImage(“GPU”,图像输出);
        等待键(0);
        cvReleaseImage(&image_输出);
        }
        void mandelbrotGPU(字符*图像\缓冲区)
        {
        字符*d_图像_缓冲区;
        cudaAssertSuccess(cudaMalloc(&d_图像_缓冲区,宽度*高度));
        dim3块尺寸(16,16);
        dim3网格尺寸(宽度/块尺寸.x,高度/块尺寸.y);
        计算(d_图像_缓冲区);
        cudaAssertSuccess(cudaPeekAtLastError());
        cudaAssertSuccess(cudaDeviceSynchronize());
        cudaAssertSuccess(cudaMemcpy(图像缓冲区、数据图像缓冲区、高度*宽度、cudaMemcpyDeviceToHost));
        cudaAssertSuccess(cudaFree(d_映像_缓冲区));
        }
        __全局无效计算(字符*图像缓冲区)
        {
        int row=blockIdx.y*blockDim.y+threadIdx.y;//宽度
        int col=blockIdx.x*blockDim.x+threadIdx.x;//高度
        int idx=行*宽+列;
        如果(列>=宽度| |行>=高度)返回;
        浮点数x0=((浮点数)列/宽度)*3.5f-2.5f;
        浮动y0=((浮动)行/高度)*3.5f-1.75f;
        浮动x=0.0f;
        浮动y=0.0f;
        int-iter=0;
        浮动xtemp;
        而((x*x+y*y=256)color=0;
        图像缓冲区[idx]=颜色;
        }
        
        输出:

        最重要的变化是:

        • 删除了
          \uuu syncthreads();
          。此算法不使用其他线程生成的数据,因此不需要同步线程
        • 已删除将主机缓冲区复制到设备的操作。由于Mandelbrot算法写入整个设备缓冲区,因此无需执行此操作
        • 修复了不正确的网格大小计算
        • 已删除主机内存的malloc,因为结果将直接复制到OpenCV图像缓冲区
        • 将缓冲区更改为使用字节而不是整数,这在具有8位分辨率的单个灰色通道时更方便
        • 删除了一些不必要的浮点类型转换。在计算中与浮点一起使用整数时,整数将自动升级为浮点
        • 修复了Mandelbrot算法中的两个问题:
          • x
            y
            被声明为
            int
            s,而它们应该是
            float
            s
          • while
            循环中的第一个表达式应该包含
            +
            ,而不是
            -

        您的第4项不正确。向同一个流发出的CUDA操作(在这里它们都在同一个默认流中)会自动序列化。
        cudaMemcpy
        操作将在其前面的
        calc
        内核完成后才会开始。无需调用
        cudaDeviceSynchronize()
        启动后,如果问题正在等待内核完成。您好,请发布用于构建项目的命令/工具,我非常感激
        if(col > WIDTH || row > HEIGHT || idx > N) return;
        
        pos[idx] = color;
        
        if(col >= WIDTH || row >= HEIGHT || idx >= N) return;
        
        #include "cuda_runtime.h"
        #include "device_launch_parameters.h"
        #include <iostream>
        #include <opencv2/core/core.hpp>
        #include <opencv2/highgui/highgui.hpp>
        
        using namespace cv;
        using namespace std;
        
        #define HEIGHT 512 // must be multiple of block_size.y
        #define WIDTH 512 // must be multiple of block_size.x
        #define MAX_ITER 10000
        
        void mandelbrotGPU(char*);
        __global__ void calc(char* image_buffer);
        
        #define cudaAssertSuccess(ans) { _cudaAssertSuccess((ans), __FILE__, __LINE__); }
        inline void _cudaAssertSuccess(cudaError_t code, char *file, int line)
        {
          if (code != cudaSuccess)  {
            fprintf(stderr,"_cudaAssertSuccess: %s %s %d\n", cudaGetErrorString(code), file, line);
            exit(code);
          }
        }
        
        int main(int argc, char** argv)
        {
          IplImage* image_output = cvCreateImage(cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1);
          mandelbrotGPU(image_output->imageData);
          cvShowImage("GPU", image_output);
          waitKey(0);
          cvReleaseImage(&image_output);
        }
        
        void mandelbrotGPU(char* image_buffer)
        {
          char* d_image_buffer;
          cudaAssertSuccess(cudaMalloc(&d_image_buffer, WIDTH * HEIGHT));
          dim3 block_size(16, 16);
          dim3 grid_size(WIDTH / block_size.x, HEIGHT / block_size.y);
          calc<<<grid_size, block_size>>>(d_image_buffer);
          cudaAssertSuccess(cudaPeekAtLastError());
          cudaAssertSuccess(cudaDeviceSynchronize());
          cudaAssertSuccess(cudaMemcpy(image_buffer, d_image_buffer, HEIGHT * WIDTH, cudaMemcpyDeviceToHost));
          cudaAssertSuccess(cudaFree(d_image_buffer));
        }
        
        __global__ void calc(char* image_buffer)
        {
          int row = blockIdx.y * blockDim.y + threadIdx.y;  // WIDTH
          int col = blockIdx.x * blockDim.x + threadIdx.x;  // HEIGHT
          int idx = row * WIDTH + col;
          if(col >= WIDTH || row >= HEIGHT) return;
        
          float x0 = ((float)col / WIDTH) * 3.5f - 2.5f;
          float y0 = ((float)row / HEIGHT) * 3.5f - 1.75f;
        
          float x = 0.0f;
          float y = 0.0f;
          int iter = 0;
          float xtemp;
          while((x * x + y * y <= 4.0f) && (iter < MAX_ITER))
          { 
            xtemp = x * x - y * y + x0;
            y = 2.0f * x * y + y0;
            x = xtemp;
            iter++;
          }
        
          int color = iter * 5;
          if (color >= 256) color = 0;
          image_buffer[idx] = color;
        }