RCCL/NCCL中的Transports方式选择:P2P or SHM or NET

本篇文章主要总结以下在传输路径方式选择的时候,选择每一种方式应该满足的条件和优先度。

本文初步总结,之后还会进行更新,欢迎大家补充

源码位置:tools/topo_expl

Topo结构:

初始化判断前 ret设置为0,代表此类方法不可使用,如果满足transports中的某一类,则设置 ret = 1.

PATH_LOC为节点到自己,PATH_NVL表示路径上的边都是NVLink,PATH_PIX表示经过最多一个PCIe switch,PATH_PXB表示经过了多个PCIe witch,但是没有经过CPU,PATH_PHB表示经过了CPU,PATH_SYS表示不同numa之间的路径。

# define


// Local (myself)
#define PATH_LOC 0

// Connection traversing NVLink
#define PATH_NVL 1

// Connection through NVLink using an intermediate GPU
#define PATH_NVB 2

// Connection traversing at most a single PCIe bridge
#define PATH_PIX 3

// Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
#define PATH_PXB 4

// Connection between a GPU and a NIC using an intermediate GPU. Used to enable rail-local, aggregated network send/recv operations.
#define PATH_PXN 5

// Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
#define PATH_PHB 6

// Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
#define PATH_SYS 7

// Connection through the network
#define PATH_NET 8

// Disconnected
#define PATH_DIS 9

P2P:

看一下源码的逻辑过程和源码

1. 检查设备是否支持精细粒度 GPU 操作

如果任一设备不支持 Fine-Grain 操作(精细粒度的 GPU 共享内存),直接判定两设备无法使用 P2P 通信。

2. 检查设备是否属于同一主机或容器

比较 hostHash 和 shmDev:
hostHash:表示设备所属主机的唯一标识。
shmDev:表示设备是否共享同一块内存设备(如共享同一块显存)。
如果设备不在同一主机或共享内存域,判定无法使用 P2P 通信。

3. 检查设备间的拓扑关系和通信路径

调用 ncclTopoCheckP2p 检查两设备之间的 P2P 拓扑关系:
如果 *ret = 0:表示设备间无直接 P2P 通信路径。
如果 intermediateRank != -1:表示设备间通信需要通过第三方设备中转。
如果 useMemcpy(标志位)为真,优先禁用 P2P 通信

4. 判断是否使用网络通信更优

调用 ncclTopoCheckNet 检查是否通过网络通信(如 NIC)会比 P2P 更优:
如果 useNet = 1:说明网络通信更适合,禁用 P2P。
 

/* Determine if two peers can communicate with P2P */
ncclResult_t p2pCanConnect(int* ret, struct ncclTopoSystem* topo, struct ncclTopoGraph* graph, struct ncclPeerInfo* info1, struct ncclPeerInfo* info2) {
  if (!info1->hasFineGrain || !info2->hasFineGrain)  {
    *ret = 0;
    return ncclSuccess;
  }

  // Rule out different nodes / isolated containers
  if (info1->hostHash != info2->hostHash || info1->shmDev != info2->shmDev) {
    *ret = 0;
    return ncclSuccess;
  }

  // Check topology / p2p level.
  int intermediateRank;
  NCCLCHECK(ncclTopoCheckP2p(topo, info1->busId, info2->busId, ret, NULL, &intermediateRank));
  if (*ret == 0) return ncclSuccess;
  if (intermediateRank != -1) {
    if (useMemcpy) *ret = 0;
    return ncclSuccess;
  }

  // Check if NET would work better
  int useNet = 0;
  NCCLCHECK(ncclTopoCheckNet(topo, info1->busId, info2->busId, &useNet));
  if (useNet) {
    *ret = 0;
    return ncclSuccess;
  }

  *ret = 1;
  return ncclSuccess;
}

这里主要是再看一下ncclTopoCheckP2p,这个函数中会看Topo结构中两个GPU之间是否满足p2p,主要是p2p_Level 是否满足,看一下源码,如果CPU类型是 ARM CPUs/ CPU_ARCH_X86(Intel / ZHAOXIN)p2pLevel 有进一步的要求   p2pLevel = PATH_PXB,实际路径满足 path->type <= p2pLevel, 允许 p2p = 1.

