/*******************************************************************************************************************
*文件说明:
* 第一个CUDA程序-------核函数的调用
*开发环境:
* win7+OpenCv2.4.8+cuda5.0+NIVIDA NVS 3100M
*时间地点:
* 陕西师范大学 2017.1.7
*作 者:
* 九月
********************************************************************************************************************/
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <iostream>
/*******************************************************************************************************************
*模块说明:
* CUDA中,核函数的定义
*函数说明:
* 1--主机代码(Host Code)-------在CPU上运行的代码,成为【主机代码】
* 2--设备代码(Device Code)-----在GPU上运行的代码成为【设备代码】
*__global__修饰符的解释:
* 1--这个修饰符是CUDA C为标准C语言增加的【关键字修饰符】
* 2--这个修饰符将告诉编译器,这个函数应该被编译为在设备上运行的代码,而不应该被编译为在主机上运行的代码
* 3--在这个简单的例子中,函数kernel()将被交给编译设备代码的编译器进行编译,而main函数将被交给主机编译器编译
* 4--那么,kernel()函数的调用究竟代表什么含义,并且为什么必须加上尖括号和两个数值呢?注意,这正是使用CUDA的地方
* 5--我们已经看到,CUDA C需要通过某种语法标记的方法讲一个函数标记为【设备代码---Device Code】,这并没有什么特别
* 之处,而只是一种简单的表示方法
* 6--表示将【主机代码】发送到一个编译器,而将设备代码发送到另一个编译器
********************************************************************************************************************/
__global__ void kernel(void)
{
}
/*******************************************************************************************************************
*模块说明:
* 传递参数
*模块说明:
* 1--注意,这里增加了多行代码,在这些代码中,包含两个概念:
* 1--可以像调用【C函数】那样,将参数传递给【核函数】
* 2--当【设备】执行任何有用的操作是,都需要分配内存;例如:将计算值返回给【主机】
* 3--在将【参数】传递给【核函数】的过程中,没有任何的特别之处;除了【尖括号的语法】之外,【核函数】的外表
* 和行为看上去和标准C语言中的任何函数的调用一样。【运行时系统】负责处理参数从【主机】传递给【设备】
* 的过程中的所有复杂操作
* 4--更需要注意的地方在于通过调用cudaMalloc()来分配内存。这个函数的行为非常类似于标准C语言中的malloc
* 函数,但cudaMalloc函数的作用是告诉【CUDA运行时】在【设备】上分配内存。
*malloc函数:
* 1--函数原型:void* malloc(size_t size)
*
******************************************************************************************************************/
/*******************************************************************************************************************
*malloc函数说明:
*函数原型:
* void* malloc(size_t size)
*函数作用:
* malloc函数用于分配一个指定大小的内存空间;如果分类成功,函数返回一个指向该内存空间起始地址的void类型的指针;
* 如果分配失败,函数返回0值指针NULL.
*函数参数:
* 参数size表示申请分配的字节数,类型size_t一般为unsigned int
*cudaMalloc函数说明:
* __device__ __attribute__((nv_weak)) cudaError_t cudaMalloc(void **p, size_t s)
*函数作用:
* 在【设备】上分配s个字节的线性存储单元的存储空间,并且以*p的形式返回一个指向分配空间起始地址,有p是一个二级
* 指针,针对任何类型的变量,合理的调整所分配内存的空间。这个空间不会被清除,如果出现错误,cudaMalloc将会返回
* cudaErrorMemoryAllocation
*需要注意的一点是:
* 1--程序员一定不能在【主机代码】中对cudaMalloc()返回的指针进行解引用Deference;
* 2--但是,【主机代码】可以将这个指针作为参数传递,对其执行算数运算,甚至可以将其转换为另一种不同的类型;
* 3--但是,绝对不可以使用这个指针来读取或者写入内存
*【设备指针】的使用限制如下所示:
* 1--可以将cudaMalloc函数分配的指针传递给设备上执行的函数
* 2--可以在【设备代码】中使用cudaMalloc分配的函数进行【内存的读写】
* 3--可以将cudaMalloc分配的指针传递给在主机上执行的函数
* 4--不能在主机代码中使用cudaMalloc分配的指针对【内存】进行读写
*代码说明:
* 1--通过上面的解释,我们已经看到了如何在【设备】上分配内存和释放内存,同时,也清楚的看到,在【主机】上不能对这
* 块内存做任何修改。
* 2--在示例程序中剩下来的两行代码给出了访问【设备内存】的两种最常见的方法:
* 1--在【设备代码】中使用设备内存
* 2--以及调用cudaMemcpy()
* 3--【设备指针】的使用方式与【标准C语言】中指针的使用方式完全一致。语句*c=a+b的含义同样非常简单,将参数a和b
* 相加,并将结果保存在c指向的内存中。
*注 意:
* 【主机指针】只能访问【主机代码】中的内存,而【设备指针】也只能访问【设备代码】中的【内存】
*C/C++中的【内存拷贝函数】函数说明:
*函数原型:
* extern void *memcpy(void *dest, const void *src, size_t n)
*函数作用:
* 从源src指针所指向的起始地址位置拷贝n个字节的内容,拷贝到dest所指向的内存的起始地址位置
*cudaMemcpy函数说明:
*函数原型:
*extern __host__ cudaError_t CUDARTAPI cudaMemcpy(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind);
*函数参数:
* enum cudaMemcpyKind kind---这个枚举类,有三个值:
* 1--cudaMemcpyDeviceToHost
* 2--cudaMemcpyHostToDevice
* 3--cudaMemcpyDeviceToDevice
* 这些参数都是用指定【设备指针】究竟是【源指针】还是【目标指针】
******************************************************************************************************************/
__global__ void add(int a,int b,int* c)
{
*c =a+b;
}
/*******************************************************************************************************************
*模块说明:
* 控制台应用程序的入口函数----Main函数
********************************************************************************************************************/
int main(void)
{
kernel<<<1,1>>>();
printf("Hello CUDA!\n");
int c = 0;
int* dev_c = NULL;
cudaMalloc((void**)&dev_c,sizeof(int)); //【1】在设备内存中开辟n个字节的内存空间
add<<<1,1>>>(3,7,dev_c); //【2】调用【核函数】,并且在【设备代码】中使用【设备指针】
cudaMemcpy(&c,dev_c,sizeof(int),cudaMemcpyDeviceToHost); //【3】将dev_c所指内存的起始地址位置的n个字节的内容拷贝到c所指针的内存中
printf("3+7 = %d\n",c);
cudaFree(dev_c); //【4】释放在【设备】中开辟的【内存空间】
std::system("pause");
return 0;
}
CUDA从入门到精通到精通_笔记3:第一个CUDA程序及其代码详解
最新推荐文章于 2024-06-27 23:03:00 发布