[CUDA 学习笔记] CUDA kernel 的 grid_size 和 block_size 选择

CUDA kernel 的 grid_size 和 block_size 选择

核函数执行配置

Execution Configuration

cuda_kernel<<< Dg, Db, Ns, S >>>(...)
  • Dg: grid 的维度和大小 (grid_size). 类型 dim3. : Dg.x * Dg.y * Dg.z 为启动的线程块(block)数.
  • Db: 每个线程块的维度和大小 (block_size). 类型 dim3. Db.x * Db.y * Db.z 为每个线程块的线程数.
  • Ns: 每个线程块需动态分配的共享内存的字节数. 类型 size_t. 默认值 0.
  • S: 指定的相关联的 CUDA 流. 类型 cudaStream_t. 默认值 0.

block_size 选择

NVIDIA GPU 算力及规格参数

  • 大于 0, 上限为 1024

  • x 维度和 y 维度上限 1024, z 维度上限 64

  • 最好是 32 的倍数. 因为一个 warp 有 32 个线程.

  • 最好是不小于 SM 上最大同时执行的线程数(Maximum number of resident threads per SM)和最大同时执行的线程块数(Maximum number of resident blocks per SM)的比值.
    因为要尽可能让 GPU 占有率(Occupancy, SM 上并发执行的线程数和 SM 上最大支持的线程数的比值)达到 100%, 所以

    S M 理论线程数 = b l o c k _ s i z e × S M 最大 b l o c k 数 ≥ S M 最大线程数 ⇒ b l o c k _ s i z e ≥ S M 最大线程数 / S M 最大 b l o c k 数 \begin{aligned} & SM理论线程数=block\_size\times SM最大block数\geq SM最大线程数\\ &\Rightarrow \ block\_size \geq SM最大线程数/SM最大block数 \end{aligned} SM理论线程数=block_size×SM最大blockSM最大线程数 block_sizeSM最大线程数/SM最大block
    V100 、 A100、 GTX 1080 Ti 为 2048 / 32 = 64, RTX 3090 为 1536 / 16 = 96. 因此 block_size 不应小于 96.

  • 最好是 SM 最大线程数的约数(因数). 因为 block 调度到 SM 的过程是原子的, 即该 block 中的所有线程都在同一 SM 上执行, 因此 block_size 为 SM 最大线程数的约数时可以确保 SM 不会有一直空闲的线程.
    主流架构最大线程数(2048, 1536, 1024)的公约数为 512, 256, 128.

  • 寄存器、共享内存等资源对应到每个线程不能超过上限(每个 block 的 32 位寄存器数量, 每个 block 的共享内存大小上限). 这里指明为"对应到每个线程", 即每个线程所使用的寄存器数、共享内存应小于上限/ block_size.

在不考虑线程同步等其他因素的情况下:

  • 当寄存器和共享内存使用较少时, 可以将 block_size 设置为较大的 512、1024(SM 最大线程数不为 1536 时);
  • 反之, 当寄存器和共享内存使用较多时, 可以将 block_size 设置的较小, 即 128、256.
  • ※ 在笔者接触的一些 CUDA 库中, block_size 一般多被设置为 128、256

grid_size 选择

  • x 维度上限 231-1, y 维度和 z 维度上限 65535.
  • 不应低于 GPU 上 SM 的数量 (A100 为 108 个). 因为至少让每个 SM 都启动 1 个 block
  • 最好不低于 S M 数 × 每个 S M 最大 b l o c k 数 SM数\times 每个SM最大block数 SM×每个SM最大block. 这样一批 GPU 可以一次几乎同时完成的 block 称之为 wave, 这里的"每个 SM 最大 block 数"根据实际情况会不同.
  • 数量足够多的整数个 wave, 或数量足够大. 考虑到 GPU 的多 CUDA 流等情况, 仍可能出现尾效应(tail effect, 一个 wave 完成后, GPU 上将只有很少的 block 在执行), 因此 grid_size 足够大可以让 GPU 尽可能充分调度运行.

如下是 Oneflow 中的计算方式:

