深度学习部署(十三): CUDA RunTime API thread_layout线程布局

1. 知识点

  1. 在.vscode/settings.json中配置"*.cu": "cuda-cpp"可以实现对cuda的语法解析
    在这里插入图片描述

  2. layout是设置核函数执行的线程数,要明白最大值、block最大线程数、warpsize取值

    • maxGridSize对应gridDim的取值最大值
    • maxThreadsDim对应blockDim的取值最大值
    • warpSize对应线程束中的线程数量
    • maxThreadsPerBlock对应blockDim元素乘积最大值
  3. layout的4个主要变量的关系

    • gridDim是layout维度,其对应的索引是blockIdx
      • blockIdx的最大值是0到gridDim-1
    • blockDim是layout维度,其对应的索引是threadIdx
      • threadIdx的最大值是0到blockDim-1
      • blockDim维度乘积必须小于等于maxThreadsPerBlock
    • 所以称gridDim、blockDim为维度,启动核函数后是固定的
    • 所以称blockIdx、threadIdx为索引,启动核函数后,枚举每一个维度值,不同线程取值不同
    • 关于线程束带概念这里不讲,可以自行查询
  4. 核函数启动时,<<<>>>的参数分别为:<<<gridDim, blockDim, shraed_memory_size, cudaStream_t>>>

    • shared_memory_size请看后面关于shared memory的讲解,配置动态的shared memory大小

2. 图解知识点

.1 如何理解layout是设置核函数执行的线程数,要明白最大值、block最大线程数、warpsize取值?
请添加图片描述
layout就是一个一个grid,每个block里面有一堆的block, block里面放的是thread

Warp size指的是GPU中一个线程束内包含的线程数量,同时也是最小的调度单元,即GPU会将同一个warp中的线程一起调度,以便实现并行计算。

  1. 如果我这个GPU的warp size = 32, 最小的调度单元是32个线程是吗?

是的,每个SM内部的所有线程都被划分为以warp size为大小的warp,每个warp内的线程并行执行,并且最小的调度单元是一个warp,即32个线程。如果某个warp中的线程出现了分支或者条件语句,这些线程将会被分成不同的warp分别执行,这可能会导致性能下降。因此,尽量避免分支和条件语句可以提高GPU的执行效率。

  1. 案例计算:
    请添加图片描述
    这个案例里面的layout
  • girdDim.x = 3
  • gridDim.y = 2
  • gridDim.z = 1 (这里用的是默认值)
  • blockDim.x = 4
  • blockDim.y = 2
  • blockDim.z = 1 (这里用的是默认值)

从上面把数字带进去计算就可以得到黄色格子是13了。

3. main.cpp文件

#include <cuda_runtime.h>
#include <stdio.h>

#define checkRuntime(op)  __check_cuda_runtime((op), #op, __FILE__, __LINE__)

bool __check_cuda_runtime(cudaError_t code, const char* op, const char* file, int line){
    if(code != cudaSuccess){    
        const char* err_name = cudaGetErrorName(code);    
        const char* err_message = cudaGetErrorString(code);  
        printf("runtime error %s:%d  %s failed. \n  code = %s, message = %s\n", file, line, op, err_name, err_message);   
        return false;
    }
    return true;
}

void launch(int* grids, int* blocks);

int main(){

    cudaDeviceProp prop;
    checkRuntime(cudaGetDeviceProperties(&prop, 0));

    // 通过查询maxGridSize和maxThreadsDim参数,得知能够设计的gridDims、blockDims的最大值
    // warpSize则是线程束的线程数量
    // maxThreadsPerBlock则是一个block中能够容纳的最大线程数,也就是说blockDims[0] * blockDims[1] * blockDims[2] <= maxThreadsPerBlock
    printf("prop.maxGridSize = %d, %d, %d\n", prop.maxGridSize[0], prop.maxGridSize[1], prop.maxGridSize[2]);
    printf("prop.maxThreadsDim = %d, %d, %d\n", prop.maxThreadsDim[0], prop.maxThreadsDim[1], prop.maxThreadsDim[2]);
    printf("prop.warpSize = %d\n", prop.warpSize);
    printf("prop.maxThreadsPerBlock = %d\n", prop.maxThreadsPerBlock);

    int grids[] = {1, 2, 3};     // gridDim.x  gridDim.y  gridDim.z 
    int blocks[] = {1024, 1, 1}; // blockDim.x blockDim.y blockDim.z 
    // launch(grids, blocks);       // grids表示的是有几个大格子,blocks表示的是每个大格子里面有多少个小格子
    checkRuntime(cudaPeekAtLastError());   // 获取错误 code 但不清楚error
    checkRuntime(cudaDeviceSynchronize()); // 进行同步,这句话以上的代码全部可以异步操作
    printf("done\n");
    return 0;
}

