ROCm数据布局与HIP实施

数据布局

3D数据的布局使得i方向上的网格点在内存中是连续的,而k方向上的栅格点则以nx*ny为步长。此映射以宏为例:

#define u(i, j, k) h_u[(i) + (j) * nx  + (k) * nx * ny]

其中i、j和k周围的括号确保了等表达式的正确展开。在网格点位置应用的拉普拉斯模板,如图4-1所示。

[n1] [2] 

图4-1 在网格点位置应用的拉普拉斯模板

由于跨步数据布局,在j和k方向上彼此相邻的网格点在内存中实际上相距甚远。例如,考虑当nx=ny=nz=5时,中心差异模板的条纹存储空间架构,看到需要h_u[]数组(红色)中的哪些条目来更新输出数组h_f[]。这些条目不是连续的,如图4-2所示。

 

图4-2 中心差异模板的条纹存储空间

展示如何在AMD GPU上有效地处理这种内存访问模式。

4.1.4 HIP实施

首先,考虑一个大立方体,其中nx=ny=nz=512。首先使用双精度为输入数组d_u和输出数组d_f分配内存:

// 参数

// 使用精度为double型[n3] [4] 

size_t nx = 512, ny = 512, nz = 512; // 立方体尺寸

// 网格点间距

precision hx = 1.0 / (nx - 1), hy = 1.0 / (ny - 1), hz = 1.0 / (nz - 1);

// 输入输出数组

precision *d_u, *d_f;

// 设备上分配

size_t numbytes = nx * ny * nz * sizeof(precision);

hipMalloc((void**)&d_u, numbytes);

hipMalloc((void**)&d_f, numbytes);

d_u输入数组使用二次测试函数初始化,简化了验证正确性的任务(为简洁起见未显示)。

以下代码片段展示了拉普拉斯算子的初始HIP实现:

template <typename T>

__global__ void laplacian_kernel(T * f, const T * u, int nx, int ny, int nz, T invhx2, T invhy2, T invhz2, T invhxyz2) {

    int i = threadIdx.x + blockIdx.x * blockDim.x;

    int j = threadIdx.y + blockIdx.y * blockDim.y;

    int k = threadIdx.z + blockIdx.z * blockDim.z;

    // 如果此线程位于边界上,则退出

    if (i == 0 || i >= nx - 1 ||

        j == 0 || j >= ny - 1 ||

        k == 0 || k >= nz - 1)


      return;

    const int slice = nx * ny;

    size_t pos = i + nx * j + slice * k;

    // 计算模板操作的结果

    f[pos] = u[pos] * invhxyz2

           + (u[pos - 1]     + u[pos + 1]) * invhx2

           + (u[pos - nx]    + u[pos + nx]) * invhy2

           + (u[pos - slice] + u[pos + slice]) * invhz2;

}

 

template <typename T>

void laplacian(T *d_f, T *d_u, int nx, int ny, int nz, int BLK_X, int BLK_Y, int BLK_Z, T hx, T hy, T hz) {

    dim3 block(BLK_X, BLK_Y, BLK_Z);

    dim3 grid((nx - 1) / block.x + 1, (ny - 1) / block.y + 1, (nz - 1) / block.z + 1);

    T invhx2 = (T)1./hx/hx;

    T invhy2 = (T)1./hy/hy;

    T invhz2 = (T)1./hz/hz;

    T invhxyz2 = -2. * (invhx2 + invhy2 + invhz2);

    laplacian_kernel<<<grid, block>>>(d_f, d_u, nx, ny, nz, invhx2, invhy2, invhz2, invhxyz2);

}

拉普拉斯宿主函数负责启动设备内核拉普拉斯核,线程块大小为BLK_X=256,BLK_Y=1,BLK_Z=1。BLK_X*BLK_Y*BLK_Z=256的当前线程块大小是推荐的默认选择,因为它很好地映射到硬件工作调度器,但其他选择可能会更好。一般来说,选择此性能参数可能高度依赖于问题大小、内核实现和设备的硬件特性。虽然这个内核实现支持3D块大小,但GPU没有2D和3D的概念。定义3D组的可能性是作为程序员的便利功能提供的。

HIP实现适用于GPU内存中适合的任何问题大小。对于不能平均除以线程块大小的问题大小,引入了处理剩余部分的其他组。如果剩余部分很小,即许多线程映射到计算域之外没有工作可做的区域,这些额外的线程块可能会具有较低的线程利用率。这种低线程利用率会对性能产生负面影响。将关注可被线程块大小整除的问题大小。要调度的块数由上限操作(nx-1)/block.x+1,…决定。如前所述,它对组的数量进行四舍五入,以确保覆盖整个计算域。

内核中的退出条件。当线程位于边界上或边界外时,返回(退出),因为只计算内部点的有限差分。内核退出策略在实践中的工作原理是,由于波阵面以锁步方式执行指令,因此边界外的任何线程都将被其余内核屏蔽。被屏蔽的线程在执行指令期间将处于空闲状态。回到性能问题,块大小不能平均分配问题大小。如果选择nx=258,将在x方向上得到两个线程块,但第二个线程块中只有一个线程有工作要做。

    // 计算模板操作的结果

    f[pos] = u[pos] * invhxyz2

           + (u[pos - 1]     + u[pos + 1]) * invhx2

           + (u[pos - nx]    + u[pos + nx]) * invhy2

           + (u[pos - slice] + u[pos + slice]) * invhz2;

