首页 > 编程语言 >CUDA 简单程序的基本框架和自定义设备函数

CUDA 简单程序的基本框架和自定义设备函数

时间:2023-08-11 09:34:13浏览次数:28  
标签:const 自定义 框架 double 指针 CUDA 主机 设备 函数

1 cuda程序的基本框架

框架包含:

  • 头文件
  • 常量或者宏定义
  • C++自定义函数和cuda核函数的原型声明
  • main函数
  • C++自定义函数核CUDA核函数的定义实现
    其中main函数中
1 int main()
2 {
3 分配主机与设备代码内存
4 初始化主机中的数据
5 将某些数据从主机复制到设备
6 调用核函数在设备中进行计算
7 将某些数据从设备复制到主机
8 释放主机与设备内存
9 }

示例代码如下。

 1 #include<math.h>
 2 #include<stdio.h>
 3 const double EPSILON=1.0e-15;
 4 const double a=1.23;
 5 const double b=2.34;
 6 const double c=3.57;
 7 void __global__ add(const double *x,const double *y,double *z);
 8 void check(const double *z,const int N);
 9 int main(void)
10 {
11         const int N=100000000;
12         const int M=sizeof(double) *N;
13         double *h_x=(double*)malloc(M);
14         double *h_y=(double*)malloc(M);
15         double *h_z=(double*)malloc(M);
16         for(int n=0;n<N;++n)
17         {
18            h_x[n]=a;
19            h_y[n]=b;
20         }
21         double *d_x,*d_y,*d_z;
22         cudaMalloc((void **)&d_x,M);
23         cudaMalloc((void **)&d_y,M);
24         cudaMalloc((void **)&d_z,M);
25         cudaMemcpy(d_x,h_x,M,cudaMemcpyHostToDevice);
26         cudaMemcpy(d_y,h_y,M,cudaMemcpyHostToDevice);
27         const int block_size=128;
28         const int grid_size=N/block_size;
29         add<<<grid_size,block_size>>>(d_x,d_y,d_z);
30         cudaMemcpy(h_z,d_z,M,cudaMemcpyHostToDevice);
31         check(h_z,N);
32         free(h_x);
33         free(h_y);
34         free(h_z);
35         cudaFree(d_x);
36         cudaFree(d_y);
37         cudaFree(d_z);
38         return 0;
39 }
40 void __global__ add(const double *x,const double *y,double *z)
41 {
42         const int n = blockDim.x*blockIdx.x+threadIdx.x;
43         z[n]=x[n]+y[n];
44 }
45 void check(const double *z,const int N)
46 {
47         bool has_error=false;
48         for(int n=0;n<N;++n)
49         {
50            if(fabs(z[n]-c)>EPSILON)
51            {
52                 has_error =true;
53            }
54           printf("%s\n",has_error?"Has errors":"No errors");
55         }
56 }

1.1 隐形的设备初始化
  在cuda运行时API中,没有明显地初始化设备(GPU)的函数。在第一次调用一个和设备管理及版本管理及版本查询功能无关的运行时API函数时,设备将自动地初始化。

