【GPU】Nvidia CUDA 编程高级教程——NVSHMEM 内存模型

news2024/11/17 11:56:55

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持!
博主链接

本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。


博客内容主要围绕:
       5G/6G协议讲解
       算力网络讲解(云计算,边缘计算,端计算)
       高级C语言讲解
       Rust语言讲解



NVSHMEM 内存模型

在这里插入图片描述

PE:处理单元(process entity)

对称内存

       NVSHMEM 的内存分配 API nvshmem_malloc(),其工作方式有点类似于标准的cudaMalloc(),但cudaMalloc()会返回一个本地 GPU 的私有地址1使用nvshmem_malloc()分配的对象称为对称数据对象每个对称数据对象在所有 PE 上都有一个名称、类型和大小相同的对应数据对象。由nvshmem_malloc()返回的指针对应的虚拟地址称为对称地址。在 NVSHMEM 通信例程中使用对称地址对其他 PE 进行远程访问是合法的(对称地址也可以直接用于对 PE 本地内存的访问)。我们可以像操作普通本地地址一样操作虚拟地址。如要使用 NVSHMEM API 访问远程 PE 上的对称数据对象副本,我们可以像通常那样以指针作为存储索引,并使用远程目标 PE 中的相应位置。例如,

       如果我们执行了下面的语句:

int* a = (int*) nvshmem_malloc(sizeof(int));

那么我们既可以在本地 PE 上进行本地内存访问,也可以在远程 PE 上进行远程内存访问,来获取a[0]的值。理解这个操作的一种思考方法是,给定 M 个 PE,我们将长度为M的数组里的数据元素均匀地分配到所有 PE 上,这样每个 PE 只有一个元素。由于在本例中,对称数据对象的长度为 1,我们在任何 PE 上只需访问a[0]。

请添加图片描述
       在 NVSHMEM 中,对称数据对象的动态内存分配来自一个名为对称堆(symmetric heap)的特殊内存区域,由 NVSHMEM 在程序执行期间2创建,然后用于后续的动态内存分配。

练习1

       下面我们把cudaMalloc()的调用替换为nvshmem_malloc()的调用。我们仍然可以对分配在本地的数据使用atomicAdd(),这样每个 PE 上的对称对象副本就会得到与之前相同的结果。

       其次,我们对所有 PE 的结果求和。这是一次联合操作,它是全局归约操作。在 NVSHMEM 中,我们可以使用 nvshmem_int_sum_reduce(team, dest, source, nreduce) 对对称对象的所有实例求和。

  • source:是我们要求和的对称地址;
  • destination:是储存结果的地方;
  • nreduce:是要归约的元素个数(对我们而言只有一个,因为我们的数据是标量);
  • team:是要进行求和运算的一组 PE3(我们将使用默认组NVSHMEM_TEAM_WORLD,这是所有 PE 的集合);

总而言之,我们要做的是:

// 累积所有 PE 的结果
int* d_hits_total = (int*) nvshmem_malloc(sizeof(int));
nvshmem_int_sum_reduce(NVSHMEM_TEAM_WORLD, d_hits_total, d_hits, 1);

请添加图片描述
现在,所有的 PE 都有计数的总和,所以我们要做的第三个更改就是只需要在单个 PE 上打印结果。按照惯例,我们通常在 PE0 上进行打印。

if (my_pe == 0) {
    // 将最终结果复制回主机
    ...

    // 计算 pi 的最终值
    ...

    // 打印结果
    ...
}

完整代码如下(file name:nvshmem_pi_step3.cpp):

#include <iostream>
#include <curand_kernel.h>

#include <nvshmem.h>
#include <nvshmemx.h>

inline void CUDA_CHECK (cudaError_t err) {
    if (err != cudaSuccess) {
        fprintf(stderr, "CUDA error: %s\n", cudaGetErrorString(err));
        exit(-1);
    }
}

#define N 1024*1024

__global__ void calculate_pi(int* hits, int seed) {
    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    // 初始化随机数状态(网格中的每个线程不得重复)
    int offset = 0;
    curandState_t curand_state;
    curand_init(seed, idx, offset, &curand_state);

    // 在 (0.0, 1.0] 内生成随机坐标
    float x = curand_uniform(&curand_state);
    float y = curand_uniform(&curand_state);

    // 如果这一点在圈内,增加点击计数器
    if (x * x + y * y <= 1.0f) {
        atomicAdd(hits, 1);
    }
}


