diff --git a/src/ucp/core/ucp_context.c b/src/ucp/core/ucp_context.c index 81bd0220d3a..e78c1d2cb11 100644 --- a/src/ucp/core/ucp_context.c +++ b/src/ucp/core/ucp_context.c @@ -629,7 +629,10 @@ static ucs_config_field_t ucp_context_config_table[] = { {"GPU_NIC_ASSIGNMENT_MODE", "auto", "Assign NICs to GPUs within each topology group, and restrict the lanes\n" "for a GPU's memory to the NICs assigned to that GPU.\n" - "All ports of a NIC are assigned together.\n" + "All ports of a NIC are assigned together, and all GPUs with the same PCI\n" + "address are assigned together (e.g. MLOPart partitions of a GPU).\n" + "NICs without memory registration and DPUs are skipped during assignment.\n" + "NICs excluded by UCX_NET_DEVICES or UCX_TLS are ignored.\n" "The 'flip', 'round_robin' and 'shared' modes apply on any hardware.\n" "With 'flip' and 'round_robin', a group with fewer NICs than GPUs leaves\n" "some GPUs without any NICs.\n" @@ -2783,16 +2786,67 @@ ucp_version_check(unsigned api_major_version, unsigned api_minor_version) ucs_debug("Configured with: %s", UCX_CONFIGURE_FLAGS); } -static ucs_status_t -ucp_context_gpu_nic_assignment_init(ucp_gpu_nic_assignment_mode_t mode, - ucp_gpu_nic_assignment_t **assignment_p) +static int +ucp_context_is_net_device_assignable(ucp_context_h context, + const ucp_tl_resource_desc_t *rsc) +{ + const uct_tl_resource_desc_t *resource = &rsc->tl_rsc; + const ucp_tl_md_t *md = &context->tl_mds[rsc->md_index]; + + if ((resource->dev_type != UCT_DEVICE_TYPE_NET) || + (resource->sys_device == UCS_SYS_DEVICE_ID_UNKNOWN)) { + return 0; + } + + if (rsc->flags & UCP_TL_RSC_FLAG_AUX) { + ucs_debug(UCT_TL_RESOURCE_DESC_FMT + " is ignored for gpu-nic assignment: auxiliary transport", + UCT_TL_RESOURCE_DESC_ARG(resource)); + return 0; + } + + if (!(md->attr.flags & UCT_MD_FLAG_REG)) { + ucs_debug(UCT_TL_RESOURCE_DESC_FMT + " is ignored for gpu-nic assignment: no memory registration", + UCT_TL_RESOURCE_DESC_ARG(resource)); + return 0; + } + + if (ucs_topo_sys_device_get_flags(resource->sys_device) & + UCS_TOPO_DEVICE_FLAG_DPU) { + ucs_debug(UCT_TL_RESOURCE_DESC_FMT + " is ignored for gpu-nic assignment: dpu device", + UCT_TL_RESOURCE_DESC_ARG(resource)); + return 0; + } + + ucs_trace(UCT_TL_RESOURCE_DESC_FMT " is used for gpu-nic assignment", + UCT_TL_RESOURCE_DESC_ARG(resource)); + return 1; +} + +static void ucp_context_gpu_nic_assignment_net_device_filter_init( + ucp_context_h context, ucs_sys_device_bitmap_t *net_device_filter) +{ + const ucp_tl_resource_desc_t *rsc; + + ucs_carray_for_each(rsc, context->tl_rscs, context->num_tls) { + if (ucp_context_is_net_device_assignable(context, rsc)) { + UCS_STATIC_BITMAP_SET(net_device_filter, rsc->tl_rsc.sys_device); + } + } +} + +static ucs_status_t ucp_context_gpu_nic_assignment_init(ucp_context_h context) { + ucp_gpu_nic_assignment_mode_t mode = + context->config.ext.gpu_nic_assignment_mode; + ucs_sys_device_bitmap_t net_device_filter = + UCS_STATIC_BITMAP_ZERO_INITIALIZER; ucp_gpu_nic_assignment_t *assignment; ucs_topo_groups_t groups; ucs_status_t status; - *assignment_p = NULL; - if (mode == UCP_GPU_NIC_ASSIGNMENT_MODE_AUTO) { /* TODO: Improve Vera Rubin detection by checking NICs/GPUs models. */ if (ucs_arch_get_cpu_model() != UCS_CPU_MODEL_NVIDIA_VERA) { @@ -2810,7 +2864,23 @@ ucp_context_gpu_nic_assignment_init(ucp_gpu_nic_assignment_mode_t mode, ucs_debug("gpu-nic assignment mode %s", ucp_gpu_nic_assignment_modes[mode]); - status = ucs_topo_build_groups(&groups); + ucp_context_gpu_nic_assignment_net_device_filter_init(context, + &net_device_filter); + if (UCS_STATIC_BITMAP_IS_ZERO(net_device_filter)) { + if (context->config.ext.gpu_nic_assignment_mode == + UCP_GPU_NIC_ASSIGNMENT_MODE_AUTO) { + ucs_diag("gpu-nic assignment is disabled: no assignable network " + "devices"); + return UCS_OK; + } + + ucs_error("no assignable network devices for gpu-nic assignment mode " + "%s, set UCX_GPU_NIC_ASSIGNMENT_MODE=off to disable it", + ucp_gpu_nic_assignment_modes[mode]); + return UCS_ERR_INVALID_PARAM; + } + + status = ucs_topo_build_groups(&net_device_filter, &groups); if (status != UCS_OK) { return status; } @@ -2833,7 +2903,7 @@ ucp_context_gpu_nic_assignment_init(ucp_gpu_nic_assignment_mode_t mode, goto out_release_groups; } - *assignment_p = assignment; + context->gpu_nic_assignment = assignment; out_release_groups: ucs_topo_release_groups(&groups); @@ -2894,9 +2964,7 @@ ucs_status_t ucp_init_version(unsigned api_major_version, unsigned api_minor_ver goto err_thread_lock_finalize; } - status = ucp_context_gpu_nic_assignment_init( - context->config.ext.gpu_nic_assignment_mode, - &context->gpu_nic_assignment); + status = ucp_context_gpu_nic_assignment_init(context); if (status != UCS_OK) { goto err_free_res; } diff --git a/src/ucp/core/ucp_gpu_nic_assignment.c b/src/ucp/core/ucp_gpu_nic_assignment.c index 682fc9f770e..c6308ac6d72 100644 --- a/src/ucp/core/ucp_gpu_nic_assignment.c +++ b/src/ucp/core/ucp_gpu_nic_assignment.c @@ -57,7 +57,7 @@ ucp_gpu_nic_assignment_get_gpu_idx(ucp_gpu_nic_assignment_mode_t mode, } static void -ucp_gpu_nic_bitmap_add_nic(ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap, +ucp_gpu_nic_bitmap_add_nic(ucs_sys_device_bitmap_t *nic_sys_dev_bitmap, const ucs_topo_group_element_t *nic) { const ucs_sys_device_t *nic_sys_dev; @@ -72,7 +72,7 @@ ucp_gpu_nic_bitmap_add_nic(ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap, } } -const ucp_gpu_nic_sys_dev_bitmap_t * +const ucs_sys_device_bitmap_t * ucp_gpu_nic_assignment_lookup(const ucp_gpu_nic_assignment_t *assignment, ucs_sys_device_t gpu_sys_dev) { @@ -135,12 +135,12 @@ static void ucp_gpu_nic_assignment_log_gpu(const ucp_gpu_nic_assignment_t *assignment, const ucs_topo_group_t *group, const ucs_topo_group_element_t *gpu, - ucp_gpu_nic_sys_dev_bitmap_t *assigned_nics) + ucs_sys_device_bitmap_t *assigned_nics) { UCS_STRING_BUFFER_ONSTACK(gpu_strb, 128); UCP_GPU_NIC_STRING_BUFFERS_ONSTACK(nic_strbs, 256); char bdf_name[UCS_SYS_BDF_NAME_MAX]; - const ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap; + const ucs_sys_device_bitmap_t *nic_sys_dev_bitmap; const ucs_topo_group_element_t *nic; ucs_assert((gpu->num_sys_devs > 0) && @@ -182,7 +182,7 @@ ucp_gpu_nic_assignment_log_gpu(const ucp_gpu_nic_assignment_t *assignment, static void ucp_gpu_nic_assignment_log_unassigned_nics( const ucs_topo_groups_t *groups, - const ucp_gpu_nic_sys_dev_bitmap_t *assigned_nics) + const ucs_sys_device_bitmap_t *assigned_nics) { UCP_GPU_NIC_STRING_BUFFERS_ONSTACK(nic_strbs, 256); const ucs_topo_group_element_t *nic; @@ -211,8 +211,7 @@ static void ucp_gpu_nic_assignment_log(const ucp_gpu_nic_assignment_t *assignment, const ucs_topo_groups_t *groups) { - ucp_gpu_nic_sys_dev_bitmap_t assigned_nics = - UCS_STATIC_BITMAP_ZERO_INITIALIZER; + ucs_sys_device_bitmap_t assigned_nics = UCS_STATIC_BITMAP_ZERO_INITIALIZER; const ucs_topo_group_element_t *gpu; const ucs_topo_group_t *group; @@ -331,13 +330,13 @@ ucp_gpu_nic_assignment_add_nic_to_gpu(ucp_gpu_nic_assignment_t *assignment, const ucs_topo_group_element_t *gpu, const ucs_topo_group_element_t *nic) { - ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap; + ucs_sys_device_bitmap_t *nic_sys_dev_bitmap; ucs_assert((gpu->num_sys_devs > 0) && (gpu->sys_devs[0] != UCS_SYS_DEVICE_ID_UNKNOWN)); nic_sys_dev_bitmap = ucs_const_cast( - ucp_gpu_nic_sys_dev_bitmap_t*, + ucs_sys_device_bitmap_t*, ucp_gpu_nic_assignment_lookup(assignment, gpu->sys_devs[0])); ucs_assert(nic_sys_dev_bitmap != NULL); @@ -404,7 +403,7 @@ ucp_gpu_nic_assignment_build(const ucs_topo_groups_t *groups, return UCS_OK; } -int ucp_gpu_nic_bitmap_get(const ucp_gpu_nic_sys_dev_bitmap_t *bitmap, +int ucp_gpu_nic_bitmap_get(const ucs_sys_device_bitmap_t *bitmap, ucs_sys_device_t net_sys_dev) { ucs_assert(bitmap != NULL); diff --git a/src/ucp/core/ucp_gpu_nic_assignment.h b/src/ucp/core/ucp_gpu_nic_assignment.h index ff39dbe476a..c0a3dffba5f 100644 --- a/src/ucp/core/ucp_gpu_nic_assignment.h +++ b/src/ucp/core/ucp_gpu_nic_assignment.h @@ -21,13 +21,9 @@ BEGIN_C_DECLS #define UCP_GPU_NIC_BITMAP_INDEX_INVALID UCS_SYS_DEVICE_ID_COUNT -typedef ucs_static_bitmap_s(UCS_SYS_DEVICE_ID_COUNT) - ucp_gpu_nic_sys_dev_bitmap_t; - - struct ucp_gpu_nic_assignment { /* NIC sys_dev bitmaps referenced by bitmap_idx_by_gpu_sys_dev. */ - ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmaps; + ucs_sys_device_bitmap_t *nic_sys_dev_bitmaps; /* Number of entries in nic_sys_dev_bitmaps. */ size_t num_bitmaps; @@ -66,7 +62,7 @@ ucp_gpu_nic_assignment_build(const ucs_topo_groups_t *groups, * has no assigned NICs. Returns NULL if @a gpu_sys_dev is unknown or * is not represented in the assignment. */ -const ucp_gpu_nic_sys_dev_bitmap_t * +const ucs_sys_device_bitmap_t * ucp_gpu_nic_assignment_lookup(const ucp_gpu_nic_assignment_t *assignment, ucs_sys_device_t gpu_sys_dev); @@ -80,7 +76,7 @@ ucp_gpu_nic_assignment_lookup(const ucp_gpu_nic_assignment_t *assignment, * @return Nonzero if @a net_sys_dev is present in @a bitmap, or zero if the * system device is unknown or the bit is not set. */ -int ucp_gpu_nic_bitmap_get(const ucp_gpu_nic_sys_dev_bitmap_t *bitmap, +int ucp_gpu_nic_bitmap_get(const ucs_sys_device_bitmap_t *bitmap, ucs_sys_device_t net_sys_dev); diff --git a/src/ucp/core/ucp_types.h b/src/ucp/core/ucp_types.h index 161ddb4601b..72d6ea4946f 100644 --- a/src/ucp/core/ucp_types.h +++ b/src/ucp/core/ucp_types.h @@ -249,6 +249,9 @@ typedef enum { * across the N GPUs of the group. * The group's NICs are assigned to the following GPU indices in order: * 0, 1, ..., N-1, N-1, ..., 1, 0, 0, 1, ... + * This targets architectures where only some of the NICs share a PCIe + * switch with a local SSD, so that each GPU gets NICs both with and without + * direct SSD access. */ UCP_GPU_NIC_ASSIGNMENT_MODE_FLIP, diff --git a/src/ucs/sys/topo/base/topo.c b/src/ucs/sys/topo/base/topo.c index d8c7be4eaa1..0295ab8744f 100644 --- a/src/ucs/sys/topo/base/topo.c +++ b/src/ucs/sys/topo/base/topo.c @@ -517,6 +517,7 @@ ucs_topo_find_device_by_bus_id_value(const ucs_sys_bus_id_t *bus_id, device->pci_id = pci_id; device->user_value = user_value; device->device_class = UCS_TOPO_DEVICE_CLASS_UNKNOWN; + device->flags = 0; device->class_ordinal = UCS_SYS_DEVICE_ORDINAL_INVALID; device->sibling_role = UCS_TOPO_SIBLING_ROLE_NONE; device->sibling_sys_dev = UCS_SYS_DEVICE_ID_UNKNOWN; @@ -1119,6 +1120,51 @@ ucs_status_t ucs_topo_sys_device_set_class(ucs_sys_device_t sys_dev, return status; } +ucs_status_t +ucs_topo_sys_device_add_flags(ucs_sys_device_t sys_dev, unsigned flags) +{ + ucs_status_t status = UCS_OK; + + if (sys_dev == UCS_SYS_DEVICE_ID_UNKNOWN) { + ucs_error("system device %d is unknown", sys_dev); + return UCS_ERR_INVALID_PARAM; + } + + ucs_spin_lock(&ucs_topo_global_ctx.lock); + + if (sys_dev >= ucs_topo_global_ctx.num_devices) { + ucs_error("system device %d is invalid (max: %u)", sys_dev, + ucs_topo_global_ctx.num_devices); + status = UCS_ERR_INVALID_PARAM; + goto out_unlock; + } + + ucs_topo_global_ctx.devices[sys_dev].flags |= flags; + +out_unlock: + ucs_spin_unlock(&ucs_topo_global_ctx.lock); + return status; +} + +unsigned ucs_topo_sys_device_get_flags(ucs_sys_device_t sys_dev) +{ + unsigned flags; + + if (sys_dev == UCS_SYS_DEVICE_ID_UNKNOWN) { + return 0; + } + + ucs_spin_lock(&ucs_topo_global_ctx.lock); + if (sys_dev < ucs_topo_global_ctx.num_devices) { + flags = ucs_topo_global_ctx.devices[sys_dev].flags; + } else { + flags = 0; + } + ucs_spin_unlock(&ucs_topo_global_ctx.lock); + + return flags; +} + ucs_status_t ucs_topo_device_class_mark_incomplete(ucs_topo_device_class_t device_class) { @@ -1446,14 +1492,16 @@ static void ucs_topo_release_devices() } } -ucs_status_t ucs_topo_build_groups(ucs_topo_groups_t *groups_p) +ucs_status_t +ucs_topo_build_groups(const ucs_sys_device_bitmap_t *net_device_filter, + ucs_topo_groups_t *groups_p) { ucs_status_t status; ucs_spin_lock(&ucs_topo_global_ctx.lock); status = ucs_topo_build_groups_inner(ucs_topo_global_ctx.devices, ucs_topo_global_ctx.num_devices, - groups_p); + net_device_filter, groups_p); ucs_spin_unlock(&ucs_topo_global_ctx.lock); return status; diff --git a/src/ucs/sys/topo/base/topo.h b/src/ucs/sys/topo/base/topo.h index 1d08264291b..b5c541b90d8 100644 --- a/src/ucs/sys/topo/base/topo.h +++ b/src/ucs/sys/topo/base/topo.h @@ -106,6 +106,15 @@ typedef enum { } ucs_topo_device_class_t; +/** + * @ingroup UCS_RESOURCE + * Properties of a system device, set by the owning transport. + */ +typedef enum { + UCS_TOPO_DEVICE_FLAG_DPU = UCS_BIT(0) /**< DPU device (e.g. BlueField) */ +} ucs_topo_device_flags_t; + + /** * @ingroup UCS_RESOURCE * Global state of the topology subsystem. @@ -473,6 +482,27 @@ ucs_status_t ucs_topo_sys_device_set_class(ucs_sys_device_t sys_dev, ucs_topo_device_class_t device_class); +/** + * Add flags to a given system device. + * + * @param [in] sys_dev System device index. + * @param [in] flags Flags to add, from @ref ucs_topo_device_flags_t. + * + * @return UCS_OK on success, error otherwise. + */ +ucs_status_t +ucs_topo_sys_device_add_flags(ucs_sys_device_t sys_dev, unsigned flags); + +/** + * Get the flags of a given system device. + * + * @param [in] sys_dev System device index. + * + * @return Flags from @ref ucs_topo_device_flags_t, or 0 if the system device + * is unknown or invalid. + */ +unsigned ucs_topo_sys_device_get_flags(ucs_sys_device_t sys_dev); + /** * Mark a device class as incomplete. * diff --git a/src/ucs/sys/topo/base/topo_groups.c b/src/ucs/sys/topo/base/topo_groups.c index 3a4fa22115e..8faf9a99fdc 100644 --- a/src/ucs/sys/topo/base/topo_groups.c +++ b/src/ucs/sys/topo/base/topo_groups.c @@ -16,17 +16,10 @@ #include #include #include -#include -#include -#include -#include #include -#define UCS_TOPO_GROUPS_FW_VER_MAX 64 - - UCS_ARRAY_DECLARE_TYPE(ucs_topo_groups_sys_dev_array_t, size_t, ucs_sys_device_t); UCS_ARRAY_DECLARE_TYPE(ucs_topo_groups_numa_node_array_t, size_t, @@ -74,146 +67,11 @@ static int ucs_topo_groups_bus_id_equal(const ucs_sys_bus_id_t *bus_id1, (bus_id1->function == bus_id2->function); } -static ucs_status_t -ucs_topo_groups_read_ib_fw_ver(const ucs_sys_bus_id_t *bus_id, char *fw_ver, - size_t max) -{ - char *sysfs_path; - struct dirent *entry; - ucs_status_t status; - size_t path_len; - DIR *dir; - - status = ucs_string_alloc_path_buffer(&sysfs_path, "sysfs_path"); - if (status != UCS_OK) { - return status; - } - - status = ucs_topo_bus_id_to_sysfs_path(bus_id, sysfs_path, PATH_MAX); - if (status != UCS_OK) { - goto out_free_sysfs_path; - } - - path_len = strlen(sysfs_path); - ucs_strncpy_safe(sysfs_path + path_len, "/infiniband", PATH_MAX - path_len); - - dir = opendir(sysfs_path); - if (dir == NULL) { - status = UCS_ERR_NO_ELEM; - goto out_free_sysfs_path; - } - - /* Find the device name directory (e.g. mlx5_0) */ - do { - entry = readdir(dir); - } while ((entry != NULL) && (entry->d_name[0] == '.')); - - if (entry == NULL) { - status = UCS_ERR_NO_ELEM; - goto out_close_dir; - } - - if (ucs_read_file_str(fw_ver, max, 1, "%s/%s/fw_ver", sysfs_path, - entry->d_name) < 0) { - status = UCS_ERR_IO_ERROR; - goto out_close_dir; - } - - ucs_strtrim(fw_ver); - status = UCS_OK; - -out_close_dir: - closedir(dir); -out_free_sysfs_path: - ucs_free(sysfs_path); - return status; -} - -static int ucs_topo_groups_is_nic_cx9(const ucs_topo_sys_device_info_t *device, - const char **reason_p) -{ - const ucs_sys_pci_id_t *pci_id = &device->pci_id; - const ucs_sys_bus_id_t *bus_id = &device->bus_id; - char fw_ver[UCS_TOPO_GROUPS_FW_VER_MAX]; - ucs_status_t status; - - if (pci_id->vendor != UCS_TOPO_GROUPS_MELLANOX_VENDOR_ID) { - *reason_p = "not a mellanox device"; - return 0; - } - - if (pci_id->device == UCS_TOPO_GROUPS_CX9_DEVICE_ID) { - *reason_p = "cx9 device by device id"; - return 1; - } - - if (pci_id->device != UCS_TOPO_GROUPS_MLX5_VF_DEVICE_ID) { - *reason_p = "not a cx9 device by device id"; - return 0; - } - - /* PCI device ID is not indicative when the device is a VF, instead use - * the fact that fw version is 82.XX.XXXX for CX9 */ - status = ucs_topo_groups_read_ib_fw_ver(bus_id, fw_ver, sizeof(fw_ver)); - if (status != UCS_OK) { - ucs_debug("could not read firmware version (error: %s)", - ucs_status_string(status)); - *reason_p = "vf device, could not read firmware version"; - return 0; - } - - if (strncmp(fw_ver, "82.", 3) != 0) { - *reason_p = "vf device, firmware version mismatch"; - return 0; - } - - *reason_p = "cx9 device by firmware version"; - return 1; -} - -static void -ucs_topo_groups_nics_cx9_filter(const ucs_topo_sys_device_info_t *devices, - ucs_topo_groups_sys_dev_array_t *nics) -{ - size_t dst = 0; - const ucs_topo_sys_device_info_t *device; - ucs_sys_device_t sys_dev; - const char *reason; - size_t src; - int is_cx9; - - if (ucs_array_is_empty(nics)) { - return; - } - - ucs_assert(ucs_array_begin(nics) != NULL); - - for (src = 0; src < ucs_array_length(nics); ++src) { - sys_dev = ucs_array_elem(nics, src); - device = &devices[sys_dev]; - - /* TODO: Refactor to have this provided by UCT */ - is_cx9 = ucs_topo_groups_is_nic_cx9(device, &reason); - if (is_cx9) { - ucs_array_elem(nics, dst++) = sys_dev; - } - - ucs_debug("cx9_filter: network device sys_dev=%u, " - "bus_id=" UCS_SYS_BUS_ID_FMT ", pci_id=" UCS_SYS_PCI_ID_FMT - " %s (%s)", - sys_dev, UCS_SYS_BUS_ID_ARG(&device->bus_id), - UCS_SYS_PCI_ID_ARG(&device->pci_id), - is_cx9 ? "added" : "skipped", reason); - } - - ucs_array_set_length(nics, dst); -} - -static ucs_status_t -ucs_topo_groups_devices_collect(const ucs_topo_sys_device_info_t *devices, - unsigned num_devices, - ucs_topo_groups_sys_dev_array_t *acc_devices, - ucs_topo_groups_sys_dev_array_t *net_devices) +static ucs_status_t ucs_topo_groups_devices_collect( + const ucs_topo_sys_device_info_t *devices, unsigned num_devices, + const ucs_sys_device_bitmap_t *net_device_filter, + ucs_topo_groups_sys_dev_array_t *acc_devices, + ucs_topo_groups_sys_dev_array_t *net_devices) { ucs_topo_groups_sys_dev_array_t *target_array; unsigned i; @@ -222,6 +80,14 @@ ucs_topo_groups_devices_collect(const ucs_topo_sys_device_info_t *devices, if (devices[i].device_class == UCS_TOPO_DEVICE_CLASS_ACC) { target_array = acc_devices; } else if (devices[i].device_class == UCS_TOPO_DEVICE_CLASS_NET) { + if ((net_device_filter != NULL) && + !UCS_STATIC_BITMAP_GET(*net_device_filter, i)) { + ucs_debug("skipping network device %s (sys_dev=%u): not in " + "the device filter", + devices[i].name, i); + continue; + } + target_array = net_devices; } else { continue; @@ -305,10 +171,10 @@ void ucs_topo_release_group(ucs_topo_group_t *group) ucs_array_cleanup_dynamic(&group->gpus); } -static ucs_status_t -ucs_topo_groups_inventory_build(const ucs_topo_sys_device_info_t *devices, - unsigned num_devices, int is_vera_rubin, - ucs_topo_group_t *inventory_p) +static ucs_status_t ucs_topo_groups_inventory_build( + const ucs_topo_sys_device_info_t *devices, unsigned num_devices, + const ucs_sys_device_bitmap_t *net_device_filter, + ucs_topo_group_t *inventory_p) { ucs_topo_groups_sys_dev_array_t acc_devices = UCS_ARRAY_DYNAMIC_INITIALIZER; ucs_topo_groups_sys_dev_array_t net_devices = UCS_ARRAY_DYNAMIC_INITIALIZER; @@ -317,7 +183,8 @@ ucs_topo_groups_inventory_build(const ucs_topo_sys_device_info_t *devices, ucs_topo_init_group(&inventory); - status = ucs_topo_groups_devices_collect(devices, num_devices, &acc_devices, + status = ucs_topo_groups_devices_collect(devices, num_devices, + net_device_filter, &acc_devices, &net_devices); if (status != UCS_OK) { goto err_free_arrays; @@ -326,10 +193,6 @@ ucs_topo_groups_inventory_build(const ucs_topo_sys_device_info_t *devices, ucs_topo_groups_sys_dev_sort(&acc_devices, devices); ucs_topo_groups_sys_dev_sort(&net_devices, devices); - if (is_vera_rubin) { - ucs_topo_groups_nics_cx9_filter(devices, &net_devices); - } - /* Accelerator devices (GPUs) are grouped by full bus id equality. */ status = ucs_topo_groups_elements_build(devices, &acc_devices, ucs_topo_groups_bus_id_equal, @@ -506,7 +369,9 @@ static void ucs_topo_groups_log(const ucs_topo_sys_device_info_t *devices, ucs_status_t ucs_topo_build_groups_inner(const ucs_topo_sys_device_info_t *devices, - unsigned num_devices, ucs_topo_groups_t *groups_p) + unsigned num_devices, + const ucs_sys_device_bitmap_t *net_device_filter, + ucs_topo_groups_t *groups_p) { ucs_topo_group_t inventory; ucs_topo_groups_t groups; @@ -514,8 +379,8 @@ ucs_topo_build_groups_inner(const ucs_topo_sys_device_info_t *devices, ucs_topo_init_groups(&groups); - status = ucs_topo_groups_inventory_build(devices, num_devices, 1, - &inventory); + status = ucs_topo_groups_inventory_build(devices, num_devices, + net_device_filter, &inventory); if (status != UCS_OK) { return status; } diff --git a/src/ucs/sys/topo/base/topo_groups.h b/src/ucs/sys/topo/base/topo_groups.h index 8c1a0c435d9..ebe12a34f21 100644 --- a/src/ucs/sys/topo/base/topo_groups.h +++ b/src/ucs/sys/topo/base/topo_groups.h @@ -9,16 +9,12 @@ #include #include +#include BEGIN_C_DECLS #define UCS_TOPO_MAX_SYS_DEVS_PER_ELEMENT 8 -/* CX-9 PCI identifiers */ -#define UCS_TOPO_GROUPS_MELLANOX_VENDOR_ID 0x15b3 -#define UCS_TOPO_GROUPS_CX9_DEVICE_ID 0x1025 -#define UCS_TOPO_GROUPS_MLX5_VF_DEVICE_ID 0x101e - /** * @ingroup UCS_RESOURCE @@ -54,18 +50,29 @@ UCS_ARRAY_DECLARE_TYPE(ucs_topo_group_array_t, size_t, ucs_topo_group_t); typedef ucs_topo_group_array_t ucs_topo_groups_t; +/** + * @ingroup UCS_RESOURCE + * Bitmap of system devices. + */ +typedef ucs_static_bitmap_s(UCS_SYS_DEVICE_ID_COUNT) ucs_sys_device_bitmap_t; + + /** * Build system topology groups. * * The caller takes ownership of the returned group data and must release it * with @ref ucs_topo_release_groups. * - * @param [out] groups_p Initialized topology groups. + * @param [in] net_device_filter Network devices to include in the groups, + * or NULL to include all network devices. + * @param [out] groups_p Initialized topology groups. * * @return UCS_OK on success, or an error status if topology group * initialization failed. */ -ucs_status_t ucs_topo_build_groups(ucs_topo_groups_t *groups_p); +ucs_status_t +ucs_topo_build_groups(const ucs_sys_device_bitmap_t *net_device_filter, + ucs_topo_groups_t *groups_p); /** @@ -95,16 +102,20 @@ void ucs_topo_release_group(ucs_topo_group_t *group); /** * Build system topology groups (internal function). * - * @param [in] devices Array of registered system devices. - * @param [in] num_devices Number of elements in @a devices. - * @param [out] groups_p Initialized topology groups. + * @param [in] devices Array of registered system devices. + * @param [in] num_devices Number of elements in @a devices. + * @param [in] net_device_filter Network devices to include in the groups, + * or NULL to include all network devices. + * @param [out] groups_p Initialized topology groups. * * @return UCS_OK on success, or an error status if topology group * initialization failed. */ ucs_status_t ucs_topo_build_groups_inner(const ucs_topo_sys_device_info_t *devices, - unsigned num_devices, ucs_topo_groups_t *groups_p); + unsigned num_devices, + const ucs_sys_device_bitmap_t *net_device_filter, + ucs_topo_groups_t *groups_p); END_C_DECLS diff --git a/src/ucs/sys/topo/base/topo_int.h b/src/ucs/sys/topo/base/topo_int.h index 7aa953a3010..42a96f1f04f 100644 --- a/src/ucs/sys/topo/base/topo_int.h +++ b/src/ucs/sys/topo/base/topo_int.h @@ -32,6 +32,7 @@ typedef struct { ucs_sys_pci_id_t pci_id; uintptr_t user_value; ucs_topo_device_class_t device_class; + unsigned flags; /* ucs_topo_device_flags_t */ /* Cached rank of the device's BDF within its class, or * UCS_SYS_DEVICE_ORDINAL_INVALID if not yet computed. diff --git a/src/uct/ib/base/ib_device.c b/src/uct/ib/base/ib_device.c index 94b89dc73d9..a4d41453691 100644 --- a/src/uct/ib/base/ib_device.c +++ b/src/uct/ib/base/ib_device.c @@ -170,16 +170,19 @@ static uct_ib_device_spec_t uct_ib_builtin_device_specs[] = { UCT_IB_DEVICE_FLAG_DC_V2, 100}, {"BlueField", {0x15b3, 0xa2d2}, UCT_IB_DEVICE_FLAG_MELLANOX | UCT_IB_DEVICE_FLAG_MLX5_PRM | - UCT_IB_DEVICE_FLAG_DC_V2, 41}, + UCT_IB_DEVICE_FLAG_DC_V2 | UCT_IB_DEVICE_FLAG_DPU, 41}, {"BlueField VF", {0x15b3, 0xa2d3}, UCT_IB_DEVICE_FLAG_MELLANOX | UCT_IB_DEVICE_FLAG_MLX5_PRM | - UCT_IB_DEVICE_FLAG_DC_V2, 41}, + UCT_IB_DEVICE_FLAG_DC_V2 | UCT_IB_DEVICE_FLAG_DPU, 41}, {"BlueField 2", {0x15b3, 0xa2d6}, UCT_IB_DEVICE_FLAG_MELLANOX | UCT_IB_DEVICE_FLAG_MLX5_PRM | - UCT_IB_DEVICE_FLAG_DC_V2, 61}, + UCT_IB_DEVICE_FLAG_DC_V2 | UCT_IB_DEVICE_FLAG_DPU, 61}, {"BlueField 3", {0x15b3, 0xa2dc}, UCT_IB_DEVICE_FLAG_MELLANOX | UCT_IB_DEVICE_FLAG_MLX5_PRM | - UCT_IB_DEVICE_FLAG_DC_V2, 61}, + UCT_IB_DEVICE_FLAG_DC_V2 | UCT_IB_DEVICE_FLAG_DPU, 61}, + {"BlueField 4", {0x15b3, 0xa2df}, + UCT_IB_DEVICE_FLAG_MELLANOX | UCT_IB_DEVICE_FLAG_MLX5_PRM | + UCT_IB_DEVICE_FLAG_DC_V2 | UCT_IB_DEVICE_FLAG_DPU, 61}, {"Generic HCA", UCS_SYS_PCI_ID_UNDEFINED, 0, 0}, {NULL} }; diff --git a/src/uct/ib/base/ib_device.h b/src/uct/ib/base/ib_device.h index 88dc6c13be2..067f8c334b2 100644 --- a/src/uct/ib/base/ib_device.h +++ b/src/uct/ib/base/ib_device.h @@ -104,7 +104,8 @@ enum { UCT_IB_DEVICE_FLAG_DC = UCT_IB_DEVICE_FLAG_DC_V1 | UCT_IB_DEVICE_FLAG_DC_V2, UCT_IB_DEVICE_FAILED = UCS_BIT(9), /* Got fatal error */ - UCT_IB_DEVICE_FLAG_MULTIPLANE = UCS_BIT(10) /* Supports multiplane */ + UCT_IB_DEVICE_FLAG_MULTIPLANE = UCS_BIT(10), /* Supports multiplane */ + UCT_IB_DEVICE_FLAG_DPU = UCS_BIT(11) /* DPU device */ }; diff --git a/src/uct/ib/base/ib_md.c b/src/uct/ib/base/ib_md.c index 6139e8c5732..9ca8b8f3847 100644 --- a/src/uct/ib/base/ib_md.c +++ b/src/uct/ib/base/ib_md.c @@ -92,6 +92,7 @@ ucs_config_field_t uct_ib_md_config_table[] = { " 'd' - DC version 1 (Connect-IB, ConnectX-4)\n" " 'D' - DC version 2 (ConnectX-5 and above)\n" " 'a' - Compact address vector support\n" + " 'b' - DPU device (e.g. BlueField)\n" " - (optional) device priority, integer.\n" "\n" "Example: The value '0x02c9:4115:ConnectX4:5d' would specify a device named ConnectX-4\n" @@ -1023,6 +1024,8 @@ uct_ib_md_parse_device_config(uct_ib_md_t *md, const uct_ib_md_config_t *md_conf spec->flags |= UCT_IB_DEVICE_FLAG_DC_V2; } else if (*p == 'a') { spec->flags |= UCT_IB_DEVICE_FLAG_AV; + } else if (*p == 'b') { + spec->flags |= UCT_IB_DEVICE_FLAG_DPU; } else { ucs_error("invalid device flag: '%c'", *p); free(flags_str); @@ -1407,6 +1410,14 @@ ucs_status_t uct_ib_md_open_common(uct_ib_md_t *md, md->dev.ah_cache_ttl = md_config->ah_cache_ttl; + /* TODO: Detect DPU VFs, which share the generic mlx5 VF PCI id, by the + * board PSID (board_id) */ + if ((md->dev.sys_dev != UCS_SYS_DEVICE_ID_UNKNOWN) && + (uct_ib_device_spec(&md->dev)->flags & UCT_IB_DEVICE_FLAG_DPU)) { + ucs_topo_sys_device_add_flags(md->dev.sys_dev, + UCS_TOPO_DEVICE_FLAG_DPU); + } + if (strlen(md_config->subnet_prefix) > 0) { status = uct_ib_md_parse_subnet_prefix(md_config->subnet_prefix, &md->subnet_filter); diff --git a/test/gtest/ucp/test_ucp_context.cc b/test/gtest/ucp/test_ucp_context.cc index 2634cf92f44..06080f9adcf 100644 --- a/test/gtest/ucp/test_ucp_context.cc +++ b/test/gtest/ucp/test_ucp_context.cc @@ -74,6 +74,59 @@ UCS_TEST_P(test_ucp_context, max_hca_per_gpu_config) UCP_INSTANTIATE_TEST_CASE_TLS(test_ucp_context, all, "all") +class test_ucp_context_gpu_nic_assignment : public test_ucp_context { +protected: + void check_no_assignable_nic(const char *mode, const char *tls, + ucs_status_t exp_status) + { + ucs::handle config; + ucp_context_h ucph; + ucs_status_t status; + + UCS_TEST_CREATE_HANDLE(ucp_config_t*, config, ucp_config_release, + ucp_config_read, NULL, NULL); + ASSERT_UCS_OK(ucp_config_modify(config.get(), "GPU_NIC_ASSIGNMENT_MODE", + mode)); + ASSERT_UCS_OK(ucp_config_modify(config.get(), "TLS", tls)); + + { + const scoped_log_handler slh(hide_errors_logger); + status = ucp_init(&get_variant_ctx_params(), config.get(), &ucph); + } + + EXPECT_EQ(exp_status, status); + if (status == UCS_OK) { + EXPECT_EQ(nullptr, ucph->gpu_nic_assignment); + ucp_cleanup(ucph); + } + } +}; + +/* shm has no network devices, and the tcp md has no UCT_MD_FLAG_REG, so + * neither provides a assignable NICs */ + +UCS_TEST_P(test_ucp_context_gpu_nic_assignment, auto_mode_shm) +{ + check_no_assignable_nic("auto", "shm", UCS_OK); +} + +UCS_TEST_P(test_ucp_context_gpu_nic_assignment, auto_mode_tcp) +{ + check_no_assignable_nic("auto", "tcp", UCS_OK); +} + +UCS_TEST_P(test_ucp_context_gpu_nic_assignment, explicit_mode_shm) +{ + check_no_assignable_nic("flip", "shm", UCS_ERR_INVALID_PARAM); +} + +UCS_TEST_P(test_ucp_context_gpu_nic_assignment, explicit_mode_tcp) +{ + check_no_assignable_nic("flip", "tcp", UCS_ERR_INVALID_PARAM); +} + +UCP_INSTANTIATE_TEST_CASE_TLS(test_ucp_context_gpu_nic_assignment, all, "all") + class test_ucp_aliases : public test_ucp_context { }; diff --git a/test/gtest/ucp/test_ucp_gpu_nic_assignment.cc b/test/gtest/ucp/test_ucp_gpu_nic_assignment.cc index 712bcccb39d..d417e738199 100644 --- a/test/gtest/ucp/test_ucp_gpu_nic_assignment.cc +++ b/test/gtest/ucp/test_ucp_gpu_nic_assignment.cc @@ -140,7 +140,7 @@ class test_ucp_gpu_nic_assignment : public ucs::test { { for (size_t gpu_idx = 0; gpu_idx < config.num_gpus(); ++gpu_idx) { size_t gpu_device_idx = 0; - const ucp_gpu_nic_sys_dev_bitmap_t *expected_bitmap = + const ucs_sys_device_bitmap_t *expected_bitmap = ucp_gpu_nic_assignment_lookup(&m_assignment, gpu_sys_dev(config, gpu_idx, gpu_device_idx)); @@ -149,7 +149,7 @@ class test_ucp_gpu_nic_assignment : public ucs::test { /* Devices under the same GPU share the exact assignment bitmap. */ for (gpu_device_idx = 1; gpu_device_idx < config.num_gpu_devices; ++gpu_device_idx) { - const ucp_gpu_nic_sys_dev_bitmap_t *actual_bitmap = + const ucs_sys_device_bitmap_t *actual_bitmap = ucp_gpu_nic_assignment_lookup( &m_assignment, gpu_sys_dev(config, gpu_idx, gpu_device_idx)); @@ -179,7 +179,7 @@ class test_ucp_gpu_nic_assignment : public ucs::test { expected_port_counts[expected_owner] += config.num_nic_ports; for (size_t gpu_idx = 0; gpu_idx < config.num_gpus(); ++gpu_idx) { - const ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap = + const ucs_sys_device_bitmap_t *nic_sys_dev_bitmap = ucp_gpu_nic_assignment_lookup(&m_assignment, gpu_sys_dev(config, gpu_idx, 0)); @@ -215,7 +215,7 @@ class test_ucp_gpu_nic_assignment : public ucs::test { /* Verify each GPU has the expected number of assigned ports. */ for (size_t gpu_idx = 0; gpu_idx < config.num_gpus(); ++gpu_idx) { - const ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap = + const ucs_sys_device_bitmap_t *nic_sys_dev_bitmap = ucp_gpu_nic_assignment_lookup(&m_assignment, gpu_sys_dev(config, gpu_idx, 0)); @@ -238,7 +238,7 @@ class test_ucp_gpu_nic_assignment : public ucs::test { ++local_idx) { const size_t gpu_idx = (group_idx * config.num_gpus_per_group) + local_idx; - const ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap = + const ucs_sys_device_bitmap_t *nic_sys_dev_bitmap = ucp_gpu_nic_assignment_lookup(&m_assignment, gpu_sys_dev(config, gpu_idx, 0)); diff --git a/test/gtest/ucs/test_topo.cc b/test/gtest/ucs/test_topo.cc index ab0c573e171..6364f44f987 100644 --- a/test/gtest/ucs/test_topo.cc +++ b/test/gtest/ucs/test_topo.cc @@ -308,6 +308,50 @@ UCS_TEST_F(test_topo, pci_id_invalid_sys_dev) { EXPECT_EQ(UCS_SYS_PCI_ID_VALUE_UNDEFINED, pci_id.device); } +UCS_TEST_F(test_topo, device_flags) { + const unsigned num_devices = ucs_topo_num_devices(); + ucs_sys_device_t sys_dev, other_sys_dev; + ucs_sys_bus_id_t bus_id; + + bus_id.domain = 0xf1a6; + bus_id.bus = 0x01; + bus_id.slot = 0x1f; + bus_id.function = 0; + ASSERT_UCS_OK(ucs_topo_find_device_by_bus_id(&bus_id, &sys_dev)); + bus_id.function = 1; + ASSERT_UCS_OK(ucs_topo_find_device_by_bus_id(&bus_id, &other_sys_dev)); + + EXPECT_EQ(0u, ucs_topo_sys_device_get_flags(sys_dev)); + + ASSERT_UCS_OK( + ucs_topo_sys_device_add_flags(sys_dev, UCS_TOPO_DEVICE_FLAG_DPU)); + EXPECT_EQ(static_cast(UCS_TOPO_DEVICE_FLAG_DPU), + ucs_topo_sys_device_get_flags(sys_dev)); + EXPECT_EQ(0u, ucs_topo_sys_device_get_flags(other_sys_dev)); + + /* Adding no flags keeps the existing ones */ + ASSERT_UCS_OK(ucs_topo_sys_device_add_flags(sys_dev, 0)); + EXPECT_EQ(static_cast(UCS_TOPO_DEVICE_FLAG_DPU), + ucs_topo_sys_device_get_flags(sys_dev)); + + ASSERT_LT(num_devices + 2, UCS_SYS_DEVICE_ID_UNKNOWN); + const auto invalid_sys_dev = static_cast(num_devices + 2); + + EXPECT_EQ(0u, ucs_topo_sys_device_get_flags(UCS_SYS_DEVICE_ID_UNKNOWN)); + EXPECT_EQ(0u, ucs_topo_sys_device_get_flags(invalid_sys_dev)); + + { + const scoped_log_handler slh(hide_errors_logger); + + EXPECT_EQ(UCS_ERR_INVALID_PARAM, + ucs_topo_sys_device_add_flags(UCS_SYS_DEVICE_ID_UNKNOWN, + UCS_TOPO_DEVICE_FLAG_DPU)); + EXPECT_EQ(UCS_ERR_INVALID_PARAM, + ucs_topo_sys_device_add_flags(invalid_sys_dev, + UCS_TOPO_DEVICE_FLAG_DPU)); + } +} + UCS_TEST_F(test_topo, find_device_by_bus_id_and_user_value) { static const uintptr_t user_value1 = 17; static const uintptr_t user_value2 = 42; diff --git a/test/gtest/ucs/test_topo_groups.cc b/test/gtest/ucs/test_topo_groups.cc index f8d6ad70c76..2d24438593c 100644 --- a/test/gtest/ucs/test_topo_groups.cc +++ b/test/gtest/ucs/test_topo_groups.cc @@ -15,21 +15,14 @@ extern "C" { #include -static constexpr ucs_sys_pci_id_t pci_id_cx9 = { - UCS_TOPO_GROUPS_MELLANOX_VENDOR_ID, - UCS_TOPO_GROUPS_CX9_DEVICE_ID, -}; - - class test_topo_groups : public ucs::test { protected: using physical_device = std::vector; - static constexpr int num_devices_per_gpu = 2; - static constexpr int num_gpus_per_numa = 2; - static constexpr int num_ports_per_nic = 2; - static constexpr int num_cx9_nics_per_numa = 4; - static constexpr int num_nics_per_numa = num_cx9_nics_per_numa + 1; + static constexpr int num_devices_per_gpu = 2; + static constexpr int num_gpus_per_numa = 2; + static constexpr int num_ports_per_nic = 2; + static constexpr int num_nics_per_numa = 4; struct numa_devices { ucs_numa_node_t numa_node; @@ -59,10 +52,10 @@ class test_topo_groups : public ucs::test { return bus_id; } - ucs_sys_device_t - add_device(const std::string &name, const ucs_sys_bus_id_t &bus_id, - ucs_topo_device_class_t device_class, ucs_numa_node_t numa_node, - const ucs_sys_pci_id_t *pci_id, uintptr_t user_value) + ucs_sys_device_t add_device(const std::string &name, + const ucs_sys_bus_id_t &bus_id, + ucs_topo_device_class_t device_class, + ucs_numa_node_t numa_node, uintptr_t user_value) { ucs_topo_sys_device_info_t device = {}; ucs_sys_device_t sys_dev; @@ -79,10 +72,6 @@ class test_topo_groups : public ucs::test { device.sys_dev_aux = UCS_SYS_DEVICE_ID_UNKNOWN; device.sibling_sys_dev = UCS_SYS_DEVICE_ID_UNKNOWN; - if (pci_id != nullptr) { - device.pci_id = *pci_id; - } - sys_dev = static_cast(m_devices.size()); m_devices.push_back(device); return sys_dev; @@ -145,9 +134,9 @@ class test_topo_groups : public ucs::test { "." + std::to_string(device_idx); uintptr_t const user_value = static_cast(device_idx); - gpu_devices.push_back( - add_device(name, bus_id, UCS_TOPO_DEVICE_CLASS_ACC, - numa.numa_node, nullptr, user_value)); + gpu_devices.push_back(add_device(name, bus_id, + UCS_TOPO_DEVICE_CLASS_ACC, + numa.numa_node, user_value)); } numa.gpus.push_back(gpu_devices); @@ -157,7 +146,6 @@ class test_topo_groups : public ucs::test { void add_vera_rubin_nics(unsigned numa_idx, numa_devices &numa) { for (unsigned nic_idx = 0; nic_idx < num_nics_per_numa; ++nic_idx) { - const bool is_cx9 = nic_idx < num_cx9_nics_per_numa; const ucs_sys_bus_id_t slot_bus_id = generate_bus_id(); physical_device nic_ports; @@ -172,19 +160,13 @@ class test_topo_groups : public ucs::test { ucs_sys_bus_id_t port_bus_id = slot_bus_id; port_bus_id.function = static_cast(port_idx); - const ucs_sys_device_t sys_dev = add_device( - name, port_bus_id, UCS_TOPO_DEVICE_CLASS_NET, - numa.numa_node, is_cx9 ? &pci_id_cx9 : nullptr, - UCS_SYS_DEVICE_USER_VALUE_EMPTY); - - if (is_cx9) { - nic_ports.push_back(sys_dev); - } + nic_ports.push_back( + add_device(name, port_bus_id, UCS_TOPO_DEVICE_CLASS_NET, + numa.numa_node, + UCS_SYS_DEVICE_USER_VALUE_EMPTY)); } - if (is_cx9) { - numa.nics.push_back(nic_ports); - } + numa.nics.push_back(nic_ports); } } @@ -205,12 +187,23 @@ class test_topo_groups : public ucs::test { return expected_result; } - ucs_status_t build() + ucs_status_t + build(const ucs_sys_device_bitmap_t *net_device_filter = nullptr) { return ucs_topo_build_groups_inner(m_devices.data(), static_cast( m_devices.size()), - &m_groups); + net_device_filter, &m_groups); + } + + void expect_groups(const std::vector &expected_groups) + { + ASSERT_EQ(expected_groups.size(), ucs_array_length(&m_groups)); + + for (size_t i = 0; i < expected_groups.size(); ++i) { + expect_group(ucs_array_elem(&m_groups, i), expected_groups[i].gpus, + expected_groups[i].nics); + } } void expect_group(const ucs_topo_group_t &group, @@ -257,13 +250,37 @@ UCS_TEST_F(test_topo_groups, vera_groups_by_numa) { const std::vector expected_groups = add_vera_rubin_devices(); ASSERT_UCS_OK(build()); + expect_groups(expected_groups); +} - ASSERT_EQ(expected_groups.size(), ucs_array_length(&m_groups)); +UCS_TEST_F(test_topo_groups, net_device_filter) { + std::vector expected_groups = add_vera_rubin_devices(); + ucs_sys_device_bitmap_t net_device_filter; - for (size_t i = 0; i < expected_groups.size(); ++i) { - expect_group(ucs_array_elem(&m_groups, i), expected_groups[i].gpus, - expected_groups[i].nics); + /* Include all network devices in the filter */ + UCS_STATIC_BITMAP_RESET_ALL(&net_device_filter); + for (const auto &group : expected_groups) { + for (const physical_device &nic : group.nics) { + for (const ucs_sys_device_t sys_dev : nic) { + UCS_STATIC_BITMAP_SET(&net_device_filter, sys_dev); + } + } } + + /* Filter out all ports of a NIC */ + auto &group0_nics = expected_groups[0].nics; + for (const ucs_sys_device_t sys_dev : group0_nics[1]) { + UCS_STATIC_BITMAP_RESET(&net_device_filter, sys_dev); + } + group0_nics.erase(group0_nics.begin() + 1); + + /* Filter out one port of a NIC, the NIC keeps its other port */ + physical_device &partial_nic = expected_groups[1].nics[0]; + UCS_STATIC_BITMAP_RESET(&net_device_filter, partial_nic.back()); + partial_nic.pop_back(); + + ASSERT_UCS_OK(build(&net_device_filter)); + expect_groups(expected_groups); } UCS_TEST_F(test_topo_groups, undefined_numa_elements_are_skipped) { @@ -271,18 +288,17 @@ UCS_TEST_F(test_topo_groups, undefined_numa_elements_are_skipped) { ucs_numa_node_t numa_node = 0; ucs_sys_device_t gpu_sys_dev = add_device("gpu", generate_bus_id(), UCS_TOPO_DEVICE_CLASS_ACC, - numa_node, nullptr, 0); + numa_node, 0); ucs_sys_device_t nic_sys_dev = add_device("nic", generate_bus_id(), UCS_TOPO_DEVICE_CLASS_NET, - numa_node, &pci_id_cx9, + numa_node, UCS_SYS_DEVICE_USER_VALUE_EMPTY); /* Add devices with undefined numa node */ add_device("undefined_gpu", generate_bus_id(), UCS_TOPO_DEVICE_CLASS_ACC, - UCS_NUMA_NODE_UNDEFINED, nullptr, 0); + UCS_NUMA_NODE_UNDEFINED, 0); add_device("undefined_nic", generate_bus_id(), UCS_TOPO_DEVICE_CLASS_NET, - UCS_NUMA_NODE_UNDEFINED, &pci_id_cx9, - UCS_SYS_DEVICE_USER_VALUE_EMPTY); + UCS_NUMA_NODE_UNDEFINED, UCS_SYS_DEVICE_USER_VALUE_EMPTY); ASSERT_UCS_OK(build()); ASSERT_EQ(1, ucs_array_length(&m_groups)); @@ -298,11 +314,9 @@ UCS_TEST_F(test_topo_groups, nic_only_group) { const ucs_sys_device_t port1 = add_device("nic.1", port1_bus_id, UCS_TOPO_DEVICE_CLASS_NET, 0, - &pci_id_cx9, UCS_SYS_DEVICE_USER_VALUE_EMPTY); const ucs_sys_device_t port0 = add_device("nic.0", port0_bus_id, UCS_TOPO_DEVICE_CLASS_NET, 0, - &pci_id_cx9, UCS_SYS_DEVICE_USER_VALUE_EMPTY);