▶ 使用 CUDA Runtime API,运行时编译,Driver API 三种接口计算向量加法

▶ 源代码,CUDA Runtime API

 #include <stdio.h>
#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <helper_cuda.h> #define ELEMENT 50000 __global__ void vectorAdd(const float *A, const float *B, float *C, int size)
{
int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < size)
C[i] = A[i] + B[i];
} int main()
{
printf("\tStart.\n");
size_t size = ELEMENT * sizeof(float); float *h_A = (float *)malloc(size);
float *h_B = (float *)malloc(size);
float *h_C = (float *)malloc(size);
float *d_A = NULL;
float *d_B = NULL;
float *d_C = NULL;
cudaMalloc((void **)&d_A, size);
cudaMalloc((void **)&d_B, size);
cudaMalloc((void **)&d_C, size);
for (int i = ; i < ELEMENT; ++i)
{
h_A[i] = rand() / (float)RAND_MAX;
h_B[i] = rand() / (float)RAND_MAX;
}
cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice); int threadsPerBlock = ;
int blocksPerGrid = (ELEMENT + threadsPerBlock - ) / threadsPerBlock;
vectorAdd << <blocksPerGrid, threadsPerBlock >> > (d_A, d_B, d_C, ELEMENT);
cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost); for (int i = ; i < ELEMENT; ++i)
{
if (fabs(h_A[i] + h_B[i] - h_C[i]) > 1e-)
{
printf("\n\tResult error at i = %d, h_A[i] = %f, h_B[i] = %f, h_C[i] = %f\n", i, h_A[i], h_B[i], h_C[i]);
getchar();
return ;
}
} free(h_A);
free(h_B);
free(h_C);
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
printf("\n\tFinish.\n");
getchar();
return ;
}

● 输出结果:

    Start.

    Finish.

▶ 源代码,运行时编译

 // vectorAdd_kernel.cu
extern "C" __global__ void vectorAdd(const float *A, const float *B, float *C, int size)
{
int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < size)
C[i] = A[i] + B[i];
}
 // vectorAdd.cpp
#include <stdio.h>
#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <cuda.h>
#include <nvrtc_helper.h> #define ELEMENT 50000 int main()
{
printf("\n\tStart.\n"); char *ptx, *kernel_file;
size_t ptxSize;
kernel_file = "D:\\Program\\CUDA9.0\\Samples\\0_Simple\\vectorAdd_nvrtc\\vectorAdd_kernel.cu";
compileFileToPTX(kernel_file, , NULL, &ptx, &ptxSize, );
CUmodule module = loadPTX(ptx, , NULL);
CUfunction kernel_addr;
cuModuleGetFunction(&kernel_addr, module, "vectorAdd"); size_t size = ELEMENT * sizeof(float); float *h_A = (float *)malloc(size);
float *h_B = (float *)malloc(size);
float *h_C = (float *)malloc(size);
CUdeviceptr d_A, d_B, d_C;
cuMemAlloc(&d_A, size);
cuMemAlloc(&d_B, size);
cuMemAlloc(&d_C, size);
for (int i = ; i < ELEMENT; ++i)
{
h_A[i] = rand()/(float)RAND_MAX;
h_B[i] = rand()/(float)RAND_MAX;
}
cuMemcpyHtoD(d_A, h_A, size);
cuMemcpyHtoD(d_B, h_B, size); int threadsPerBlock = ;
dim3 cudaBlockSize(threadsPerBlock,,);
dim3 cudaGridSize((ELEMENT + threadsPerBlock - ) / threadsPerBlock, , );
int element = ELEMENT;
void *arr[] = { (void *)&d_A, (void *)&d_B, (void *)&d_C, (void *)&element};
cuLaunchKernel(kernel_addr, cudaGridSize.x, cudaGridSize.y, cudaGridSize.z, cudaBlockSize.x, cudaBlockSize.y, cudaBlockSize.z, , , &arr[], );
cuCtxSynchronize();
cuMemcpyDtoH(h_C, d_C, size); for (int i = ; i < ELEMENT; ++i)
{
if (fabs(h_A[i] + h_B[i] - h_C[i]) > 1e-)
{
printf("\n\tResult error at i = %d, h_A[i] = %f, h_B[i] = %f, h_C[i] = %f\n", i, h_A[i], h_B[i], h_C[i]);
getchar();
return ;
}
} free(h_A);
free(h_B);
free(h_C);
cuMemFree(d_A);
cuMemFree(d_B);
cuMemFree(d_C);
printf("\n\tFinish.\n");
getchar();
return ;
}

● 输出结果:

        Start.
> Using CUDA Device []: GeForce GTX
> GPU Device has SM 6.1 compute capability Finish.

▶ 源代码,Driver API,也需要上面的 vectorAdd_kernel.cu,调用核函数有三种方式,中间那种有点问题,结果不对

 #include <stdio.h>