1.2 设备内存的分配与释放
  在上述程序中,我们首先在主机中定义了三个数组并进行了初始化,通过cudaMalloc函数将它们指向了设备中的内存,而不是主机的内存。该函数是一个cuda运行时API函数,所有cuda运行时API函数都以cuda开头。
  在c++中由malloc()函数动态分配内存,在cuda中,设备内存的动态分配可由cudaMalloc()函数实现,函数原型如下。
  cudaError_t cudaMalloc(void **address,size_t size);

  • 其中第一个参数address是待分配设备内存的指针。因为内存(地址)本身就是一个指针,所以待分配设备内存的指针就是指针的指针,即双重指针。
  • 第二个参数size是待分配内存的字节数。
  • 返回值是一个错误代码,如果调用成功,返回cudaSuccess,否则会返回一个代表错误的代号。

  调用cudaMalloc()函数时传入的第一个参数(void *)&d_x比较难懂。其中d_x是一个double类型的指针,他的地址就是指针的指针,也就是双重指针,而使用(void * * )是一个强制类型转换操作。转换为void类型的双重指针。这种类型的转换可以不明确的写出来。所以cudaMalloc()函数的调用也可以简写为 cudaMalloc(&d_x,M);
  用cudaMalloc()函数为什么需要一个双重指针作为变量呢?该函数的功能是改变指针d_x本身的值(将一个指针赋值给d_x),而不是改变d_x所指内存缓冲区中的变量值。需要将d_x的地址&d_x传给函数cudaMalloc()才能达到修改指针d_x本身的值的效果。
  总之,使用cudaMalloc函数可以为不同类型的指针变量分配设备内存。为了区分主机和设备中的变量,使用d_作为所有设备变量的前缀,使用h_作为对应主机变量的前缀。
  正如mallloc()函数分配的主机内存需要使用free()释放一样,用cudaMalloc()函数分配的设备内存需要用cudaFree()函数释放。该函数原型为cudaError_t cudaFree(void address);
  这里参数address就是待释放的设备内存变量(不是双重指针),返回值是一个错误代号。

1.3 主机与设备之间数据的传递
  在分配了设备内存之后,就可以将一些数据从主机传递到设备中去,使用cudaMemcpy()方法主机中的变量数据复制到设备中相应变量d_x和d_y所指向的缓冲区中。其方法的原型是。

  • 第一个参数dst是目标地址。
  • 第二个参数src是源地址。
  • 第三个参数count是复制数据的字节数。
  • 第四个参数kind是一个枚举类型的变量,标志数据传递方向。其中udaMemcpyHostToHost表示从主机复制到主机。还有其他数据传递方向。
  • 返回值是一个错误代号
  • 该函数的作用是将一定字节的数据从源地址所值缓存区复制到目标地址所指缓存区。

1.4 核函数的要求

  • 1.返回值是void
  • 2.限定符
  • 3.函数名无特殊要求,支持C++中的重载,可以用同一个函数名表示具有不同参数列表的函数。
  • 4.不支持可变数据的参数列表,即参数的个数必须确定。
  • 5.可以向核函数传递非指针变量,其内容对每个线程可见。
  • 6.除非使用统一内存编程机制,否则传给核函数的数组(指针)必须指向设备内存。
  • 7.核函数不可成为一个类的成员,通常是用一个包装函数调用核函数,而将包装函数定义为类的成员。
  • 8.在计算能力3.5之前,核函数之间不能互相调用。从计算能力3.5之后,引入 了动态并行机制,在核汉书内部可以调用其他核函数,甚至可以调用自己(递归)。
  • 9.无论是从主机调用,还是从设备调用,核函数都是在设备中执行。调用核函数时必须指定执行配置,即三括号和它里面的参数。

2 自定义设备函数
  核函数可以调用不带执行配置的自定义函数,这样的自定义函数称为设备函数。他是在设备中执行,并在设备中调用的。与之相比,核函数是在设备中执行,但是在主机端被调用的。

2.1函数执行空间表示符

  • 1.用__gloabal__ 修饰的函数称为核函数,一般是由主机调用,在设备中执行。
  • 2.用__device__修饰的函数成为设备函数,只能被核函数或者其他设备函数调用,在设备中执行。
  • 3.用 host 修饰的函数就是主机端的普通C++函数,在主机中被调用,在主机中执行,修饰符可省。
  • 4.不能同时用device和global 修饰一个函数,即不能将一个函数同时定义为设备函数和核函数。
  • 5.也不能同时用host核global修饰一个函数。

2.2 代码示例

 1 double __device__ add1_device(const double x, const double y)
 2  {
 3 return (x + y);
 4 }
 5 void __global__ add1(const double *x, const double *y, double *z,
 6 const int N)
 7  {
 8    const int n = blockDim.x * blockIdx.x + threadIdx.x;
 9 if (n < N)
10 {
11     z[n] = add1_device(x[n], y[n]);
12 }
13 }

 