多次访问数组u。对于每次访问,编译器将生成一条全局加载指令,该指令将从全局内存中访问数据,除非该数据已存在于缓存中。正如将看到的,这些全局加载指令可能会对性能产生重大影响。

 

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

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

相关文章

推荐几本专著1《AI芯片开发核心技术详解》、2《智能汽车传感器:原理设计应用》、3《TVM编译器原理与实践》、4《LLVM编译器原理与实践》

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

《自然语言处理实战 : 从入门到项目实践》 | PDF免费下载

《自然语言处理实战:从入门到项目实践》系统讲解 NLP 基础知识与核心技术,涵盖文本分类、情感分析、机器翻译等内容,并通过实际项目演示如何应用深度学习模型解决 NLP 问题。适合 AI 初学者、开发者及数据科学家,助力高效掌握 NLP 技能。《自然语言处理实战 : 从入门到项目…

数组与指针的区别

一、理解数组类型 指针存储的是内存的地址,而内存的地址实际上是一个64位无符号的整数。我们可以发现指针实际上是内存上的一处空间的值保存着另一处空间的地址。1、算数方法获取相邻内存的值 首先定义 x 和 y 两个变量,然后分别输出他们的地址。 int x = 1; int y = 123; co…

《自然语言处理实战 : 预训练模型应用及其产品化》 | PDF免费下载

《自然语言处理实战:预训练模型应用及其产品化》系统讲解了 NLP 领域的最新技术,涵盖 BERT、GPT 等预训练模型的应用,并结合实际案例展示如何将 NLP 技术产品化。适合开发者、数据科学家及 AI 从业者,助力高效落地 NLP 解决方案。点击下载 书籍信息 作者: Ankur A. Patel /…

[以太网/汽车网络] 车载服务通信(SOME/IP)设计实践 [转]

序 1 引入在SOA架构中,服务是构成系统的基本单元,它代表了系统中的某个功能或操作。服务通过明确的接口与外界进行交互,实现了功能的封装和重用。 SOA架构的核心就是服务: 它通过将应用程序划分为一系列的服务来降低系统的复杂度,提高系统的灵活性和可维护性。 在SOA中,服…

小白尖叫!DeepSeek安装竟偷占C盘?这样做路径配置 直接根治存储焦虑!

🚀 个人主页 极客小俊 ✍🏻 作者简介:web开发者、设计师、技术分享 🐋 希望大家多多支持, 我们一起学习和进步! 🏅 欢迎评论 ❤️点赞💬评论 📂收藏 📂加关注前言 之前给大家讲解了关于Ollama+DeepSeek的使用和本地部署, 有些朋友表示遇到一些问题,无法解决! …

智能工厂搭建:系统数量与选型的深度剖析

当今制造业加速迈向智能化的时代,智能工厂成为众多企业追求的目标。它宛如一座现代化的智慧堡垒,融合了先进技术与高效管理流程,能大幅提升生产效率、优化产品质量。然而,构建智能工厂并非一蹴而就,其中一个关键且容易让人困惑的问题便是:究竟要引入多少系统?搞懂这一点…

20款好用的SSH客户端工具,你在用哪个?

20款好用的SSH客户端工具,你在用哪个? 有些小伙伴购买了Linux服务器之后,不知道该用什么工具来实现本地连接,而不是每次打开服务器厂家所提供的 web 命令页面来操作。操作步骤:登录账号 - 找到服务器 - 打开web命令页面SSH工具:打开软件 - 配置连接通过SSH工具大大减少了…

Spring AOP 的实现原理

一、AOP的基本概念 将横切关注点(日志、事务、权限)从业务逻辑中分离出来,提高代码的可维护性。 下面将解释,AOP专属名词,切面、连接点、切点、通知、目标对象、代理对象:切面:切面是封装横切关注点的模块,比如日志记录。 @Aspect 修饰类,如 LoggingAspect 连接点:连…

drm study

学习过程 0319:对于任何驱动来说,buffer是最重要的,知道了buffer的创建使用这个驱动就会一半了;现在感觉是一个无头苍蝇,感觉非常复杂:数据结构非常多,之间的关系也非常复杂;不过没关系,先研究buffer通路;可以看见应用层对mmap写入的hello world,驱动中vkms_obj->…

pcie 简介及引脚定义

随着现代处理器技术的发展,在互连领域中,使用高速差分总线替代并行总线是大势所趋。与单端并行信号相比,高速差分信号可以使用更高的时钟频率,从而使用更少的信号线,完成之前需要许多单端并行数据信号才能达到的总线带宽。 PCI总线使用并行总线结构,在同一条总线上的所有…

C++ 基础(1)

0x01 第一个C++程序 #include <iostream>int main() {std::cout << "Hello World!\n"; } // std::cout 向控制台输出内容的指令 // << 输出的运算符 // "" 字符串内容的边界符 // \n 输出换行 // Hello World 输出字符…