源码位置是编译过后的位置:build/release/hipify/src/graph/paths.cc

int ncclTopoUserP2pLevel = -1;
ncclResult_t ncclTopoCheckP2p(struct ncclTopoSystem* system, int64_t id1, int64_t id2, int* p2p, int *read, int* intermediateRank) {
  *p2p = 0;
  if (read) *read = 0;
  if (intermediateRank) *intermediateRank = -1;

  // Get GPUs from topology
  int g1, g2;
  NCCLCHECK(ncclTopoIdToIndex(system, GPU, id1, &g1));
  struct ncclTopoNode* gpu1 = system->nodes[GPU].nodes+g1;
  if (ncclTopoIdToIndex(system, GPU, id2, &g2) == ncclInternalError) {
    // GPU not found, we can't use p2p.
    return ncclSuccess;
  }

  int intermediateIndex = -1;
  // Set intermediate GPU rank, if routing through an intermediate GPU.
  struct ncclTopoLinkList* path = gpu1->paths[GPU]+g2;
  if (path->count == 2) {
    struct ncclTopoNode* intermediateNode = path->list[0]->remNode;
    if (intermediateNode->type == GPU) {
      intermediateIndex = intermediateNode - system->nodes[GPU].nodes;
      if (intermediateRank) *intermediateRank = intermediateNode->gpu.rank;
    }
  }

  // In general, use P2P whenever we can.
  int p2pLevel = PATH_SYS;

  // User override
  if (ncclTopoUserP2pLevel == -1)
    NCCLCHECK(ncclGetLevel(&ncclTopoUserP2pLevel, "NCCL_P2P_DISABLE", "NCCL_P2P_LEVEL"));
  if (ncclTopoUserP2pLevel != -2) {
    p2pLevel = ncclTopoUserP2pLevel;
    goto compare;
  }

  // Don't use P2P through ARM CPUs
  int arch, vendor, model;
  NCCLCHECK(ncclTopoCpuType(system, &arch, &vendor, &model));
  if (arch == NCCL_TOPO_CPU_ARCH_ARM) p2pLevel = PATH_PXB;
  if (arch == NCCL_TOPO_CPU_ARCH_X86 && vendor == NCCL_TOPO_CPU_VENDOR_INTEL) {
    p2pLevel = PATH_PXB;
  }
  if (arch == NCCL_TOPO_CPU_ARCH_X86 && vendor == NCCL_TOPO_CPU_VENDOR_ZHAOXIN) {
    p2pLevel = PATH_PXB;
  }

compare:
  // Compute the PCI distance and compare with the p2pLevel.
  if (path->type <= p2pLevel) *p2p = 1;

#if defined(__HIP_PLATFORM_AMD__) || defined(__HIPCC__)
#else
  if (*p2p == 1) {
    // NCCL_IGNORE_DISABLED_P2P=2 is used by unit tests that don't want to
    // validate against NVML at all since they are pretending to be on other hw.
    if (g1 != g2 && ncclParamIgnoreDisabledP2p() != 2) {
      int indexes[3] = {-1,-1,-1};
      int verticeN = 0;
      NCCLCHECK(ncclNvmlEnsureInitialized());

      indexes[verticeN++] = system->nodes[GPU].nodes[g1].gpu.dev;
      if (intermediateIndex != -1) indexes[verticeN++] = system->nodes[GPU].nodes[intermediateIndex].gpu.dev;
      indexes[verticeN++] = system->nodes[GPU].nodes[g2].gpu.dev;

      for (int i=1; i < verticeN; i++) {
        nvmlGpuP2PStatus_t status;
        status = ncclNvmlDevicePairs[indexes[i-1]][indexes[i-0]].p2pStatusRead;
        bool good = status == NVML_P2P_STATUS_OK;
        status = ncclNvmlDevicePairs[indexes[i-1]][indexes[i-0]].p2pStatusWrite;
        good &= status == NVML_P2P_STATUS_OK;
        if (!good) {
          if (!ncclParamIgnoreDisabledP2p()) {
            if (path->type <= PATH_NVB) {
              WARN("P2P is disabled between NVLINK connected GPUs %d and %d. This should not be the case given their connectivity, and is probably due to a hardware issue. If you still want to proceed, you can set NCCL_IGNORE_DISABLED_P2P=1.", indexes[i-1], indexes[i-0]);
              return ncclUnhandledCudaError;
            } else if (path->type < PATH_SYS) {
              INFO(NCCL_INIT, "P2P is disabled between connected GPUs %d and %d. You can repress this message with NCCL_IGNORE_DISABLED_P2P=1.", indexes[i-1], indexes[i-0]);
            }
          }
          *p2p = 0;
        }
      }
    }
  }
#endif

  if (path->type == PATH_NVL) {
    struct ncclTopoNode* gpu2 = system->nodes[GPU].nodes+g2;
    // Enable P2P Read for Ampere/NVLink only
    if (read && (gpu1->gpu.cudaCompCap == gpu2->gpu.cudaCompCap) && (gpu1->gpu.cudaCompCap == 80)) *read = 1;
  }

  return ncclSuccess;
}

