Repository navigation
UCP/CORE: Add shared topology assignment policy #11980
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
3f1fa07
8514fbe
e66bc85
8d616a0
e651c57
abc8ac4
9413b2a
fe3025b
173d40f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -108,6 +108,15 @@ static const char *ucp_fence_modes[] = { | |||||||||||||||||
| [UCP_FENCE_MODE_LAST] = NULL | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| static const char *ucp_gpu_nic_assignment_modes[] = { | ||||||||||||||||||
| [UCP_GPU_NIC_ASSIGNMENT_MODE_AUTO] = "auto", | ||||||||||||||||||
| [UCP_GPU_NIC_ASSIGNMENT_MODE_OFF] = "off", | ||||||||||||||||||
| [UCP_GPU_NIC_ASSIGNMENT_MODE_FLIP] = "flip", | ||||||||||||||||||
| [UCP_GPU_NIC_ASSIGNMENT_MODE_ROUND_ROBIN] = "round_robin", | ||||||||||||||||||
| [UCP_GPU_NIC_ASSIGNMENT_MODE_SHARED] = "shared", | ||||||||||||||||||
| [UCP_GPU_NIC_ASSIGNMENT_MODE_LAST] = NULL | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| static const char *ucp_rndv_modes[] = { | ||||||||||||||||||
| [UCP_RNDV_MODE_AUTO] = "auto", | ||||||||||||||||||
| [UCP_RNDV_MODE_GET_ZCOPY] = "get_zcopy", | ||||||||||||||||||
|
|
@@ -162,6 +171,7 @@ const char *ucp_extra_op_attr_flags_names[] = { | |||||||||||||||||
| static UCS_CONFIG_DEFINE_ARRAY(memunit_sizes, sizeof(size_t), | ||||||||||||||||||
| UCS_CONFIG_TYPE_MEMUNITS); | ||||||||||||||||||
|
|
||||||||||||||||||
| /* clang-format off */ | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: the Rationale: only |
||||||||||||||||||
| static ucs_config_field_t ucp_context_config_table[] = { | ||||||||||||||||||
| {"SELECT_DISTANCE_MD", "cuda_cpy", | ||||||||||||||||||
| "MD whose distance is queried when evaluating transport selection score", | ||||||||||||||||||
|
|
@@ -615,6 +625,16 @@ static ucs_config_field_t ucp_context_config_table[] = { | |||||||||||||||||
| ucs_offsetof(ucp_context_config_t, connect_all_to_all), | ||||||||||||||||||
| UCS_CONFIG_TYPE_BOOL}, | ||||||||||||||||||
|
|
||||||||||||||||||
| {"GPU_NIC_ASSIGNMENT_MODE", "auto", | ||||||||||||||||||
|
tvegas1 marked this conversation as resolved.
Resolved
|
||||||||||||||||||
| "Select how NICs are assigned to GPUs.\n" | ||||||||||||||||||
| " - auto : enable automatically on supported hardware, otherwise disable.\n" | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think it should mention what policy will be used, no?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general the policy can be adapted automatically according to whatever hw is detected, so I decided to not be too specific here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "not shared" wording is hard to follow for users reading
Suggested change
|
||||||||||||||||||
| " - off : disable GPU-to-NIC assignment, fallback to free lane selection.\n" | ||||||||||||||||||
| " - flip : require the not shared flip assignment policy.\n" | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: "require the not shared flip assignment policy" is hard to parse; pls describe what each policy does.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. help text wording — minor: "require the not shared ... policy" is hard to parse for users. Suggested: |
||||||||||||||||||
| " - round_robin : require the not shared round-robin assignment policy.\n" | ||||||||||||||||||
| " - shared : require the shared assignment policy.", | ||||||||||||||||||
| ucs_offsetof(ucp_context_config_t, gpu_nic_assignment_mode), | ||||||||||||||||||
| UCS_CONFIG_TYPE_ENUM(ucp_gpu_nic_assignment_modes)}, | ||||||||||||||||||
|
|
||||||||||||||||||
| {"SINGLE_NET_DEVICE", "n", | ||||||||||||||||||
| "Restrict each protocol's lanes to one network device.\n" | ||||||||||||||||||
| "The device is picked among the closest eligible network devices using \n" | ||||||||||||||||||
|
|
@@ -650,6 +670,7 @@ static ucs_config_field_t ucp_context_config_table[] = { | |||||||||||||||||
|
|
||||||||||||||||||
| {NULL} | ||||||||||||||||||
| }; | ||||||||||||||||||
| /* clang-format on */ | ||||||||||||||||||
|
|
||||||||||||||||||
| static ucs_config_field_t ucp_config_table[] = { | ||||||||||||||||||
| {"NET_DEVICES", UCP_RSC_CONFIG_ALL, | ||||||||||||||||||
|
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,35 @@ typedef struct { | |
| } ucp_nics_string_buffers_t; | ||
|
|
||
|
|
||
| int ucp_gpu_nic_assignment_policy_resolve( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we drop
the streamlined check in ucp_context_gpu_nic_assignment_init() would be like below and this leaves the PR with just the shared policy, the config knob and the shared tests. ucp_gpu_nic_assignment_mode_t mode =
context->config.ext.gpu_nic_assignment_mode;
...
if (mode == UCP_GPU_NIC_ASSIGNMENT_MODE_AUTO) {
/* TODO: Improve Vera Rubin detection by checking NICs/GPUs models. */
mode = (ucs_arch_get_cpu_model() == UCS_CPU_MODEL_NVIDIA_VERA) ?
UCP_GPU_NIC_ASSIGNMENT_MODE_FLIP :
UCP_GPU_NIC_ASSIGNMENT_MODE_OFF;
}
if (mode == UCP_GPU_NIC_ASSIGNMENT_MODE_OFF) {
ucs_debug("gpu-nic assignment is disabled, cpu model %s",
ucs_cpu_model_name());
return UCS_OK;
}
ucs_debug("gpu-nic assignment mode %s, cpu model %s",
ucp_gpu_nic_assignment_modes[mode], ucs_cpu_model_name());
/* ... build groups, allocate assignment ... */
status = ucp_gpu_nic_assignment_build(&groups, mode, assignment);There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pls add a gtest for Rationale: the whole user-visible behavior added by this PR is the mode→policy resolution; |
||
| ucp_gpu_nic_assignment_mode_t mode, ucs_cpu_model_t cpu_model, | ||
| ucp_gpu_nic_assignment_policy_t *policy_p) | ||
| { | ||
| ucs_assert(policy_p != NULL); | ||
|
|
||
| switch (mode) { | ||
| case UCP_GPU_NIC_ASSIGNMENT_MODE_AUTO: | ||
| if (cpu_model != UCS_CPU_MODEL_NVIDIA_VERA) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This happens implicitly with the other policies too, no? Is this really needed if the topology groups aren't being created on vera anyway?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When #11976 is merged I would remove the other check and depend only on this function to check if groups and assignments should be built |
||
| return 0; | ||
| } | ||
| *policy_p = UCP_GPU_NIC_ASSIGNMENT_POLICY_FLIP; | ||
| return 1; | ||
| case UCP_GPU_NIC_ASSIGNMENT_MODE_OFF: | ||
| return 0; | ||
| case UCP_GPU_NIC_ASSIGNMENT_MODE_FLIP: | ||
| *policy_p = UCP_GPU_NIC_ASSIGNMENT_POLICY_FLIP; | ||
| return 1; | ||
| case UCP_GPU_NIC_ASSIGNMENT_MODE_ROUND_ROBIN: | ||
| *policy_p = UCP_GPU_NIC_ASSIGNMENT_POLICY_ROUND_ROBIN; | ||
| return 1; | ||
| case UCP_GPU_NIC_ASSIGNMENT_MODE_SHARED: | ||
| *policy_p = UCP_GPU_NIC_ASSIGNMENT_POLICY_SHARED; | ||
| return 1; | ||
| default: | ||
| ucs_fatal("invalid gpu-nic assignment mode %d", (int)mode); | ||
| } | ||
| } | ||
|
|
||
| static size_t | ||
| ucp_gpu_nic_assignment_get_gpu_idx(ucp_gpu_nic_assignment_policy_t policy, | ||
| size_t num_gpus, size_t nic_idx) | ||
|
|
@@ -327,16 +356,39 @@ ucp_gpu_nic_assignment_init(ucp_gpu_nic_assignment_t *assignment, | |
| } | ||
|
|
||
| static void | ||
| ucp_gpu_nic_assignment_add_group(ucp_gpu_nic_assignment_t *assignment, | ||
| const ucs_topo_group_t *group, | ||
| ucp_gpu_nic_assignment_policy_t policy) | ||
| ucp_gpu_nic_assignment_add_group_shared(ucp_gpu_nic_assignment_t *assignment, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we merge add_group_shared() and add_group_not_shared() into a single function either one of the two loop order below so that we have one assignment area? static void
ucp_gpu_nic_assignment_add_group(ucp_gpu_nic_assignment_t *assignment,
const ucs_topo_group_t *group,
ucp_gpu_nic_assignment_policy_t policy)
{
size_t num_gpus = ucs_array_length(&group->gpus);
ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap;
const ucs_topo_group_element_t *gpu, *nic;
size_t gpu_idx, nic_idx;
ucs_array_for_each_index(gpu, gpu_idx, &group->gpus) {
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*,
ucp_gpu_nic_assignment_lookup(assignment, gpu->sys_devs[0]));
ucs_assert(nic_sys_dev_bitmap != NULL);
ucs_array_for_each_index(nic, nic_idx, &group->nics) {
if ((policy != UCP_GPU_NIC_ASSIGNMENT_POLICY_SHARED) &&
(ucp_gpu_nic_assignment_get_gpu_idx(policy, num_gpus,
nic_idx) != gpu_idx)) {
continue;
}
ucp_gpu_nic_bitmap_add_nic(nic_sys_dev_bitmap, nic);
}
}
}iterating the nics first in the shared case sets the same bits, so the tests should not change: static void
ucp_gpu_nic_assignment_add_group(ucp_gpu_nic_assignment_t *assignment,
const ucs_topo_group_t *group,
ucp_gpu_nic_assignment_mode_t mode)
{
size_t num_gpus = ucs_array_length(&group->gpus);
const ucs_topo_group_element_t *gpu, *nic;
size_t nic_idx, gpu_idx;
ucs_array_for_each_index(nic, nic_idx, &group->nics) {
if (mode == UCP_GPU_NIC_ASSIGNMENT_MODE_SHARED) {
/* Assign the NIC to every GPU in the group. */
ucs_array_for_each(gpu, &group->gpus) {
ucp_gpu_nic_assignment_add_nic_to_gpu(assignment, gpu, nic);
}
} else {
gpu_idx = ucp_gpu_nic_assignment_get_gpu_idx(mode, num_gpus,
nic_idx);
gpu = &ucs_array_elem(&group->gpus, gpu_idx);
ucp_gpu_nic_assignment_add_nic_to_gpu(assignment, gpu, nic);
}
}
} |
||
| const ucs_topo_group_t *group) | ||
| { | ||
| ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap; | ||
| const ucs_topo_group_element_t *gpu, *nic; | ||
|
|
||
| ucs_array_for_each(gpu, &group->gpus) { | ||
| ucs_assert((gpu->num_sys_devs > 0) && | ||
| (gpu->sys_devs[0] != UCS_SYS_DEVICE_ID_UNKNOWN)); | ||
|
|
||
| nic_sys_dev_bitmap = ucs_const_cast( | ||
|
guy-ealey-morag marked this conversation as resolved.
Resolved
guy-ealey-morag marked this conversation as resolved.
Resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the gpu bitmap lookup and asserts here are a copy of the block in |
||
| ucp_gpu_nic_sys_dev_bitmap_t*, | ||
| ucp_gpu_nic_assignment_lookup(assignment, gpu->sys_devs[0])); | ||
| ucs_assert(nic_sys_dev_bitmap != NULL); | ||
|
|
||
| /* Assign all NICs in the group to the GPU. */ | ||
| ucs_array_for_each(nic, &group->nics) { | ||
| ucp_gpu_nic_bitmap_add_nic(nic_sys_dev_bitmap, nic); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| static void ucp_gpu_nic_assignment_add_group_not_shared( | ||
| ucp_gpu_nic_assignment_t *assignment, const ucs_topo_group_t *group, | ||
| ucp_gpu_nic_assignment_policy_t policy) | ||
| { | ||
| size_t num_gpus = ucs_array_length(&group->gpus); | ||
| ucp_gpu_nic_sys_dev_bitmap_t *nic_sys_dev_bitmap; | ||
| const ucs_topo_group_element_t *nic; | ||
| const ucs_topo_group_element_t *gpu; | ||
| size_t nic_idx; | ||
| size_t gpu_idx; | ||
| const ucs_topo_group_element_t *gpu, *nic; | ||
| size_t nic_idx, gpu_idx; | ||
|
|
||
| ucs_assertv(policy != UCP_GPU_NIC_ASSIGNMENT_POLICY_SHARED, | ||
| "invalid policy: %d", (int)policy); | ||
|
|
||
| ucs_array_for_each_index(nic, nic_idx, &group->nics) { | ||
| gpu_idx = ucp_gpu_nic_assignment_get_gpu_idx(policy, num_gpus, nic_idx); | ||
|
|
@@ -354,6 +406,18 @@ ucp_gpu_nic_assignment_add_group(ucp_gpu_nic_assignment_t *assignment, | |
| } | ||
| } | ||
|
|
||
| static void | ||
| ucp_gpu_nic_assignment_add_group(ucp_gpu_nic_assignment_t *assignment, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this and inject policy in the called function, implement shared/not shared in one function |
||
| const ucs_topo_group_t *group, | ||
| ucp_gpu_nic_assignment_policy_t policy) | ||
| { | ||
| if (policy == UCP_GPU_NIC_ASSIGNMENT_POLICY_SHARED) { | ||
| ucp_gpu_nic_assignment_add_group_shared(assignment, group); | ||
| } else { | ||
| ucp_gpu_nic_assignment_add_group_not_shared(assignment, group, policy); | ||
| } | ||
| } | ||
|
|
||
| ucs_status_t | ||
| ucp_gpu_nic_assignment_build(const ucs_topo_groups_t *groups, | ||
| ucp_gpu_nic_assignment_policy_t policy, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,9 @@ | |
| #ifndef UCP_GPU_NIC_ASSIGNMENT_H_ | ||
| #define UCP_GPU_NIC_ASSIGNMENT_H_ | ||
|
|
||
| #include "ucp_types.h" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe define |
||
|
|
||
| #include <ucs/arch/cpu.h> | ||
| #include <ucs/datastruct/static_bitmap.h> | ||
| #include <ucs/sys/topo/base/topo_groups.h> | ||
|
|
||
|
|
@@ -52,10 +55,30 @@ typedef enum { | |
| */ | ||
| UCP_GPU_NIC_ASSIGNMENT_POLICY_ROUND_ROBIN, | ||
|
|
||
| /** | ||
| * Assign every NIC, with all of its ports, to every GPU in the group. | ||
| */ | ||
| UCP_GPU_NIC_ASSIGNMENT_POLICY_SHARED, | ||
|
|
||
| UCP_GPU_NIC_ASSIGNMENT_POLICY_LAST | ||
| } ucp_gpu_nic_assignment_policy_t; | ||
|
|
||
|
|
||
| /** | ||
| * Resolve the GPU-to-NIC assignment policy. | ||
| * | ||
| * @param [in] mode GPU-to-NIC assignment mode. | ||
| * @param [in] cpu_model CPU model used to resolve automatic mode. | ||
| * @param [out] policy_p Resolved assignment policy, | ||
| * populated only when assignment is enabled. | ||
| * | ||
| * @return Nonzero if assignment is enabled, or zero if it is disabled. | ||
| */ | ||
| int ucp_gpu_nic_assignment_policy_resolve( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| ucp_gpu_nic_assignment_mode_t mode, ucs_cpu_model_t cpu_model, | ||
| ucp_gpu_nic_assignment_policy_t *policy_p); | ||
|
|
||
|
|
||
| /** | ||
| * Build GPU-to-NIC assignments from topology groups. | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| /** | ||
| * Copyright (c) NVIDIA CORPORATION & AFFILIATES, 2001-2017. ALL RIGHTS RESERVED. | ||
| * Copyright (c) NVIDIA CORPORATION & AFFILIATES, 2001-2026. ALL RIGHTS RESERVED. | ||
| * | ||
| * See file LICENSE for terms. | ||
| */ | ||
|
|
@@ -233,6 +233,19 @@ typedef enum { | |
| } ucp_fence_mode_t; | ||
|
|
||
|
|
||
| /** | ||
| * GPU-to-NIC assignment mode. | ||
| */ | ||
| typedef enum { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: these per-value comments repeat the config help string in Rationale: the flip/round_robin/shared semantics are now written out in three places, so they will drift when a policy is added or changed. |
||
| UCP_GPU_NIC_ASSIGNMENT_MODE_AUTO, | ||
|
tvegas1 marked this conversation as resolved.
Resolved
|
||
| UCP_GPU_NIC_ASSIGNMENT_MODE_OFF, | ||
| UCP_GPU_NIC_ASSIGNMENT_MODE_FLIP, | ||
| UCP_GPU_NIC_ASSIGNMENT_MODE_ROUND_ROBIN, | ||
| UCP_GPU_NIC_ASSIGNMENT_MODE_SHARED, | ||
| UCP_GPU_NIC_ASSIGNMENT_MODE_LAST | ||
| } ucp_gpu_nic_assignment_mode_t; | ||
|
|
||
|
|
||
| /** | ||
| * Communication scheme in RNDV protocol. | ||
| */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for my understanding: can you pls remind me when/why the flip policy is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's because only one of the NICs on a CX9 board has SSD memory, so the goal is to have each GPU assigned to one with and one without SSD memory access.