int main(int argc, char** argv) {
    // 初始化 NVSHMEM
    nvshmem_init();

    // 获取 NVSHMEM 处理元素 ID 和 PE 数量
    int my_pe = nvshmem_my_pe();
    int n_pes = nvshmem_n_pes();

    // 每个 PE(任意)选择与其 ID 对应的 GPU
    int device = my_pe;
    CUDA_CHECK(cudaSetDevice(device));

    // 分配主机和设备值
    int* hits = (int*) malloc(sizeof(int));
    int* d_hits = (int*) nvshmem_malloc(sizeof(int));

    // 初始化点击次数并复制到设备
    *hits = 0;
    CUDA_CHECK(cudaMemcpy(d_hits, hits, sizeof(int), cudaMemcpyHostToDevice));

    // 启动核函数进行计算
    int threads_per_block = 256;
    int blocks = (N / n_pes + threads_per_block - 1) / threads_per_block;

    int seed = my_pe;
    calculate_pi<<<blocks, threads_per_block>>>(d_hits, seed);
    CUDA_CHECK(cudaDeviceSynchronize());

    // 累积所有 PE 的结果
    int* d_hits_total = (int*) nvshmem_malloc(sizeof(int));
    nvshmem_int_sum_reduce(NVSHMEM_TEAM_WORLD, d_hits_total, d_hits, 1);

    if (my_pe == 0) {
        // 将最终结果复制回主机
        CUDA_CHECK(cudaMemcpy(hits, d_hits_total, sizeof(int), cudaMemcpyDeviceToHost));

        // 计算 pi 的最终值
        float pi_est = (float) *hits / (float) (N) * 4.0f;

        // 打印结果
        std::cout << "Estimated value of pi averaged over all PEs = " << pi_est << std::endl;
        std::cout << "Relative error averaged over all PEs = " << std::abs((M_PI - pi_est) / pi_est) << std::endl;
    }

    free(hits);
    nvshmem_free(d_hits);
    nvshmem_free(d_hits_total);

    // 最终确定 nvshmem
    nvshmem_finalize();

    return 0;
}

编译和运行指令如下:

nvcc -x cu -arch=sm_70 -rdc=true -I $NVSHMEM_HOME/include -L $NVSHMEM_HOME/lib -lnvshmem -lcuda -o nvshmem_pi_step3 exercises/nvshmem_pi_step3.cpp
nvshmrun -np $NUM_DEVICES ./nvshmem_pi_step3

结果如下:

Estimated value of pi averaged over all PEs = 3.14072
Relative error averaged over all PEs = 0.000277734


在这里插入图片描述


  1. 例外情况在于,在使用 NVLink 连接 GPU 的系统中,可以使用 CUDA IPC 机制 让 GPU 直接访问彼此的内存。 ↩︎

  2. 对称堆的默认大小是 1GB,可通过环境变量 NVSHMEM_SYMMETRIC_SIZE 加以控制。 ↩︎

  3. 在 OpenSHMEM 1.5 规范的基础上,使用team指定涉及多个 PE 组的操作是 NVSHMEM 2.0 的新功能。 ↩︎

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

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

相关文章

【Python学习】字典和集合

前言 往期文章 【Python学习】列表和元组 字典和集合 字典是一系列无序元素的组合&#xff0c;其长度大小可变&#xff0c;元素可以任意地删减和改变。不过要注意&#xff0c;这里的元素&#xff0c;是一对键&#xff08;key&#xff09;和值&#xff08;value&#xff09;…

【nvidia CUDA 高级编程】NVSHMEM 直方图——分布式方法

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Redis基础命令操作五之集合类型ZSET