// MNNVL: Check whether peers are in the same fabric cluster and clique
ncclResult_t ncclTopoCheckMNNVL(struct ncclTopoSystem* system, struct ncclPeerInfo* info1, struct ncclPeerInfo* info2, int* ret) {
  *ret = 0;

  nvmlGpuFabricInfoV_t *fabricInfo1 = &info1->fabricInfo;
  nvmlGpuFabricInfoV_t *fabricInfo2 = &info2->fabricInfo;
  // A zero UUID means we don't have MNNVL fabric info
  if ((((long *)&fabricInfo2->clusterUuid)[0]|((long *)fabricInfo2->clusterUuid)[1]) == 0) return ncclSuccess;
  if ((memcmp(fabricInfo1->clusterUuid, fabricInfo2->clusterUuid, NVML_GPU_FABRIC_UUID_LEN) == 0) &&
      (fabricInfo1->cliqueId == fabricInfo2->cliqueId)) {
    INFO(NCCL_NET, "MNNVL matching peer 0x%lx UUID %lx.%lx cliqueId 0x%x",
         info2->busId, ((long *)fabricInfo2->clusterUuid)[0], ((long *)fabricInfo2->clusterUuid)[1], fabricInfo2->cliqueId);
    *ret = 1;
  }
  return ncclSuccess;
}

SHM:

看一下源码的逻辑过程和源码

1.初始化 ret 为0;

2.检查是否禁用共享内存SHM;

3.检查是否需要通过网络通信;

4.判断两个设备是否在同一主机;

5.检查设备是否共享相同的 /dev/shm;

6.满足条件,ret = 1;

/* Determine if two peers can communicate with SHM */
ncclResult_t shmCanConnect(int* ret, struct ncclTopoSystem* topo, struct ncclTopoGraph* graph, struct ncclPeerInfo* info1, struct ncclPeerInfo* info2) {
  *ret = 0;
  if (ncclParamShmDisable() == 1) return ncclSuccess;

  int useNet = 0;
  NCCLCHECK(ncclTopoCheckNet(topo, info1->busId, info2->busId, &useNet));
  if (useNet) return ncclSuccess;

  // Same host?
  TRACE(NCCL_INIT|NCCL_SHM, "peer1 hostHash %lx peer2 hostHash %lx", info1->hostHash, info2->hostHash);
  if (info1->hostHash != info2->hostHash) return ncclSuccess;

  // Common /dev/shm (between containers) ?
  TRACE(NCCL_INIT|NCCL_SHM, "peer1 shmDev %lx peer2 shmDev %lx", info1->shmDev, info2->shmDev);
  if (info1->shmDev != info2->shmDev) return ncclSuccess;

  *ret = 1;
  return ncclSuccess;
}

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

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

