CUDA入门笔记(三)GPU编程基础——一个典型GPU程序

2023-10-29

参考:

优达学城:https://classroom.udacity.com/courses/cs344/lessons/55120467/concepts/670611900923

 

一、典型GPU程序构成

一个典型GPU程序有如下几个部分:

①CPU在GPU上分配内存

②CPU将CPU中的数据copy到GPU中

③调用内核函数来处理数据

④CPU将GPU中的数据copy到CPU中

 

*可以看出,四个步骤中有两个是数据的copy,因此如果你的程序需要不断地进行copy,那么运行效率会比较低,不适合利用GPU运算。

一般情况下,最好的方式是,让GPU进行大量运算,同时保证计算量与通信的比值很高。

 

二、运行程序时GPU是如何运作的?

前面提到,我们将运算看作是一个由一系列或多个内核组成的结构。GPU有很多并行的计算单元,那么当我们写kernels的时候,应该充分利用这些硬件并行。

 

★Big Idea(one of the very core concept of CUDA):

当你在写程序的时候,你把它写的像是一个串行的程序,就好像是在一个单独的线程里运行一样。当你从CPU调用核的时候,就给核规定好要启动几个线程,每一个线程都会运行这个程序(的一部分?,存疑)。

 

小结:

GPU擅长:①启动很多的线程   ②并行地运行很多线程

因此,如果你的程序没有利用它进行多线程计算,那么就没有很好的利用GPU。

 

三、一个典型的程序

程序要求:对一个数组当中的所有元素进行平方计算。

 

先看一下C语言版本的程序:

for (int i = 0; i < 64; i++){
    out[i] = in[i] * in[i];
}

C语言的程序有以下两个特点:

①只有一个线程在执行计算,该线程遍历输入数组内所有元素。(将该线程定义为“执行代码的一个独立路径”,这一定义也将适用于GPU代码中。)

②代码中没有显式并行性,是串行代码。这段代码是一个循环64次的线程,每一个循环进行一次平方计算。

 

对于GPU来说,程序要分为两个部分:①在CPU上运行   ②在GPU上运行的

图3.1 GPU程序构成

GPU上运行的程序很简单,可以看作是一个普通的串行运算,在这个例子里就是 OUT = IN * IN,即计算平方。那么这个核函数就可以看作跟“并行”无关。

CPU上的程序则要负责分配内存、从GPU复制数值、将数值传递给GPU、启动Kernel函数

*CPU启动kernels的过程:用64个线程,启动一个执行平方计算的kernel,即square_kernel。每一个内核的实例(instance)将运算一个平方计算。

*线程索引:分辨每一个独立的内核做的工作。

CPU code:

square_kernel<<<64>>>(input_array, output_array)

完整的代码如下:

#include <stdio.h>

//内核函数,就跟一个串行程序一样
//__global__ : 定义说明符,用来表明这是一个内核,而非普通函数
//kernel的参数都必须是分配在GPU上的,不然会程序崩溃
__global__ void square(float * d_out, float * d_in){
    int idx = threadIdx.x; //用来得到线程的索引值,threadIdx是一个CUDA内置变量,其本质是一个C结构,有三个成员,x、y、z。
    float f = d_in[idx];
    d_out[idx] = f * f;
}

//下面是CPU代码
int main(int argc, char ** argv) {
    const int ARRAY_SIZE = 64;
    const int ARRAY_BYTES = ARRAY_SIZE * sizeof(float);

//generate input array on the host
    float h_in[ARRAY_SIZE];
    for (int i = 0; i < ARRAY_SIZE; i++){
        h_in[i] = float(i);
    }
    float h_out[ARRAY_SIZE];

//declare GPU memory pointers,看起来跟c program一样,是一个普通的数组
    float * d_in;
    float * d_out;

//allocate GPU memory,在这里给它分配GPU内存
    cudaMalloc((void **) &d_in, ARRAY_BYTES);
    cudaMalloc((void **) &d_out, ARRAY_BYTES);

//transfer the array to the GPU,前三个参数跟C Memcpy一样,目标地址、源地址、字节数,最后一个参数表明转移方向cudaMemcpyHostToDevice, cudaMemcpyDeviceToHost,cudaMemcpyDeviceToDevice
    cudaMencpy(d_in, h_in, ARRAY_BYTES,cudaMemcpyHostToDevice);

//launch the kernel, cuda启动运算符,在一个具有64个元素的block上启动一个核,两个参数d_in,d_out
//这句话告诉CPU,在GPU上启动64个线程,运行64个内核副本
//注意,我们只能在调用内核处理GPU数据,而不能处理CPU数据
    square<<<1,ARRAY_SIZE>>>(d_out, d_in);

//copy back the result array to the CPU,完成内核运行以后,结果在d_out中
    cudaMemcpy(h_out, d_out, ATTAY_BYTES, cudaMemcpyDeviceToHost);

//print out the resulting array
    for (int i = 0; i < ARRAY_SIZE; i++){
        printf("%f",h_out[i]);
        printf(((i % 4) != 3) ? "\t" : "\n" );
    }

//free GPU memory allocation
    cudaFree(d_in);
    cudaFree(d_out);

    return 0;
}

 