unsigned grid_size = std::max<int>(1, std::min<int64_t>((n + kBlockSize - 1) / kBlockSize,sm_count * tpm / kBlockSize * kNumWaves));
  • n: 数据个数
  • kBlockSize: block_size
  • sm_count: SM 个数
  • tpm: SM 上最大同时执行的线程数(Maximum number of resident blocks per SM)
  • kNumWaves: wave 个数(上文有提到), 一般设置为 32. 使 grid 为整数个 wave.

数据量较小的情况下, 不会启动过多的线程块 ((n + kBlockSize - 1) / kBlockSize); 在数据量较大的情况下, 尽可能将线程块数目设置为数量足够多的整数个 wave, 以保证 GPU 实际利用率够高 (sm_count * tpm / kBlockSize * kNumWaves).

参考资料

  • 如何设置CUDA Kernel中的grid_size和block_size? - 知乎
  • 高效、易用、可拓展我全都要:OneFlow CUDA Elementwise 模板库的设计优化思路 - 知乎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(超详细)8-YOLOV5改进-添加EMA意力机制

1、在yolov5/models下面新建一个EMA.py文件&#xff0c;在里面放入下面的代码 代码如下&#xff1a; import torch from torch import nnclass EMA(nn.Module):def __init__(self, channels, factor8):super(EMA, self).__init__()self.groups factorassert channels // sel…

MapReduce基础知识

MapReduce 1、介绍MapReduce ​ MapReduce的思想核心是“分而治之”&#xff0c;适用于大量复杂的任务处理场景&#xff08;大规模数据处理场景&#xff09;。 ​ Map负责“分”&#xff0c;即把复杂的任务分解为若干个“简单的任务”来并行处理。可以进行拆分的前提是这些小…

React16源码: React中的PortalComponent创建, 调和, 更新的源码实现

PortalComponent 1 &#xff09;概述 React Portal之所以叫Portal&#xff0c;因为做的就是和“传送门”一样的事情render到一个组件里面去&#xff0c;实际改变的是网页上另一处的DOM结构主要关注 portal的创建, 调和, 更新过程 2 &#xff09;源码 定位到 packages/react-…

Docker(一)简介和基本概念:什么是 Docker?用它会带来什么样的好处?

作者主页&#xff1a; 正函数的个人主页 文章收录专栏&#xff1a; Docker 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01; 一、简介 本章将带领你进入 Docker 的世界。 什么是 Docker&#xff1f; 用它会带来什么样的好处&#xff1f; 好吧&#xff0c;让我们带…

python插件架构介绍

一、插件架构 在 Python 中&#xff0c;插件架构通常指的是一种软件架构模式&#xff0c;它允许开发者在不改变主应用程序代码的情况下&#xff0c;向应用程序添加新的功能或修改现有功能。这种架构使得应用程序可以通过加载外部模块或组件来扩展其功能&#xff0c;这些外部模…

【ROS2】实现自定义服务接口

1 定义服务接口 在之前创建的ROS接口功能包的基础上。 int32 num1 int32 num2 --- int32 num3 2 在CmakerLists.txt中增加如下语句&#xff0c;实现对服务接口的生成 # 为接口文件生成源代码 rosidl_generate_interfaces(${PROJECT_NAME}"msg/Student.msg""…

IP劫持的危害分析及应对策略

在当今数字化时代&#xff0c;网络安全问题备受关注&#xff0c;其中IP劫持是一种常见而危险的威胁。本文将深入探讨IP劫持的危害&#xff0c;并提供一些有效的应对策略。 第一部分&#xff1a;IP劫持的定义 IP劫持是指黑客通过各种手段获取并篡改目标IP地址的控制权&#xf…

vue3+vite:封装Svg组件

前言 在项目开发过程中&#xff0c;以svg图片引入时&#xff0c;会遇到当hover态时图片颜色修改的场景&#xff0c;我们可能需要去引入另一张不同颜色的svg图片&#xff0c;或者用css方式修改&#xff0c;为了方便这种情况&#xff0c;需要封装svg组件来自定义宽高和颜色&…

react 页签(自行封装)

