当前位置: 首页 > news >正文

如何让 RTX 5090 开启 PCIE P2P 以加速多卡通信

如何让 RTX 5090 开启 PCIE P2P 以加速多卡通信

    • 一、 背景与原理:为什么要折腾这个?
      • 1. 什么是 PCIE P2P?
      • 2. 为什么 RTX 5090 默认不支持?
      • 3. 性能提升有多大?
    • 二、 准备工作与环境
    • 三、 操作步骤
      • 阶段 1:BIOS 设置
      • 阶段 2:操作系统准备
      • 阶段 3:提取 NVIDIA-SMI 工具
      • 阶段 4:Patch 并编译内核驱动(核心步骤)
        • 1. 下载源码
        • 2. 制作 Patch
        • 2. 应用 Patch
        • 3. 编译与安装
      • 阶段 5:验证驱动
    • 四、 测试:Docker 与 PyTorch
      • 1. 创建测试容器
      • 2. 升级 NCCL
      • 3. 生成测试代码
    • 五、 总结

一、 背景与原理:为什么要折腾这个?

1. 什么是 PCIE P2P?

PCIE P2P (Peer-to-Peer)指的是显卡(GPU)之间可以直接通过主板PCIe总线交换数据,不经过CPU和系统内存

  • 无 P2P(默认路径):GPU 1 → 显存 → 系统内存 → CPU → 系统内存 → GPU 2 显存(延迟高,占用内存带宽)。
  • 有 P2P(开启后):GPU 1 → PCIe 总线 → GPU 2 显存(延迟极低,不占CPU资源)。

2. 为什么 RTX 5090 默认不支持?

RTX 5090 基于新的 Blackwell 架构。NVIDIA 出于对某些主板兼容性(如 IOMMU、Resizable BAR 策略)的保守考虑,屏蔽了 5090 的 BAR1 P2P 功能
我们需要通过 Patch 驱动源码,强制开启这一隐藏功能。

3. 性能提升有多大?

开启 P2P 后,PyTorch 的集合通信算子(Multi-GPU 训练的核心)延迟显著降低,All-Reduce 甚至降低了 60% 以上

算子 (Collective Op)关闭 P2P (us)开启 P2P (us)提升幅度
all_reduce2417.000864.667↓ 64%
all_gather1211.333516.333↓ 57%
scatter650.000384.333↓ 41%
gather633.000373.667↓ 41%
reduce1307.667758.333↓ 42%
broadcast1282.000733.000↓ 43%
p2p1274.667737.000↓ 42%
reduce_scatter1226.333547.333↓ 55%

二、 准备工作与环境

测试环境

  • OS: Ubuntu 24.04.3 LTS
  • Kernel: 6.8.0-110-generic
  • GPU: RTX 5090 x 2
  • 目标: 让两张卡互相直接通信。

三、 操作步骤

阶段 1:BIOS 设置

这一步是为了拆除路障。操作系统和显卡之间的内存映射机制必须允许 GPU 直接访问彼此的内存地址。

进入 BIOS 高级模式(Advanced Mode),按如下修改:

  • Advanced->AMD CBS->NBIO Common Options->IOMMU : Disable
  • Advanced->AMD CBS->NBIO Common Options->ACS :Disable
  • Advanced->CPU Configuration->SVM Mode :Disable
  • Advanced->PCI Subsystem Settings->Above 4G Decoding :Enable
  • Advanced->PCI Subsystem Settings->Re-Size BAR Support :Enable
  • Advanced->PCI Subsystem Settings->SR-IOV Support :Disable

解释:

设置项推荐值为什么
IOMMUDisabled虚拟化技术。开启时会拦截设备间的直接访问,导致 P2P 失败。
ACSDisabled访问控制服务。开启后会强制隔离 PCIe 设备,阻止 P2P。
SVM ModeDisabledAMD CPU 的虚拟化开关,同上,关掉以减少干扰。
Above 4G DecodingEnabled必开。允许显卡使用超过 4GB 的内存地址空间,P2P 的前提。
Resizable BAREnabled必开。让 CPU 能访问整张显卡的显存,现代多卡通信必备。
SR-IOVDisabled虚拟化功能,会干扰物理直通。

阶段 2:操作系统准备

确认刚才的设置生效,并清理旧的驱动残留。