4. cu文件

#include <cuda_runtime.h>
#include <stdio.h>

__global__ void demo_kernel(){

    if(blockIdx.x == 0 && threadIdx.x == 0)
        printf("Run kernel. blockIdx = %d,%d,%d  threadIdx = %d,%d,%d\n",
            blockIdx.x, blockIdx.y, blockIdx.z,
            threadIdx.x, threadIdx.y, threadIdx.z
        );
}

void launch(int* grids, int* blocks){

    dim3 grid_dims(grids[0], grids[1], grids[2]);
    dim3 block_dims(blocks[0], blocks[1], blocks[2]);
    demo_kernel<<<grid_dims, block_dims, 0, nullptr>>>();
}

5. 代码拆解

void search_demo()
{
    // 定义一个结构体用来储存设备信息
    // 返回一个指向0号设备的指针, 如果写1号设备但是没有,checkRuntime会报错
    cudaDeviceProp prop;
    checkRuntime(cudaGetDeviceProperties(&prop, 0)); 

    // 查询maxGrid的数量,也是看每一个维度能放多少个block
    printf("prop.maxGridSize = %d, %d, %d\n", prop.maxGridSize[0], 
    prop.maxGridSize[1], prop.maxGridSize[2]);

    // 查询每一个block不同维度的最大线程数,看能放多少个线程
    printf("prop.maxThreadsDim = %d, %d, %d\n", prop.maxThreadsDim[0], prop.maxThreadsDim[1], prop.maxThreadsDim[2]);
    
    // 查询warp size
    printf("prop.warpSize = %d\n", prop.warpSize);

    printf("prop.maxThreadsPerBlock = %d\n", prop.maxThreadsPerBlock);
}
prop.maxGridSize = 2147483647, 65535, 65535
prop.maxThreadsDim = 1024, 1024, 64
prop.warpSize = 32
prop.maxThreadsPerBlock = 1024

定义一个结构体用来储存设备信息

返回一个指向0号设备的指针, 如果写1号设备但是没有,checkRuntime会报错

查询maxGrid的数量,也是看每一个维度能放多少个block

查询每一个block不同维度的最大线程数,看能放多少个线程

查询warp size

6. cu文件解读

调用在main.cpp文件里面

main.cpp

int main(){
    search_demo(); // 查询设备信息,可以通过查询设备信息了解到

    // 布局的demo, 定义布局
    int grids[] = {1, 2, 3}; // girdDim.x, gridDim.y, gridDim.z
    int blocks[] = {1024, 1, 1}; // blockDim.x, blockDim.y, blockDim.z
    launch(grids, blocks);   // grids表示的是有几个大格子,blocks表示的是每个大格子里面有多少个小格子
    checkRuntime(cudaPeekAtLastError());   // 获取错误 code 但不清楚error
    checkRuntime(cudaDeviceSynchronize()); // 进行同步,这句话以上的代码全部可以异步操作
    return 0;
}

.cu

#include <cuda_runtime.h>
#include <stdio.h>

__global__ void demo_kernel()
{
    // 这个案例是去每一个grid里面的第一个block, 第一个block的第一个线程输出信息
    // 因为block是grid的索引,thread是block的索引
    if (blockIdx.x == 0 && threadIdx.x == 0)
    {
        printf("Run kernel. blockIdx = %d,%d,%d  threadIdx = %d,%d,%d\n",
               blockIdx.x, blockIdx.y, blockIdx.z,
               threadIdx.x, threadIdx.y, threadIdx.z);
    }
}

void launch(int* grids, int* blocks)
{
    dim3 gird_dims(grids[0], grids[1], grids[2]);
    dim3 blocks_dims(blocks[0], blocks[1], blocks[2]);
    demo_kernel<<<gird_dims, blocks_dims, 0, nullptr>>>();
}
prop.maxGridSize = 2147483647, 65535, 65535
prop.maxThreadsDim = 1024, 1024, 64
prop.warpSize = 32
prop.maxThreadsPerBlock = 1024
Run kernel. blockIdx = 0,0,1  threadIdx = 0,0,0
Run kernel. blockIdx = 0,1,2  threadIdx = 0,0,0
Run kernel. blockIdx = 0,1,1  threadIdx = 0,0,0
Run kernel. blockIdx = 0,0,2  threadIdx = 0,0,0
Run kernel. blockIdx = 0,0,0  threadIdx = 0,0,0
Run kernel. blockIdx = 0,1,0  threadIdx = 0,0,0

