CUDA Mandelbrot集
这是一个连续的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 =
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()
。块中的线程彼此不通信pos
的设备内存cudamaloc
),并确保一切正常cudaDeviceSynchronize()
来完成此操作。在您的情况下,您不必这样做,因为CUDA memcpy将等待内核完成这肯定是不对的:
dim3 grid_size((N)/block_size.x, (int) N / block_size.y);
这会导致内核中的越界访问。您希望总共启动WIDTH
xHEIGHT
线程,图像中的每个像素对应一个线程。而是启动N
/16 xN
/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
s,而它们应该是int
sfloat
循环中的第一个表达式应该包含while
,而不是+
-
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;
}