标签:const,自定义,框架,double,指针,CUDA,主机,设备,函数
From: https://www.cnblogs.com/ybqjymy/p/17622199.html

相关文章

  • 《CUDA编程:基础与实践》读书笔记(4):CUDA流
    1.CUDA流一个CUDA流指的是由主机发出的在一个设备中执行的CUDA操作序列。除主机端发出的流之外,还有设备端发出的流,但本文不考虑后者。一个CUDA流中的各个操作按照主机发布的次序执行;但来自两个不同CUDA流的操作不一定按照某个次序执行,有可能是并发或者交错地执行。任何CUDA操作......
  • CUDA 编程基础
    基于c/c++的编程方法支持异构编程的扩展方法简单明了的apis,能够轻松的管理存储系统cuda支持的编程语言:c/c++/python/fortran/java…1、CUDA并行计算基础异构计算CUDA安装CUDA程序的编写CUDA程序编译利用NVProf查看程序执行情况gpu不是单独的在计算机中完成任......
  • WEB自动化-Allure报告的自定义
    生成了Allure报告,可以自定义一些属性,使报告看起来层级更明显,看起来更清晰。下图显示有些优化的选项 创建测试用例:importallure#importlogging#logging.basicConfig(level=logging.INFO)@allure.epic("测试版本:V1.1")@allure.feature("首页模块")@allure.title("......
  • 利用pytorch自定义CNN网络(五):保存、加载自定义模型【转载】
    本文转载自:PyTorch|保存和加载模型1.简介本文主要介绍如何加载和保存PyTorch的模型。这里主要有三个核心函数:torch.save:把序列化的对象保存到硬盘。它利用了Python的pickle来实现序列化。模型、张量以及字典都可以用该函数进行保存;torch.load:采用pickle将反序列......
  • 探索 OSGi 框架的组件运行机制
    OSGi框架为基于Java的组件开发提供了一套通用的和标准的解决方案,通过OSGi框架可以轻松实现组件信息的隐藏和共享。本文介绍了OSGi框架中的组件(Bundle)的运行机制,并结合实际示例加以说明,读者可以进一步深入了解OSGi框架的基本原理,并解决实际开发工作中遇到的类似问题。在目......
  • 分布式服务框架 Zookeeper -- 管理分布式环境中的数据
    简介:Zookeeper分布式服务框架是ApacheHadoop的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。本文将从使用者角度详细介绍Zookeeper的安装和配置文件中各个配置项的意义,以及分析Zo......
  • java自定义注解
    Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在java.lang.annotation包中。1、元注解元注解是指注解的注解。包括 @Retention@Target@Document@Inherite......
  • 语音合成技术4:StarGANv2-VC: 一个多样化、无监督、非平行的自然音声转换框架
    StarGANv2-VC:一个多样化、无监督、非平行的自然音声转换框架摘要我们提出了一种使用生成对抗网络(GAN)的无监督非平行多对多声音转换(VC)方法,称为StarGANv2。通过使用对抗性源分类器损失和感知损失的组合,我们的模型明显优于先前的VC模型。虽然我们的模型仅通过20名英语讲话者进行......
  • 利用pytorch自定义CNN网络(四):损失函数和优化器
    本文是利用pytorch自定义CNN网络系列的第四篇,主要介绍如何训练一个CNN网络,关于本系列的全文见这里。笔者的运行设备与软件:CPU(AMDRyzen™54600U)+pytorch(1.13,CPU版)+jupyter;训练模型是为了得到合适的参数权重,设计模型的训练时,最重要的就是损失函数和优化器的选择。损......
  • avue组件自定义按钮/标题/内容/搜索栏
    话不多说笔记直接分享!!一、自定义crud搜索栏组件<templateslot-scope="scope"slot="provinceCodeSearch"> <avue-select v-model="objFrom.provinceCode"//这是存放省份的code placeholder="请选择省市" :di......