这里的 launch 函数中 blocks[0] 为 1024,其它两个维度为 1,表示一个 block 中有 1024 个线程。grids 数组表示了整个网格的大小,其中 grids[0] 表示 x 方向上有 1 个 block,grids[1] 表示 y 方向上有 2 个 block,grids[2] 表示 z 方向上有 3 个 block。因此,总共有 6 个 block,每个 block 有 1024 个线程,所以总共有 6144 个线程。

demo_kernel()

这个案例是去每一个grid里面的第一个block, 第一个block的第一个线程输出信息

因为block是grid的索引,thread是block的索引

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7106.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

酷炫的青蛇探针serverMmon

本文软件由网友 114514 推荐&#xff1b; 什么是 serverMmon &#xff1f; serverMmon (青蛇探针)是 nodeJs 开发的一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针。 主要功能介绍&#xff1a; 全球服务器分布世界地图服务器&#xff08;控制端&#xff09; ping…

简单3招教你设置电脑时间

案例&#xff1a;电脑时间怎么设置&#xff1f; 【我使用电脑时&#xff0c;电脑显示的时间一直不对&#xff0c;这导致我非常不方便&#xff0c;想问下大家平常使用电脑时有什么设置电脑时间比较简单的方法吗&#xff1f;】 电脑的时间设置很重要&#xff0c;不仅可以保证电…

Java单例模式、阻塞队列、定时器、线程池

目录1. 单例模式1.1 饿汉模式实现单例1.2 懒汉模式实现单例1.2.1 加锁实现懒汉模式线程安全1.2.2 volatile实现懒汉模式线程安全1.3 饿汉模式和懒汉模式小结&#xff08;面试题&#xff09;2. 阻塞队列2.1 单线程下阻塞队列2.2 多线程下阻塞队列——生产者消费者模型2.3 模拟写…

【蓝桥集训18】二分图(2 / 2)

二分图定义&#xff1a;将所有点分成两个集合&#xff0c;使得所有边只出现在集合之间&#xff0c;就是二分图 目录 860. 染色法判定二分图 1、dfs 2、bfs 861. 二分图的最大匹配 - 匈牙利算法ntr算法 860. 染色法判定二分图 活动 - AcWing 1、dfs 思路&#xff1a; 对每…

白农:Imagination将继续致力于推进车规半导体IP技术创新和应用

4月2日Imagination中国董事长白农在中国电动汽车百人论坛上发表演讲&#xff0c;探讨了车规半导体核心IP技术如何推动汽车智能化发展&#xff0c;并接受了媒体采访。本次论坛上&#xff0c;他强调了IP技术在汽车产业链中日益重要的地位和供应商的位置前移。类比手机行业的发展&…

树、森林、二叉树:相互之间的转换

你好&#xff0c;我是王健伟。 前面我们讲过了各种二叉树&#xff0c;这方面的知识已经够多的了&#xff0c;本节就来讲一讲更通用的概念&#xff1a;树、森林以及与二叉树之间的转换问题。 树的存储结构 前面我们学习了树形结构的基本概念&#xff0c;在满足这个概念的前提…

python 包、模块学习总结

、模块基础 1、基本概念 模块是最高级别的程序组织单元&#xff0c;它将程序代码和数据封装起来以便重用。从实际角度来看&#xff0c;模块往往对应于python程序文件&#xff08;或是用外部语言如C、Java或C#编写而成的扩展&#xff09;。每一个文件都是一个模块&#xff0c;并…

小驰私房菜_11_mm-camera 添加客制化分辨率

#小驰私房菜# #mm-camera# #客制化分辨率# 本篇文章分下面几点展开&#xff1a; 1) mm-camera框架下&#xff0c;是在哪个文件添加客制化分辨率&#xff1f; 2&#xff09; 新添加分辨率的stall duration如何计算&#xff1f; 3&#xff09; 新添加的分辨率会有哪些影响&…

CentOS7操作系统离线安装docker

