UCP/DEVICE: Add multi-lane support#11268
Conversation
ca9ba6b to
af04b9e
Compare
af04b9e to
fa7e9fb
Compare
7714a0b to
60e5be9
Compare
8127934 to
b59dcb1
Compare
b59dcb1 to
71d7b9c
Compare
|
|
||
| static ucp_lane_index_t ucp_device_ep_find_lane(const ucp_ep_h ep, ucp_rsc_index_t tl_id) | ||
| { | ||
| ucp_ep_config_t *ep_config = ucp_ep_config(ep); |
There was a problem hiding this comment.
Wouldn't it better to use ucp_ep_num_lanes to get num lanes here, as you don't need ep_config var in this function?
| iface_attr->ctl_device = uct_cuda_get_cuda_device(iface->cuda_dev); | ||
| iface_attr->dev_num_paths = 1; |
There was a problem hiding this comment.
| iface_attr->ctl_device = uct_cuda_get_cuda_device(iface->cuda_dev); | |
| iface_attr->dev_num_paths = 1; | |
| iface_attr->ctl_device = uct_cuda_get_cuda_device(iface->cuda_dev); | |
| iface_attr->dev_num_paths = 1; |
| (remote_sys_dev != lane_key->dst_sys_dev)) { | ||
| ucs_trace("lane[%u] wrong destination sys_dev: dst_sys_dev=%u", | ||
| lane, lane_key->dst_sys_dev); | ||
| if (wiface->attr.ctl_device != local_sys_dev) { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| void *local_addr; | ||
|
|
||
| ucp_device_get_tl_bitmap(worker, tl_bitmap, local_sys_dev); | ||
| num_lanes = UCS_STATIC_BITMAP_POPCOUNT(tl_bitmap[tl_type]); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
we don't need to pack anything lane specific for no-lkey lanes, so we don't allocate data for it
| unsigned mem_list_index, void **addr_p) | ||
| { | ||
| const size_t elem_size = sizeof(uct_device_remote_mem_list_elem_t); | ||
| const size_t elem_size = sizeof(uct_device_remote_mem_elem_t); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Pull request overview
Adds multi-lane support for UCP device memory lists and updates UCT device-element packing/types so device-side operations can select among multiple device-EP lanes.
Changes:
- Introduce new device memory element/layout types (
uct_device_mem_elem_t, per-lane TL arrays) and propagate signature updates across UCT/UCP and CUDA test kernels. - Extend UCT iface attributes/capabilities with
ctl_deviceandUCT_IFACE_FLAG_DEVICE_LKEYto support correct device endpoint selection and packing behavior. - Rework UCP device mem-list creation/packing to build multi-lane descriptors and adjust wireup path selection behavior for device lanes.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/gtest/uct/test_device.cc | Updates CUDA context handling and switches tests to the new packed device mem element type. |
| test/gtest/uct/cuda/test_kernels_uct.h | Updates kernel launcher prototypes to use uct_device_mem_elem_t. |
| test/gtest/uct/cuda/test_kernels_uct.cu | Updates CUDA kernels/launchers to accept uct_device_mem_elem_t. |
| test/gtest/uct/cuda/test_kernels.h | Updates test kernel APIs to use uct_device_mem_elem_t. |
| test/gtest/uct/cuda/test_kernels.cu | Updates CUDA kernels to use uct_device_mem_elem_t. |
| test/gtest/uct/cuda/test_cuda_ipc_device.cc | Updates CUDA IPC device tests to the new packed mem element type. |
| test/gtest/ucp/test_ucp_device.cc | Adjusts kernel test expectations/usage to match updated device structures. |
| test/gtest/ucp/cuda/test_kernels.h | Removes per-kernel state fields from the device-kernel result struct. |
| test/gtest/ucp/cuda/test_kernels.cu | Removes device-side state parsing logic tied to the old lane/layout assumptions. |
| src/uct/ib/mlx5/gdaki/gdaki.cuh | Updates GDA device EP APIs to accept uct_device_mem_elem_t and new source element semantics. |
| src/uct/ib/mlx5/gdaki/gdaki.c | Exposes DEVICE_LKEY capability and sets ctl_device for GDA iface. |
| src/uct/ib/mlx5/dv/ib_mlx5dv_md.c | Updates MD mem element pack signature to the new type. |
| src/uct/cuda/cuda_ipc/cuda_ipc_md.c | Updates CUDA IPC MD mem element pack signature to the new type. |
| src/uct/cuda/cuda_ipc/cuda_ipc_iface.c | Initializes ctl_device for CUDA IPC iface attributes. |
| src/uct/cuda/cuda_ipc/cuda_ipc.cuh | Updates CUDA IPC device EP functions to take uct_device_mem_elem_t. |
| src/uct/base/uct_md.h | Updates MD ops callback typedef to use uct_device_mem_elem_t. |
| src/uct/base/uct_md.c | Updates uct_md_mem_elem_pack() signature to use uct_device_mem_elem_t. |
| src/uct/api/v2/uct_v2.h | Updates the public v2 API signature for uct_md_mem_elem_pack(). |
| src/uct/api/uct_def.h | Renames/introduces device element typedefs for multi-lane descriptors. |
| src/uct/api/uct.h | Adds UCT_IFACE_FLAG_DEVICE_LKEY and uct_iface_attr::ctl_device. |
| src/uct/api/device/uct_device_types.h | Redefines device memory list element layouts for multi-lane support. |
| src/uct/api/device/uct_device_impl.h | Updates device EP put/atomic/get_ptr APIs to use uct_device_mem_elem_t. |
| src/ucp/wireup/select.c | Adjusts path-count logic for DEVICE lane selection. |
| src/ucp/wireup/address.c | Forces num_paths=1 for device endpoints when gathering devices. |
| src/ucp/core/ucp_device.c | Reworks host-side packing/allocation of local/remote device mem list handles for multi-lane descriptors. |
| src/ucp/api/device/ucp_device_types.h | Adds num_lanes to device mem list handle headers and updates element types. |
| src/ucp/api/device/ucp_device_impl.h | Adds lane selection macros and updates device-side send/put/counter paths for multi-lane descriptors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for (i = 0; i < num_lanes;) { | ||
| UCS_STATIC_BITMAP_FOR_EACH_BIT(tl_id, tl_bitmap) { | ||
| status = ucp_device_remote_mem_list_element_pack(ucp_element, tl_id, | ||
| tl_element); | ||
| if (status != UCS_OK) { | ||
| return status; | ||
| } | ||
|
|
||
| tl_element = UCS_PTR_TYPE_OFFSET(tl_element, *tl_element); | ||
| i++; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
ucp_device_remote_mem_list_fill() repeats packing the TL bitmap until i == num_lanes. If UCS_STATIC_BITMAP_POPCOUNT(*tl_bitmap) differs from num_lanes, this will either duplicate TL entries (popcount < num_lanes) or overflow the allocated tl[] array (popcount > num_lanes). It would be safer to iterate the bitmap once and assert/verify that the number of packed entries equals num_lanes.
| for (i = 0; i < num_lanes;) { | |
| UCS_STATIC_BITMAP_FOR_EACH_BIT(tl_id, tl_bitmap) { | |
| status = ucp_device_remote_mem_list_element_pack(ucp_element, tl_id, | |
| tl_element); | |
| if (status != UCS_OK) { | |
| return status; | |
| } | |
| tl_element = UCS_PTR_TYPE_OFFSET(tl_element, *tl_element); | |
| i++; | |
| } | |
| } | |
| i = 0; | |
| UCS_STATIC_BITMAP_FOR_EACH_BIT(tl_id, tl_bitmap) { | |
| if (i >= num_lanes) { | |
| return UCS_ERR_INVALID_PARAM; | |
| } | |
| status = ucp_device_remote_mem_list_element_pack(ucp_element, tl_id, | |
| tl_element); | |
| if (status != UCS_OK) { | |
| return status; | |
| } | |
| tl_element = UCS_PTR_TYPE_OFFSET(tl_element, *tl_element); | |
| i++; | |
| } | |
| if (i != num_lanes) { | |
| return UCS_ERR_INVALID_PARAM; | |
| } |
| } | ||
| } | ||
|
|
||
| ucs_assert(tl_type < UCP_DEVICE_TL_TYPE_LAST); |
There was a problem hiding this comment.
If no tl_type bitmap matches an element EP, this ucs_assert() will abort the process. This can be triggered by runtime configuration mismatches and should return an error status (propagated to the caller) rather than asserting, so applications can handle it gracefully.
| ucs_assert(tl_type < UCP_DEVICE_TL_TYPE_LAST); | |
| if (tl_type == UCP_DEVICE_TL_TYPE_LAST) { | |
| ucs_error("failed to find matching tl_type for remote mem " | |
| "list element"); | |
| status = UCS_ERR_INVALID_PARAM; | |
| goto out; | |
| } |
| /* Interface capability */ | ||
| #define UCT_IFACE_FLAG_INTER_NODE UCS_BIT(54) /**< Interface is inter-node capable */ | ||
| #define UCT_IFACE_FLAG_DEVICE_EP UCS_BIT(55) /**< Interface supports device endpoint */ | ||
| #define UCT_IFACE_FLAG_DEVICE_LKEY UCS_BIT(56) /**< Interface require lkey for device operations */ |
There was a problem hiding this comment.
Grammar in the flag description should be singular: "Interface requires lkey for device operations".
| #define UCT_IFACE_FLAG_DEVICE_LKEY UCS_BIT(56) /**< Interface require lkey for device operations */ | |
| #define UCT_IFACE_FLAG_DEVICE_LKEY UCS_BIT(56) /**< Interface requires lkey for device operations */ |
| const auto mem_element = static_cast<uct_device_remote_mem_elem_t*>( | ||
| UCS_PTR_BYTE_OFFSET(mem_list_h->mem_elements, | ||
| mem_list_index * elem_size)); | ||
|
|
||
| return uct_device_ep_get_ptr(mem_element->device_ep, | ||
| &mem_element->uct_mem_element, | ||
| return uct_device_ep_get_ptr(mem_element->tl[0].ep, &mem_element->tl[0].uct, |
There was a problem hiding this comment.
ucp_device_get_ptr() indexes mem_elements with a fixed sizeof(uct_device_remote_mem_elem_t) stride, but remote mem list elements are now variable-sized (depend on mem_list_h->num_lanes). This will compute the wrong element address and can read out-of-bounds when num_lanes > 1. Use the same stride calculation as UCP_DEVICE_GET_ELEM(...) (or reuse the macro) to locate the mem_list_index element.
| int tl_type = UCP_DEVICE_TL_TYPE_LKEY; | ||
| ucp_tl_bitmap_t tl_bitmap[UCP_DEVICE_TL_TYPE_LAST] = {}; |
There was a problem hiding this comment.
ucp_device_local_mem_list_create_handle() initializes tl_type to UCP_DEVICE_TL_TYPE_LKEY and never switches to UCP_DEVICE_TL_TYPE_NOLKEY if there are no DEVICE_LKEY transports. This can lead to exporting a handle with num_lanes == 0, which later causes division/modulo by zero in UCP_DEVICE_GET_LANE() and leaves no packed TL elements. Add a fallback/selection based on which bitmap is non-empty (or return an error) to guarantee num_lanes >= 1.
| ucp_device_get_tl_bitmap(ep->worker, tl_bitmap, local_sys_dev); | ||
| num_lanes = UCS_STATIC_BITMAP_POPCOUNT(tl_bitmap[UCP_DEVICE_TL_TYPE_LKEY]); | ||
| if (!num_lanes) { |
There was a problem hiding this comment.
num_lanes is derived only from the LKEY bitmap here, but later tl_type may be selected per-element (LKEY vs NOLKEY). If an element ends up using the NOLKEY bitmap (different popcount), the code will pack a different number of TL entries than num_lanes implies, risking duplicate entries or out-of-bounds writes. Consider selecting a single tl_type/num_lanes for the whole handle or validating that all elements match the chosen bitmap size.
| uct_element = UCS_PTR_BYTE_OFFSET(uct_element, uct_elem_size); | ||
| } | ||
|
|
||
| handle->version = UCP_DEVICE_MEM_LIST_VERSION_V1; |
There was a problem hiding this comment.
Should we consider UCP_DEVICE_MEM_LIST_MULTI_LANE as the handle structure changed?
| #define UCP_DEVICE_GET_LANE(_handle, _channel_id, _lane, _uct_channel_id) \ | ||
| _lane = _channel_id % _handle->num_lanes; \ | ||
| _uct_channel_id = _channel_id / _handle->num_lanes; |
There was a problem hiding this comment.
ucs_assertv(_handle != NULL, "dest memlist can't be null")
before deref, clearer failure for users
There was a problem hiding this comment.
in other APIs we not validate objects for NULL
| #define UCP_DEVICE_GET_ELEM(_handle, _index, _lane) \ | ||
| static_cast<ucs_typeof(_handle->mem_elements[0])*>(UCS_PTR_BYTE_OFFSET( \ | ||
| _handle->mem_elements, \ | ||
| (sizeof(_handle->mem_elements[0]) + \ | ||
| (sizeof(_handle->mem_elements[0].tl[0]) * _handle->num_lanes)) * \ | ||
| _index)) |
| _uct_channel_id = _channel_id / _handle->num_lanes; | ||
|
|
||
|
|
||
| #define UCP_DEVICE_GET_ELEM(_handle, _index, _lane) \ |
There was a problem hiding this comment.
| #define UCP_DEVICE_GET_ELEM(_handle, _index, _lane) \ | |
| #define UCP_DEVICE_GET_ELEM(_handle, _index) \ |
| return status; | ||
| } | ||
|
|
||
| static ucp_lane_index_t ucp_device_ep_find_lane(const ucp_ep_h ep, ucp_rsc_index_t tl_id) |
There was a problem hiding this comment.
Is it safe to assume tl_id is a device lane?
There was a problem hiding this comment.
device API working with device lanes, but this function is not specific
| #define UCP_DEVICE_GET_ELEM(_handle, _index) \ | ||
| static_cast<ucs_typeof(_handle->mem_elements[0])*>(UCS_PTR_BYTE_OFFSET( \ |
| static_cast<ucs_typeof(_handle->mem_elements[0])*>(UCS_PTR_BYTE_OFFSET( \ | ||
| _handle->mem_elements, \ | ||
| (sizeof(_handle->mem_elements[0]) + \ | ||
| (sizeof(_handle->mem_elements[0].tl[0]) * _handle->num_lanes)) * \ |
| /** | ||
| * Number of lanes in each memory descriptor. | ||
| */ | ||
| uint16_t num_lanes; |
| /** | ||
| * Number of lanes in each memory descriptor. | ||
| */ | ||
| uint16_t num_lanes; |
There was a problem hiding this comment.
consider optimizing this to be something like MAX_LANES or MAX_MDS
| int tl_type = UCP_DEVICE_TL_TYPE_LKEY; | ||
| ucp_tl_bitmap_t tl_bitmap[UCP_DEVICE_TL_TYPE_LAST] = {}; |
| uct_element->addr = ucp_element->remote_addr; | ||
| tl_element = uct_element->tl; | ||
| for (i = 0; i < num_lanes;) { | ||
| UCS_STATIC_BITMAP_FOR_EACH_BIT(tl_id, tl_bitmap) { |
There was a problem hiding this comment.
does it mean we could pack tl which does not have a lane on the current endpoint? because tl_bitmap was not created according to ep lanes
| if (!(iface_attr->cap.flags & UCT_IFACE_FLAG_DEVICE_EP)) { | ||
| dev->num_paths = ucs_min(max_num_paths, iface_attr->dev_num_paths); |
| local_num_paths = iface_attr->dev_num_paths; | ||
| remote_num_paths = ae->dev_num_paths; | ||
|
|
||
| if (bw_info->criteria.lane_type == UCP_LANE_TYPE_DEVICE) { |
There was a problem hiding this comment.
looks weird..
what is the value of iface_attr->dev_num_paths ?
| /* Interface capability */ | ||
| #define UCT_IFACE_FLAG_INTER_NODE UCS_BIT(54) /**< Interface is inter-node capable */ | ||
| #define UCT_IFACE_FLAG_DEVICE_EP UCS_BIT(55) /**< Interface supports device endpoint */ | ||
| #define UCT_IFACE_FLAG_DEVICE_LKEY UCS_BIT(56) /**< Interface requires lkey for device operations */ |
There was a problem hiding this comment.
why needed?
and can we add it to query v2?
| compared to using only a single | ||
| endpoint. */ | ||
|
|
||
| ucs_sys_device_t ctl_device; /**< System device controlling this iface, |
ofirfarjun7
left a comment
There was a problem hiding this comment.
Fix comments in next PR
No description provided.