今天开始整cuda编程处理图像,好久没玩cuda,又从小白开始。情况不妙,第一个工程坑不少,记录一下如下2个重要的错误:
(1)来自 CUDA 12.1.targets 的MSB3721错误
错误 命令““C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\bin\nvcc.exe” -XXXXX-C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\include" -G --keep-dir x64\Debug -maxrregcount=0 --machine 64 --compile ”已退出,返回代码为 255。XXXXXX\CUDA 12.1.targets。
总之就是除了报这个错误,还有一长串别的都是跟sm_相关的错误,检查代码计算没有问题,就是编译一直一长串。。。
那么按照如下操作看看:
1)检查工程配置属性
鼠标落在解决方案上->右键->生成依赖项->生成自定义,查看确保已经选中如下:
2)查看.cu文件的属性
鼠标落点.cu文件,右键->属性,查看项类型为如下:
3)检查编译器,确保为X64(此处非常容易忽略)
查看状态栏:
查看解决方案->属性:
(2)提示调用语法错误‘<’
这个问题比较烦神,搜罗一圈都说cpp中不能直接调用核函数<<<,>>>,需要extern "c"去修饰,但是也不太明白怎么个修饰安置法。那么我再仔细理一下:
先上代码:
.cpp 文件如下:
#include "processImg.cuh"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>int main()
{int N = 1 << 20;int nBytes = N * sizeof(float);// 申请host内存float* x, * y, * z;x = (float*)malloc(nBytes);y = (float*)malloc(nBytes);z = (float*)malloc(nBytes);// 初始化数据for (int i = 0; i < N; ++i){x[i] = 10.0f;y[i] = 20.0f;}//------------调用核函数封装函数-------------------------------AddKernelFunction(x, y, z);// 检查执行结果float maxError = 0.f;for (int i = 0; i < N; i++)maxError = fmax(maxError, fabs(z[i] - 30.0f));std::cout << "最大误差: " << maxError << std::endl;// 释放host内存free(x);free(y);free(z);return 0;
}
.cuh 文件如下:
//------#######-------------------------------------
声明文件,声明在cu文件中定义的核函数及其封装函数
//------#######-------------------------------------#include "cuda_runtime.h"
#include "device_launch_parameters.h"#include <stdio.h>
#include <stdlib.h>
#include <assert.h>//--------供cpp调用的封装核函数-----------------------------
extern "C" void AddKernelFunction(float* x, float* y, float* z);//-----------核函数--------------------------------------------
__global__ void add(float* x, float* y, float* z, int n);
.cu 文件如下:
//------#######------------------
核函数定义及封装核函数的调用函数定义
//------#######------------------#include "processImg.cuh" #include "cuda_runtime.h"
#include "device_launch_parameters.h"__global__ void add(float* x, float* y, float* z, int n)
{// 获取全局索引int index = threadIdx.x + blockIdx.x * blockDim.x;// 步长int stride = blockDim.x * gridDim.x;for (int i = index; i < n; i += stride){z[i] = x[i] + y[i];}
}
extern "C" void AddKernelFunction(float* x, float*y, float*z)
{int N = 1 << 20;int nBytes = N * sizeof(float);float* d_x, * d_y, * d_z;cudaMalloc((void**)&d_x, nBytes);cudaMalloc((void**)&d_y, nBytes);cudaMalloc((void**)&d_z, nBytes);cudaMemcpy((void*)d_x, (void*)x, nBytes, cudaMemcpyHostToDevice);cudaMemcpy((void*)d_y, (void*)y, nBytes, cudaMemcpyHostToDevice);dim3 blockSize(256);dim3 gridSize((N + blockSize.x - 1) / blockSize.x);// 执行kerneladd <<<gridSize,blockSize>>>(d_x, d_y, d_z, N);cudaMemcpy((void*)z, (void*)d_z, nBytes, cudaMemcpyHostToDevice);// 释放device内存cudaFree(d_x);cudaFree(d_y);cudaFree(d_z);
}
没错,整个测试小工程有3个文件组成:
.cpp文件包含了工程的入口main()函数,里面定义了一些在CPU上的变量分配,并调用了核函数封装函数。
.cuh文件,就是cu文件的声明头文件,声明了cu文件中定义的函数。
.cu文件,核函数定义文件,同时定义了供外部调用的封装函数。
当然了,其实cuda中的函数的定义和调用封装等还有很多小细节有待挖掘和优化,计算前 memset一下会更好,路漫漫其修远兮~