思路&#xff1a;封装一个页签组件&#xff0c;包裹页面组件&#xff0c;页面渲染之后把数据缓存到全局状态实现页面缓存。 浏览本博客之前先看一下我的博客实现的功能是否满足需求&#xff0c;实现功能&#xff1a; - 页面缓存 - 关闭当前页 - 鼠标右键>关闭当前 - 鼠标右…

Endnote文章编号从10开始

前部分章节已经写好&#xff0c;后续添加&#xff0c;endnote参考文献需要从特定序号如10开始 知乎回答 在word中点击Endnote&#xff0c;instant Formatting is on右下角有一个小箭头&#xff0c; 点开箭头后点击layout, 下边有一个Start with bibliography 里面输入要开始的…

Python中类的继承实现

""派生类继承了基类的一切"&#xff0c;这里创建基类曲线&#xff0c;派生类有椭圆。派生类调用基类的方法&#xff0c;只需方法名前加上基类基类名作为前缀&#xff0c;再将派生类的self和其他参数传入。 当派生类与基类有同名的方法时&#xff0c;调用的是派…

按键+数码管

key.c #include "key.h" //把led.h文件包含进来 #include "system.h" //把timer0.h文件包含进来 #include "smg.h"extern uint num; char key_value; //有按键按下 char key_shourtflag;//没有按键按下uint KeyScan () //按键扫描函数 {…

Linux中关于head命令详解

head的作用 head用于查看文件的开头部分的内容。 head的参数 -q隐藏文件名-v 显示文件名-c<数目>显示的字节数-n<数目>显示的行数 head的案例 # 查看yum.log前五行内容 head -5 yum.log

vue2打包

首先&#xff0c;请确保您已经安装了Vue CLI。 打开终端或命令提示符&#xff0c;进入您的Vue项目的根目录。 运行以下命令来安装所需的依赖项&#xff1a; npm install安装完成后&#xff0c;运行以下命令来打包您的Vue项目&#xff1a; npm run build这将在您的项目根目录…

Cortex-M3/M4内核NVIC及HAL库函数详解(4):使用HAL库配置外部中断

0 工具准备 Keil uVision5 Cortex M3权威指南&#xff08;中文&#xff09; Cortex M3与M4权威指南 stm32f407的HAL库工程 STM32F4xx中文参考手册 1 使用HAL库配置外部中断 前面我们已经熟悉了有关内核部分的寄存器配置&#xff0c;接下来我们结合stm32f407的GPIO外设&#xf…

站长为什么都说WordPress太复杂不会用要放弃?

网络上经常看到有站长说要放弃WordPress&#xff0c;理由各有不同&#xff0c;比如有些说WordPress太复杂不会用&#xff1b;有些说WordPress是国外建站系统&#xff0c;在国内用来搭建访问速度太慢&#xff1b;也有些说WordPress是针对谷歌优化的&#xff0c;不适合国内的搜索…

UE 可靠UDP实现原理

发送 我们的消息发送都是通过 UChannel 来处理的&#xff0c;通过调用 UChannel::SendBunch 统一处理。 发送的 Bunch 是以 FOutBunch 的形式存在的。当 bReliable 为 True 的时候&#xff0c;表示 Bunch 是可靠的。 发送逻辑直接从UChannel::SendBunch处开始分析 1、大小限…

【算法与数据结构】1049、LeetCode 最后一块石头的重量 II

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题需要得到石头之间两两粉碎之后的最小值&#xff0c;那么一个简单的思路就是将这堆石头划分成大小相…

【MySQL】where和having的区别

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 用途: 使用位置: 操作对象: 聚合函数: 示例&#xff1a; 结语 我的其他博客 前言 数据库中的 WHERE 和 HAVING 子句在 SQL 查…

线程池最佳实践!这几个坑使用不当绝对生产事故!!

拿来即用!这篇文章我会介绍我使用线程池的时候应该注意的坑以及一些优秀的实践。 1、正确声明线程池 线程池必须手动通过 ThreadPoolExecutor 的构造函数来声明&#xff0c;避免使用Executors 类创建线程池&#xff0c;会有 OOM 风险。 Executors 返回线程池对象的弊端如下(…