UCT/ROCM: initial commit for device initiated ipc put - #11299
Conversation
ee24de0 to
67b5b78
Compare
67b5b78 to
0459bdd
Compare
|
This PR is now ready for review. |
0459bdd to
3c778a2
Compare
mshanthagit
left a comment
There was a problem hiding this comment.
@ofirfarjun7 addressed your comments.
| ucp_context_h context = select_params->ep->worker->context; | ||
| unsigned ep_init_flags = ucp_wireup_ep_init_flags(select_params, | ||
| select_ctx); | ||
| static const ucs_memory_type_t device_mem_types[] = { |
There was a problem hiding this comment.
maybe add const UCP_MEMORY_TYPES_DEVICE
(UCS_BIT(UCS_MEMORY_TYPE_CUDA) | UCS_BIT(UCS_MEMORY_TYPE_ROCM)
and use ucs_memory_type_for_each to iterate skiping non-DEVICE memtypes, here and in ucp_device_detect_export_mem_type
There was a problem hiding this comment.
addressed this comment. added a #define in ucp_mm.h and used ucs_for_each_bit(mem_type, UCP_DEVICE_MEM_TYPES) within the files.
| return status; | ||
| } | ||
|
|
||
| status = ucp_device_remote_mem_list_create_handle(params, export_mem_type, |
There was a problem hiding this comment.
pass first ep so it won't need to look again
| ucs_status_t status; | ||
| uct_allocated_memory_t mem; | ||
| ucs_sys_device_t sys_dev; | ||
| ucp_ep_h ep = ucp_device_remote_mem_list_get_first_ep(params); |
There was a problem hiding this comment.
initialized vars first
| } | ||
|
|
||
| uct_rocm_ipc_component_t uct_rocm_ipc_component = { | ||
| .super = {.query_md_resources = uct_rocm_base_query_md_resources, |
There was a problem hiding this comment.
strange code format
mshanthagit
left a comment
There was a problem hiding this comment.
@Artemy-Mellanox incorporated your suggestions in the latest commit.
| } | ||
|
|
||
| uct_rocm_ipc_component_t uct_rocm_ipc_component = { | ||
| .super = {.query_md_resources = uct_rocm_base_query_md_resources, |
| ucp_context_h context = select_params->ep->worker->context; | ||
| unsigned ep_init_flags = ucp_wireup_ep_init_flags(select_params, | ||
| select_ctx); | ||
| static const ucs_memory_type_t device_mem_types[] = { |
There was a problem hiding this comment.
addressed this comment. added a #define in ucp_mm.h and used ucs_for_each_bit(mem_type, UCP_DEVICE_MEM_TYPES) within the files.
| ucs_status_t status; | ||
| uct_allocated_memory_t mem; | ||
| ucs_sys_device_t sys_dev; | ||
| ucp_ep_h ep = ucp_device_remote_mem_list_get_first_ep(params); |
| return status; | ||
| } | ||
|
|
||
| status = ucp_device_remote_mem_list_create_handle(params, export_mem_type, |
|
@Artemy-Mellanox did you get a chance to review the changes? |
|
I just wanted to add a comment here that I know that I am listed as reviewer and I am happy to sign off on the PR. @mshanthagit and me have discussed the issue and the actual ticket internally multiple times, so I am very well aware of the technical aspects of it. |
927735e to
b8832e5
Compare
|
@ofirfarjun7 addressed your comments except the one related to "UCT_CUDA_IPC_IS_ALIGNED_POW2". Can we move it to ucs/sys/device_code.h and name it as UCT_IPC_IS_ALIGNED_POW2? |
bdbf299 to
a5c4b47
Compare
|
@ofirfarjun7 rebased and addressed all comments. |
| #define UCS_DEVICE_NUM_THREADS_IN_WARP 32 | ||
|
|
||
| /* Check if _n is aligned to a power-of-2 boundary _p */ | ||
| #define UCT_IPC_IS_ALIGNED_POW2(_n, _p) (!((_n) & ((_p) - 1))) |
There was a problem hiding this comment.
maybe UCS_DEVICE_IS_ALIGNED_POW2?
There was a problem hiding this comment.
makes sense, my bad.
|
|
||
| HIPCC ?= hipcc | ||
|
|
||
| HIPCC_CMD = $(HIPCC) -DHAVE_CONFIG_H -DUCT_DEVICE_CODE_HIP -fPIE -I$(top_srcdir)/src -I$(top_builddir)/src $(BASE_CXXFLAGS) $(CXXFLAGS) $(HIP_CPPFLAGS) $(HIP_CXXFLAGS) $(HIPCC_EXTRA_FLAGS) -Wno-c++20-extensions -c $< -MT $@ -MF $(DEPDIR)/hip/$@.d -MMD -o $@ |
There was a problem hiding this comment.
better $(DEFS) for -DHAVE_CONFIG_H
| ucs_status_t status; | ||
| uct_allocated_memory_t mem; | ||
| const ucp_worker_h worker = UCS_PARAM_VALUE(UCP_DEVICE_MEM_LIST_PARAMS_FIELD, | ||
| params, worker, WORKER, NULL); |
| if (status != UCS_OK) { | ||
| ucs_error("Failed to create ROCm IPC component cache: %s", | ||
| ucs_status_string(status)); | ||
| pthread_mutex_unlock(&uct_rocm_ipc_component.lock); |
There was a problem hiding this comment.
where is it locked? isn't it leftover?
There was a problem hiding this comment.
Yes, missed cleaning it up.
| ucs_status_t status; | ||
|
|
||
| UCS_INIT_ONCE(&cache_init_once) { | ||
| if (uct_rocm_ipc_component.ipc_cache == NULL) { |
There was a problem hiding this comment.
isn't UCS_INIT_ONCE already do this?
| UCS_DEVICE_IS_ALIGNED_POW2((intptr_t)d1, sizeof(vec4))) { | ||
| const vec4 *s4 = reinterpret_cast<const vec4*>(s1); | ||
| vec4 *d4 = reinterpret_cast<vec4*>(d1); | ||
| size_t n4 = len / sizeof(vec4); |
There was a problem hiding this comment.
n4 is num_lines in block, what's diff?
why warp/block should have separate implementations?
There was a problem hiding this comment.
merged the implementations.
|
|
||
| /* System-wide atomic increment */ | ||
| __device__ static inline void | ||
| uct_rocm_ipc_atomic_inc(uint64_t *dst, uint64_t inc_value) |
There was a problem hiding this comment.
I'd call it atomic_add
|
|
||
| #define UCS_DEVICE_LEVEL_EXEC_ID 1 | ||
|
|
||
| #define UCS_DEVICE_LEVEL_EXEC_SELECT(scope_ok, count, id) \ |
There was a problem hiding this comment.
couldn't it be static __device__ function?
| { | ||
| unsigned int thread_id = threadIdx.x; | ||
| unsigned int num_threads = blockDim.x; | ||
| unsigned int warp_id = thread_id / 64; // ROCm wavefront size |
There was a problem hiding this comment.
why not use UCT_ROCM_IPC_WAVEFRONT_SIZE ?
| if HAVE_GNUXX11 | ||
| HIPCC_EXTRA_FLAGS = \ | ||
| $(HIP_CPPFLAGS) \ | ||
| -DHAVE_ROCM=1 \ |
There was a problem hiding this comment.
why not use __HIPCC__?
bcb736f to
a4ae783
Compare
|
@ofirfarjun7 @Artemy-Mellanox if the changes are satisfactory and the PR is ready to be merged, I would first like to squash the commits with an appropriate commit message and force push it (unless it allows me to squash it online). |
|
@mshanthagit please fix all issues that cause CI to fail. |
@ofirfarjun7 looks like the CI issues are related to "docker pull" failures. Please let me know if I missed anything obvious. |
a4ae783 to
7d70850
Compare
|
@ofirfarjun7 @Artemy-Mellanox I have rebased and there are no conflicts. There seems to be a failure, but I suspect it is not related to this PR. Please let me know if there's anything else blocking the approval. As noted earlier, I would like to squash the PR into a single commit, shall I do that now? |
| self->remote_pid = *(const pid_t*)params->iface_addr; | ||
|
|
||
| snprintf(target_name, sizeof(target_name), "dest:%d", *(pid_t*)params->iface_addr); | ||
| status = uct_rocm_ipc_create_cache(&self->remote_memh_cache, target_name); |
There was a problem hiding this comment.
Can it create issues if cache is not private for each EP and lookup criteria is only remote VA?
There was a problem hiding this comment.
In addition to the remote VA, ipc handles are compared as well to avoid conflicts. Do you foresee any issues with this appoach?
There was a problem hiding this comment.
But if ipc handles are not the same you remove it from the cache because it is "stale region".
But what if two remote processes has two regions with same VA?
There was a problem hiding this comment.
In that case, we might see a ping-pong of effect that may impact performance, as the process has to now go though hsa_amd_ipc_memory_attach instead of using cached entry.
There was a problem hiding this comment.
Maybe add another dimension to the key? You can examine cuda ipc cache.
If you think it will just impact performance and you prefer to leave it as is let me know.
|
Could we try to get this PR over the finish line and have it merged? It has been opened on March 15, so its now nearly five months that it is pending. |
| self->remote_pid = *(const pid_t*)params->iface_addr; | ||
|
|
||
| snprintf(target_name, sizeof(target_name), "dest:%d", *(pid_t*)params->iface_addr); | ||
| status = uct_rocm_ipc_create_cache(&self->remote_memh_cache, target_name); |
There was a problem hiding this comment.
But if ipc handles are not the same you remove it from the cache because it is "stale region".
But what if two remote processes has two regions with same VA?
If these two are not a concern from your point of view let us know and we will finish the review Potential performance issue: |
|
@edgargabriel @mshanthagit Cross-linking the W7900 compatibility result from ai-dynamo/nixl#2039. I tested No handle-cache or device-initiated PUT code was changed. Full methods and hashes: Would you prefer the capability flag and a multi-process peer-exit regression to be absorbed into this PR, or handled as a small dependent follow-up? |
@ofirfarjun7 thank you, those things are a concern for us, and we discussed this with @mshanthagit internally. We think the most efficient way forward would be to merge this PR with a clear understanding of the shortcomings. The host-path is from the correctness perspective not affected (so we do not introduce a regression). There is potential for a performance regression in certain scenarios. However, because this is a massive PR we think its better to get it merged and fix the caching issue in a subsequent PR (which might come as soon as next week). The follow-up PR would only touch rocm_ipc and would have no impact on the rest of the UCX code base. With this current PR, we are constantly rebasing to pull in updates to the repo, and had to resolve a number of conflicts over the weeks, its one of the reasons we would see benefits in merging this PR and fix the problems in a follow-up PR. |
Introduces device initiated IPC put operation for the ROCm component. - Add device-side rocm_ipc.h with HIP __device__ put/atomic_add/get_ptr, including a strided int4/int2 vectorized copy at thread/warp/block levels. - Add MD mem_elem_pack/rkey_ptr that map the remote IPC handle via a shared, lazily-initialized process-wide handle cache; iface/ep now expose a device ep.
4dddf15 to
57556bb
Compare
I merged so you can progress. |
| static ucs_status_t | ||
| ucp_device_detect_local_sys_dev(ucp_context_h context, | ||
| ucs_memory_type_t mem_type, | ||
| ucp_device_detect_local_sys_dev(const ucp_context_h context, |
There was a problem hiding this comment.
Please remove this const. Since it's typedef struct ucp_context *ucp_context_h, it does not work as readers might expect.
| if (worker == NULL) { | ||
| ucs_error("missing worker in local mem list params"); | ||
| return UCS_ERR_INVALID_PARAM; | ||
| } |
There was a problem hiding this comment.
Please refactor this to avoid checking this parameter twice.
| const ucs_memory_type_t mem_type, uct_allocated_memory_t *mem, | ||
| const ucs_sys_device_t local_sys_dev) |
There was a problem hiding this comment.
Please swap the last two parameters, so that all input parameters go before the output.
What?
This PR introduces device initiated IPC put operation for the rocm component.
Why?
It is a new functionality to enable device initiated communication.
How?
It is optional, but for complex PRs, please provide information about the design,
architecture, approach, etc.