CUDA 编程入门

2023-11-01

CUDA 编程入门

更好的阅读体验

CUDA 概述

CUDA 是 NVIDIA 推出的用于其发布的 GPU 的并行计算架构,使用 CUDA 可以利用 GPU 的并行计算引擎更加高效的完成复杂的计算难题。

在目前主流使用的冯·诺依曼体系结构的计算机中,GPU 属于一个外置设备,因此即便在利用 GPU 进行并行计算的时候也无法脱离 CPU,需要与 CPU 协同工作。因此当我们在说 GPU 并行计算时,其实指的是基于 CPU+GPU 的异构计算架构。在异构计算架构中,CPU 和 GPU 通过 PCI-E 总线连接在一起进行协同工作,所以 CPU 所在位置称为 Host,GPU 所在位置称为 Device,如下图所示。

从上图可以看到,GPU 中有着更多的运算核心,非常适合数据并行的计算密集型任务,比如大型的矩阵计算。

CUDA 编程模型基础

在了解了 CUDA 的基本概念之后,还需要了解 CUDA 编程模型的基本概念以便于之后利用 CUDA 编写并行计算程序。

CUDA 模型时一个异构模型,需要 CPU 和 GPU 协同工作,在 CUDA 中一般用 Host 指代 CPU 及其内存,Device 指代 GPU 及其内存。CUDA 程序中既包含在 Host 上运行的程序,也包含在 Device 上运行的程序,并且 Host 和 Device 之间可以进行通信,如进行数据拷贝等操作。一般的将需要串行执行的程序放在 Host 上执行,需要并行执行的程序放在 Device 上进行。

异构编程

CUDA 程序一般的执行流程:

  1. 分配 Host 内存,并进行数据初始化
  2. 分配 Device 内存,并将 Host 上的数据拷贝到 Device 上
  3. 调用 CUDA Kernel 在 Device 上进行并行运算
  4. 将运算结果从 Device 上拷贝到 Host 上,并释放 Device 上对应的内存
  5. 并行运算结束,Host 得到运算结果,释放 Host 上分配的内存,程序结束

在第 3 步中,CUDA Kernel 指的是在 Device 线程上并行执行的函数,在程序中利用 __global__ 符号声明,在调用时需要用 <<<grid, block>>> 来指定 Kernel 执行的线程数量,在 CUDA 中每一个线程都要执行 Kernel 函数,并且每个线程会被分配到一个唯一的 Thread ID,这个 ID 值可以通过 Kernel 的内置变量 threadIdx 来获得。

__gloabl__ vectorAddition(float* device_a, float* device_b, float* device_c);  // 定义 Kernel
int main()
{
    /*
    some codes
    */
    vectorAddition<<<10, 32>>>(parameters);  // 调用 Kernel 并指定 grid 为 10, block 为 32
    /*
    some codes
    */
}

Kernel 的层次结构

Kernel 在 Device 执行的时候实际上是启动很多线程,这些线程都执行 Kernel 这个函数。其中,由这个 Kernel 启动的所有线程称为一个 grid,同一个 grid 中的线程共享相同的 Global memory,grid 是线程结构的第一个层次。一个 grid 又可以划分为多个 block,每一个 block 包含多个线程,其中的所有线程又共享 Per-block shared memory,block 是线程结构的第二个层次。最后,每一个线程(thread)有着自己的 Per-thread local memory。

线程两层组织结构

内存层次结构

下图是一个线程两层组织结构的示意图,其中 grid 和 block 均为 2-dim 的线程组织。grid 和 block 都是定义为 dim3 类型的变量,dim3 可以看成是包含三个无符号整数(x, y, z)成员的结构体变量,在定义时,缺省值初始化为1。

dim3 grid(3, 2);
dim3 block(5, 3);
kernel<<<grid, block>>>(parameters);

从线程的组织结构可以得知,一个线程是由(blockIdx, threadIdx)来唯一标识的,blockIdx 和 threadIdx 都是 dim3 类型的变量,其中 blockIdx 指定线程所在 block 在 grid 中的位置,threadIdx 指定线程在 block 中的位置,如图中的 Thread(2,1) 满足:

threadIdx.x = 2;
threadIdx.y = 1;
blockIdx.x = 1;
blockIdx.y = 1;

一个 block 是放在同一个流式多处理器(SM)上运行的,但是单个 SM 上的运算核心(cuda core)有限,这导致线程块中的线程数是有限制的,因此在设置 grid 和 block 的 shape 时需要根据所使用的 Device 来设计。

如果要知道一个线程在 block 中的全局 ID,就必须要根据 block 的组织结构来计算,对于一个 2-dim 的 block( D x D_x Dx, D y D_y Dy),线程( x x x, y y y)的 ID 值为 x + y ∗ D x x+y*D_x x+yDx,如果是 3-dim 的 block( D x D_x Dx, D y D_y Dy, D z D_z Dz),线程( x x x, y y y, z z z)的 ID 值为 x + y ∗ D x + z ∗ D x ∗ D y x+y*D_x+z*D_x*D_y x+yDx+zDxDy

CUDA 实现向量加法

查看 Device 基本信息

在进行 CUDA 编程之前,需要先看一下自己的 Device 的配置,便于之后自己设定 grid 和 block 更好的利用 GPU。

#include <stdio.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
int main()
{
    cudaDeviceProp deviceProp;
    cudaGetDeviceProperties(&deviceProp, 0);
    printf("Device 0 information:\n");
    printf("设备名称与型号: %s\n", deviceProp.name);
    printf("显存大小: %d MB\n", (int)(deviceProp.totalGlobalMem / 1024 / 1024));
    printf("含有的SM数量: %d\n", deviceProp.multiProcessorCount);
    printf("CUDA CORE数量: %d\n", deviceProp.multiProcessorCount * 192);
    printf("计算能力: %d.%d\n", deviceProp.major, deviceProp.minor);
}

Device 0 information:
设备名称与型号: Tesla K20c
显存大小: 4743 MB
含有的SM数量: 13
CUDA CORE数量: 2496
计算能力: 3.5
Device 1 information:
设备名称与型号: Tesla K20c
显存大小: 4743 MB
含有的SM数量: 13
CUDA CORE数量: 2496
计算能力: 3.5

其中第 12 行乘 192 的原因是我所使用的设备为 Tesla K20,而 Tesla K 系列均采用 Kepler 架构,该架构下每个 SM 中的 cuda core 的数量为 192。

实现 Vector Addition
#include <stdio.h>
#include <time.h>
#include <math.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

const int LENGTH = 5e4;
clock_t start, end;
void vectorAdditionOnDevice(float*, float*, float*, const int);
__global__ void additionKernelVersion(float*, float*, float*, const int);
int main()
{
    start = clock();
    float A[LENGTH], B[LENGTH], C[LENGTH] = {0};
    for (int i = 0; i < LENGTH; i ++) A[i] = 6, B[i] = 5;
    vectorAdditionOnDevice(A, B, C, LENGTH);  //calculation on GPU
    end = clock();
    printf("Calculation on GPU version1 use %.8f seconds.\n", (float)(end - start) / CLOCKS_PER_SEC);
}
void vectorAdditionOnDevice(float* A, float* B, float* C, const int size)
{
    float* device_A = NULL;
    float* device_B = NULL;
    float* device_C = NULL;
    cudaMalloc((void**)&device_A, sizeof(float) * size);  // 分配内存
    cudaMalloc((void**)&device_B, sizeof(float) * size);  // 分配内存
    cudaMalloc((void**)&device_C, sizeof(float) * size);  // 分配内存
    const float perBlockThreads = 192.0;
    cudaMemcpy(device_A, A, sizeof(float) * size, cudaMemcpyHostToDevice);  // 将数据从 Host 拷贝到 Device
    cudaMemcpy(device_B, B, sizeof(float) * size, cudaMemcpyHostToDevice);  // 将数据从 Host 拷贝到 Device
    additionKernelVersion<<<ceil(size / perBlockThreads), perBlockThreads>>>(device_A, device_B, device_C, size);  // 调用 Kernel 进行并行计算
    cudaDeviceSynchronize();
    cudaMemcpy(device_C, C, sizeof(float) * size, cudaMemcpyDeviceToHost);  // 将数据从 Device 拷贝到 Host
    cudaFree(device_A);  // 释放内存
    cudaFree(device_B);  // 释放内存
    cudaFree(device_C);  // 释放内存
}
__global__ void additionKernelVersion(float* A, float* B, float* C, const int size)
{
    // 此处定义用于向量加法的 Kernel
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    C[i] = A[i] + B[i];
}