#include <helper_cuda.h>
#include <cuda.h>
#include <string>
#include <drvapi_error_string.h> #define ELEMENT 50000
#define PATH "C:\\ProgramData\\NVIDIA Corporation\\CUDA Samples\\v9.1\\0_Simple\\vectorAddDrv\\data\\" #if defined(_WIN64) || defined(__LP64__)
#define PTX_FILE "vectorAdd_kernel64.ptx"
#else
#define PTX_FILE "vectorAdd_kernel32.ptx"
#endif using namespace std; void RandomInit(float *data, int n)
{
for (int i = ; i < n; ++i)
data[i] = rand() / (float)RAND_MAX;
} int main(int argc, char **argv)
{
printf("\n\tStart.\n");
cuInit();// 相当于 runtime API 的 cudaSetDevice(0);,要先初始化设备才能创建上下文
CUcontext cuContext;
cuCtxCreate(&cuContext, , ); // 编译
string module_path, ptx_source;
module_path = PATH"vectorAdd_kernel64.ptx";
FILE *fp = fopen(module_path.c_str(), "rb");
fseek(fp, , SEEK_END);
int file_size = ftell(fp);
char *buf = new char[file_size + ];
fseek(fp, , SEEK_SET);
fread(buf, sizeof(char), file_size, fp);
fclose(fp);
buf[file_size] = '\0';
ptx_source = buf;
delete[] buf; CUmodule cuModule;
if (module_path.rfind("ptx") != string::npos)// 使用的是.ptx,需要运行时编译
{
// 设定编译参数,CUjit_option 放置参数名,jitOptVals 放置参数值
const unsigned int jitNumOptions = ;
CUjit_option *jitOptions = new CUjit_option[jitNumOptions];
void **jitOptVals = new void *[jitNumOptions];
// 编译日志长度
jitOptions[] = CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES;
int jitLogBufferSize = ;
jitOptVals[] = (void *)(size_t)jitLogBufferSize;
// 编译日志内容
jitOptions[] = CU_JIT_INFO_LOG_BUFFER;
char *jitLogBuffer = new char[jitLogBufferSize];
jitOptVals[] = jitLogBuffer;
// 设定一个内核使用的寄存器数量
jitOptions[] = CU_JIT_MAX_REGISTERS;
int jitRegCount = ;
jitOptVals[] = (void *)(size_t)jitRegCount;
// 编译模块
cuModuleLoadDataEx(&cuModule, ptx_source.c_str(), jitNumOptions, jitOptions, (void **)jitOptVals);
//printf("> PTX JIT log:\n%s\n", jitLogBuffer);// 输出编译日志
delete[] jitLogBuffer;
delete[] jitOptVals;
delete[] jitOptions;
}
else// 使用的是 .cubin,不用编译(本例中不经过这个分支)
cuModuleLoad(&cuModule, module_path.c_str()); CUfunction vecAdd_kernel;
cuModuleGetFunction(&vecAdd_kernel, cuModule, "VecAdd_kernel");// 取出编译好的模块中的函数 // 申请内存,开始运算
int element = ELEMENT;
size_t size = ELEMENT * sizeof(float);
float * h_A, *h_B, *h_C;
CUdeviceptr d_A, d_B, d_C;
h_A = (float *)malloc(size);
h_B = (float *)malloc(size);
h_C = (float *)malloc(size);
RandomInit(h_A, ELEMENT);
RandomInit(h_B, ELEMENT);
cuMemAlloc(&d_A, size);
cuMemAlloc(&d_B, size);
cuMemAlloc(&d_C, size);
cuMemcpyHtoD(d_A, h_A, size);
cuMemcpyHtoD(d_B, h_B, size); int threadsPerBlock = ;
int blocksPerGrid = (ELEMENT + threadsPerBlock - ) / threadsPerBlock;
if () // 三种调用 Driver API 的方式
{
void *args[] = { &d_A, &d_B, &d_C, &element };
cuLaunchKernel(vecAdd_kernel, blocksPerGrid, , , threadsPerBlock, , , , NULL, args, NULL);
}
else if () // 有问题
{
int offset = ;
void *argBuffer[];
*((CUdeviceptr *)&argBuffer[offset]) = d_A;
offset += sizeof(d_A);
*((CUdeviceptr *)&argBuffer[offset]) = d_B;
offset += sizeof(d_B);
*((CUdeviceptr *)&argBuffer[offset]) = d_C;
offset += sizeof(d_C);
*((int *)&argBuffer[offset]) = element;
offset += sizeof(element);
cuLaunchKernel(vecAdd_kernel, blocksPerGrid, , , threadsPerBlock, , , , NULL, NULL, argBuffer);
}
else // 正确的
{
int offset = ;
char argBuffer[];
*((CUdeviceptr *)&argBuffer[offset]) = d_A;
offset += sizeof(d_A);
*((CUdeviceptr *)&argBuffer[offset]) = d_B;
offset += sizeof(d_B);
*((CUdeviceptr *)&argBuffer[offset]) = d_C;
offset += sizeof(d_C);
*((int *)&argBuffer[offset]) = element;
offset += sizeof(element);
void *kernel_launch_config[] =
{ CU_LAUNCH_PARAM_BUFFER_POINTER, argBuffer,CU_LAUNCH_PARAM_BUFFER_SIZE,&offset,CU_LAUNCH_PARAM_END };
cuLaunchKernel(vecAdd_kernel, blocksPerGrid, , , threadsPerBlock, , , , NULL, NULL, (void **)&kernel_launch_config);
}
cuCtxSynchronize();
cuMemcpyDtoH(h_C, d_C, size);
int i;
for (i = ; i < ELEMENT; ++i)
{
float sum = h_A[i] + h_B[i];
if (fabs(h_C[i] - sum) > 1e-7f)
{
printf("Error at i == %d, h_C[i] == %f, sum == %f", i, h_C[i], sum);
break;
}
}
printf("\n\tFinish: %s\n", (i == ELEMENT) ? "Pass" : "Fail");
getchar();
return ;
}