# 1. 确认 IOMMU 已关闭(输出应为空或显示 Disabled)cat/sys/class/iommu/dmar0/intel-iommu/enabled2>/dev/null||cat/sys/kernel/iommu_groups/*/type2>/dev/nulldmesg|grep-i"iommu\|DMAR\|IVRS"# 2. 确认系统干净,没有残留的旧版 NVIDIA 驱动模块find/lib/modules/`uname-r`/-name"nvidia*.ko"# 如果有输出,请先卸载旧驱动: sudo apt purge nvidia*

阶段 3:提取 NVIDIA-SMI 工具

由于我们要自己编译驱动,为了监控显卡状态,我们需要先单独提取nvidia-smi工具(不需要安装完整驱动包)。

# 下载驱动仓库文件(仅用于提取工具)wgethttps://developer.download.nvidia.com/compute/nvidia-driver/570.148.08/local_installers/nvidia-driver-local-repo-ubuntu2404-570.148.08_1.0-1_amd64.deb dpkg-invidia-driver-local-repo-ubuntu2404-570.148.08_1.0-1_amd64.deb# 解压 utils 包,提取 nvidia-smidpkg-X./var/nvidia-driver-local-repo-ubuntu2404-570.148.08/nvidia-utils-570_570.148.08-0ubuntu1_amd64.deb../usr/bin/nvidia-smicpusr/bin/nvidia-smi /usr/bin/-rf# 清理垃圾文件rmvar usr-rf

阶段 4:Patch 并编译内核驱动(核心步骤)

这是最关键的步骤。我们需要修改 NVIDIA 开源驱动的代码。

1. 下载源码
gitclone https://github.com/NVIDIA/open-gpu-kernel-modules.gitcdopen-gpu-kernel-modulesgitcheckout570.148.08
2. 制作 Patch
  • 强制开启 Coherency:告诉系统这张卡支持一致性访问。
  • 强制 BAR1 P2P:绕过检查,强制使用 BAR1 方式进行 P2P。
  • 修复地址映射:修改 MMU(内存管理单元)代码,让 GPU 能正确解析对端显存的物理地址。