Calculation on GPU version1 use 0.14711700 seconds.

参考资料

CUDA编程入门极简教程

CUDA C Programming Guide

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA 编程入门 的相关文章

  • 无法在 CUDA 中执行设备内核

    我正在尝试在全局内核中调用设备内核 我的全局内核是矩阵乘法 我的设备内核正在查找乘积矩阵每列中的最大值和索引 以下是代码 device void MaxFunction float Pd float max int x threadIdx
  • 从 CUDA 设备写入输出文件

    我是 CUDA 编程的新手 正在将 C 代码重写为并行 CUDA 新代码 有没有一种方法可以直接从设备写入输出数据文件 而无需将数组从设备复制到主机 我假设如果cuPrintf存在 一定有地方可以写一个cuFprintf 抱歉 如果答案已经
  • CUDA、NPP 滤波器

    CUDA NPP 库支持使用 nppiFilter 8u C1R 命令过滤图像 但不断出现错误 我可以毫无问题地启动并运行 boxFilterNPP 示例代码 eStatusNPP nppiFilterBox 8u C1R oDeviceS
  • “gld/st_throughput”和“dram_read/write_throughput”指标之间有什么区别?

    在 CUDA 可视化分析器版本 5 中 我知道 gld st requested throughput 是应用程序请求的内存吞吐量 然而 当我试图找到硬件的实际吞吐量时 我很困惑 因为有两对似乎合格的指标 它们是 gld st throug
  • 如何运行和理解CUDA Visual Profiler?

    我已经设置了 CUDA 5 0 并且我的 CUDA 项目运行良好 但我不知道如何使用 Visual Profiler 分析我的 CUDA 项目 如何运行它 我还需要安装更多吗 又该如何做呢 我的电脑使用Window 7 64位 CUDA 5
  • PyInstaller 是否包含 CUDA

    我正在开发一个Python脚本 我使用Python 3 7 3 它使用tensorflow gpu 1 14 0 并使用PyInstaller 3 5将此脚本转换为可执行文件 我使用的是 CUDA 10 0 和 cuDNN 7 6 1 我的
  • CUDA Thrust 的多 GPU 使用

    我想使用我的两张显卡通过 CUDA Thrust 进行计算 我有两张显卡 在单卡上运行对于两张卡都适用 即使我在 std vector 中存储两个 device vector 也是如此 如果我同时使用两张卡 循环中的第一个周期将起作用并且不
  • CUDA 的嵌套循环

    我想将我的 C 代码移植到 CUDA 主要计算部分包含3个for嵌套循环 for int i 0 i lt Nx i for int j 0 j
  • 使用 GPU 进行 Matlab 卷积

    我用gpuArray尝试了matlab的卷积函数conv2 convn 例如 convn gpuArray rand 100 100 10 single gpuArray rand 5 single 并将其与 cpu 版本 convn ra
  • 无法在 CUDA 中找到 1 到 100 数字的简单和?

    我正在研究使用 CUDA 的图像处理算法 在我的算法中 我想使用 CUDA 内核找到图像所有像素的总和 所以我在cuda中制作了内核方法 来测量16位灰度图像的所有像素的总和 但我得到了错误的答案 所以我在cuda中编写了一个简单的程序来查
  • 如何安装libcusolver.so.11

    我正在尝试安装 Tensorflow 但它要求 libcusolver so 11 而我只有 libcusolver so 10 有人可以告诉我我做错了什么吗 这是我的 Ubuntu nvidia 和 CUDA 版本 uname a Lin
  • 直接在主机上访问设备向量元素的最快方法

    我请您参考以下页面http code google com p thrust wiki QuickStartGuide Vectors http code google com p thrust wiki QuickStartGuide V
  • CUDA 和 Eigen 的成员“已声明”错误

    我只是 CUDA 和 Nsight 的初学者 希望利用出色的 GPU 性能进行线性代数运算 例如 CUBLAS 我在以下人员的帮助下编写了很多自定义代码Eigen http eigen tuxfamily org index php tit
  • 使用推力来处理 CUDA 类中的向量?

    我对 C 类的推力的适用性有疑问 我正在尝试实现一个类对象 该对象接收顶点的 x y z 坐标作为 ver1 ver2 和 ver3 然后 分配给一个三角形并计算面积和法向量 然而 我不太明白如何创建一类推力向量 这是我从文件中读取的顶点坐
  • CUDA-Kernel 应该根据块大小动态崩溃

    我想做稀疏矩阵 密集向量乘法 假设用于压缩矩阵中条目的唯一存储格式是压缩行存储 CRS 我的内核如下所示 global void krnlSpMVmul1 float data mat int num nonzeroes unsigned
  • 完全禁用 NVCC 优化

    我正在尝试测量 GPU 上的峰值单精度触发器 为此我正在修改 PTX 文件以在寄存器上执行连续的 MAD 指令 不幸的是 编译器正在删除所有代码 因为它实际上没有做任何有用的事情 因为我没有执行任何数据的加载 存储 是否有编译器标志或编译指
  • CUDA 中的 JPEG 库

    我正在尝试在 CUDA 中压缩和解压缩图像 到目前为止我已经找到了这个库 http sourceforge net projects cuj2k source navbar http sourceforge net projects cuj
  • CUDA cutil.h 在哪里?

    有谁知道包含 cutil h 的 SDK 工具包在哪里 我尝试了 CUDA toolkits3 2 和 toolkits5 0 我知道这个版本已经不支持 cutil h 我还注意到一些提到的如何在 Linux 中包含 cutil h htt
  • 如何转储所有 NVCC 预处理器定义?

    我想达到同样的效果 gcc dM E lt dev null 如所描述的here https stackoverflow com q 2224334 1593077 但对于 nvcc 也就是说 我想转储所有 nvcc 的预处理器定义 唉 n
  • 如何使用 Visual Studio 2008 调试 CUDA 内核代码?

    嘿 我正在使用带有 CUDA 3 2 的 Visual Studio 2008 我正在尝试调试具有此签名的函数 MatrixMultiplication Kernel lt lt

