TL/UCP: add exact mixed-radix allgather schedules - #1327
Conversation
2dab095 to
828683a
Compare
367c6f9 to
828683a
Compare
|
Maintainer note on the I intentionally reduced this file to the functional seven-line The minimal diff may therefore make the codestyle check fail. Could maintainers |
da58ec5 to
d737a5a
Compare
Add explicit per-phase radix schedules to TL/UCP K-nomial AllGather while preserving the fixed-radix and AllGatherV paths. Parse and validate exact schedules through the existing team configuration.
Cover schedule parsing, legacy fixed-radix behavior, and exact mixed-radix peer and segment layouts.
d737a5a to
94d3bd9
Compare
|
| Filename | Overview |
|---|---|
| src/coll_patterns/knomial.h | Introduces the radix-sequence representation, indexed access, and exact-product validation. |
| src/coll_patterns/recursive_knomial.h | Persists the initialization sequence and advances the active radix between mixed-radix phases. |
| src/coll_patterns/sra_knomial.h | Extends AllGather pattern initialization to exact mixed-radix schedules while preserving fixed-radix initialization. |
| src/components/tl/ucp/allgather/allgather_knomial.c | Selects configured schedules and uses each phase’s active radix during AllGather communication. |
| src/components/tl/ucp/tl_ucp.c | Changes ALLGATHER_KN_RADIX to the new sequence-capable configuration type. |
| src/utils/ucc_parser.c | Implements parsing, cloning, lookup storage, formatting, and destruction for ranged radix schedules. |
| src/utils/ucc_parser.h | Defines the sequence-aware ranged configuration structures and parser type. |
| test/gtest/coll/test_knomial_seq.cc | Covers fixed-radix compatibility and exact mixed-radix peer and segment layouts. |
| test/gtest/utils/test_parser.cc | Covers valid and invalid schedules, range selection, formatting bounds, and deep cloning. |
Reviews (6): Last reviewed commit: "TL/UCP: unify radix sequence state" | Re-trigger Greptile
|
/build |
| UCC_CONFIG_TYPE_UINT_RANGED}, | ||
|
|
||
| {"ALLGATHER_KN_MIXED_RADICES", "", | ||
| "Optional exact mixed-radix schedule for knomial allgather, for example " |
There was a problem hiding this comment.
i would maybe change semantic here, instead of exact decompostion consider it as allowed factors in decomposition so it generalises to any team size in a run.
There was a problem hiding this comment.
don't we want the option for the user to provide the exact order ? (between 8x6 and 6x8 for example) I'm thinking that maybe the user would for example want to start with the first radix being the number of ranks in one node.
In the second PR, I provide an auto tuner that selects the radices and the order anyways but if the user chooses to select, I was thinking we ggive him "full control"
There was a problem hiding this comment.
Agree, but at the same time if we consider this config as exact decomposition then it is less useful. If context creates multiple teams of different size then most of them will skip this value. Maybe extend with extra "=", for instance
RADIX="2x3x4" tells UCC to decompose using provided values
RADIX="=2x3x4" use exact decomposition and works for team size 24 only
There was a problem hiding this comment.
I kept the x-separated value as an exact ordered sequence. We already have auto for team-size-independent selection and the explicit sequence for users who need exact ordering. To handle contexts containing teams of different sizes, a sequence-product mismatch now falls back to auto instead of failing. This addresses the multi-team concern without introducing a third allowed-factors mode or additional = syntax.
|
🤖 CI Triage Agent — TL;DR: The Full analysisSummary: clang-tidy failed with 1 warning-treated-as-error: "Value stored to 'radix' is never read" in Root cause: In Implicated commit: d17161b — "TL/UCP: address mixed-radix review" by jeffnvidia (the exact commit under test); the mixed-radix pattern work in ec51644 is the origin of the pattern-init reshuffle. File: src/components/tl/ucp/allgather/allgather_knomial.c:250 Suggested fix: Delete the dead assignment Related: PR #1327 (this change); prior mixed-radix PRs touching this file (#1176, #1072). No existing issue found for this specific warning. |
|
🤖 CI Triage Agent — TL;DR: The Full analysisSummary: clang-tidy Root cause: In Implicated commit: File: Suggested fix: Remove the now-unused Related: PR #1327 (this PR, |
|
🤖 CI Triage Agent — TL;DR: The Full analysisSummary: clang-tidy-17 static analysis failed with 1 warning treated as error: dead store to Root cause: In Implicated commit: d17161b — jeffnvidia, "TL/UCP: address mixed-radix review" (HEAD of PR #1327; the dead-store pattern originates in the mixed-radix series starting ec51644). File: src/components/tl/ucp/allgather/allgather_knomial.c:250 Suggested fix: Delete the dead assignment on line 250 ( Related: PR #1327 (jmahou/ucc-mixed-radix-clean); prior mixed-radix commit ec51644. |
| if (nradices == 1) { | ||
| ucc_knomial_pattern_init(size, rank, radices[0], p); | ||
| p->type = KN_PATTERN_ALLGATHER; | ||
| p->count = count; | ||
| p->block_size = p->radix_pow * p->radix; | ||
| p->block_offset = ucc_knomial_pattern_loop_rank(p, rank) / | ||
| p->block_size * p->block_size; | ||
| return; | ||
| } | ||
|
|
||
| p->radix = radices[0]; | ||
| p->type = KN_PATTERN_ALLGATHER; | ||
| p->iteration = 0; | ||
| p->n_iters = nradices; | ||
| p->node_type = KN_NODE_BASE; | ||
| p->backward = 0; | ||
| p->radix_pow = 1; | ||
| p->full_pow_size = size; | ||
| p->size = size; | ||
| p->rank = rank; | ||
| p->n_extra = 0; | ||
| p->count = count; | ||
| p->block_size = p->radix_pow * radix; | ||
| p->block_offset = ucc_knomial_pattern_loop_rank(p, rank) / p->block_size * | ||
| p->block_size; | ||
| p->block_size = p->radix; | ||
| p->block_offset = ucc_knomial_pattern_loop_rank(p, rank) / | ||
| p->block_size * p->block_size; | ||
| p->radices = radices; |
There was a problem hiding this comment.
this can be simplified, most of the field here relevant for nradices=1 and nradices>1
There was a problem hiding this comment.
Done. Fixed and exact sequences now both use ucc_knomial_pattern_init(). The exact case only overrides its specific invariants, and the common AllGather fields are initialized once.
| ucc_rank_t block_size; | ||
| ptrdiff_t block_offset; | ||
| int is64; | ||
| const ucc_kn_radix_t *radices; |
| typedef uint16_t ucc_kn_radix_t; | ||
| #define UCC_KN_MAX_RADIX_PHASES (sizeof(ucc_rank_t) * CHAR_BIT - 1) | ||
|
|
||
| typedef struct ucc_kn_radix_schedule { |
There was a problem hiding this comment.
this strucutre belongs to knomial pattern. Also schedule is not a good name, it mixes with ucc_schedule_t . Maybe ucc_kn_radix_seq?
There was a problem hiding this comment.
Done. The radix type and sequence now live in coll_patterns/knomial.h, and I renamed the type to ucc_kn_radix_seq_t to avoid confusion with ucc_schedule_t.
| ucc_rank_t block_size; | ||
| ptrdiff_t block_offset; | ||
| int is64; | ||
| const ucc_kn_radix_t *radices; |
There was a problem hiding this comment.
why not to use ucc_kn_radix_schedule?
There was a problem hiding this comment.
Done. The pattern now keeps a pointer to the complete ucc_kn_radix_seq_t, rather than only the raw radix array.
| task->allgather_kn.p.n_iters = schedule->n_radices; | ||
| } else { | ||
| task->allgather_kn.p.radices = NULL; | ||
| task->allgather_kn.p.n_iters = 0; |
There was a problem hiding this comment.
why need to set n_iters here? It should be part of init or reset
There was a problem hiding this comment.
Done. Collective initialization now only stores the sequence pointer. n_iters is set by ucc_kn_ag_pattern_init() whenever the pattern is initialized or restarted.
Keep the exact radix sequence with the K-nomial pattern, initialize fixed and exact patterns through the common path, and fall back to automatic radix selection when the sequence product does not match the team size. Extend focused tests to cover exact-pattern invariants and restart.
| ucc_kn_radix_t radix, | ||
| const ucc_kn_radix_seq_t *radix_seq, size_t count, |
There was a problem hiding this comment.
let's pass only radix_seq here as argument. No reason to keep both while single value radix can be represented as radix_seq of len 1
There was a problem hiding this comment.
Done. ucc_kn_ag_pattern_init() now takes only radix_seq and derives the initial radix from it. A fixed radix is represented as a sequence of length one.
| ucc_status_t ucc_tl_ucp_allgather_knomial_init_r( | ||
| ucc_base_coll_args_t *coll_args, ucc_base_team_t *team, | ||
| ucc_coll_task_t **task_h, ucc_kn_radix_t radix) | ||
| { | ||
| return ucc_tl_ucp_allgather_knomial_init_common( | ||
| coll_args, team, task_h, radix, NULL); | ||
| } |
There was a problem hiding this comment.
why do we need init_common if it just same as init_r?
There was a problem hiding this comment.
Removed init_common. The sequence initializer is now the private implementation. The existing scalar init_r entry point is retained as a thin compatibility wrapper and delegates through a one-element sequence.
| const ucc_kn_radix_seq_t *radix_seq = p->radix_seq; | ||
| ucc_kn_radix_t radix = radix_seq ? radix_seq->radices[0] : | ||
| p->radix; |
| task->subset.map = sbgp->map; | ||
| } | ||
| task->allgather_kn.p.radix = radix; | ||
| task->allgather_kn.p.radix_seq = |
There was a problem hiding this comment.
keep only radix_seq, single radix is radix_seq of size 1
There was a problem hiding this comment.
Done. The task now stores only the persistent radix_seq. Fixed radix is stored as a one-element sequence. p->radix is initialized by the pattern and is used only as the active radix for the current phase.
| coll_args, team, task_h, radix); | ||
| } | ||
| if (!ucc_tl_ucp_allgather_knomial_seq_matches(radix_seq, tsize)) { | ||
| tl_debug(UCC_TL_TEAM_LIB(tl_team), |
There was a problem hiding this comment.
rework code duplication
There was a problem hiding this comment.
Done. Initialization now constructs the auto sequence once and only overrides it for a valid configured fixed or exact sequence. An invalid exact sequence simply leaves the auto value in place. Sequence validation is centralized.
| return ucc_tl_ucp_allgather_knomial_init_r( | ||
| coll_args, team, task_h, radix); | ||
| } | ||
| if (!ucc_tl_ucp_allgather_knomial_seq_matches(radix_seq, tsize)) { |
There was a problem hiding this comment.
is it enough? will it work if we have a sequence like this [0]?
There was a problem hiding this comment.
Handled. The parser rejects radix zero, and validation independently rejects a constructed one-element zero sequence, zero inside a mixed sequence, missing storage, overflow, and product mismatch. These cases are covered by the new validation test.
| ucc_rank_t block_size; | ||
| ptrdiff_t block_offset; | ||
| int is64; | ||
| const ucc_kn_radix_seq_t *radix_seq; |
|
|
||
| ASSERT_TRUE(ucc_config_sscanf_kn_radix( | ||
| "0-4K:host:8x6,4K-inf:cuda:4,auto", &p, NULL)); | ||
| expect_schedule( |
There was a problem hiding this comment.
need to rename after changing kn_schedule > kn_seq. Here and other places
There was a problem hiding this comment.
Done. The helper, test names, test file, and configuration descriptions now consistently use “sequence” rather than “schedule”.
| gtest_LDADD += $(UCX_LIBS) $(UCX_LIBADD) | ||
| endif | ||
|
|
||
| if TL_UCP_ENABLED |
There was a problem hiding this comment.
why test knomial_schedule depends on TL UCP?
There was a problem hiding this comment.
It no longer depends on TL/UCP. The test was renamed to test_knomial_seq.cc, uses only the generic K-nomial pattern code, and is now included unconditionally in the gtest sources.
What
Add exact per-phase radix schedules to TL/UCP K-nomial AllGather. A schedule
such as
8x6uses radix 8 in the first phase and radix 6 in the second; itsproduct must equal the team size.
Set an explicit schedule with, for example:
The same option accepts a fixed radix or
auto. The existing fixed-radix pathand AllGatherV behavior remain unchanged. Invalid schedules are rejected, and
existing algorithm tuning still decides whether K-nomial AllGather is selected.
Why
For non-power team sizes, a fixed radix can produce a truncated final phase or
proxy/extra ranks. An exact mixed schedule covers the complete team with an
explicit radix for every phase.
Across three tested environments at 96 ranks, a representative exact schedule
improved the large-message endpoint by 1.81x--1.99x over the best measured
fixed radix by avoiding the fixed-radix remainder path.
Performance evidence
Results are intentionally anonymized and normalized to the best measured
fixed-radix execution for each environment. Each row uses one exact schedule
at the endpoint; it is not a pointwise best-schedule envelope.
4x4x62x2x2x2x2x38x3x4These relative results demonstrate the remainder-path mechanism; they are not
intended as absolute system-performance comparisons.
Validation
8x2,2x8,and
4x4; all cases passed with zero failures.exact mixed peer sets, segment sizes, and offsets for every rank.
Automatic schedule selection is proposed separately in #1328.