ZSET 命令举例说明ZADD ZADD [KEY][序号1][序号1的值]集合中添加元素ZREMZREM [KEY][序号的值]移除集合中元素ZRANGEZRANGE [KEY][下标1][下标2]获取指定区间集合元素ZRAGNEBYSCOREZRANGEBYSOCRE [KEY] -INF INF集合中按照序号从小到大排列ZREVRANGEZREVRANGE [key][序…

四,Spring注解开发

Spring day04 1 Spring基于注解的开发 XML方式配置bean存在的问题&#xff1a;开发效率低下。Spring2.x提供了开发效率更高的注解式配置。注解开发替换XML配置的好处&#xff1a;简化编程&#xff0c;提高开发效率。 XML方式&#xff1a;配置繁琐&#xff0c;但功能强大&…

测试开发的一次实践总结

这些年&#xff0c;测开越来越火&#xff0c;火的原因之一就是因为大部分公司都有设测开岗位并有招聘需求。那测试开发到底是做什么&#xff0c;和测试又有什么区别呢&#xff1f;接下来&#xff0c;说说我对测开的理解与实际工作的总结。 01—测试开发的理解 测试分类 从市场…

测试碎碎念(基础篇_1)

一、软件测试1.1 什么是测试测试行为 在生活中是十分常见的~在生活中&#xff0c;我们有许多 "测试" 的行为&#xff0c;比如说&#xff0c;在坐地铁之前&#xff0c;需要用金属探测仪在身上刷一下&#xff0c;需要把身上的背包等物品放在闸机上过一下~比如说&#x…

Rockchip开发系列 - 8. IO电源域配置

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 RK3566 RK3568 IO 电源域配置指南概述第一步:获取硬件原理图并确认硬件电源的设计方案第二步:查找对应的内核dts配置文件第三步:修…

Open3D 网格滤波(Python版本)

文章目录 一、简介二、滤波2.1 均值滤波2.2 Laplacian滤波2.3 Taubin滤波三、实现效果参考资料一、简介 网格数据的滤波其本质上仍是针对点的滤波过程,具体的过程如下所示。 二、滤波 2.1 均值滤波 如下公式所示,均值滤波其实就是该点与其邻近点之间的平均值: Open3D中的相…

在Ubuntu上安装OpenShift并使用

服务器信息 在阿里云买了个抢占式的服务器&#xff0c;地区为华南广州&#xff0c;系统为Ubuntu 20.04&#xff0c;8核16GB。 安装Docker 命令如下&#xff1a; $ apt-get update -y $ apt-get upgrade -y $ apt-get install -y docker.io 安装成功后&#xff0c;检查一下版…

2023 年你应该知道的所有机器学习算法

在过去的几年里&#xff0c;根据自己的工作经验&#xff0c;整理了我认为最重要的机器学习算法。 通过这个&#xff0c;我希望提供一个工具和技术的存储库&#xff0c;以便您可以解决各种数据科学问题&#xff01; 让我们深入研究六种最重要的机器学习算法&#xff1a; 解释…

状态机原理

前言状态机在实际工作开发中应用非常广泛&#xff0c;在刚进入公司的时候&#xff0c;根据公司产品做流程图的时候&#xff0c;发现自己经常会漏了这样或那样的状态&#xff0c;导致整体流程会有问题&#xff0c;后来知道了状态机这样的东西&#xff0c;发现用这幅图就可以很清…

简单步骤比别人抢红包快一步

&#x1f935;‍♂️ 个人主页老虎也淘气 个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f44d;&#x1f3fb; 收藏…

Slurm中集群配置文件slurm.conf

1.slurm.conf简介slurm.conf是一个ASCII文件&#xff0c;它描述了一般的Slurm 配置信息、要管理的节点、有关如何将这些节点分组到分区中&#xff0c;以及各种调度与这些分区关联的参数。此文件应为在群集中的所有节点上保持一致。可以通过设置SLURM_CONF在执行时修改文件位置 …

203:vue+openlayers 地图旋转移动动画、CSS缩放动画,介绍animate的使用方法

第203个 点击查看专栏目录 本示例的目的是介绍如何在vue+openlayers项目中创建动画,地图上使用的是view中的animate方法, CSS中使用的是keyframes ,animation,transform等方法。这两将两者融合在一个示例中,api用的不全,但是能起到一个抛转引玉的作用。 地图 view.anima…

Java while和do while循环详解

循环是程序中的重要流程结构之一。循环语句能够使程序代码重复执行&#xff0c;适用于需要重复一段代码直到满足特定条件为止的情况。所有流行的编程语言中都有循环语句。Java 中采用的循环语句与C语言中的循环语句相似&#xff0c;主要有 while、do-while 和 for。另外 Java 5…

ROS2机器人编程简述humble-第一章-Introduction

ROS2机器人编程简述新书推荐-A Concise Introduction to Robot Programming with ROS2学习笔记流水账-推荐阅读原书。第一章&#xff1a;简要介绍宏观概念&#xff0c;配置编译一下本书配套的源码包。支持版本个人测试foxy和humble全部都OK。硬件软件机器人应用关系如下图所示&…

【阶段四】Python深度学习01篇:深度学习基础知识:神经网络历史及优势、神经网络基础单元与梯度下降:正向传播和反向传播

本篇的思维导图: 神经网络历史及优势 1958年,计算机科学家罗森布拉特(Rosenblatt)就提出了一种具有单层网络特性的神经网络结构,称为“感知器”(perceptron)。感知器出现之后很受瞩目,大家对它的期望很高。然而好景不长—一段时间后,人们发现感知器的实用性很…

2022.12 青少年机器人技术等级考试理论综合试卷(一级)

2022年12月 青少年机器人技术等级考试理论综合试卷&#xff08;一级&#xff09; 分数&#xff1a; 100 题数&#xff1a; 45 一、 单选题(共 30 题&#xff0c; 共 60 分) 1.下列哪个是机器人?&#xff08; &#xff09; A.a B.b C.c D.d 标准答案&#xff1a; C 2.机器人的电…

1-计算机系统概述(CO)

计算机组成原理&#xff1a;实现计算机体系结构所体现的属性&#xff0c;具体指令的实现对程序员透明&#xff0c;即研究如何用硬件实现所定义的接口 计算机系统硬件&#xff08;计算机的实体&#xff0c;如主机、外设&#xff09;软件&#xff08;由具有各类特殊功能的程序组…

【博客587】ipvs hook点在netfilter中的位置以及优先级

ipvs hook点在netfilter中的位置以及优先级 1、netfilter栈全景图 2、Netfilter hooks 五个hook点&#xff1a; 每个 hook 在内核网络栈中对应特定的触发点位置&#xff0c;以 IPv4 协议栈为例&#xff0c;有以下 netfilter hooks 定义&#xff1a; NF_INET_PRE_ROUTING:…