需要注意的是,在CUDA程序中,我们以h_开头表示host上的数据,d_开头表示GPU上的数据。

针对代码,有值得注意的几点:

①square<<<1,64>>>(d_out, d_in)

参数说明: 

1:number of blocks

64:Threads Per Block

从硬件角度说,①硬件可以同时运行多个块(blocks),②每个块有线程数限制,较新的GPU一个块可以支持1024个线程,旧的512.

 

②另外,这是一个一维diagram,只在一个维度发展。如果想要处理2/3等维度问题,则需要如下代码:

Kernel<<<GRID OF BLOCKS, BLOCK OF THREADS,shemem>>>(...)

说明: 

GRID OF BLOCKS:线程块网格维数,取值1-3

BLOCK OF THREADS:每个块中线程维数,取值1-3

dim3(x,y,z):线程/blocks维数 = x*y*z,xyz分别代表三个方向的值

shemem:每一个块共享的内存,字节数

 

③线程索引

threadIdx:线程索引,有threadIdx.x,threadIdx.y,threadIdx.z来找三个方向的索引。

blockIdx:块索引,同上。

*CUDA擅长处理多块、多线程、多维度问题。

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

CUDA入门笔记(三)GPU编程基础——一个典型GPU程序 的相关文章

  • 【转】详细解析电源滤波电容的选取与计算

    本文转载自电源联盟 电感的阻抗与频率成正比 电容的阻抗与频率成反比 所以 电感可以阻扼高频通过 电容可以阻扼低频通过 二者适当组合 就可过滤各种频率信号 如在整流电路中 将电容并在负载上或将电感串联在负载上 可滤去交流纹波 电容滤波属电压滤
  • 基于随机响应机制的本地差分隐私【谷歌】论文笔记

    RAPPOR Randomized Aggregatable Privacy Preserving Ordinal Response 论文阅读 写在前面的话 自己的理解 整理 攻击模型 注意事项 相关工作 总结 写在前面的话 这篇文章是我在
  • asyncio+requests个人笔记

    requests库结合asyncio 使用asyncio和requests库 由于request是同步的 会阻塞asyncio 所以为每个request请求都创建多一个事件轮询器 这边我理解是多一个事件轮询器对应一个多线程 去跑reques
  • AR互动技术是什么

    AR互动技术是什么 AR技术是属于对现实增强的技术 AR互动体验的互动性 创意性和高体验感的特点将成为商家和会展的选择 AR互动应用从普通的商城发展到科技馆 博物馆 甚至跨界到医疗 军事等方面 接下来由数字平原总结AR互动体验展示的优点在哪
  • Reinforcement Learning 强化学习(一)

    Task01 本次学习主要参照Datawhale开源学习及强化学习蘑菇书Easy RL 部分内容参考Shusen Wang的github开源项目DRL 第1章 强化学习基础 1 1 强化学习概述 强化学习 reinforcement lea
  • 概率统计——概率论与数理统计

    一 随机变量 1 1 概率 随机事件 A A A发生的可能性度量 称为 A A A发生的概率 记为 P
  • java入门二:java流程控制

    1 用户交互Scanner java util Scanner是Java5的新特性 可以通过Scanner类来获取用户的输入 基本语法 Scanner s new Scanner System in 通过Scanner类的next 与nex