● 输出结果

    Start.

    Finish.

▶ 涨姿势:

● 从源代码中删减了的部分

 CUresult CleanupNoFailure() //检查内存错误的函数
{
CUresult error;
// Free device memory
if (d_A)
error = cuMemFree(d_A);
if (d_B)
error = cuMemFree(d_B);
if (d_C)
error = cuMemFree(d_C);
// Free host memory
if (h_A)
free(h_A);
if (h_B)
free(h_B);
if (h_C)
free(h_C);
error = cuCtxDestroy(cuContext);
return error;
} void Cleanup(bool noError) // 报告错误
{
CUresult error = CleanupNoFailure();
if (!noError || error != CUDA_SUCCESS)
{
printf("Function call failed\nFAILED\n");
exit(EXIT_FAILURE);
}
if (!noprompt)
{
printf("\nPress ENTER to exit...\n");
fflush(stdout);
fflush(stderr);
getchar();
}
} if (error != CUDA_SUCCESS) // 外部调用 cleanup
Cleanup(false); if (argc > ) // 主函数中使用参数 -device=n 指定设备号
{
bool bFound = false;
for (int param = ; param < argc; param++) // 逐个检查参数
{
int string_start = ;
while (argv[param][string_start] == '-') // 跳过 "-" 号
string_start++;
char *string_argv = &argv[param][string_start];
if (!strncmp(string_argv, "device", )) // 看参数是否是 device
{
int len = (int)strlen(string_argv);
while (string_argv[len] != '=')
len--;
devID = atoi(&string_argv[++len]);
bFound = true;
}
if (bFound)
break;
}
}

0_Simple__vectorAdd + 0_Simple__vectorAdd_nvrtc + 0_Simple__vectorAddDrv的更多相关文章

随机推荐

  1. (2)bytes类型

    bytes类型就是字节类型 把8个二进制一组称为一个byte,用16进制来表示 Python2里面字符串其实更应该称为字节串,但是python2里面有一个类型是butes,所以在Python2里面by ...

  2. hdu1165 规律递推

    题意:给了公式,求A(m,n). 并不知道为什么被杭电分类塞进了dp专题,但是我一开始显然看到这个题就觉得给那个公式用函数递归一下答案肯定能出来了,只不过既然放在了dp专题里面估计这样暴力求解会TLE ...

  3. 前端css规范

    文章整理了Web前端开发中的各种CSS规范,包括文件规范.注释规范.命名规范.书写规范.测试规范等. 一.文件规范 1.文件均归档至约定的目录中(具体要求以豆瓣的CSS规范为例进行讲解): 所有的CS ...

  4. 将一个list转成json数组-晚上坐49路回去打卡

  5. SysRq魔法键的使用

    SysRq魔法键的使用 1.SysRq简介它能够在系统处于极端环境时响应按键并完成相应的处理.这在大多数时候有用.SysRq 经常被称为 Magic System Request,它被定义为一系列按键 ...

  6. vue-router 知识点

    vue-router配置scrollBehavior 第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用. 注意: 这个功能只在 ...

  7. 分布式数据存储 shard(切片) 和 repali(副本) 的 节点数的关系。

    1 , node 的 数量 应该大于等于 副本(指的是单个 shard 的 主副本+备份副本数)的 数量 ,如果 副本的数量大于 node 数量,那么 一个node 必定有2 个相同的 副本,这个多出 ...

  8. Microsoft Dynamics CRM 2011 面向Internet部署 (IFD) CRM 登录出现会话超时的解决办法

    一.IFD 登录的时候,过了一段时间,会马上出现“您的会话已过期”,怎么解决这个问题呢,可以通过改变这个时间.具体图如二 Link to Dynamics CRM Wiki Home Page 二.S ...

  9. ASP.NET WEB SERVICE 创建、部署与使用

    PS: 开发工具 VS2010, 所有工程都为Debug状态,本人刚接触 Web Service,此文为菜鸟入门用例,高手勿笑! 转载请注明出处 :http://www.cnblogs.com/yyc ...

  10. C++中,关于#include<***.h>和#include"***.h"的区别

    转载:天南韩立CSDN博客 #include<>直接从编译器自带的函数库中寻找文件 #include" "是先从自定义的文件中找 ,如果找不到在从函数库中寻找文件 采用 ...