相关文章

upload-labs关卡记录11

先上传一个一句话木马试试&#xff0c;居然可以上传成功&#xff0c;复制图片链接&#xff0c;在另一个窗口打开&#xff1a; 会发现&#xff0c;我们明明上传的是shell.php&#xff0c;但是这里就是没有了php,这样我们在执行我们相关的语句的时候就无法执行了&#xff1a; 就…

elementUI——upload限制图片或者文件只能上传一个——公开版

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是上传图片&#xff0c;有且仅能上传一张。 效果图如下&#xff1a; 功能描述&#xff1a;上传图片时&#xff0c;仅支持单选&#xff0c;如果上传图片成功后&#xff0c;展示图片&#xff0c;并隐藏添加图片的…

springboot餐厅点餐系统丨源码+数据库+万字文档+PPT

作者简介&#xff1a; 作者&#xff1a;学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”&#xff0c;支持远程部署调试、运行安装。 技术框架 开发语言&#xff1a;Java 框架&#xff1a;springbo…

ArkTs组件(2)

一.下拉列表组件&#xff1a;Select 1.接口 Select(options: Array<SelectOption>) 参数名类型必填说明optionsArray<SelectOption>是设置下拉选项。 SelectOption对象说明 名称类型必填说明valueResourceStr是 下拉选项内容。 iconResourceStr否 下拉选项图片…

【MATLAB第110期】#保姆级教学 | 基于MATLAB的PAWN全局敏感性分析方法(无目标函数)含特征变量置信区间分析

【MATLAB第110期】#保姆级教学 | 基于MATLAB的PAWN全局敏感性分析方法&#xff08;无目标函数&#xff09;含特征变量置信区间分析 一、介绍 PAWN&#xff08;Probabilistic Analysis With Numerical Uncertainties&#xff09;是一种基于密度的全局敏感性分析&#xff08;Gl…

请购单一直提示需求部门不能为空无法提交

终于发现了它的逻辑。用户很多次反馈&#xff0c;提交请购单时&#xff0c;提示需求部门不能为空&#xff0c;既使选择了需求部门&#xff0c;保存时&#xff0c;神奇的是会清空掉部门的信息&#xff0c;提交时就会有错误提示出来。 原因&#xff1a;光选择单头上的需求部门是…

leetcode 面试经典 150 题:矩阵置零

链接矩阵置零题序号73题型二维数组解题方法标记数组法难度中等熟练度✅✅✅✅ 题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1]…

AIGC:生成图像动力学

文章目录 前言一、介绍二、方法2.1、运动预测模块运动纹理 2.2、图像渲染模块 三、数据集实验总结 前言 让静态的风景图能够动起来真的很有意思&#xff0c;不得不说CVPR2024 best paper实质名归&#xff0c;创意十足的一篇文章&#xff01;&#xff01;&#xff01; paper&a…

python: Oracle Stored Procedure query table

oracel sql script CREATE OR REPLACE PROCEDURE SelectSchool(paramSchoolId IN char,p_cursor OUT SYS_REFCURSOR ) AS BEGINOPEN p_cursor FORSELECT *FROM SchoolWHERE SchoolId paramSchoolId; END SelectSchool; /-- 查询所有 CREATE OR REPLACE PROCEDURE SelectScho…

社区版Dify 轻松实现文生图,Dify+LLM+ComfyUI

社区版Dify 轻松实文生图&#xff0c;DifyLLMComfyUI Dify 安装可参考这里ComfyUI 其实 比 WebUI更简单更实用DifyComfyUIDifyLLM1. Qwen 通义千问大模型系列2. OpenAI大模型系列3. 本地Ollama搭建 DifyLLMComfyUI Dify 安装可参考这里 这是一个在Dify上实现 文生图的教程&…

Docker部署Sentinel

一、简介 是什么&#xff1a;面向分布式、多语言异构化服务架构的流量治理组件 能干嘛&#xff1a;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性 官网地址&#xff1a;https://sentinelguard.io/zh-c…