随机推荐

  • 软件项目管理知识回顾---网络图

    网络图 9 网络图 9 1简介 1 分类 AOA 双代号 ADM AON PDM 单代号 前导图 2 活动的逻辑管理 头到头 尾 尾到头 尾 依赖关系 3 工序 紧前 紧后 9 2绘制规则 1 两个节点只能一条线 不能是平行线 平行的话就不
  • 开源网络引擎firefly:环境搭建

    原文来自 http blog csdn net losophy article details 17000769 我自己配置的时候修改了几处 一 安装Python windows下安装Python 1 下载对应系统的python版本 现在多
  • 基于三维激光点云的树木建模(枝叶分离)

    基于三维激光点云的树木建模 2019 05 30 三维激光点云数据采集 2019 06 15 点云的枝叶分离 树枝 树干提取 枝干骨架提取 枝干骨架优化 构建三维模型 测试软件 链接 https pan baidu com s 1LhxOg
  • Java的自动装箱与拆箱详细分析

    Java的自动装箱与拆箱详细分析 1 既然说是装箱与拆箱 那么到底是装的什么 拆的什么 装箱 将基本数据类型封装起来 用他对应的引用类 包装类 来处理 拆箱 就是把引用类里面的基本数据拆出来 2 说到了基础数据类型 Java中的基础数据类型
  • Prometheus怎么监控docker容器 给我个详细的教程

    Prometheus可以通过Docker容器服务检测来监控Docker容器 具体步骤如下 1 安装Prometheus和Node Exporter 并将它们部署到Docker容器中 2 在Prometheus配置文件中添加Node Expo
  • 集合(四):Map接口

    文章目录 1 Map的实现类的结构 2 HashMap的底层实现原理 以JDK7为说明 3 LinkedHashMap的底层实现原理 4 Map接口 常用方法 5 TreeMap 6 Properties 1 Map的实现类的结构 Map
  • Ubuntu中文件系统根目录上的磁盘空间不足的详细解决方案

    目录 Ubuntu中文件系统根目录上的磁盘空间不足的详细解决方案 一 问题提出 二 解决问题 2 1 安装gparted管理器 2 2 打开 2 3 右键点击分区 选择调整大小 移动 一 问题提出 在使用Ubuntu时 可能会出现下图中的提
  • Protobuf初次使用小记

    本来是正在研究学习netty 教程中出现了protobuf 索性仔细研究了一番 厚积薄发 说不定哪一天就突然要用到 protobuf是一种类似于json和xml的数据传输格式 优势在于高效的序列化和反序列化 关于这个 我没有去测试 只是把整
  • AT&T汇编指令介绍

    linux中使用的AT T格式的汇编指令 所以总结一下一些比较重要的指令 1 寻址模式 有多种不同的寻址模式 允许不同形式的存储器引用 我们用符号Ea表示任意寄存器 R Ea 表示它的值 M addr 表示addr处地址的值 题目 答案 0
  • 专业级技巧:利用Vue3 provide / inject机制更轻松地完成祖先和后代组件之间的通信管理

    部分数据来源 ChatGPT 简介 在 Vue 中 使用 props 和 emit 等方式可以实现祖先和后代组件之间的通信 但是当组件层级较多时 这种方式会比较繁琐和复杂 为了解决这个问题 Vue3 提供了新的 provide inject
  • 【LeetCode第2场双周赛】

    第 2 场双周赛 A 模拟 class Solution public int sumOfDigits vector
  • 【LeetCode刷题】303 区域和检索 -数组不可变 java

    题目 给定一个整数数组 nums 处理以下类型的多个查询 计算索引 left 和 right 包含 left 和 right 之间的 nums 元素的 和 其中 left lt right 实现 NumArray 类 NumArray in
  • python3 [爬虫入门实战] 查看网站有多少个网页(站点)

    前提 进行爬虫的时候需要进行站点的爬取 再选用合适的爬虫框架 所以这里不得不需要知道一下一个网站到底有多少个网页组成 一个域名网站中到底有多少个站点 查看的方法很简单 直接百度就可以了 例如需要知道豆丁网的站点有多少个 直接在百度中输入 s
  • C# 关闭进程

    using System Diagnostics string fileName example txt Process processes Process GetProcessesByName processName foreach Pr
  • (Qt)day4

    widget h ifndef WIDGET H define WIDGET H include
  • ElasticSearch简介

    文章目录 ElasticSearch简介 正向索引和倒排索引 正向索引 倒排索引 ElasticSearch和MySQL的区别 ElasticSearch简介 什么是ElasticSearch ElasticSearch 是一款非常强大的开
  • stlink仿真器报错及处理过程记录

    项目使用stlink连接stm32f101系列的芯片 因为没有仔细阅读相关资料 出一些莫名的错 搞了大半天 前言 使用正版的stlink系列仿真器 身在山寨之国 貌似不用盗版不太合适 这里的盗版指的是别人生产来卖钱的 自己根据电路图做的不算
  • 知识的融入-增强深度学习的学习 Shades of Knowledge- Infused Learning for Enhancing Deep Learning

    知识的融入 增强深度学习的学习 摘要 SHALLOW INFUSION OF KNOWLEDGE 知识的浅层注入 Word embeddings Enriched word embeddings Deep neural language m
  • ctfshow 菜狗杯wp

    果然菜狗杯是教育我们是菜狗的 我是从第二天开始做的 这里只做了一个上午 因为下午网没了 做不了 做出来的有点少 社工也做出来挺多但是感觉社工的wp感觉就没有啥必要写了 目录 misc 签到题 损坏的压缩包 web web签到 web2 c0
  • CUDA入门笔记(三)GPU编程基础——一个典型GPU程序

    参考 优达学城 https classroom udacity com courses cs344 lessons 55120467 concepts 670611900923 一 典型GPU程序构成 一个典型GPU程序有如下几个部分 CP