随机推荐

  • 【Python】输入输出与运算符

    目录 1 输入输出 1 1 和用户交互 1 2 通过控制台输出 1 3 通过控制台输入 2 运算符 2 1 算数运算符 2 2 关系运算符 2 3 逻辑运算符 2 4 赋值运算符 1 输入输出 1 1 和用户交互 程序需要和用户进行交互 用
  • GlusterFS云存储分布式文件系统 35课

    主要应用在集群系统中 具有很好的可扩展性 软件的结构设计良好 易于扩展和配置 通过各个模块的灵活搭配以得到针对性的解决方案 可解决以下问题 网络存储 联合存储 融合多个节点上的存储空间 冗余备份 大文件的负载均衡 分块 由于缺乏一些关键特性
  • MPChart的饼状图使用

    控件项目地址 https github com PhilJay MPAndroidChart 效果图 使用 1 导库 可以去下载jar包 下载地址 https github com PhilJay MPAndroidChart releas
  • R语言基础——R包的安装与使用

    R语言基础 R包的安装与使用 R包的安装 选择镜像站点 下载R包 使用函数library 来查看库里有哪些安装包 R包的使用 载入包 列出包的帮助文档 列出R包中所有包含的函数 列出R包中包含的数据集 移除加载的包 删除已安装的包 remo
  • 在Windows中搭建Python Web开发环境

    最近的一个外包项目 客户要求IE8 兼容 之前做自己的个人项目都是在Ubuntu下开发 然后在Chrome上跑一下就OK 完全没有管IE兼容性 这次不行了 得啃下这个骨头 测IE兼容有一款工具必不可少 那就是IETester 从IE5 5到
  • 常用算法之验证回文串

    今天给大家分享一道面试中经常碰到的简单算法题目 检测回文串 题目 给定一个字符串 验证它是否是回文串 只考虑字母和数字字符 可以忽略字母的大小写 示例1 输入 A man a plan a canal Panama 输出 true 示例2
  • vscode运行Python出现问题import cv2 ModuleNotFoundError: No module named 'cv2'

    import cv2 ModuleNotFoundError No module named cv2 vscode运行Python时出现问题 PS D bmi bmi project gt python demo py Traceback
  • 深港澳金融科技师(SHMFTTP)一级考试

    说明 个人整理的简易程序知识点笔记 比较好的地方是将刷题过程中遇到的题目 一起附在知识点后面了 结合题目对知识点的理解会更深 目录 一 金融标准化t35 50 一 伦理与职业素养t100 120 二 战略性新兴产业t1 20 正文 一 金融
  • 《Python进阶系列》二十三:解决线性规划和二次型规划问题的CVXOPT模块

    Python CVXOPT模块 Python中支持Convex Optimization 凸规划 的模块为CVXOPT 能够解决线性规划和二次型规划问题 其应用场景如SVM中的Hard Margin SVM Creating matrice
  • gtiee教程(三板斧)-------好东西我们一起来学习

    作者前言 这是我的gitee仓库 https gitee com qin laoda python exercises 有兴趣的小可爱们可以点进去看看 gtiee网址 https gitee com login 下面我来简单介绍一下gtie
  • 接口测试_无业务关联的单接口——注册功能测试设计

    接口文档大致如下 接口测试分析 案例设计 具体的案例省略 测试代码如下 encoding utf 8 import requests json os hashlib re def reg username password email ex
  • 创建第一个servlet项目(简单版创建)--详细图文教程

    Servlet 是一种实现动态页面的技术 是一组 Tomcat 提供给程序猿的 API 帮助程序猿简单高效的开发一 个 web app 今天讲一下如何建立一个servlet项目 注意 基于meven创建servlet项目 前提meven要下
  • Clion远程调试树莓派并传递视频流

    Clion远程调试树莓派并传递视频流 0 前言 1 远程调试配置 1 1 远端配置 1 2 本地配置 2 视频流传输 环境 windows10 LTSC raspi 0 前言 近期学习opencv 并准备一些比赛项目 听学长介绍Clion可
  • Linux 网卡重新获取IP

    1 所有网卡驱动重新加载 service network restart 2 对单一网卡进行操作 ifconfig a 获取所有网卡信息 可以看到所有网卡的名字 ifconfig 网卡名称 down ifconfig 网卡名称 up 3 D
  • nvme测试工具:nvme_cli

    nvme cli工具是用于对nvme盘测试的一款通用工具 提供了读写块 查看control namespace信息等功能 下载路径 nvme cli工具是用于对nvme盘进行测试的一款通用工具 其它文档类资源 CSDN下载 如果需要交叉编译
  • 运行node出现“ operation not permitted”错误解决办法

    windows系统下使用node js在使用npm安装express时报错的解决方法 安装时出现如下错误 C Users admin gt npm uninstall express gnpm ERR Windows NT 10 0 143
  • 雷军写的代码上热搜了

    雷军写的代码 一词突然上了微博热搜 一瞬间 我想起了这张图 到底发生了什么 好奇的我点进去一看 原来是因为雷军预告年度演讲的微博里配了一张海报 这张海报信息量非常大 一眼就能看到有很多代码元素 放大一点看看局部 这还是16位实模式下的汇编语
  • JSONObject重复引用导致结果中出现$ref的问题

    转自链接 https blog csdn net baceng article details 92836486 解决办法 先把JSONObject转换成String 然后再转换回JSONObject 例 bussinessData JSO
  • MAYA基础知识和技巧总结

    目录 自定义工具架 自定义热盒 打开Maya时隐藏Output Window 快捷键 小技巧 元素选择技巧 隐藏和显示元素的几种方法 多切割工具 加线 切割 补面的几种方法 复制的几种方法 加入参考图并锁定不动 曲线建模技巧 双轨成型工具
  • CUDA 编程入门

    CUDA 编程入门 更好的阅读体验 CUDA 概述 CUDA 是 NVIDIA 推出的用于其发布的 GPU 的并行计算架构 使用 CUDA 可以利用 GPU 的并行计算引擎更加高效的完成复杂的计算难题 在目前主流使用的冯 诺依曼体系结构的计