From dc9323d5996a4a7686f1a114c73c668780492435 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Thu, 26 Feb 2026 13:24:11 +0200 Subject: [PATCH 01/10] feat: Add AMD accelerator detection and tracking in libfabric topology --- src/utils/libfabric/libfabric_topology.cpp | 91 ++++++++++++++++++---- src/utils/libfabric/libfabric_topology.h | 16 +++- 2 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index eab2f263..0620dff3 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -35,6 +35,7 @@ nixlLibfabricTopology::nixlLibfabricTopology() : num_aws_accel(0), num_nvidia_accel(0), + num_amd_accel(0), num_numa_nodes(0), num_devices(0), topology_discovered(false), @@ -86,8 +87,8 @@ nixlLibfabricTopology::discoverTopology() { NIXL_ERROR << "Failed to discover hwloc topology"; return status; } - // Build nVidia accelerator to EFA mapping based on PCIe topology - if (num_nvidia_accel > 0) { + // Build accelerator to EFA mapping based on PCIe topology + if (num_nvidia_accel > 0 || num_amd_accel > 0) { status = buildAccelToEfaMapping(); if (status != NIXL_SUCCESS) { NIXL_ERROR << "Failed to build accelerator to EFA mapping"; @@ -189,7 +190,9 @@ void nixlLibfabricTopology::printTopologyInfo() const { NIXL_TRACE << "=== Libfabric Topology Information ==="; NIXL_TRACE << "Topology discovered: " << (topology_discovered ? "Yes" : "No"); - NIXL_TRACE << "Number of AWS accelerators: " << num_aws_accel; + NIXL_TRACE << "Number of NVIDIA accelerators: " << num_nvidia_accel; + NIXL_TRACE << "Number of AMD accelerators: " << num_amd_accel; + NIXL_TRACE << "Number of AWS Neuron accelerators: " << num_aws_accel; NIXL_TRACE << "Number of NUMA nodes: " << num_numa_nodes; NIXL_TRACE << "Number of EFA devices: " << num_devices; NIXL_TRACE << "EFA devices: "; @@ -215,7 +218,9 @@ std::string nixlLibfabricTopology::getTopologyString() const { std::stringstream ss; ss << "Libfabric Topology: "; - ss << "AWS_Accelerators=" << num_aws_accel << ", "; + ss << "NVIDIA_GPUs=" << num_nvidia_accel << ", "; + ss << "AMD_GPUs=" << num_amd_accel << ", "; + ss << "Neuron_Accelerators=" << num_aws_accel << ", "; ss << "NUMA=" << num_numa_nodes << ", "; ss << "EFA=" << num_devices << ", "; ss << "Discovered=" << (topology_discovered ? "Yes" : "No"); @@ -328,29 +333,41 @@ nixl_status_t nixlLibfabricTopology::discoverAccelWithHwloc() { num_aws_accel = 0; num_nvidia_accel = 0; + num_amd_accel = 0; // Find all PCI devices and log detailed information - static const char *vendor_names[2] = {"NEURON", "NVIDIA"}; hwloc_obj_t pci_obj = nullptr; while ((pci_obj = hwloc_get_next_pcidev(hwloc_topology, pci_obj)) != nullptr) { const bool is_nvidia_accel = isNvidiaAccel(pci_obj); - if (is_nvidia_accel || isNeuronAccel(pci_obj)) { + const bool is_neuron_accel = isNeuronAccel(pci_obj); + const bool is_amd_accel = isAmdAccel(pci_obj); + + if (is_nvidia_accel || is_neuron_accel || is_amd_accel) { std::string pcie_addr = getPcieAddressFromHwlocObj(pci_obj); // Get device and vendor info uint16_t vendor_id = pci_obj->attr->pcidev.vendor_id; uint16_t device_id = pci_obj->attr->pcidev.device_id; uint16_t class_id = pci_obj->attr->pcidev.class_id; - NIXL_TRACE << "Found " << vendor_names[is_nvidia_accel] << " accelerator " - << num_aws_accel << ": " << pcie_addr << " (vendor=" << std::hex << vendor_id + const char *vendor_name = is_nvidia_accel ? "NVIDIA" : + is_amd_accel ? "AMD" : "NEURON"; + + NIXL_TRACE << "Found " << vendor_name << " accelerator: " << pcie_addr + << " (vendor=" << std::hex << vendor_id << ", device=" << device_id << ", class=" << class_id << std::dec << ")"; - num_aws_accel++; - num_nvidia_accel += is_nvidia_accel; + if (is_nvidia_accel) { + num_nvidia_accel++; + } else if (is_amd_accel) { + num_amd_accel++; + } else { + num_aws_accel++; + } } } - NIXL_TRACE << "Discovered " << num_aws_accel << " " - << vendor_names[num_aws_accel == num_nvidia_accel] << " devices via hwloc"; + NIXL_TRACE << "Discovered " << num_nvidia_accel << " NVIDIA, " + << num_amd_accel << " AMD, and " + << num_aws_accel << " Neuron accelerators via hwloc"; // If we found more than 8 NVIDIA accelerators on P5en, investigate further if (num_nvidia_accel > 8) { @@ -514,10 +531,10 @@ nixlLibfabricTopology::buildTopologyAwareGrouping() { NIXL_WARN << "Could not find hwloc object for PCIe address: " << pcie_addr; } } - // Step 2: Discover accelerators + // Step 2: Discover accelerators (NVIDIA and AMD) hwloc_obj_t pci_obj = nullptr; while ((pci_obj = hwloc_get_next_pcidev(hwloc_topology, pci_obj)) != nullptr) { - if (isNvidiaAccel(pci_obj)) { + if (isNvidiaAccel(pci_obj) || isAmdAccel(pci_obj)) { AccelInfo accel; accel.hwloc_node = pci_obj; accel.domain_id = pci_obj->attr->pcidev.domain; @@ -643,6 +660,52 @@ nixlLibfabricTopology::isNeuronAccel(hwloc_obj_t obj) const { obj->attr->pcidev.device_id) != std::end(NEURON_DEVICE_IDS); } +bool +nixlLibfabricTopology::isAmdAccel(hwloc_obj_t obj) const { + if (!obj || obj->type != HWLOC_OBJ_PCI_DEVICE) { + return false; + } + // AMD vendor ID is 0x1002 + if (obj->attr->pcidev.vendor_id != 0x1002) { + return false; + } + // AMD MI300x/MI355/MI455 device IDs + // MI300X: 0x74a0-0x74af range + // MI355/MI455: Will be added when device IDs are known + static const uint16_t AMD_GPU_DEVICE_IDS[] = { + 0x74a0, // MI300X + 0x74a1, // MI300X variant + 0x74a2, // MI300X variant + 0x74a3, // MI300X variant + 0x74a4, // MI300X variant + 0x74a5, // MI300X variant + 0x74a6, // MI300X variant + 0x74a7, // MI300X variant + 0x74a8, // MI300X variant + 0x74a9, // MI300X variant + 0x74aa, // MI300X variant + 0x74ab, // MI300X variant + 0x74ac, // MI300X variant + 0x74ad, // MI300X variant + 0x74ae, // MI300X variant + 0x74af, // MI300X variant + }; + + uint16_t device_id = obj->attr->pcidev.device_id; + + // Check if it's in the known device ID list + if (std::find(std::begin(AMD_GPU_DEVICE_IDS), + std::end(AMD_GPU_DEVICE_IDS), + device_id) != std::end(AMD_GPU_DEVICE_IDS)) { + return true; + } + + // Fallback: Check PCI class ID for display controller (GPU) + // Class 0x300-0x3ff for display controllers (similar to NVIDIA check) + uint16_t class_id = obj->attr->pcidev.class_id; + return (class_id >= 0x300 && class_id < 0x400); +} + bool nixlLibfabricTopology::isEfaDevice(hwloc_obj_t obj) const { if (!obj || obj->type != HWLOC_OBJ_PCI_DEVICE) { diff --git a/src/utils/libfabric/libfabric_topology.h b/src/utils/libfabric/libfabric_topology.h index 09dbeec1..9b1672b6 100644 --- a/src/utils/libfabric/libfabric_topology.h +++ b/src/utils/libfabric/libfabric_topology.h @@ -44,6 +44,7 @@ class nixlLibfabricTopology { // System information int num_aws_accel; // AWS Trainium accelerators int num_nvidia_accel; // NVIDIA GPU accelerators + int num_amd_accel; // AMD GPU accelerators (MI300x, MI355, MI455) int num_numa_nodes; int num_devices; @@ -122,6 +123,8 @@ class nixlLibfabricTopology { bool isNeuronAccel(hwloc_obj_t obj) const; bool + isAmdAccel(hwloc_obj_t obj) const; + bool isEfaDevice(hwloc_obj_t obj) const; public: @@ -143,6 +146,11 @@ class nixlLibfabricTopology { return num_nvidia_accel; } + int + getNumAmdAccel() const { + return num_amd_accel; + } + const std::vector & getAllDevices() const { return all_devices; @@ -164,7 +172,13 @@ class nixlLibfabricTopology { enum fi_hmem_iface getMrAttrIface(int device_id) const { - return (device_id < num_nvidia_accel) ? FI_HMEM_CUDA : FI_HMEM_NEURON; + if (device_id < num_nvidia_accel) { + return FI_HMEM_CUDA; + } else if (device_id < num_nvidia_accel + num_amd_accel) { + return FI_HMEM_ROCR; + } else { + return FI_HMEM_NEURON; + } } // Debug/info From 8fbe1adf40859a6b64bff2f342d820a0c348cb82 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Fri, 27 Feb 2026 14:06:34 +0200 Subject: [PATCH 02/10] fix: Update AMD accelerator device ID list for MI300 and MI355 series --- src/utils/libfabric/libfabric_topology.cpp | 40 ++++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index 0620dff3..c532001c 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -669,26 +669,28 @@ nixlLibfabricTopology::isAmdAccel(hwloc_obj_t obj) const { if (obj->attr->pcidev.vendor_id != 0x1002) { return false; } - // AMD MI300x/MI355/MI455 device IDs - // MI300X: 0x74a0-0x74af range - // MI355/MI455: Will be added when device IDs are known + // AMD Instinct MI300/MI355 series device IDs + // Sources: + // - https://github.com/GPUOpen-Tools/device_info/blob/master/DeviceInfo.cpp + // - https://github.com/openbsd/src/blob/master/sys/dev/pci/drm/amd/amdgpu/amdgpu_devlist.h + // - https://github.com/ROCm/k8s-device-plugin/issues/112 + // - https://github.com/ROCm/ROCm/issues/5891 + // Architecture: CDNA3 (gfx942) and CDNA4 (gfx950) static const uint16_t AMD_GPU_DEVICE_IDS[] = { - 0x74a0, // MI300X - 0x74a1, // MI300X variant - 0x74a2, // MI300X variant - 0x74a3, // MI300X variant - 0x74a4, // MI300X variant - 0x74a5, // MI300X variant - 0x74a6, // MI300X variant - 0x74a7, // MI300X variant - 0x74a8, // MI300X variant - 0x74a9, // MI300X variant - 0x74aa, // MI300X variant - 0x74ab, // MI300X variant - 0x74ac, // MI300X variant - 0x74ad, // MI300X variant - 0x74ae, // MI300X variant - 0x74af, // MI300X variant + // MI300 Series (CDNA3 - gfx942) + 0x74a0, // MI300A APU + 0x74a1, // MI300X dGPU (most common) + 0x74a2, // MI308X + 0x74a5, // MI325X + 0x74a9, // MI300XHF + 0x74b5, // MI300X VF (Virtual Function) + + // MI355 Series (CDNA4 - gfx950) + 0x75a0, // MI355X + 0x75a1, // MI355X variant + 0x75a3, // MI355X variant (Chip ID 30115) + + // Note: MI455X (CDNA5) device IDs not yet available (H2 2026 release) }; uint16_t device_id = obj->attr->pcidev.device_id; From 77e1225983f3e9be206b3db40b464df83239534c Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Mon, 2 Mar 2026 13:33:30 +0000 Subject: [PATCH 03/10] feat: Add HIP support for AMD accelerators in libfabric plugin and tests --- src/plugins/libfabric/libfabric_backend.h | 4 ++++ src/plugins/libfabric/meson.build | 12 ++++++++++-- src/utils/libfabric/libfabric_rail_manager.h | 4 ++++ src/utils/libfabric/libfabric_topology.cpp | 19 ++++++++++--------- src/utils/libfabric/meson.build | 18 +++++++++++++----- .../libfabric/libfabric_topology_test.cpp | 6 +++++- test/unit/utils/libfabric/meson.build | 10 +++++++++- 7 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/plugins/libfabric/libfabric_backend.h b/src/plugins/libfabric/libfabric_backend.h index 912e7255..2c218939 100644 --- a/src/plugins/libfabric/libfabric_backend.h +++ b/src/plugins/libfabric/libfabric_backend.h @@ -38,9 +38,13 @@ #include "libfabric/libfabric_common.h" #ifdef HAVE_CUDA +#ifdef __HIP_PLATFORM_AMD__ +#include +#else #include #include #endif +#endif // Forward declarations class nixlLibfabricEngine; diff --git a/src/plugins/libfabric/meson.build b/src/plugins/libfabric/meson.build index 1fdb6fb7..97cfa60f 100644 --- a/src/plugins/libfabric/meson.build +++ b/src/plugins/libfabric/meson.build @@ -16,6 +16,14 @@ # LibFabric plugin configuration +# Hipify sources that include cuda_runtime.h for ROCm/HIP builds +hipify_cmd = find_program('hipify-perl') +hipify_src = generator(hipify_cmd, + output : ['@BASENAME@_hip.cpp'], + arguments : ['@INPUT@', '@EXTRA_ARGS@', '@OUTPUT@']) + +libfabric_backend_hip_src = hipify_src.process('libfabric_backend.cpp', extra_args: '-o') + # Enable libfabric utils layer libfabric_plugin_deps = [ nixl_infra, @@ -38,7 +46,7 @@ endif if 'LIBFABRIC' in static_plugins libfabric_backend_lib = static_library( 'LIBFABRIC', - 'libfabric_backend.cpp', + libfabric_backend_hip_src, 'libfabric_backend.h', 'libfabric_plugin.cpp', dependencies: libfabric_plugin_deps, @@ -50,7 +58,7 @@ if 'LIBFABRIC' in static_plugins else libfabric_backend_lib = shared_library( 'LIBFABRIC', - 'libfabric_backend.cpp', + libfabric_backend_hip_src, 'libfabric_backend.h', 'libfabric_plugin.cpp', dependencies: libfabric_plugin_deps, diff --git a/src/utils/libfabric/libfabric_rail_manager.h b/src/utils/libfabric/libfabric_rail_manager.h index b2294170..150d0897 100644 --- a/src/utils/libfabric/libfabric_rail_manager.h +++ b/src/utils/libfabric/libfabric_rail_manager.h @@ -28,9 +28,13 @@ #include "libfabric_rail.h" #ifdef HAVE_CUDA +#ifdef __HIP_PLATFORM_AMD__ +#include +#else #include #include #endif +#endif // Forward declarations class nixlLibfabricTopology; diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index c532001c..7ef5264c 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -29,8 +29,12 @@ #include #ifdef HAVE_CUDA +#ifdef __HIP_PLATFORM_AMD__ +#include +#else #include #endif +#endif nixlLibfabricTopology::nixlLibfabricTopology() : num_aws_accel(0), @@ -348,12 +352,11 @@ nixlLibfabricTopology::discoverAccelWithHwloc() { uint16_t device_id = pci_obj->attr->pcidev.device_id; uint16_t class_id = pci_obj->attr->pcidev.class_id; - const char *vendor_name = is_nvidia_accel ? "NVIDIA" : - is_amd_accel ? "AMD" : "NEURON"; + const char *vendor_name = is_nvidia_accel ? "NVIDIA" : is_amd_accel ? "AMD" : "NEURON"; NIXL_TRACE << "Found " << vendor_name << " accelerator: " << pcie_addr - << " (vendor=" << std::hex << vendor_id - << ", device=" << device_id << ", class=" << class_id << std::dec << ")"; + << " (vendor=" << std::hex << vendor_id << ", device=" << device_id + << ", class=" << class_id << std::dec << ")"; if (is_nvidia_accel) { num_nvidia_accel++; @@ -365,8 +368,7 @@ nixlLibfabricTopology::discoverAccelWithHwloc() { } } - NIXL_TRACE << "Discovered " << num_nvidia_accel << " NVIDIA, " - << num_amd_accel << " AMD, and " + NIXL_TRACE << "Discovered " << num_nvidia_accel << " NVIDIA, " << num_amd_accel << " AMD, and " << num_aws_accel << " Neuron accelerators via hwloc"; // If we found more than 8 NVIDIA accelerators on P5en, investigate further @@ -696,9 +698,8 @@ nixlLibfabricTopology::isAmdAccel(hwloc_obj_t obj) const { uint16_t device_id = obj->attr->pcidev.device_id; // Check if it's in the known device ID list - if (std::find(std::begin(AMD_GPU_DEVICE_IDS), - std::end(AMD_GPU_DEVICE_IDS), - device_id) != std::end(AMD_GPU_DEVICE_IDS)) { + if (std::find(std::begin(AMD_GPU_DEVICE_IDS), std::end(AMD_GPU_DEVICE_IDS), device_id) != + std::end(AMD_GPU_DEVICE_IDS)) { return true; } diff --git a/src/utils/libfabric/meson.build b/src/utils/libfabric/meson.build index 67eb3696..35d0d7a8 100644 --- a/src/utils/libfabric/meson.build +++ b/src/utils/libfabric/meson.build @@ -14,14 +14,22 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Hipify sources that include cuda_runtime.h for ROCm/HIP builds +hipify_cmd = find_program('hipify-perl') +hipify_src = generator(hipify_cmd, + output : ['@BASENAME@_hip.cpp'], + arguments : ['@INPUT@', '@EXTRA_ARGS@', '@OUTPUT@']) + +libfabric_topology_hip_src = hipify_src.process('libfabric_topology.cpp', extra_args: '-o') +libfabric_rail_manager_hip_src = hipify_src.process('libfabric_rail_manager.cpp', extra_args: '-o') + # Source files -libfabric_utils_sources = files( +libfabric_utils_sources = [ 'libfabric_rail.cpp', - 'libfabric_rail_manager.cpp', 'libfabric_common.cpp', - 'libfabric_topology.cpp', - # More implementation files will be added as we create them -) + libfabric_topology_hip_src, + libfabric_rail_manager_hip_src, +] # Header files libfabric_utils_headers = files( diff --git a/test/unit/utils/libfabric/libfabric_topology_test.cpp b/test/unit/utils/libfabric/libfabric_topology_test.cpp index 6bb4cfe2..92840145 100644 --- a/test/unit/utils/libfabric/libfabric_topology_test.cpp +++ b/test/unit/utils/libfabric/libfabric_topology_test.cpp @@ -21,8 +21,12 @@ #include "common/nixl_log.h" #ifdef CUDA_FOUND +#ifdef __HIP_PLATFORM_AMD__ +#include +#else #include #endif +#endif int main() { @@ -47,7 +51,7 @@ main() { #ifdef CUDA_FOUND // Get PCI bus ID for this GPU cudaDeviceProp prop; - cudaGetDeviceProperties(&prop, gpu_id); + (void)cudaGetDeviceProperties(&prop, gpu_id); char pci_bus_id[32]; snprintf(pci_bus_id, diff --git a/test/unit/utils/libfabric/meson.build b/test/unit/utils/libfabric/meson.build index 85f8528b..e47810b5 100644 --- a/test/unit/utils/libfabric/meson.build +++ b/test/unit/utils/libfabric/meson.build @@ -14,6 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Hipify sources that include cuda_runtime.h for ROCm/HIP builds +hipify_cmd = find_program('hipify-perl') +hipify_src = generator(hipify_cmd, + output : ['@BASENAME@_hip.cpp'], + arguments : ['@INPUT@', '@EXTRA_ARGS@', '@OUTPUT@']) + +libfabric_topology_test_hip_src = hipify_src.process('libfabric_topology_test.cpp', extra_args: '-o') + libfabric_utils_dep = [ libfabric_dep, nixl_common_deps ] libfabric_test_cpp_args = [] @@ -25,7 +33,7 @@ endif if get_option('buildtype') != 'release' libfabric_topology_test_bin = executable('libfabric_topology_test', - 'libfabric_topology_test.cpp', + libfabric_topology_test_hip_src, dependencies: libfabric_utils_dep, include_directories: [nixl_inc_dirs, utils_inc_dirs], link_with: libfabric_utils_lib, From 1937abd73ec88e9be4f46f14fe324158db3dfc36 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Fri, 6 Mar 2026 10:13:27 +0000 Subject: [PATCH 04/10] fix: add CUcontext/CUdevice AMD mapping --- src/plugins/libfabric/libfabric_backend.h | 4 ++ .../libfabric/libfabric_rail_manager.cpp | 4 ++ src/utils/libfabric/libfabric_topology.cpp | 39 ++----------------- src/utils/libfabric/libfabric_topology.h | 2 +- 4 files changed, 13 insertions(+), 36 deletions(-) diff --git a/src/plugins/libfabric/libfabric_backend.h b/src/plugins/libfabric/libfabric_backend.h index 2c218939..d153e72a 100644 --- a/src/plugins/libfabric/libfabric_backend.h +++ b/src/plugins/libfabric/libfabric_backend.h @@ -40,6 +40,10 @@ #ifdef HAVE_CUDA #ifdef __HIP_PLATFORM_AMD__ #include +#include +// Define CUDA types as HIP equivalents for AMD +typedef hipCtx_t CUcontext; +typedef hipDevice_t CUdevice; #else #include #include diff --git a/src/utils/libfabric/libfabric_rail_manager.cpp b/src/utils/libfabric/libfabric_rail_manager.cpp index 7d9b9c04..2edb19aa 100644 --- a/src/utils/libfabric/libfabric_rail_manager.cpp +++ b/src/utils/libfabric/libfabric_rail_manager.cpp @@ -51,6 +51,10 @@ nixlLibfabricRailManager::nixlLibfabricRailManager(size_t striping_threshold) runtime_ = FI_HMEM_CUDA; NIXL_INFO << "System runtime: CUDA for " << topology->getNumNvidiaAccel() << " NVIDIA GPU(s)"; + } else if (topology->getNumAmdAccel() > 0) { + runtime_ = FI_HMEM_ROCR; + NIXL_INFO << "System runtime: ROCr for " << topology->getNumAmdAccel() + << " AMD GPU(s)"; } else if (topology->getNumAwsAccel() > 0) { runtime_ = FI_HMEM_NEURON; NIXL_INFO << "System runtime: NEURON for " << topology->getNumAwsAccel() diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index 7ef5264c..f5e991b2 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -671,42 +671,11 @@ nixlLibfabricTopology::isAmdAccel(hwloc_obj_t obj) const { if (obj->attr->pcidev.vendor_id != 0x1002) { return false; } - // AMD Instinct MI300/MI355 series device IDs - // Sources: - // - https://github.com/GPUOpen-Tools/device_info/blob/master/DeviceInfo.cpp - // - https://github.com/openbsd/src/blob/master/sys/dev/pci/drm/amd/amdgpu/amdgpu_devlist.h - // - https://github.com/ROCm/k8s-device-plugin/issues/112 - // - https://github.com/ROCm/ROCm/issues/5891 - // Architecture: CDNA3 (gfx942) and CDNA4 (gfx950) - static const uint16_t AMD_GPU_DEVICE_IDS[] = { - // MI300 Series (CDNA3 - gfx942) - 0x74a0, // MI300A APU - 0x74a1, // MI300X dGPU (most common) - 0x74a2, // MI308X - 0x74a5, // MI325X - 0x74a9, // MI300XHF - 0x74b5, // MI300X VF (Virtual Function) - - // MI355 Series (CDNA4 - gfx950) - 0x75a0, // MI355X - 0x75a1, // MI355X variant - 0x75a3, // MI355X variant (Chip ID 30115) - - // Note: MI455X (CDNA5) device IDs not yet available (H2 2026 release) - }; - - uint16_t device_id = obj->attr->pcidev.device_id; - - // Check if it's in the known device ID list - if (std::find(std::begin(AMD_GPU_DEVICE_IDS), std::end(AMD_GPU_DEVICE_IDS), device_id) != - std::end(AMD_GPU_DEVICE_IDS)) { - return true; - } - - // Fallback: Check PCI class ID for display controller (GPU) - // Class 0x300-0x3ff for display controllers (similar to NVIDIA check) + // Only count devices with GPU class (0x300-0x3ff for display controllers) + // Class 0x302 is 3D controller (GPU), 0x680 is other devices (network, etc.) + // MI300X uses class 0x1200 (Processing accelerators), consumer GPUs use 0x300-0x3ff uint16_t class_id = obj->attr->pcidev.class_id; - return (class_id >= 0x300 && class_id < 0x400); + return (class_id >= 0x300 && class_id < 0x400) || (class_id == 0x1200); } bool diff --git a/src/utils/libfabric/libfabric_topology.h b/src/utils/libfabric/libfabric_topology.h index 9b1672b6..78abc941 100644 --- a/src/utils/libfabric/libfabric_topology.h +++ b/src/utils/libfabric/libfabric_topology.h @@ -44,7 +44,7 @@ class nixlLibfabricTopology { // System information int num_aws_accel; // AWS Trainium accelerators int num_nvidia_accel; // NVIDIA GPU accelerators - int num_amd_accel; // AMD GPU accelerators (MI300x, MI355, MI455) + int num_amd_accel; // AMD GPU accelerators int num_numa_nodes; int num_devices; From fb4af618f96bcdd110e8e055a4fbfc3bc17c000b Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Thu, 12 Mar 2026 13:43:31 +0000 Subject: [PATCH 05/10] feat: support AMD ROCm runtime in memory registration --- src/plugins/libfabric/libfabric_backend.cpp | 2 +- src/utils/libfabric/libfabric_rail_manager.cpp | 3 +-- subprojects/.wraplock | 0 3 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 subprojects/.wraplock diff --git a/src/plugins/libfabric/libfabric_backend.cpp b/src/plugins/libfabric/libfabric_backend.cpp index 2998cc82..31ba55a6 100644 --- a/src/plugins/libfabric/libfabric_backend.cpp +++ b/src/plugins/libfabric/libfabric_backend.cpp @@ -727,7 +727,7 @@ nixlLibfabricEngine::registerMem(const nixlBlobDesc &mem, // Use system runtime type to determine device-specific operations if (nixl_mem == VRAM_SEG) { #ifdef HAVE_CUDA - if (runtime_ == FI_HMEM_CUDA) { + if (runtime_ == FI_HMEM_CUDA || runtime_ == FI_HMEM_ROCR) { // CUDA-specific address query // For multi-GPU support, skip CUDA address workaround if (cuda_addr_wa_) { diff --git a/src/utils/libfabric/libfabric_rail_manager.cpp b/src/utils/libfabric/libfabric_rail_manager.cpp index 2edb19aa..c37faed1 100644 --- a/src/utils/libfabric/libfabric_rail_manager.cpp +++ b/src/utils/libfabric/libfabric_rail_manager.cpp @@ -53,8 +53,7 @@ nixlLibfabricRailManager::nixlLibfabricRailManager(size_t striping_threshold) << " NVIDIA GPU(s)"; } else if (topology->getNumAmdAccel() > 0) { runtime_ = FI_HMEM_ROCR; - NIXL_INFO << "System runtime: ROCr for " << topology->getNumAmdAccel() - << " AMD GPU(s)"; + NIXL_INFO << "System runtime: ROCr for " << topology->getNumAmdAccel() << " AMD GPU(s)"; } else if (topology->getNumAwsAccel() > 0) { runtime_ = FI_HMEM_NEURON; NIXL_INFO << "System runtime: NEURON for " << topology->getNumAwsAccel() diff --git a/subprojects/.wraplock b/subprojects/.wraplock new file mode 100644 index 00000000..e69de29b From 48c5c65cb185f5b779c28853bfc3751005a274d7 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Thu, 12 Mar 2026 15:57:28 +0000 Subject: [PATCH 06/10] feat: Implement AMD ROCr support for memory registration and topology discovery --- .gitignore | 5 +- src/plugins/libfabric/libfabric_backend.cpp | 140 ++++++++++++++++-- src/plugins/libfabric/libfabric_backend.h | 4 + src/utils/libfabric/libfabric_rail.cpp | 7 + .../libfabric/libfabric_rail_manager.cpp | 3 + src/utils/libfabric/libfabric_topology.cpp | 55 +++---- src/utils/libfabric/libfabric_topology.h | 2 +- .../libfabric/libfabric_topology_test.cpp | 2 +- 8 files changed, 165 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index d352dd75..31b5895e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,7 @@ cufile.log .cache/ # Asio -subprojects/asio-* \ No newline at end of file +subprojects/asio-* + +build +subprojects/.wraplock \ No newline at end of file diff --git a/src/plugins/libfabric/libfabric_backend.cpp b/src/plugins/libfabric/libfabric_backend.cpp index 2998cc82..90fb8fb1 100644 --- a/src/plugins/libfabric/libfabric_backend.cpp +++ b/src/plugins/libfabric/libfabric_backend.cpp @@ -76,6 +76,110 @@ nrtQueryAddr(const void *va, std::string *efa_bdf) { return -1; } +// ROCr (AMD GPU) runtime library loading +void * +dlopen_libhsa() { + // Try libhsa-runtime64.so first + static void *handle = dlopen("libhsa-runtime64.so.1", RTLD_NOW | RTLD_LAZY); + if (handle) { + return handle; + } + // Fallback to versioned library + handle = dlopen("libhsa-runtime64.so", RTLD_NOW | RTLD_LAZY); + return handle; +} + +void * +dlopen_libhip() { + // Try libamdhip64.so (HIP Runtime) as alternative + static void *handle = dlopen("libamdhip64.so.6", RTLD_NOW | RTLD_LAZY); + if (handle) { + return handle; + } + // Fallback to unversioned library + handle = dlopen("libamdhip64.so", RTLD_NOW | RTLD_LAZY); + return handle; +} + +template +Fn * +_load_hsa_symbol(const char *fn_name, Fn *) { + void *hsa_handle = dlopen_libhsa(); + if (hsa_handle) { + return reinterpret_cast(dlsym(hsa_handle, fn_name)); + } + return nullptr; +} + +template +Fn * +_load_hip_symbol(const char *fn_name, Fn *) { + void *hip_handle = dlopen_libhip(); + if (hip_handle) { + return reinterpret_cast(dlsym(hip_handle, fn_name)); + } + return nullptr; +} + +#define LOAD_HSA_SYMBOL(sym) _load_hsa_symbol(#sym, &sym) +#define LOAD_HIP_SYMBOL(sym) _load_hip_symbol(#sym, &sym) + +// HIP API function signatures for dynamic loading +using hipGetDeviceProperties_fn = int (*)(void *prop, int device); +using hipPointerGetAttribute_fn = int (*)(void *data, int attribute, const void *ptr); +using hipDeviceGetPCIBusId_fn = int (*)(char *pciBusId, int len, int device); + +// ROCr (AMD GPU) memory address query using HIP APIs +int +rocrQueryAddr(const void *va, std::string *efa_bdf) { + // Strategy: Use HIP runtime to query PCI bus ID from memory address + // HIP API: hipPointerGetAttribute -> get device ID -> hipDeviceGetPCIBusId + + // Load HIP symbols dynamically + hipPointerGetAttribute_fn hipPointerGetAttribute = nullptr; + hipDeviceGetPCIBusId_fn hipDeviceGetPCIBusId = nullptr; + + void *hip_handle = dlopen_libhip(); + if (hip_handle) { + hipPointerGetAttribute = reinterpret_cast( + dlsym(hip_handle, "hipPointerGetAttribute")); + hipDeviceGetPCIBusId = reinterpret_cast( + dlsym(hip_handle, "hipDeviceGetPCIBusId")); + } + + if (!hipPointerGetAttribute || !hipDeviceGetPCIBusId) { + // HIP library not available - this is acceptable, fall back to all rails + NIXL_TRACE << "HIP runtime library not available - using all rails for AMD GPU memory"; + return -1; + } + + // Query device ID from memory pointer + int device_id = -1; + // hipPointerAttribute_t::device = 2 + constexpr int hipPointerAttributeDevice = 2; + int ret = hipPointerGetAttribute(&device_id, hipPointerAttributeDevice, va); + if (ret != 0 || device_id < 0) { + NIXL_TRACE << "Failed to query device ID from memory address " << va + << " - using all rails"; + return -1; + } + + // Query PCI bus ID from device ID + char pci_bus_id[64]; + ret = hipDeviceGetPCIBusId(pci_bus_id, sizeof(pci_bus_id), device_id); + if (ret != 0) { + NIXL_TRACE << "Failed to query PCI bus ID for AMD GPU device " << device_id + << " - using all rails"; + return -1; + } + + // Format PCI bus ID (HIP returns format like "0000:59:00.0") + efa_bdf->assign(pci_bus_id); + NIXL_DEBUG << "ROCr query: memory " << va << " -> device " << device_id + << " -> PCI " << *efa_bdf; + return 0; +} + } // namespace #ifdef HAVE_CUDA @@ -301,6 +405,7 @@ nixlLibfabricEngine::nixlLibfabricEngine(const nixlBackendInitParams *init_param NIXL_INFO << "System runtime: " << (runtime_ == FI_HMEM_CUDA ? "CUDA" : + runtime_ == FI_HMEM_ROCR ? "ROCr" : runtime_ == FI_HMEM_NEURON ? "NEURON" : "SYSTEM"); @@ -727,8 +832,8 @@ nixlLibfabricEngine::registerMem(const nixlBlobDesc &mem, // Use system runtime type to determine device-specific operations if (nixl_mem == VRAM_SEG) { #ifdef HAVE_CUDA - if (runtime_ == FI_HMEM_CUDA) { - // CUDA-specific address query + if (runtime_ == FI_HMEM_CUDA || runtime_ == FI_HMEM_ROCR) { + // GPU-specific address query (CUDA or ROCr) // For multi-GPU support, skip CUDA address workaround if (cuda_addr_wa_) { bool need_restart; @@ -753,17 +858,28 @@ nixlLibfabricEngine::registerMem(const nixlBlobDesc &mem, } // Query PCI bus ID from memory address (AFTER setting context) - bool is_dev; - CUdevice dev; - CUcontext ctx; - - int ret = cudaQueryAddr((void *)mem.addr, is_dev, dev, ctx, pci_bus_id); - if (ret || !is_dev) { - NIXL_ERROR << "Failed to query device from memory " << (void *)mem.addr; - return NIXL_ERR_BACKEND; - } + if (runtime_ == FI_HMEM_CUDA) { + bool is_dev; + CUdevice dev; + CUcontext ctx; + + int ret = cudaQueryAddr((void *)mem.addr, is_dev, dev, ctx, pci_bus_id); + if (ret || !is_dev) { + NIXL_ERROR << "Failed to query device from memory " << (void *)mem.addr; + return NIXL_ERR_BACKEND; + } - NIXL_DEBUG << "Queried PCI bus ID: " << pci_bus_id << " for GPU " << mem.devId; + NIXL_DEBUG << "Queried PCI bus ID: " << pci_bus_id << " for GPU " << mem.devId; + } else if (runtime_ == FI_HMEM_ROCR) { + // AMD ROCr-specific address query + int ret = rocrQueryAddr((void *)mem.addr, &pci_bus_id); + if (ret) { + NIXL_ERROR << "Failed to query device from memory " << (void *)mem.addr; + return NIXL_ERR_BACKEND; + } + + NIXL_DEBUG << "Queried PCI bus ID: " << pci_bus_id << " for GPU " << mem.devId; + } } #endif if (runtime_ == FI_HMEM_NEURON) { diff --git a/src/plugins/libfabric/libfabric_backend.h b/src/plugins/libfabric/libfabric_backend.h index 2c218939..d153e72a 100644 --- a/src/plugins/libfabric/libfabric_backend.h +++ b/src/plugins/libfabric/libfabric_backend.h @@ -40,6 +40,10 @@ #ifdef HAVE_CUDA #ifdef __HIP_PLATFORM_AMD__ #include +#include +// Define CUDA types as HIP equivalents for AMD +typedef hipCtx_t CUcontext; +typedef hipDevice_t CUdevice; #else #include #include diff --git a/src/utils/libfabric/libfabric_rail.cpp b/src/utils/libfabric/libfabric_rail.cpp index 9b8a64c6..4311c041 100644 --- a/src/utils/libfabric/libfabric_rail.cpp +++ b/src/utils/libfabric/libfabric_rail.cpp @@ -1285,6 +1285,13 @@ nixlLibfabricRail::registerMemory(void *buffer, mr_attr.device.cuda = device_id; NIXL_DEBUG << "CUDA memory registration - iface: FI_HMEM_CUDA, device.cuda: " << device_id; + } else if (iface == FI_HMEM_ROCR) { + // AMD ROCr memory registration + // ROCr uses HSA agent handles for device identification + // The device_id corresponds to the GPU index (0-based) + mr_attr.device.rocr = device_id; + NIXL_DEBUG << "ROCr memory registration - iface: FI_HMEM_ROCR, device.rocr: " + << device_id; } else if (iface == FI_HMEM_NEURON) { /* * Store a sentinel; libfabric requires this to be initialized. diff --git a/src/utils/libfabric/libfabric_rail_manager.cpp b/src/utils/libfabric/libfabric_rail_manager.cpp index 7d9b9c04..c37faed1 100644 --- a/src/utils/libfabric/libfabric_rail_manager.cpp +++ b/src/utils/libfabric/libfabric_rail_manager.cpp @@ -51,6 +51,9 @@ nixlLibfabricRailManager::nixlLibfabricRailManager(size_t striping_threshold) runtime_ = FI_HMEM_CUDA; NIXL_INFO << "System runtime: CUDA for " << topology->getNumNvidiaAccel() << " NVIDIA GPU(s)"; + } else if (topology->getNumAmdAccel() > 0) { + runtime_ = FI_HMEM_ROCR; + NIXL_INFO << "System runtime: ROCr for " << topology->getNumAmdAccel() << " AMD GPU(s)"; } else if (topology->getNumAwsAccel() > 0) { runtime_ = FI_HMEM_NEURON; NIXL_INFO << "System runtime: NEURON for " << topology->getNumAwsAccel() diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index 7ef5264c..0626636f 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -104,10 +104,20 @@ nixlLibfabricTopology::discoverTopology() { NIXL_INFO << "Using simplified topology for " << provider_name << " devices (no topology mapping needed)"; - // Set basic values without hwloc discovery - num_aws_accel = 0; // TCP doesn't need accelerator topology - num_numa_nodes = 1; // Simple fallback + // Still discover GPUs even in simplified mode for GPU memory registration + status = initHwlocTopology(); + if (status == NIXL_SUCCESS) { + status = discoverAccelWithHwloc(); + if (status != NIXL_SUCCESS) { + NIXL_WARN << "GPU discovery failed in simplified topology mode"; + // Not a fatal error - continue without GPUs + } + cleanupHwlocTopology(); + } else { + NIXL_WARN << "hwloc initialization failed - no GPU detection available"; + } + num_numa_nodes = 1; // Simple fallback // For TCP/sockets devices, no accelerator-mapping required. NIXL_INFO << "TCP devices available globally - no accelerator-specific mapping required"; } @@ -671,42 +681,11 @@ nixlLibfabricTopology::isAmdAccel(hwloc_obj_t obj) const { if (obj->attr->pcidev.vendor_id != 0x1002) { return false; } - // AMD Instinct MI300/MI355 series device IDs - // Sources: - // - https://github.com/GPUOpen-Tools/device_info/blob/master/DeviceInfo.cpp - // - https://github.com/openbsd/src/blob/master/sys/dev/pci/drm/amd/amdgpu/amdgpu_devlist.h - // - https://github.com/ROCm/k8s-device-plugin/issues/112 - // - https://github.com/ROCm/ROCm/issues/5891 - // Architecture: CDNA3 (gfx942) and CDNA4 (gfx950) - static const uint16_t AMD_GPU_DEVICE_IDS[] = { - // MI300 Series (CDNA3 - gfx942) - 0x74a0, // MI300A APU - 0x74a1, // MI300X dGPU (most common) - 0x74a2, // MI308X - 0x74a5, // MI325X - 0x74a9, // MI300XHF - 0x74b5, // MI300X VF (Virtual Function) - - // MI355 Series (CDNA4 - gfx950) - 0x75a0, // MI355X - 0x75a1, // MI355X variant - 0x75a3, // MI355X variant (Chip ID 30115) - - // Note: MI455X (CDNA5) device IDs not yet available (H2 2026 release) - }; - - uint16_t device_id = obj->attr->pcidev.device_id; - - // Check if it's in the known device ID list - if (std::find(std::begin(AMD_GPU_DEVICE_IDS), std::end(AMD_GPU_DEVICE_IDS), device_id) != - std::end(AMD_GPU_DEVICE_IDS)) { - return true; - } - - // Fallback: Check PCI class ID for display controller (GPU) - // Class 0x300-0x3ff for display controllers (similar to NVIDIA check) + // Only count devices with GPU class (0x300-0x3ff for display controllers) + // Class 0x302 is 3D controller (GPU), 0x680 is other devices (network, etc.) + // MI300X uses class 0x1200 (Processing accelerators), consumer GPUs use 0x300-0x3ff uint16_t class_id = obj->attr->pcidev.class_id; - return (class_id >= 0x300 && class_id < 0x400); + return (class_id >= 0x300 && class_id < 0x400) || (class_id == 0x1200); } bool diff --git a/src/utils/libfabric/libfabric_topology.h b/src/utils/libfabric/libfabric_topology.h index 9b1672b6..78abc941 100644 --- a/src/utils/libfabric/libfabric_topology.h +++ b/src/utils/libfabric/libfabric_topology.h @@ -44,7 +44,7 @@ class nixlLibfabricTopology { // System information int num_aws_accel; // AWS Trainium accelerators int num_nvidia_accel; // NVIDIA GPU accelerators - int num_amd_accel; // AMD GPU accelerators (MI300x, MI355, MI455) + int num_amd_accel; // AMD GPU accelerators int num_numa_nodes; int num_devices; diff --git a/test/unit/utils/libfabric/libfabric_topology_test.cpp b/test/unit/utils/libfabric/libfabric_topology_test.cpp index 92840145..04cc3e32 100644 --- a/test/unit/utils/libfabric/libfabric_topology_test.cpp +++ b/test/unit/utils/libfabric/libfabric_topology_test.cpp @@ -43,7 +43,7 @@ main() { topology.printTopologyInfo(); // Test GPU-specific queries only if GPUs are detected - int num_gpus = topology.getNumNvidiaAccel(); + int num_gpus = topology.getNumNvidiaAccel() + topology.getNumAmdAccel(); if (num_gpus > 0) { NIXL_INFO << "3. Testing GPU-specific queries (detected " << num_gpus << " GPUs)..."; int test_gpus = std::min(num_gpus, 3); // Test up to 3 GPUs or all available From 626c3af5b6eb6cbbf32a3fd7c696dd468cf9056a Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Fri, 13 Mar 2026 10:52:55 +0000 Subject: [PATCH 07/10] fix: remove duplicated HIP functionality --- examples/python/expanded_two_peers.py | 23 +++- src/plugins/libfabric/libfabric_backend.cpp | 137 ++------------------ src/utils/libfabric/libfabric_topology.cpp | 16 +-- 3 files changed, 34 insertions(+), 142 deletions(-) diff --git a/examples/python/expanded_two_peers.py b/examples/python/expanded_two_peers.py index 2ac4bce2..aaebfdb0 100755 --- a/examples/python/expanded_two_peers.py +++ b/examples/python/expanded_two_peers.py @@ -6,14 +6,27 @@ import argparse import pickle import random +import sys import numpy as np import torch -from nixl._api import nixl_agent, nixl_agent_config -from nixl.logging import get_logger +try: + try: + from nixl._api import nixl_agent, nixl_agent_config + from nixl.logging import get_logger + except ImportError: + from rixl._api import nixl_agent, nixl_agent_config + from rixl.logging import get_logger + + logger = get_logger(__name__) + NIXL_AVAILABLE = True +except ImportError: + import logging -logger = get_logger(__name__) + logger = logging.getLogger(__name__) + logger.error("NIXL API missing install NIXL.") + NIXL_AVAILABLE = False def parse_args(): @@ -32,6 +45,10 @@ def parse_args(): if __name__ == "__main__": + if not NIXL_AVAILABLE: + logger.warning("Skipping example - NIXL bindings not available") + sys.exit(0) + args = parse_args() # initiator use default port diff --git a/src/plugins/libfabric/libfabric_backend.cpp b/src/plugins/libfabric/libfabric_backend.cpp index 90fb8fb1..bac6b2bb 100644 --- a/src/plugins/libfabric/libfabric_backend.cpp +++ b/src/plugins/libfabric/libfabric_backend.cpp @@ -76,110 +76,6 @@ nrtQueryAddr(const void *va, std::string *efa_bdf) { return -1; } -// ROCr (AMD GPU) runtime library loading -void * -dlopen_libhsa() { - // Try libhsa-runtime64.so first - static void *handle = dlopen("libhsa-runtime64.so.1", RTLD_NOW | RTLD_LAZY); - if (handle) { - return handle; - } - // Fallback to versioned library - handle = dlopen("libhsa-runtime64.so", RTLD_NOW | RTLD_LAZY); - return handle; -} - -void * -dlopen_libhip() { - // Try libamdhip64.so (HIP Runtime) as alternative - static void *handle = dlopen("libamdhip64.so.6", RTLD_NOW | RTLD_LAZY); - if (handle) { - return handle; - } - // Fallback to unversioned library - handle = dlopen("libamdhip64.so", RTLD_NOW | RTLD_LAZY); - return handle; -} - -template -Fn * -_load_hsa_symbol(const char *fn_name, Fn *) { - void *hsa_handle = dlopen_libhsa(); - if (hsa_handle) { - return reinterpret_cast(dlsym(hsa_handle, fn_name)); - } - return nullptr; -} - -template -Fn * -_load_hip_symbol(const char *fn_name, Fn *) { - void *hip_handle = dlopen_libhip(); - if (hip_handle) { - return reinterpret_cast(dlsym(hip_handle, fn_name)); - } - return nullptr; -} - -#define LOAD_HSA_SYMBOL(sym) _load_hsa_symbol(#sym, &sym) -#define LOAD_HIP_SYMBOL(sym) _load_hip_symbol(#sym, &sym) - -// HIP API function signatures for dynamic loading -using hipGetDeviceProperties_fn = int (*)(void *prop, int device); -using hipPointerGetAttribute_fn = int (*)(void *data, int attribute, const void *ptr); -using hipDeviceGetPCIBusId_fn = int (*)(char *pciBusId, int len, int device); - -// ROCr (AMD GPU) memory address query using HIP APIs -int -rocrQueryAddr(const void *va, std::string *efa_bdf) { - // Strategy: Use HIP runtime to query PCI bus ID from memory address - // HIP API: hipPointerGetAttribute -> get device ID -> hipDeviceGetPCIBusId - - // Load HIP symbols dynamically - hipPointerGetAttribute_fn hipPointerGetAttribute = nullptr; - hipDeviceGetPCIBusId_fn hipDeviceGetPCIBusId = nullptr; - - void *hip_handle = dlopen_libhip(); - if (hip_handle) { - hipPointerGetAttribute = reinterpret_cast( - dlsym(hip_handle, "hipPointerGetAttribute")); - hipDeviceGetPCIBusId = reinterpret_cast( - dlsym(hip_handle, "hipDeviceGetPCIBusId")); - } - - if (!hipPointerGetAttribute || !hipDeviceGetPCIBusId) { - // HIP library not available - this is acceptable, fall back to all rails - NIXL_TRACE << "HIP runtime library not available - using all rails for AMD GPU memory"; - return -1; - } - - // Query device ID from memory pointer - int device_id = -1; - // hipPointerAttribute_t::device = 2 - constexpr int hipPointerAttributeDevice = 2; - int ret = hipPointerGetAttribute(&device_id, hipPointerAttributeDevice, va); - if (ret != 0 || device_id < 0) { - NIXL_TRACE << "Failed to query device ID from memory address " << va - << " - using all rails"; - return -1; - } - - // Query PCI bus ID from device ID - char pci_bus_id[64]; - ret = hipDeviceGetPCIBusId(pci_bus_id, sizeof(pci_bus_id), device_id); - if (ret != 0) { - NIXL_TRACE << "Failed to query PCI bus ID for AMD GPU device " << device_id - << " - using all rails"; - return -1; - } - - // Format PCI bus ID (HIP returns format like "0000:59:00.0") - efa_bdf->assign(pci_bus_id); - NIXL_DEBUG << "ROCr query: memory " << va << " -> device " << device_id - << " -> PCI " << *efa_bdf; - return 0; -} - } // namespace #ifdef HAVE_CUDA @@ -833,7 +729,7 @@ nixlLibfabricEngine::registerMem(const nixlBlobDesc &mem, if (nixl_mem == VRAM_SEG) { #ifdef HAVE_CUDA if (runtime_ == FI_HMEM_CUDA || runtime_ == FI_HMEM_ROCR) { - // GPU-specific address query (CUDA or ROCr) + // CUDA-specific address query // For multi-GPU support, skip CUDA address workaround if (cuda_addr_wa_) { bool need_restart; @@ -858,28 +754,17 @@ nixlLibfabricEngine::registerMem(const nixlBlobDesc &mem, } // Query PCI bus ID from memory address (AFTER setting context) - if (runtime_ == FI_HMEM_CUDA) { - bool is_dev; - CUdevice dev; - CUcontext ctx; - - int ret = cudaQueryAddr((void *)mem.addr, is_dev, dev, ctx, pci_bus_id); - if (ret || !is_dev) { - NIXL_ERROR << "Failed to query device from memory " << (void *)mem.addr; - return NIXL_ERR_BACKEND; - } - - NIXL_DEBUG << "Queried PCI bus ID: " << pci_bus_id << " for GPU " << mem.devId; - } else if (runtime_ == FI_HMEM_ROCR) { - // AMD ROCr-specific address query - int ret = rocrQueryAddr((void *)mem.addr, &pci_bus_id); - if (ret) { - NIXL_ERROR << "Failed to query device from memory " << (void *)mem.addr; - return NIXL_ERR_BACKEND; - } - - NIXL_DEBUG << "Queried PCI bus ID: " << pci_bus_id << " for GPU " << mem.devId; + bool is_dev; + CUdevice dev; + CUcontext ctx; + + int ret = cudaQueryAddr((void *)mem.addr, is_dev, dev, ctx, pci_bus_id); + if (ret || !is_dev) { + NIXL_ERROR << "Failed to query device from memory " << (void *)mem.addr; + return NIXL_ERR_BACKEND; } + + NIXL_DEBUG << "Queried PCI bus ID: " << pci_bus_id << " for GPU " << mem.devId; } #endif if (runtime_ == FI_HMEM_NEURON) { diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index 0626636f..f5e991b2 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -104,20 +104,10 @@ nixlLibfabricTopology::discoverTopology() { NIXL_INFO << "Using simplified topology for " << provider_name << " devices (no topology mapping needed)"; - // Still discover GPUs even in simplified mode for GPU memory registration - status = initHwlocTopology(); - if (status == NIXL_SUCCESS) { - status = discoverAccelWithHwloc(); - if (status != NIXL_SUCCESS) { - NIXL_WARN << "GPU discovery failed in simplified topology mode"; - // Not a fatal error - continue without GPUs - } - cleanupHwlocTopology(); - } else { - NIXL_WARN << "hwloc initialization failed - no GPU detection available"; - } - + // Set basic values without hwloc discovery + num_aws_accel = 0; // TCP doesn't need accelerator topology num_numa_nodes = 1; // Simple fallback + // For TCP/sockets devices, no accelerator-mapping required. NIXL_INFO << "TCP devices available globally - no accelerator-specific mapping required"; } From d5fcb0afc2eb9c7143d6d8a3e6a335b6ad57b095 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Tue, 17 Mar 2026 13:34:21 +0200 Subject: [PATCH 08/10] feat: enhance libfabric support for CUDA and ROCr --- src/plugins/libfabric/libfabric_backend.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/libfabric/libfabric_backend.cpp b/src/plugins/libfabric/libfabric_backend.cpp index fc568543..515a6113 100644 --- a/src/plugins/libfabric/libfabric_backend.cpp +++ b/src/plugins/libfabric/libfabric_backend.cpp @@ -312,7 +312,7 @@ nixlLibfabricEngine::nixlLibfabricEngine(const nixlBackendInitParams *init_param "SYSTEM"); #ifdef HAVE_CUDA - if (runtime_ == FI_HMEM_CUDA) { + if (runtime_ == FI_HMEM_CUDA || runtime_ == FI_HMEM_ROCR) { // Initialize CUDA context management vramInitCtx(); // CUDA address workaround @@ -670,7 +670,7 @@ nixlLibfabricEngine::getSupportedMems() const { nixl_mem_list_t mems; mems.push_back(DRAM_SEG); #ifdef HAVE_CUDA - if (runtime_ == FI_HMEM_CUDA) { + if (runtime_ == FI_HMEM_CUDA || runtime_ == FI_HMEM_ROCR) { NIXL_DEBUG << "CUDA runtime detected, adding VRAM support"; mems.push_back(VRAM_SEG); } else { @@ -759,7 +759,7 @@ nixlLibfabricEngine::registerMem(const nixlBlobDesc &mem, #ifdef HAVE_CUDA // Set CUDA context before libfabric operations for VRAM - if (nixl_mem == VRAM_SEG && runtime_ == FI_HMEM_CUDA) { + if (nixl_mem == VRAM_SEG && (runtime_ == FI_HMEM_CUDA || runtime_ == FI_HMEM_ROCR)) { vramApplyCtx(); } #endif From 3bc5832e4131272816a35db3ad57d8129b230408 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Thu, 23 Apr 2026 08:16:58 +0000 Subject: [PATCH 09/10] tests: make topology test work with verbs;ofi_rxd provider on MI300X machine --- .codespellrc | 2 +- src/utils/libfabric/libfabric_common.cpp | 2 + src/utils/libfabric/libfabric_rail.cpp | 5 + src/utils/libfabric/libfabric_topology.cpp | 53 +- src/utils/libfabric/libfabric_topology.h | 2 + .../libfabric/libfabric_topology_test.cpp | 96 +- .../unit/utils/libfabric/topo/mi300x-topo.xml | 2696 +++++++++++++++++ 7 files changed, 2831 insertions(+), 25 deletions(-) create mode 100644 test/unit/utils/libfabric/topo/mi300x-topo.xml diff --git a/.codespellrc b/.codespellrc index b9251751..8187fdbe 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,2 +1,2 @@ [codespell] -ignore-words-list = crate, trait, dyn, async +ignore-words-list = crate, trait, dyn, async, hsa diff --git a/src/utils/libfabric/libfabric_common.cpp b/src/utils/libfabric/libfabric_common.cpp index c1127cc9..e279d310 100644 --- a/src/utils/libfabric/libfabric_common.cpp +++ b/src/utils/libfabric/libfabric_common.cpp @@ -102,6 +102,8 @@ getAvailableNetworkDevices() { return {"cxi", provider_device_map["cxi"]}; } else if (provider_device_map.find("efa") != provider_device_map.end()) { return {"efa", provider_device_map["efa"]}; + } else if (provider_device_map.find("verbs;ofi_rxd") != provider_device_map.end()) { + return {"verbs;ofi_rxd", provider_device_map["verbs;ofi_rxd"]}; } else if (provider_device_map.find("tcp") != provider_device_map.end()) { return {"tcp", {provider_device_map["tcp"][0]}}; } else if (provider_device_map.find("sockets") != provider_device_map.end()) { diff --git a/src/utils/libfabric/libfabric_rail.cpp b/src/utils/libfabric/libfabric_rail.cpp index b7937e7f..0d531507 100644 --- a/src/utils/libfabric/libfabric_rail.cpp +++ b/src/utils/libfabric/libfabric_rail.cpp @@ -424,6 +424,11 @@ nixlLibfabricRail::nixlLibfabricRail(const std::string &device, hints->caps |= FI_RMA_EVENT; hints->domain_attr->mr_mode = FI_MR_LOCAL | FI_MR_HMEM | FI_MR_VIRT_ADDR | FI_MR_ALLOCATED | FI_MR_PROV_KEY | FI_MR_ENDPOINT; + } else if (provider == "verbs;ofi_rxd") { + // // Verbs;ofi_rxd reports mr_mode=[] (basic), let provider negotiate mr_mode + // hints->domain_attr->mr_mode = FI_MR_LOCAL | FI_MR_ALLOCATED; + hints->domain_attr->mr_mode = + FI_MR_LOCAL | FI_MR_HMEM | FI_MR_VIRT_ADDR | FI_MR_ALLOCATED | FI_MR_PROV_KEY; } else { // EFA and other providers support advanced memory registration hints->domain_attr->mr_mode = diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index c101ab25..6bae900a 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -80,13 +80,13 @@ nixlLibfabricTopology::discoverTopology() { if (status != NIXL_SUCCESS) { return status; } - // For EFA devices, build PCIe to Libfabric device mapping and full topology - if (provider_name == "efa") { + // For EFA and verbs devices, build PCIe to Libfabric device mapping and full topology + if (provider_name == "efa" || provider_name == "verbs;ofi_rxd") { // Build PCIe to Libfabric device mapping status = buildPcieToLibfabricMapping(); if (status != NIXL_SUCCESS) { - NIXL_ERROR << "Failed to build PCIe to Libfabric mapping - this is required for EFA " - "topology discovery"; + NIXL_ERROR << "Failed to build PCIe to Libfabric mapping - this is required for " + << provider_name << " topology discovery"; return status; } // Discover hardware topology using hwloc @@ -99,7 +99,7 @@ nixlLibfabricTopology::discoverTopology() { if (num_nvidia_accel > 0 || num_amd_accel > 0) { status = buildAccelToEfaMapping(); if (status != NIXL_SUCCESS) { - NIXL_ERROR << "Failed to build accelerator to EFA mapping"; + NIXL_ERROR << "Failed to build accelerator to NIC mapping"; return status; } } @@ -133,6 +133,8 @@ nixlLibfabricTopology::discoverProviderWithDevices() { // Set device type based on discovered provider if (provider_name == "efa") { NIXL_INFO << "Discovered " << num_devices << " EFA devices"; + } else if (provider_name == "verbs;ofi_rxd") { + NIXL_INFO << "Discovered " << num_devices << " InfiniBand (verbs;ofi_rxd) devices"; } else if (provider_name == "tcp" || provider_name == "sockets") { NIXL_INFO << "Discovered " << num_devices << " " << provider_name << " devices (TCP fallback)"; @@ -455,25 +457,32 @@ nixlLibfabricTopology::discoverAccelWithHwloc() { return NIXL_SUCCESS; } +// The naming of the method and some variables not aligned anymore with +// the change to support verbs;ofi_rxd, but the logic is still valid +// for both EFA and verbs devices since both are PCIe devices discovered via hwloc. +// We can refactor the naming in a future cleanup if needed. nixl_status_t nixlLibfabricTopology::discoverEfaDevicesWithHwloc() { - // EFA devices are already discovered via libfabric + // Network devices are already discovered via libfabric // This method validates the hwloc discovery matches libfabric discovery - int hwloc_efa_count = 0; + int hwloc_nic_count = 0; hwloc_obj_t pci_obj = nullptr; while ((pci_obj = hwloc_get_next_pcidev(hwloc_topology, pci_obj)) != nullptr) { - if (isEfaDevice(pci_obj)) { - hwloc_efa_count++; - NIXL_TRACE << "Found EFA device via hwloc: " << getPcieAddressFromHwlocObj(pci_obj); + bool is_target_device = (provider_name == "verbs;ofi_rxd") ? isInfiniBandDevice(pci_obj) + : isEfaDevice(pci_obj); + if (is_target_device) { + hwloc_nic_count++; + NIXL_TRACE << "Found " << provider_name + << " device via hwloc: " << getPcieAddressFromHwlocObj(pci_obj); } } - NIXL_TRACE << "hwloc found " << hwloc_efa_count << " EFA devices, libfabric found " - << num_devices; + NIXL_TRACE << "hwloc found " << hwloc_nic_count << " " << provider_name + << " devices, libfabric found " << num_devices; - if (hwloc_efa_count != num_devices) { - NIXL_DEBUG << "Mismatch between hwloc (" << hwloc_efa_count << ") and libfabric (" - << num_devices << ") EFA device counts"; + if (hwloc_nic_count != num_devices) { + NIXL_DEBUG << "Mismatch between hwloc (" << hwloc_nic_count << ") and libfabric (" + << num_devices << ") " << provider_name << " device counts"; } return NIXL_SUCCESS; @@ -795,6 +804,20 @@ nixlLibfabricTopology::isEfaDevice(hwloc_obj_t obj) const { (obj->attr->pcidev.device_id & 0xfff0) == 0xefa0; } +bool +nixlLibfabricTopology::isInfiniBandDevice(hwloc_obj_t obj) const { + if (!obj || obj->type != HWLOC_OBJ_PCI_DEVICE) { + return false; + } + NIXL_TRACE << "Checking isInfiniBandDevice on device " << std::hex << std::showbase + << obj->attr->pcidev.vendor_id << " " << obj->attr->pcidev.device_id; + + // Mellanox/NVIDIA InfiniBand HCA vendor ID is 0x15b3 + // PCI class 0x0c06 identifies InfiniBand controllers + return obj->attr->pcidev.vendor_id == 0x15b3 && + obj->attr->pcidev.class_id == 0x0c06; +} + size_t nixlLibfabricTopology::getPcieDevSpeed(const std::string &pcie_addr) { size_t speed = 0; diff --git a/src/utils/libfabric/libfabric_topology.h b/src/utils/libfabric/libfabric_topology.h index 2b77e7dd..e49cbea5 100644 --- a/src/utils/libfabric/libfabric_topology.h +++ b/src/utils/libfabric/libfabric_topology.h @@ -147,6 +147,8 @@ class nixlLibfabricTopology { isAmdAccel(hwloc_obj_t obj) const; bool isEfaDevice(hwloc_obj_t obj) const; + bool + isInfiniBandDevice(hwloc_obj_t obj) const; // retrieves line speed of NIC from map size_t diff --git a/test/unit/utils/libfabric/libfabric_topology_test.cpp b/test/unit/utils/libfabric/libfabric_topology_test.cpp index 36d7c3f8..dd1127fc 100644 --- a/test/unit/utils/libfabric/libfabric_topology_test.cpp +++ b/test/unit/utils/libfabric/libfabric_topology_test.cpp @@ -20,6 +20,8 @@ #include "libfabric/libfabric_common.h" #include "libfabric/libfabric_rail_manager.h" #include "common/nixl_log.h" +#include "absl/log/globals.h" +#include "absl/log/initialize.h" #ifdef CUDA_FOUND #ifdef __HIP_PLATFORM_AMD__ @@ -186,7 +188,44 @@ static TopologyInfo topologies[] = { .numa_capacity = 32, // topmost switch on g6 report link speed 32 GB/s .numa_rail_count = 1, // should default to all rails, which is 1 .test_scenarios = {{false, 0}, {true, 50}, {true, 100}, {true, 200}}, - .rail_partition = {{{0}}, {{0}}}} // pretending single switch in each node, both using rail 0 + .rail_partition = {{{0}}, {{0}}}}, // pretending single switch in each node, both using rail 0 + + // + // AMD MI300X (verbs;ofi_rxd provider - RoCE) + // + + // MI300X with 8x Broadcom bnxt_re (400Gbps) + 2x Mellanox ConnectX-6 Dx (100Gbps) + // 2 NUMA nodes: NUMA 0 has bnxt_re0-3 + mlx5_0-1, NUMA 1 has bnxt_re4-7 + // Each bnxt_re NIC is behind its own PCIe switch with 63 GB/s upstream link + // bnxt_re1, mlx5_0, and mlx5_1 share a topmost PCIe switch (bus 0x20) + // Topmost switches per NUMA node: 4 (NUMA0: 0x00, 0x20, 0x40, 0x60; + // NUMA1: 0x80, 0xa0, 0xc0, 0xe0) + // Rail assignment (from NicMap iteration order in rail manager): + // 0:bnxt_re5 1:bnxt_re7 2:bnxt_re3 3:bnxt_re6 4:bnxt_re4 5:bnxt_re2 + // 6:mlx5_0 7:mlx5_1 8:bnxt_re1 9:bnxt_re0 + // NOTE: 2000 Gbps (5-rail) scenario skipped because non-uniform NUMA device count + // (6 on NUMA0 vs 4 on NUMA1) breaks test validation's full_node_rail_count assumption + {.enable = true, + .instance_type = "mi300x", + .topo_file = "mi300x-topo.xml", + // .provider = "verbs;ofi_rxd", + .numa_node_count = 2, + .nic_count = 10, // 8 bnxt_re + 2 mlx5 + .nic_line_speed = 400, // dominant NIC speed (bnxt_re), mlx5 are 100Gbps + .nic_upstream_link_speed = 56, // average: (8*504 + 2*252)/10 = 453.6 Gbps / 8 = ~56 GB/s + .switch_count = 4, // 4 topmost PCIe switches per NUMA node + .numa_capacity = 252, // 2020 Gbps / 8 = ~252 GB/s per NUMA node + .numa_rail_count = 4, // 2020 Gbps / 453 Gbps avg upstream = ~4 rails per NUMA node + .test_scenarios = {{false, 0}, + {true, 400}, + {true, 800}, + {true, 1200}, + {true, 2400}, + {true, 2800}, + {true, 3200}, + {true, 4000}}, + .rail_partition = {{{9}, {6, 7, 8}, {5}, {2}}, // NUMA 0: bus 0x00, 0x20, 0x40, 0x60 + {{4}, {0}, {3}, {1}}}} // end of list }; @@ -254,6 +293,16 @@ testNumaDramRailSelectionPolicy(const char *instance_type); int main(int argc, char *argv[]) { + // NIXL_LOG_LEVEL=TRACE didn't work without this, not sure why - maybe some + // static initialization order issue with absl logging + // or resulting log file size (~20MB log file generated with NIXL_LOG_LEVEL=TRACE) + const char *log_level = getenv("NIXL_LOG_LEVEL"); + if (log_level && std::string(log_level) == "TRACE") { + absl::SetVLogLevel("*", 2); + absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo); + } + absl::InitializeLog(); + if (argc > 1) { // testing for NUMA-aware rail selection for DRAM_SEG // the only parameter is the instance type @@ -348,6 +397,20 @@ isEfaDevice(hwloc_obj_t obj) { (obj->attr->pcidev.device_id & 0xfff0) == 0xefa0; } +static bool +isVerbsDevice(hwloc_obj_t obj) { + // Match RDMA-capable Ethernet devices that appear as OpenFabrics OS devices: + // - Mellanox/NVIDIA ConnectX (vendor 0x15b3) with Ethernet class (0x0200) + // - Broadcom bnxt_re (vendor 0x14e4) with Ethernet class (0x0200) + if (obj->attr->pcidev.vendor_id == 0x15b3 || + obj->attr->pcidev.vendor_id == 0x14e4) { + return true; + } + // Also match native InfiniBand (class 0x0c06) + return obj->attr->pcidev.vendor_id == 0x15b3 && + obj->attr->pcidev.class_id == 0x0c06; +} + // hwloc helper methods static std::string getPcieAddressFromHwlocPcidev(const hwloc_obj_attr_u::hwloc_pcidev_attr_s &pcidev) { @@ -380,7 +443,7 @@ getNicData(NicData &nic, hwloc_obj_t pci_obj) { } static int -getEfaDeviceNamesFromHwloc(NicMap &nic_map) { +getNicDeviceNamesFromHwloc(NicMap &nic_map) { // when testing we load topologies form XML, so we cannot mix that with local machine info that // comes from libfabric's fi_getinfo() - instead we discover network devices from hwloc, but // that is also missing NIC card line speed that comes in multiples of 1000^3. currently this @@ -423,7 +486,11 @@ getEfaDeviceNamesFromHwloc(NicMap &nic_map) { return 3; } - // get PCI device list, check if EFA, and build map + // get PCI device list, check if target device type, and build map + + // It is bad approach to use instance_type for provider identification, + // but the PR goal is showcasing working topology. + bool use_verbs = (strcmp(curr_topology->instance_type, "mi300x") == 0); hwloc_obj_t os_obj = nullptr; while ((os_obj = hwloc_get_next_osdev(hwloc_topology, os_obj)) != nullptr) { if (os_obj->attr->osdev.type == HWLOC_OBJ_OSDEV_OPENFABRICS) { @@ -433,7 +500,8 @@ getEfaDeviceNamesFromHwloc(NicMap &nic_map) { << " parent is not a PCI device, skipping"; continue; } - if (isEfaDevice(pci_obj)) { + bool is_target = use_verbs ? isVerbsDevice(pci_obj) : isEfaDevice(pci_obj); + if (is_target) { NicData &nic = nic_map[os_obj->name]; nic.name = os_obj->name; getNicData(nic, pci_obj); @@ -589,7 +657,7 @@ __wrap_fi_getinfo(uint32_t version, // load topology from XML file and feed result into fi_getinfo NicMap nic_map; - int res = getEfaDeviceNamesFromHwloc(nic_map); + int res = getNicDeviceNamesFromHwloc(nic_map); if (res != 0) { return res; } @@ -603,11 +671,21 @@ __wrap_fi_getinfo(uint32_t version, } itr->domain_attr = malloc_zero(); - itr->domain_attr->name = strdup(entry.second.name.c_str()); - itr->fabric_attr = malloc_zero(); - itr->fabric_attr->prov_name = strdup("efa"); - itr->fabric_attr->name = strdup("efa"); + + // MI300X instance uses verbs;ofi_rxd provider, its domain names have a "-dgram" suffix + // It is bad approach to use instance_type for provider identification, + // but the PR goal is showcasing working topology. + if (strcmp(curr_topology->instance_type, "mi300x") == 0) { + std::string domain_name = entry.second.name + "-dgram"; + itr->domain_attr->name = strdup(domain_name.c_str()); + itr->fabric_attr->prov_name = strdup("verbs;ofi_rxd"); + itr->fabric_attr->name = strdup("verbs;ofi_rxd"); + } else { + itr->domain_attr->name = strdup(entry.second.name.c_str()); + itr->fabric_attr->prov_name = strdup("efa"); + itr->fabric_attr->name = strdup("efa"); + } itr->ep_attr = malloc_zero(); itr->ep_attr->type = FI_EP_RDM; diff --git a/test/unit/utils/libfabric/topo/mi300x-topo.xml b/test/unit/utils/libfabric/topo/mi300x-topo.xml new file mode 100644 index 00000000..9ddd54ad --- /dev/null +++ b/test/unit/utils/libfabric/topo/mi300x-topo.xml @@ -0,0 +1,2696 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 1 + 10 32 32 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From de7d9a23b26b51c832da38dcb7bfa88ebb3af0f5 Mon Sep 17 00:00:00 2001 From: Matvei Pashkovskii Date: Fri, 24 Apr 2026 07:08:41 +0000 Subject: [PATCH 10/10] fix: switch from 'verbs;ofi_rxd' to 'verbs;ofi_rxm' provider in libfabric topology and tests --- src/utils/libfabric/libfabric_common.cpp | 4 +- src/utils/libfabric/libfabric_rail.cpp | 5 -- src/utils/libfabric/libfabric_topology.cpp | 29 ++++++------ .../libfabric/libfabric_topology_test.cpp | 46 ++++++------------- 4 files changed, 30 insertions(+), 54 deletions(-) diff --git a/src/utils/libfabric/libfabric_common.cpp b/src/utils/libfabric/libfabric_common.cpp index e279d310..0f963a7d 100644 --- a/src/utils/libfabric/libfabric_common.cpp +++ b/src/utils/libfabric/libfabric_common.cpp @@ -102,8 +102,8 @@ getAvailableNetworkDevices() { return {"cxi", provider_device_map["cxi"]}; } else if (provider_device_map.find("efa") != provider_device_map.end()) { return {"efa", provider_device_map["efa"]}; - } else if (provider_device_map.find("verbs;ofi_rxd") != provider_device_map.end()) { - return {"verbs;ofi_rxd", provider_device_map["verbs;ofi_rxd"]}; + } else if (provider_device_map.find("verbs;ofi_rxm") != provider_device_map.end()) { + return {"verbs;ofi_rxm", provider_device_map["verbs;ofi_rxm"]}; } else if (provider_device_map.find("tcp") != provider_device_map.end()) { return {"tcp", {provider_device_map["tcp"][0]}}; } else if (provider_device_map.find("sockets") != provider_device_map.end()) { diff --git a/src/utils/libfabric/libfabric_rail.cpp b/src/utils/libfabric/libfabric_rail.cpp index 0d531507..b7937e7f 100644 --- a/src/utils/libfabric/libfabric_rail.cpp +++ b/src/utils/libfabric/libfabric_rail.cpp @@ -424,11 +424,6 @@ nixlLibfabricRail::nixlLibfabricRail(const std::string &device, hints->caps |= FI_RMA_EVENT; hints->domain_attr->mr_mode = FI_MR_LOCAL | FI_MR_HMEM | FI_MR_VIRT_ADDR | FI_MR_ALLOCATED | FI_MR_PROV_KEY | FI_MR_ENDPOINT; - } else if (provider == "verbs;ofi_rxd") { - // // Verbs;ofi_rxd reports mr_mode=[] (basic), let provider negotiate mr_mode - // hints->domain_attr->mr_mode = FI_MR_LOCAL | FI_MR_ALLOCATED; - hints->domain_attr->mr_mode = - FI_MR_LOCAL | FI_MR_HMEM | FI_MR_VIRT_ADDR | FI_MR_ALLOCATED | FI_MR_PROV_KEY; } else { // EFA and other providers support advanced memory registration hints->domain_attr->mr_mode = diff --git a/src/utils/libfabric/libfabric_topology.cpp b/src/utils/libfabric/libfabric_topology.cpp index 6bae900a..cb2a5332 100644 --- a/src/utils/libfabric/libfabric_topology.cpp +++ b/src/utils/libfabric/libfabric_topology.cpp @@ -81,7 +81,7 @@ nixlLibfabricTopology::discoverTopology() { return status; } // For EFA and verbs devices, build PCIe to Libfabric device mapping and full topology - if (provider_name == "efa" || provider_name == "verbs;ofi_rxd") { + if (provider_name == "efa" || provider_name == "verbs;ofi_rxm") { // Build PCIe to Libfabric device mapping status = buildPcieToLibfabricMapping(); if (status != NIXL_SUCCESS) { @@ -110,6 +110,7 @@ nixlLibfabricTopology::discoverTopology() { // Set basic values without hwloc discovery num_nvidia_accel = 0; // TCP doesn't need accelerator topology + num_amd_accel = 0; // TCP doesn't need accelerator topology num_aws_accel = 0; // TCP doesn't need accelerator topology num_numa_nodes = 1; // Simple fallback @@ -133,8 +134,8 @@ nixlLibfabricTopology::discoverProviderWithDevices() { // Set device type based on discovered provider if (provider_name == "efa") { NIXL_INFO << "Discovered " << num_devices << " EFA devices"; - } else if (provider_name == "verbs;ofi_rxd") { - NIXL_INFO << "Discovered " << num_devices << " InfiniBand (verbs;ofi_rxd) devices"; + } else if (provider_name == "verbs;ofi_rxm") { + NIXL_INFO << "Discovered " << num_devices << " InfiniBand (" << provider_name << ") devices"; } else if (provider_name == "tcp" || provider_name == "sockets") { NIXL_INFO << "Discovered " << num_devices << " " << provider_name << " devices (TCP fallback)"; @@ -168,7 +169,7 @@ nixlLibfabricTopology::getEfaDevicesForPci(const std::string &pci_bus_id) const // GPU query, lookup based on GPU BDF if (auto it = pci_to_efa_devices.find(normalized_id); it != pci_to_efa_devices.end()) { - NIXL_DEBUG << "Found EFA devices for PCI " << pci_bus_id << " (normalized to " + NIXL_DEBUG << "Found EFA/IB devices for PCI " << pci_bus_id << " (normalized to " << normalized_id << ")"; return it->second; } @@ -176,14 +177,14 @@ nixlLibfabricTopology::getEfaDevicesForPci(const std::string &pci_bus_id) const // Neuron query, lookup based on EFA BDF if (auto it = pcie_to_libfabric_map.find(normalized_id); it != pcie_to_libfabric_map.end()) { - NIXL_DEBUG << "Found EFA devices for PCI " << pci_bus_id << " (normalized to " + NIXL_DEBUG << "Found EFA/IB devices for PCI " << pci_bus_id << " (normalized to " << normalized_id << ")"; return {it->second}; } // PCI ID parsed successfully but not found in mapping NIXL_WARN << "PCI bus ID " << pci_bus_id << " (normalized to " << normalized_id - << ") not found in accelerator-EFA mapping, returning all devices"; + << ") not found in accelerator-EFA/IB mapping, returning all devices"; } else { // Failed to parse PCI bus ID format NIXL_WARN << "Failed to parse PCI bus ID format: " << pci_bus_id @@ -260,12 +261,12 @@ nixlLibfabricTopology::printTopologyInfo() const { NIXL_TRACE << "Number of AMD accelerators: " << num_amd_accel; NIXL_TRACE << "Number of AWS Neuron accelerators: " << num_aws_accel; NIXL_TRACE << "Number of NUMA nodes: " << num_numa_nodes; - NIXL_TRACE << "Number of EFA devices: " << num_devices; - NIXL_TRACE << "EFA devices: "; + NIXL_TRACE << "Number of EFA/IB devices: " << num_devices; + NIXL_TRACE << "EFA/IB devices: "; for (size_t i = 0; i < all_devices.size(); ++i) { NIXL_TRACE << " [" << i << "] " << all_devices[i]; } - NIXL_TRACE << "Accelerator-PCI → EFA mapping:"; + NIXL_TRACE << "Accelerator-PCI → EFA/IB mapping:"; for (const auto &pair : pci_to_efa_devices) { std::stringstream ss; ss << " Accelerator-PCI " << pair.first << " → ["; @@ -276,7 +277,7 @@ nixlLibfabricTopology::printTopologyInfo() const { ss << "]"; NIXL_TRACE << ss.str(); } - NIXL_TRACE << "Host memory (DRAM) will limit number of EFA devices used per-NUMA node " + NIXL_TRACE << "Host memory (DRAM) will limit number of EFA/IB devices used per-NUMA node " "according to maximum PCIe switch bandwidth"; NIXL_TRACE << "====================================="; } @@ -457,10 +458,6 @@ nixlLibfabricTopology::discoverAccelWithHwloc() { return NIXL_SUCCESS; } -// The naming of the method and some variables not aligned anymore with -// the change to support verbs;ofi_rxd, but the logic is still valid -// for both EFA and verbs devices since both are PCIe devices discovered via hwloc. -// We can refactor the naming in a future cleanup if needed. nixl_status_t nixlLibfabricTopology::discoverEfaDevicesWithHwloc() { // Network devices are already discovered via libfabric @@ -468,8 +465,8 @@ nixlLibfabricTopology::discoverEfaDevicesWithHwloc() { int hwloc_nic_count = 0; hwloc_obj_t pci_obj = nullptr; while ((pci_obj = hwloc_get_next_pcidev(hwloc_topology, pci_obj)) != nullptr) { - bool is_target_device = (provider_name == "verbs;ofi_rxd") ? isInfiniBandDevice(pci_obj) - : isEfaDevice(pci_obj); + bool is_target_device = (provider_name == "verbs;ofi_rxm") ? isInfiniBandDevice(pci_obj) + : isEfaDevice(pci_obj); if (is_target_device) { hwloc_nic_count++; NIXL_TRACE << "Found " << provider_name diff --git a/test/unit/utils/libfabric/libfabric_topology_test.cpp b/test/unit/utils/libfabric/libfabric_topology_test.cpp index dd1127fc..5962262e 100644 --- a/test/unit/utils/libfabric/libfabric_topology_test.cpp +++ b/test/unit/utils/libfabric/libfabric_topology_test.cpp @@ -20,8 +20,6 @@ #include "libfabric/libfabric_common.h" #include "libfabric/libfabric_rail_manager.h" #include "common/nixl_log.h" -#include "absl/log/globals.h" -#include "absl/log/initialize.h" #ifdef CUDA_FOUND #ifdef __HIP_PLATFORM_AMD__ @@ -46,6 +44,7 @@ struct TopologyInfo { bool enable; const char *instance_type; const char *topo_file; + const char *provider; size_t numa_node_count; size_t nic_count; size_t nic_line_speed; // Gbps 1000^3 @@ -68,6 +67,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "p3dn.24xl", .topo_file = "p3dn.24xl-topo.xml", + .provider = "efa", .numa_node_count = 0, // no NIC is attached to NUMA node, the only NIC is attached to machine .nic_count = 1, .nic_line_speed = 100, @@ -82,6 +82,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "p4d.24xl", .topo_file = "p4d.24xl-topo.xml", + .provider = "efa", .numa_node_count = 2, .nic_count = 4, .nic_line_speed = 100, @@ -98,6 +99,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "p5.48xl", .topo_file = "p5.48xl-topo.xml", + .provider = "efa", .numa_node_count = 2, .nic_count = 32, .nic_line_speed = 100, @@ -120,6 +122,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "p5en.48xl", .topo_file = "p5en.48xl-topo.xml", + .provider = "efa", .numa_node_count = 2, .nic_count = 16, .nic_line_speed = 200, @@ -140,6 +143,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "p6-b200.48xl", .topo_file = "p6-b200.48xl-topo.xml", + .provider = "efa", .numa_node_count = 2, .nic_count = 8, .nic_line_speed = 400, @@ -166,6 +170,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "g5.48xl", .topo_file = "g5.48xl-topo.xml", + .provider = "efa", .numa_node_count = 0, // no NIC is attached to NUMA node, the only NIC is attached to machine .nic_count = 1, .nic_line_speed = 100, @@ -180,6 +185,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "g6.48xl", .topo_file = "g6.48xl-topo.xml", + .provider = "efa", .numa_node_count = 1, // single NIC is attached to a NUMA node .nic_count = 1, .nic_line_speed = 100, @@ -191,7 +197,7 @@ static TopologyInfo topologies[] = { .rail_partition = {{{0}}, {{0}}}}, // pretending single switch in each node, both using rail 0 // - // AMD MI300X (verbs;ofi_rxd provider - RoCE) + // AMD MI300X (verbs;ofi_rxm provider - RoCE) // // MI300X with 8x Broadcom bnxt_re (400Gbps) + 2x Mellanox ConnectX-6 Dx (100Gbps) @@ -208,7 +214,7 @@ static TopologyInfo topologies[] = { {.enable = true, .instance_type = "mi300x", .topo_file = "mi300x-topo.xml", - // .provider = "verbs;ofi_rxd", + .provider = "verbs;ofi_rxm", .numa_node_count = 2, .nic_count = 10, // 8 bnxt_re + 2 mlx5 .nic_line_speed = 400, // dominant NIC speed (bnxt_re), mlx5 are 100Gbps @@ -293,16 +299,6 @@ testNumaDramRailSelectionPolicy(const char *instance_type); int main(int argc, char *argv[]) { - // NIXL_LOG_LEVEL=TRACE didn't work without this, not sure why - maybe some - // static initialization order issue with absl logging - // or resulting log file size (~20MB log file generated with NIXL_LOG_LEVEL=TRACE) - const char *log_level = getenv("NIXL_LOG_LEVEL"); - if (log_level && std::string(log_level) == "TRACE") { - absl::SetVLogLevel("*", 2); - absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo); - } - absl::InitializeLog(); - if (argc > 1) { // testing for NUMA-aware rail selection for DRAM_SEG // the only parameter is the instance type @@ -373,7 +369,7 @@ testBasicTopology() { device_list += device; } NIXL_INFO << " GPU " << gpu_id << " (PCI: " << pci_bus_id << ") mapped to " - << gpu_devices.size() << " EFA devices: " << device_list; + << gpu_devices.size() << " EFA/IB devices: " << device_list; #else NIXL_INFO << " Skipping GPU " << gpu_id << " (CUDA not available)"; #endif @@ -488,9 +484,7 @@ getNicDeviceNamesFromHwloc(NicMap &nic_map) { // get PCI device list, check if target device type, and build map - // It is bad approach to use instance_type for provider identification, - // but the PR goal is showcasing working topology. - bool use_verbs = (strcmp(curr_topology->instance_type, "mi300x") == 0); + bool use_verbs = (strcmp(curr_topology->provider, "verbs;ofi_rxm") == 0); hwloc_obj_t os_obj = nullptr; while ((os_obj = hwloc_get_next_osdev(hwloc_topology, os_obj)) != nullptr) { if (os_obj->attr->osdev.type == HWLOC_OBJ_OSDEV_OPENFABRICS) { @@ -673,19 +667,9 @@ __wrap_fi_getinfo(uint32_t version, itr->domain_attr = malloc_zero(); itr->fabric_attr = malloc_zero(); - // MI300X instance uses verbs;ofi_rxd provider, its domain names have a "-dgram" suffix - // It is bad approach to use instance_type for provider identification, - // but the PR goal is showcasing working topology. - if (strcmp(curr_topology->instance_type, "mi300x") == 0) { - std::string domain_name = entry.second.name + "-dgram"; - itr->domain_attr->name = strdup(domain_name.c_str()); - itr->fabric_attr->prov_name = strdup("verbs;ofi_rxd"); - itr->fabric_attr->name = strdup("verbs;ofi_rxd"); - } else { - itr->domain_attr->name = strdup(entry.second.name.c_str()); - itr->fabric_attr->prov_name = strdup("efa"); - itr->fabric_attr->name = strdup("efa"); - } + itr->domain_attr->name = strdup(entry.second.name.c_str()); + itr->fabric_attr->prov_name = strdup(curr_topology->provider); + itr->fabric_attr->name = strdup(curr_topology->provider); itr->ep_attr = malloc_zero(); itr->ep_attr->type = FI_EP_RDM;