cat > p2p.patch << 'EOF' diff --git a/kernel-open/nvidia-uvm/uvm_gpu.h b/kernel-open/nvidia-uvm/uvm_gpu.h index d0977f98..9bdc4b36 100644 --- a/kernel-open/nvidia-uvm/uvm_gpu.h +++ b/kernel-open/nvidia-uvm/uvm_gpu.h @@ -1739,7 +1739,8 @@ NvU64 uvm_parent_gpu_canonical_address(uvm_parent_gpu_t *parent_gpu, NvU64 addr) static bool uvm_parent_gpu_is_coherent(const uvm_parent_gpu_t *parent_gpu) { - return parent_gpu->system_bus.memory_window_end > parent_gpu->system_bus.memory_window_start; + return true; + // return parent_gpu->system_bus.memory_window_end > parent_gpu->system_bus.memory_window_start; } static bool uvm_parent_gpu_needs_pushbuffer_segments(uvm_parent_gpu_t *parent_gpu) diff --git a/kernel-open/nvidia/nv-pci.c b/kernel-open/nvidia/nv-pci.c index 4bedd72c..8b72b374 100644 --- a/kernel-open/nvidia/nv-pci.c +++ b/kernel-open/nvidia/nv-pci.c @@ -187,7 +187,7 @@ static int nv_resize_pcie_bars(struct pci_dev *pci_dev) { struct pci_host_bridge *host; #endif - if (NVreg_EnableResizableBar == 0) + if (0/*NVreg_EnableResizableBar == 0*/) { nv_printf(NV_DBG_INFO, "NVRM: resizable BAR disabled by regkey, skipping\n"); return 0; diff --git a/src/nvidia/generated/g_kern_bus_nvoc.c b/src/nvidia/generated/g_kern_bus_nvoc.c index 7f4ee79f..e0bddcef 100644 --- a/src/nvidia/generated/g_kern_bus_nvoc.c +++ b/src/nvidia/generated/g_kern_bus_nvoc.c @@ -704,7 +704,7 @@ static void __nvoc_init_funcTable_KernelBus_1(KernelBus *pThis, RmHalspecOwner * // default else { - pThis->__kbusGetBar1P2PDmaInfo__ = &kbusGetBar1P2PDmaInfo_395e98; + pThis->__kbusGetBar1P2PDmaInfo__ = &kbusGetBar1P2PDmaInfo_GH100; } // kbusCreateP2PMappingForBar1P2P -- halified (2 hals) body @@ -716,7 +716,7 @@ static void __nvoc_init_funcTable_KernelBus_1(KernelBus *pThis, RmHalspecOwner * // default else { - pThis->__kbusCreateP2PMappingForBar1P2P__ = &kbusCreateP2PMappingForBar1P2P_395e98; + pThis->__kbusCreateP2PMappingForBar1P2P__ = &kbusCreateP2PMappingForBar1P2P_GH100; } // kbusRemoveP2PMappingForBar1P2P -- halified (2 hals) body @@ -728,7 +728,7 @@ static void __nvoc_init_funcTable_KernelBus_1(KernelBus *pThis, RmHalspecOwner * // default else { - pThis->__kbusRemoveP2PMappingForBar1P2P__ = &kbusRemoveP2PMappingForBar1P2P_395e98; + pThis->__kbusRemoveP2PMappingForBar1P2P__ = &kbusRemoveP2PMappingForBar1P2P_GH100; } // kbusHasPcieBar1P2PMapping -- halified (2 hals) body @@ -740,7 +740,7 @@ static void __nvoc_init_funcTable_KernelBus_1(KernelBus *pThis, RmHalspecOwner * // default else { - pThis->__kbusHasPcieBar1P2PMapping__ = &kbusHasPcieBar1P2PMapping_d69453; + pThis->__kbusHasPcieBar1P2PMapping__ = &kbusHasPcieBar1P2PMapping_GH100; } // kbusIsPcieBar1P2PMappingSupported -- halified (2 hals) body @@ -752,7 +752,7 @@ static void __nvoc_init_funcTable_KernelBus_1(KernelBus *pThis, RmHalspecOwner * // default else { - pThis->__kbusIsPcieBar1P2PMappingSupported__ = &kbusIsPcieBar1P2PMappingSupported_d69453; + pThis->__kbusIsPcieBar1P2PMappingSupported__ = &kbusIsPcieBar1P2PMappingSupported_GH100; } // kbusCheckFlaSupportedAndInit -- halified (2 hals) body diff --git a/src/nvidia/src/kernel/gpu/bif/kernel_bif.c b/src/nvidia/src/kernel/gpu/bif/kernel_bif.c index 3fdbb872..9cd77298 100644 --- a/src/nvidia/src/kernel/gpu/bif/kernel_bif.c +++ b/src/nvidia/src/kernel/gpu/bif/kernel_bif.c @@ -772,7 +772,7 @@ _kbifInitRegistryOverrides NvU32 data32; // P2P Override - pKernelBif->p2pOverride = BIF_P2P_NOT_OVERRIDEN; + pKernelBif->p2pOverride = 0x11; if (osReadRegistryDword(pGpu, NV_REG_STR_CL_FORCE_P2P, &data32) == NV_OK) { pKernelBif->p2pOverride = data32; @@ -781,7 +781,7 @@ _kbifInitRegistryOverrides } // P2P force type override - pKernelBif->forceP2PType = NV_REG_STR_RM_FORCE_P2P_TYPE_DEFAULT; + pKernelBif->forceP2PType = NV_REG_STR_RM_FORCE_P2P_TYPE_BAR1P2P; if (osReadRegistryDword(pGpu, NV_REG_STR_RM_FORCE_P2P_TYPE, &data32) == NV_OK && (data32 <= NV_REG_STR_RM_FORCE_P2P_TYPE_MAX)) { diff --git a/src/nvidia/src/kernel/gpu/bus/arch/pascal/kern_bus_gp100.c b/src/nvidia/src/kernel/gpu/bus/arch/pascal/kern_bus_gp100.c index ef0f26a4..65827461 100644 --- a/src/nvidia/src/kernel/gpu/bus/arch/pascal/kern_bus_gp100.c +++ b/src/nvidia/src/kernel/gpu/bus/arch/pascal/kern_bus_gp100.c @@ -65,6 +65,11 @@ kbusCreateP2PMapping_GP100 return kbusCreateP2PMappingForNvlink_HAL(pGpu0, pKernelBus0, pGpu1, pKernelBus1, peer0, peer1, attributes); } + if (FLD_TEST_DRF(_P2PAPI, _ATTRIBUTES, _CONNECTION_TYPE, _PCIE_BAR1, attributes)) + { + return kbusCreateP2PMappingForBar1P2P_HAL(pGpu0, pKernelBus0, pGpu1, pKernelBus1, attributes); + } + if (FLD_TEST_DRF(_P2PAPI, _ATTRIBUTES, _CONNECTION_TYPE, _PCIE, attributes)) { return kbusCreateP2PMappingForMailbox_HAL(pGpu0, pKernelBus0, pGpu1, pKernelBus1, peer0, peer1, attributes); @@ -632,6 +637,11 @@ kbusRemoveP2PMapping_GP100 return kbusRemoveP2PMappingForNvlink_HAL(pGpu0, pKernelBus0, pGpu1, pKernelBus1, peer0, peer1, attributes); } + if (FLD_TEST_DRF(_P2PAPI, _ATTRIBUTES, _CONNECTION_TYPE, _PCIE_BAR1, attributes)) + { + return kbusRemoveP2PMappingForBar1P2P_HAL(pGpu0, pKernelBus0, pGpu1, pKernelBus1, attributes); + } + if (FLD_TEST_DRF(_P2PAPI, _ATTRIBUTES, _CONNECTION_TYPE, _PCIE, attributes)) { return kbusRemoveP2PMappingForMailbox_HAL(pGpu0, pKernelBus0, pGpu1, pKernelBus1, peer0, peer1, attributes); diff --git a/src/nvidia/src/kernel/gpu/mem_mgr/mem_desc.c b/src/nvidia/src/kernel/gpu/mem_mgr/mem_desc.c index 1d9539fa..3db6b88e 100644 --- a/src/nvidia/src/kernel/gpu/mem_mgr/mem_desc.c +++ b/src/nvidia/src/kernel/gpu/mem_mgr/mem_desc.c @@ -1511,7 +1511,7 @@ _memdescFreeInternal } else { - NV_ASSERT_FAILED("Sysmemdesc outlived its attached pGpu"); + //NV_ASSERT_FAILED("Sysmemdesc outlived its attached pGpu"); } } diff --git a/src/nvidia/src/kernel/mem_mgr/io_vaspace.c b/src/nvidia/src/kernel/mem_mgr/io_vaspace.c index b8f4f251..90deac37 100644 --- a/src/nvidia/src/kernel/mem_mgr/io_vaspace.c +++ b/src/nvidia/src/kernel/mem_mgr/io_vaspace.c @@ -59,6 +59,7 @@ iovaspaceConstruct__IMPL void iovaspaceDestruct_IMPL(OBJIOVASPACE *pIOVAS) { + return; OBJVASPACE *pVAS = staticCast(pIOVAS, OBJVASPACE); if (pIOVAS->mappingCount != 0) @@ -589,7 +590,7 @@ OBJIOVASPACE *iovaspaceFromMapping(PIOVAMAPPING pIovaMapping) // not, the mapping has been left dangling outlasting the IOVAS it was // under. // - NV_ASSERT(pIOVAS != NULL); + //NV_ASSERT(pIOVAS != NULL); return pIOVAS; } @@ -598,6 +599,7 @@ void iovaMappingDestroy(PIOVAMAPPING pIovaMapping) { OBJIOVASPACE *pIOVAS = iovaspaceFromMapping(pIovaMapping); + if (pIOVAS == NULL) return; NV_ASSERT_OR_RETURN_VOID(pIOVAS != NULL); iovaspaceDestroyMapping(pIOVAS, pIovaMapping); } diff --git a/src/nvidia/src/kernel/rmapi/nv_gpu_ops.c b/src/nvidia/src/kernel/rmapi/nv_gpu_ops.c index c5abc71f..853132f4 100644 --- a/src/nvidia/src/kernel/rmapi/nv_gpu_ops.c +++ b/src/nvidia/src/kernel/rmapi/nv_gpu_ops.c @@ -3658,7 +3658,8 @@ nvGpuOpsBuildExternalAllocPtes NvBool isIndirectPeerSupported, NvBool isPeerSupported, NvU32 peerId, - gpuExternalMappingInfo *pGpuExternalMappingInfo + gpuExternalMappingInfo *pGpuExternalMappingInfo, + RmPhysAddr bar1BusAddr ) { NV_STATUS status = NV_OK; @@ -3809,7 +3810,11 @@ nvGpuOpsBuildExternalAllocPtes NvU32 ptePcfHw = 0; nvFieldSetBool(&pPteFmt->fldValid, NV_TRUE, pte.v8); - gmmuFieldSetAperture(&pPteFmt->fldAperture, aperture, pte.v8); + if (aperture == GMMU_APERTURE_PEER) { + gmmuFieldSetAperture(&pPteFmt->fldAperture, GMMU_APERTURE_SYS_COH, pte.v8); + } else { + gmmuFieldSetAperture(&pPteFmt->fldAperture, aperture, pte.v8); + } nvFieldSet32(&pPteFmt->fldKind, kind, pte.v8); ptePcfSw |= vol ? (1 << SW_MMU_PCF_UNCACHED_IDX) : 0; @@ -3853,7 +3858,11 @@ nvGpuOpsBuildExternalAllocPtes if (nvFieldIsValid32(&pPteFmt->fldAtomicDisable.desc)) nvFieldSetBool(&pPteFmt->fldAtomicDisable, !atomic, pte.v8); - gmmuFieldSetAperture(&pPteFmt->fldAperture, aperture, pte.v8); + if (aperture == GMMU_APERTURE_PEER) { + gmmuFieldSetAperture(&pPteFmt->fldAperture, GMMU_APERTURE_SYS_NONCOH, pte.v8); + } else { + gmmuFieldSetAperture(&pPteFmt->fldAperture, aperture, pte.v8); + } if (!isCompressedKind) { @@ -3863,8 +3872,10 @@ nvGpuOpsBuildExternalAllocPtes nvFieldSet32(&pPteFmt->fldCompTagSubIndex, 0, pte.v8); } } - - if (aperture == GMMU_APERTURE_PEER) + if (aperture == GMMU_APERTURE_PEER) { + fabricBaseAddress = bar1BusAddr; + } + if (0/*aperture == GMMU_APERTURE_PEER*/) { FlaMemory* pFlaMemory = dynamicCast(pMemory, FlaMemory); nvFieldSet32(&pPteFmt->fldPeerIndex, peerId, pte.v8); @@ -4061,7 +4072,8 @@ nvGpuOpsBuildExternalAllocPhysAddrs NvBool isIndirectPeerSupported, NvBool isPeerSupported, NvU32 peerId, - UvmGpuExternalPhysAddrInfo *pGpuExternalPhysAddrInfo + UvmGpuExternalPhysAddrInfo *pGpuExternalPhysAddrInfo, + RmPhysAddr bar1BusAddr ) { NV_STATUS status = NV_OK; @@ -4133,8 +4145,10 @@ nvGpuOpsBuildExternalAllocPhysAddrs if (!physAddrCount) return NV_ERR_BUFFER_TOO_SMALL; - - if (aperture == GMMU_APERTURE_PEER) + if (aperture == GMMU_APERTURE_PEER) { + fabricBaseAddress = bar1BusAddr; + } + if (0/*aperture == GMMU_APERTURE_PEER*/) { FlaMemory* pFlaMemory = dynamicCast(pMemory, FlaMemory); @@ -4224,6 +4238,7 @@ NV_STATUS nvGpuOpsGetExternalAllocPtesOrPhysAddrs(struct gpuAddressSpace *vaSpac Memory *pMemory = NULL; PMEMORY_DESCRIPTOR pMemDesc = NULL; OBJGPU *pMappingGpu = NULL; + RmPhysAddr bar1BusAddr = 0; NvU32 peerId = 0; NvBool isSliSupported = NV_FALSE; NvBool isPeerSupported = NV_FALSE; @@ -4375,6 +4390,8 @@ NV_STATUS nvGpuOpsGetExternalAllocPtesOrPhysAddrs(struct gpuAddressSpace *vaSpac &peerId); if (status != NV_OK) goto freeGpaMemdesc; + + bar1BusAddr = gpumgrGetGpuPhysFbAddr(pAdjustedMemDesc->pGpu); } // @@ -4454,14 +4471,14 @@ NV_STATUS nvGpuOpsGetExternalAllocPtesOrPhysAddrs(struct gpuAddressSpace *vaSpac { status = nvGpuOpsBuildExternalAllocPtes(pVAS, pMappingGpu, pAdjustedMemDesc, pMemory, offset, size, isIndirectPeerSupported, isPeerSupported, peerId, - pGpuExternalMappingInfo); + pGpuExternalMappingInfo, bar1BusAddr); } if (pGpuExternalPhysAddrInfo != NULL) { status = nvGpuOpsBuildExternalAllocPhysAddrs(pVAS, pMappingGpu, pAdjustedMemDesc, pMemory, offset, size, isIndirectPeerSupported, isPeerSupported, peerId, - pGpuExternalPhysAddrInfo); +
http://www.jsqmd.com/news/675066/

相关文章:

  • 2026年口碑好的辽宁萘系高效减水剂/早强型高性能减水剂/标准型高效减水剂/缓凝型高效减水剂生产厂家推荐 - 品牌宣传支持者
  • **发散创新:用Python构建负责任AI模型的可解释性框架**在人工智能快速发展的今天,**负
  • 5分钟解锁QQ音乐加密文件:让你的音乐收藏重获自由播放权
  • 2026年比较好的昆明变频水泵/昆明永磁变频水泵/昆明增压水泵定制加工厂家推荐 - 品牌宣传支持者
  • 【Qwen3.5-Omni 视频分析部署教程】AutoDL 算力市场选机 + vLLM 全流程实战
  • 千匠网络:纺织业渠道分销系统开发,赋能渠道高效协同,激活产业增长新动能
  • LM镜像多场景应用:游戏原画初稿、服装面料模拟、虚拟偶像建模辅助
  • 2026年评价高的标准型高性能减水剂/辽宁减水剂/聚羧酸减水剂优质公司推荐 - 行业平台推荐
  • 2026年口碑好的环保可降解水刺无纺布/宁波水刺无纺布/交叉水刺无纺布优质厂家汇总推荐 - 行业平台推荐
  • 如何解决多项目并发下的研发效率低下与
  • 生命周期评价(LCA)及SimaPro软件与碳足迹分析应用
  • 2026年评价高的昆明增压水泵/进口水泵精选厂家推荐 - 行业平台推荐
  • 国内 Gemini 使用教程:基于 4sapi 零门槛合规接入 Gemini 3.1 Pro 全系列生产级能力
  • 2026年热门的颗粒输送机/绞龙输送机厂家选择推荐 - 品牌宣传支持者
  • Pixel Aurora Engine实际应用:像素风APP图标+启动页+引导页一体化生成
  • 2026年正规的福建婚介中心/福州婚介中心/福州婚介平台用户好评推荐 - 品牌宣传支持者
  • Go语言的reflect.StructOf动态创建结构体类型与运行时元编程能力
  • # IndexedDB实战进阶:从基础操作到高性能数据管理架构设计在现代Web应用中,**In
  • TFCalc软件视频教程
  • 2026年常见的鸭嘴膏霜瓶/塑料膏霜瓶/亚力克膏霜瓶推荐品牌厂家 - 品牌宣传支持者
  • 【Claude Code 安装教程】:Mac 和 Windows 双平台完整指南(2026最新)
  • 在 PHP 中写真正的异步代码 TrueAsync .. 已支持数据库链接池
  • git notes
  • 大模型的探索与实践-课程笔记(一):大模型的定义、特点、元素……
  • 2026年口碑好的黄岛全屋定制/青岛全屋定制/青岛实木全屋定制/青岛小户型全屋定制服务型公司推荐 - 品牌宣传支持者
  • 10年老兵带你学Java(第5课):接口与抽象类 - 抽象与契约
  • Session Startup 执行机制详解
  • Blazor WebAssembly性能突破78%!2026企业刚需:如何用Server-Side Hybrid模式重构ERP前端(附Gartner验证基准)
  • 2026年质量好的颗粒输送机/车载输送机/吸粮输送机/曲阜输送机公司对比推荐 - 行业平台推荐
  • Phi-3.5-mini-instruct轻量推理优势:在低功耗GPU上实现<500ms首token延迟