前言 有时候我们没有办法联网安装各种软件包&#xff0c;这时候就需要提前下载好所需要的包&#xff0c;然后把包上传到服务&#xff0c;在服务器上进行安装。 今天我们一起来探讨了在centos7操作系统上&#xff0c;安装docker。 专栏地址&#xff1a;容器管理 &#xff0c;…

ChatGLM-6B (介绍相关概念、基础环境搭建及部署)

文章目录前言一、ChatGLM-6B是什么&#xff1f;二、安装虚拟的python环境1.下载2.安装3.设置国内源(危险)4.虚拟环境使用简介三、部署ChatGLM-6B1. clone代码2. 运行1.创建虚拟环境2.装包2.1 找到合适的pytorch版本2.1 安装依赖2.2 验证pytorch是否为GPU版本3.运行四、部署过程…

银行数字化转型导师坚鹏:银行对公客户数字化场景营销案例萃取

银行对公客户数字化场景营销案例萃取与行动落地课程背景&#xff1a; 很多银行存在以下问题&#xff1a; 不清楚银行数字化营销与场景营销内涵&#xff1f; 不知道如何开展对公客户数字化营销工作&#xff1f; 不知道对公业务数字化场景营销成功案例&#xff1f; 学员收获&a…

5.39 综合案例2.0 - ESP32蓝牙遥控小车3(摇杆控制)

综合案例2.0 - 蓝牙遥控小车1- 摇杆控制成品展示案例说明器件说明小车连线小车源码PS2摇杆手柄遥控连线摇杆代码成品展示 案例说明 用STM32单片机做了一辆蓝牙控制的麦轮小车&#xff0c;分享一下小车的原理和制作过程。 控制部分分为手机APP&#xff0c;语音模块控制&#xf…

【AI绘图学习笔记】self-attention自注意力机制

台大李宏毅21年机器学习课程 self-attention和transformer 文章目录不同模态的输入和输出Sequence LabelingSelf-attentionMulti-head Self-attentionPositional EncodingSelf-attention的应用Self-attention对比其他算法vs CNNvs RNN总结不同模态的输入和输出 之前我们所讲的一…

SpringBoot学习笔记--数据库操作

文章目录7.1 JDBCHikariDataSource7.2 整合 Druid 到 Spring-Boot7.1 JDBCHikariDataSource 需求&#xff1a;演示 Spring Boot 如何通过 jdbcHikariDataSource 完成对 Mysql 操作 说明: HikariDataSource : 目前市面上非常优秀的数据源, 是 springboot2 第一步、创建测试数…

代码随想录Day44

今天继续学习通过动态规划解决问题 96.不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 思路…

数据存储的细致介绍

本文介绍内容&#xff1a; 1&#xff1a;数据类型的详细介绍 2&#xff1a;整形的存储&#xff1a;原码&#xff0c;反码&#xff0c;补码 3&#xff1a;大小端字节序 4&#xff1a;浮点型的存储 一&#xff1a;数据类型的归类 1&#xff1a;整形家族(包括无符号&#xff09; …

Web 攻防之业务安全:本地加密传输测试.

Web 攻防之业务安全&#xff1a;本地加密传输测试. 业务安全是指保护业务系统免受安全威胁的措施或手段。广义的业务安全应包括业务运行的软硬件平台&#xff08;操作系统、数据库&#xff0c;中间件等&#xff09;、业务系统自身&#xff08;软件或设备&#xff09;、业务所提…

蓝桥杯·3月份刷题集训Day07

本篇博客旨在记录自已打卡蓝桥杯3月份刷题集训&#xff0c;同时会有自己的思路及代码解答希望可以给小伙伴一些帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误之处&#xff0c;希望小伙伴们可以在评论区指出来&#xff0c;共勉&#x1f4aa;。 文…

【C++修行之路】面向对象三大特性之多态

文章目录前言认识多态构成多态的必要条件虚函数的重写虚函数重写的两个例外final和override重载、覆盖、隐藏抽象类多态的原理单继承多继承重写了基类的虚函数没有重写基类的虚函数菱形继承和菱形虚拟继承的虚表补充补充继承与多态相关问题inline函数可以是虚函数吗&#xff1f…

ChatGPT这么火,我们能怎么办?

今天打开百度&#xff0c;看到这样一条热搜高居榜二&#xff1a;B站UP主发起停更潮&#xff0c;然后点进去了解一看&#xff0c;大体是因为最近AI创作太火&#xff0c;对高质量原创形成了巨大冲击&#xff01;记得之前看过一位UP主的分享&#xff0c;说B站UP主的年收入大体约等…