实用工具推荐----Doxygen使用方法

目录 目录 1 软件介绍 2 Doxygen软件下载方法 3 Doxygen软件配置方法 4 标准注释描述 4.1 块注释 和 特殊描述字符 4.1.1 函数描述示例 4.1.2结构体数组变量示例 特别注意&#xff1a; 4.2单行注释 4.2.1 单个变量注释示例 特别注意&#xff1a; 4.2.2对于枚举变量…

并发编程 - 死锁的产生、排查与解决方案

在多线程编程中&#xff0c;死锁是一种非常常见的问题&#xff0c;稍不留神可能就会产生死锁&#xff0c;今天就和大家分享死锁产生的原因&#xff0c;如何排查&#xff0c;以及解决办法。 线程死锁通常是因为两个或两个以上线程在资源争夺中&#xff0c;形成循环等待&#xf…

云轴科技ZStack获评OpenCloudOS社区2024年度优秀贡献单位

近日&#xff0c;由 OpenCloudOS 社区主办的 2024 OpenCloudOS 年会在北京成功召开。本次大会以“稳建基石&#xff0c;共创新篇”为主题&#xff0c;汇集了业界顶级技术专家与行业领袖&#xff0c;共同探讨下一代操作系统的建设与未来。云轴科技ZStack作为OpenCloudOS 社区的重…

clickhouse解决suspiciously many的异常

1. 问题背景 clickhouse安装在虚拟机上&#xff0c;持续写入日志时&#xff0c;突然关机&#xff0c;然后重启&#xff0c;会出现clickhouse可以正常启动&#xff0c;但是查询sql语句&#xff0c;提示suspiciously many异常&#xff0c;如图所示 2. 问题修复 touch /data/cl…

从零开始k8s-部署篇(未完待续)

从零开始k8s 1.部署k8s-部署篇 1.部署k8s-部署篇 本次部署完全学习于华子的博客点击此处进入华子主页 K8S中文官网&#xff1a;https://kubernetes.io/zh-cn 笔者从零开始部署的k8s&#xff0c;部署前置条件为 1.需要harbor仓库&#xff0c;存放镜像&#xff0c;拉取镜像&am…

Dots 常用操作

游戏中有多个蚂蚁群落&#xff0c;每个蚂蚁属于一个群落&#xff0c;如何设计数据结构&#xff1f; 方法1&#xff1a;为蚂蚁组件添加一个属性 ID&#xff0c;会造成逻辑中大量分支语句&#xff0c;如果分支语句逻辑不平衡可能带来 Job 调度问题&#xff0c;每个蚂蚁会有一份蚂…

如何通过 Kafka 将数据导入 Elasticsearch

作者&#xff1a;来自 Elastic Andre Luiz 将 Apache Kafka 与 Elasticsearch 集成的分步指南&#xff0c;以便使用 Python、Docker Compose 和 Kafka Connect 实现高效的数据提取、索引和可视化。 在本文中&#xff0c;我们将展示如何将 Apache Kafka 与 Elasticsearch 集成以…

深入浅出:AWT的基本组件及其应用

目录 前言 1. AWT简介 2. AWT基本组件 2.1 Button&#xff1a;按钮 2.2 Label&#xff1a;标签 ​编辑 2.3 TextField&#xff1a;文本框 2.4 Checkbox&#xff1a;复选框 2.5 Choice&#xff1a;下拉菜单 2.6 List&#xff1a;列表 综合案例 注意 3. AWT事件处理 …

Go Energy 跨平台框架 v2.5.1 发布

Energy 框架 是Go语言基于CEF 和 LCL 开发的跨平台 GUI 框架, 具体丰富的系统原生 UI 控件集, 丰富的 CEF 功能 API&#xff0c;简化且不失功能的 CEF 功能 API 使用。 特性&#xff1f; 特性描述跨平台支持 Windows, macOS, Linux简单Go语言的简单特性&#xff0c;使用简单…