Skip to content

UCP/RNDV: Throttle rndv fragment requests - #11062

Merged
ofirfarjun7 merged 76 commits into
openucx:masterfrom
amastbaum:add_throttling_to_rndv_fragment_requests
Nov 3, 2026
Merged

ofirfarjun7 merged 76 commits into
openucx:masterfrom
amastbaum:add_throttling_to_rndv_fragment_requests

Conversation

@amastbaum

@amastbaum amastbaum commented Dec 15, 2025 •

Copy link
Copy Markdown
Contributor

What?

Added a worker-level throttling mechanism for rndv fragment requests (both pipeline and standalone mtype requests).

Why?

Without throttling, rendezvous protocols can spawn an unbounded number of concurrent fragment requests, each allocating staging memory from GPU memory pools. Under heavy workloads, this leads to GPU memory exhaustion (OOM), as tracked in https://nvbugspro.nvidia.com/bug/5359018. The throttling mechanism bounds the number of in-flight fragments per worker, preventing resource exhaustion while allowing work to progress as fragments complete.

How?

The throttling is implemented using a worker-level flow control state (worker->rndv_ppln_fc) consisting of:

  • An active_frags counter tracking currently in-flight fragment operations
  • A pending_q queue holding throttled requests waiting for resources

When a new fragment request would exceed UCX_RNDV_PPLN_WORKER_MAX_FRAGS, the request is queued in pending_q. When fragments complete, active_frags is decremented and one queued request is rescheduled via ucs_callbackq_add_oneshot() to the main progress loop.

The mechanism applies to:

  • Pipeline fragment dispatch in rndv_ppln.c
  • Standalone mtype protocols in rndv_rtr.c, rndv_get.c, and rndv_put.c.

@amastbaum
amastbaum requested a review from gleon99 December 15, 2025 13:26
@amastbaum amastbaum added the WIP-DNM Work in progress / Do not review label Dec 15, 2025
@gleon99
gleon99 requested a review from shasson5 December 15, 2025 13:32
@amastbaum
amastbaum force-pushed the add_throttling_to_rndv_fragment_requests branch from 2be3040 to b175673 Compare December 15, 2025 14:45
@amastbaum amastbaum added Ready for Review and removed WIP-DNM Work in progress / Do not review labels Dec 15, 2025
Comment thread src/ucp/rndv/rndv_mtype.inl Outdated
Comment on lines +214 to +250
ucp_proto_rndv_mtype_fc_increment(ucp_request_t *req)
{
ucp_worker_h worker = req->send.ep->worker;

if (worker->context->config.ext.rndv_ppln_worker_fc_enable) {
worker->rndv_ppln_fc.active_frags++;
}
}

/**
* Decrement active_frags counter and reschedule pending request if any.
*/
static UCS_F_ALWAYS_INLINE void
ucp_proto_rndv_mtype_fc_decrement(ucp_request_t *req)
{
ucp_worker_h worker = req->send.ep->worker;
ucp_context_h context = worker->context;

if (!context->config.ext.rndv_ppln_worker_fc_enable) {
return;
}

ucs_assert(worker->rndv_ppln_fc.active_frags > 0);
worker->rndv_ppln_fc.active_frags--;

if (!ucs_queue_is_empty(&worker->rndv_ppln_fc.pending_q)) {
ucp_request_t *pending_req;
ucs_queue_elem_t *elem;

elem = ucs_queue_pull(&worker->rndv_ppln_fc.pending_q);
pending_req = ucs_container_of(elem, ucp_request_t,
send.rndv.ppln.queue_elem);
ucs_callbackq_add_oneshot(&worker->uct->progress_q, pending_req,
ucp_proto_rndv_mtype_fc_reschedule_cb,
pending_req);
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it can be named better, or I should divide it differently

Comment thread src/ucp/core/ucp_context.c Outdated
Comment on lines +391 to +394
{"RNDV_MTYPE_WORKER_MAX_FRAGS", "1024",
"Maximum number of concurrent mtype fragments per worker\n"
"(only applies when RNDV_MTYPE_WORKER_FC_ENABLE=y)",
ucs_offsetof(ucp_context_config_t, rndv_mtype_worker_max_frags), UCS_CONFIG_TYPE_ULUNITS},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shasson5 I am wondering if it's better to define RNDV_MTYPE_WORKER_MAX_FRAG_MEM instead, because the user shouldn't know how the amount of available memory is translated to the number of fragments.

The thing is that if we translate it in the code, it should be defined for each memory type (mem_type fragment size).

@gleon99
gleon99 requested a review from nbellalou December 31, 2025 09:43
nbellalou
nbellalou previously approved these changes Jan 1, 2026
Comment thread src/ucp/core/ucp_context.c Resolved
Comment thread src/ucp/core/ucp_worker.c Outdated
worker->counters.ep_closures = 0;
worker->counters.ep_failures = 0;

/* Initialize RNDV mtype flow control */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do it conditionally, only if fc enabled?

Comment thread src/ucp/rndv/rndv_get.c Outdated
rpriv = req->send.proto_config->priv;

if (!(req->flags & UCP_REQUEST_FLAG_PROTO_INITIALIZED)) {
/* GET priority: 80% of total fragments */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the meaning of 80%? Need to document/comment.
Will it always be a hard-coded magic value?

Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Outdated
* @return UCS_OK if not throttled, UCS_ERR_NO_RESOURCE if throttled and queued.
*/
static UCS_F_ALWAYS_INLINE ucs_status_t
ucp_proto_rndv_mtype_fc_check(ucp_request_t *req, size_t max_frags,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/ucp/rndv/rndv_rtr.c Outdated
rpriv = req->send.proto_config->priv;

/* RTR priority: 60% of total fragments */
max_frags = rpriv->fc_max_frags / 5 * 3;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain

Comment thread src/ucs/stats/libstats.h Outdated
unsigned num_counters;
unsigned class_id;
const char* counter_names[];
const char* counter_names[14]; /* Need to maintain the number of

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does that mean?

Comment thread test/gtest/ucp/test_ucp_am.cc Outdated

class test_ucp_am_nbx_rndv_mtype_fc : public test_ucp_am_nbx_rndv_ppln {
protected:
void check_stats_ge(entity &e, uint64_t cntr, uint64_t min_value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constify wherever possible

Comment thread test/gtest/ucp/test_ucp_am.cc Outdated

void verify_clean_fc_state()
{
check_active_frags_zero(sender());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

smth like

void verify_clean_fc_state()
{
    for (auto* ep : { sender(), receiver() })
    {
        check_active_frags_zero(ep);
        check_pending_queues_empty(ep);
    }
}

Comment thread test/gtest/ucp/test_ucp_am.cc Outdated
check_stats_ge(receiver(), UCP_WORKER_STAT_RNDV_RTR_MTYPE, 1);

/* No throttling should have occurred (FC is disabled) */
auto sender_throttled = UCS_STATS_GET_COUNTER(sender().worker()->stats,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern and similar are repeated multiple times across this file.

@yosefe

yosefe commented Mar 4, 2026

Copy link
Copy Markdown
Member

@rakhmets can you pls review as well?

Comment thread src/ucp/core/ucp_context.c Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
@amastbaum
amastbaum force-pushed the add_throttling_to_rndv_fragment_requests branch from 422d461 to 057df5d Compare March 11, 2026 17:42
@amastbaum
amastbaum requested review from gleon99 and rakhmets March 12, 2026 09:23
Comment thread src/ucp/core/ucp_context.c Outdated
"even if invalidation workflow isn't supported",
ucs_offsetof(ucp_context_config_t, rndv_errh_ppln_enable), UCS_CONFIG_TYPE_BOOL},

{"RNDV_MTYPE_WORKER_MAX_MEM", "inf",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to enable it by default?

Comment thread src/ucp/core/ucp_context.h Resolved
Comment thread src/ucp/core/ucp_worker.c Outdated
[UCP_WORKER_STAT_RNDV_RTR] = "rndv_rtr",
[UCP_WORKER_STAT_RNDV_RTR_MTYPE] = "rndv_rtr_mtype",
[UCP_WORKER_STAT_RNDV_RKEY_PTR] = "rndv_rkey_ptr",
[UCP_WORKER_STAT_RNDV_MTYPE_FC_THROTTLED] = "rndv_mtype_fc_throttled",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe smth like
UCP_WORKER_STAT_RNDV_FC_OK
UCP_WORKER_STAT_RNDV_FC_THROTTLED

Comment thread src/ucp/core/ucp_worker.c Outdated
Comment on lines +2631 to +2632
worker->rndv_mtype_fc.enabled = ucp_context_rndv_mtype_fc_enabled(context);
if (worker->rndv_mtype_fc.enabled) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need the variable worker->rndv_mtype_fc.enabled if already have it on the context config?
and we could initialize the queues unconditionally

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I could save loading context fields (and derefs) and also some comparisons.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could initialize the limit of frags to inf if it's unlimited - in the default case i think we want to enable the limit anyway

Comment thread src/ucp/core/ucp_worker.h Outdated
Comment on lines +406 to +408
ucs_queue_head_t put_pending_q; /* Throttled PUT (RNDV_SEND) requests */
ucs_queue_head_t get_pending_q; /* Throttled GET requests */
ucs_queue_head_t rtr_pending_q; /* Throttled RTR requests */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe 2 queues could be enough? hi-prio for get/put and low-prio for rtr

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably will do the job too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yosefe

  1. 2 queues are enough
  2. I also see that setting different memory caps for different operations is not needed, and that prioritizing PUT/GET is enough for preventing the deadlock.

Comment thread src/ucp/rndv/rndv_mtype.inl Outdated
}

/* Dequeue with priority: PUT > GET > RTR */
if (!ucs_queue_is_empty(&worker->rndv_mtype_fc.put_pending_q)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe give each queue an index (if we still need 3 queues):
UCP_WORKER_RNDV_FC_OP_PUT
UCP_WORKER_RNDV_FC_OP_GET
UCP_WORKER_RNDV_FC_OP_RTR
UCP_WORKER_RNDV_FC_OP_LAST

and keep a variable in the worker of the highest prio queue that has elements (LAST if FC is off), this way can find the relevant queue with less checks

Comment thread src/ucp/rndv/rndv_ppln.c Resolved
Comment thread src/ucp/rndv/rndv_put.c Resolved
Comment thread src/ucp/rndv/rndv_rtr.c Outdated
ucs_mpool_put_inline(req->send.rndv.mdesc);
}

ucp_proto_rndv_mtype_fc_decrement(req);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we move it inside the prev if condition?

Comment thread src/ucp/rndv/rndv_put.c Outdated

max_frags = UCP_PROTO_RNDV_MTYPE_FC_PUT_LIMIT(rpriv->bulk.fc_max_frags);
pending_q = &req->send.ep->worker->rndv_mtype_fc.put_pending_q;
if (ucp_proto_rndv_mtype_fc_throttle(req, max_frags, pending_q) ==

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems ucp_proto_rndv_mtype_fc_throttle is always called right before ucp_proto_rndv_mtype_request_init, maybe move it inside ucp_proto_rndv_mtype_request_init?

@amastbaum
amastbaum force-pushed the add_throttling_to_rndv_fragment_requests branch from 1919e03 to e0cabfd Compare March 17, 2026 15:25
@amastbaum
amastbaum requested a review from yosefe March 17, 2026 15:25
@amastbaum
amastbaum force-pushed the add_throttling_to_rndv_fragment_requests branch from e0cabfd to cba5c7d Compare March 17, 2026 15:29
@yosefe

yosefe commented Mar 17, 2026

Copy link
Copy Markdown
Member

Test failure seems related as the hang in cuda memory perftest

@amastbaum

Copy link
Copy Markdown
Contributor Author

Test failure seems related as the hang in cuda memory perftest

@yosefe Apparently it wasn't related to this PR.
It was reproduced on master as well (consistently) but when I rerun it here it succeeded.

@quasiben

Copy link
Copy Markdown

@yosefe can this PR be targeted for the upcoming v1.22 release ? I think there are already RCs but I don't see this being listed (perhaps I missed it)

Comment thread src/ucp/core/ucp_context.h Resolved
Comment thread src/ucp/core/ucp_worker.c Resolved
Comment thread src/ucp/core/ucp_context.h Resolved
Comment thread src/ucp/core/ucp_worker.h Resolved
Comment thread src/ucp/rndv/proto_rndv.c Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread test/gtest/ucp/test_ucp_am.cc Resolved
Comment thread test/gtest/ucp/test_ucp_am.cc Resolved
Comment thread test/gtest/ucp/test_ucp_am.cc Resolved
Comment thread test/gtest/ucp/test_ucp_am.cc Resolved
Comment thread src/ucp/core/ucp_context.c Resolved
Comment thread src/ucp/core/ucp_context.h Resolved
Comment thread src/ucp/core/ucp_worker.c Resolved
Comment thread src/ucp/core/ucp_worker.c Resolved
Comment thread src/ucp/rndv/proto_rndv.c Resolved
}


UCP_INSTANTIATE_TEST_CASE_GPU_AWARE(test_ucp_am_nbx_rndv_mtype_fc);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please add similar tests for get/rndv and put/rndv?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am keeping it for the next PR that will include further fixes, as this one should be merged these days

Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
Comment thread src/ucp/core/ucp_worker.c Resolved
Comment thread src/ucp/rndv/rndv_mtype.inl Resolved
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-ucx

svc-ucx commented Oct 18, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (Coverity coverity devel on coverity_rh7) · commit 45a77f13

TL;DR: The Coverity (coverity devel) stage failed with 1 new defect — an UNINIT_CTOR on rndv_frag_mpools's constructor because the POD member m_fail_ops (a ucs_mpool_ops_t) is never initialized; fix by value-initializing it (e.g. add m_fail_ops() to the ctor init list).

Full analysis

Summary: Coverity static analysis gate failed: ##[error]Coverity found 1 issues: /__w/1/s/test/gtest/ucp/rndv_frag_mpools.cc:32 Type: Uninitialized pointer field (UNINIT_CTOR).

Root cause: The build and cov-analyze both completed successfully (751 TUs, 1717 total defects, 1 flagged as new/unsuppressed), and the wrapper script exits non‑zero because nerrors=1 > 0. The reported defect is in the new test helper added by this PR: rndv_frag_mpools::rndv_frag_mpools(ucp_worker_h, ucs_memory_type_t) only initializes m_worker in its member-init list. The class member ucs_mpool_ops_t m_fail_ops (declared at test/gtest/ucp/rndv_frag_mpools.h:75) is a plain struct of function pointers, so its fields chunk_alloc, chunk_release, obj_init, obj_cleanup, obj_str are left indeterminate at the close of the constructor (line 32). Coverity reports all five as uninit_member. Functionally it is later overwritten in fail_alloc() (m_fail_ops = *mpool->data->ops; at line 86), so this is a real-but-benign uninitialized-field warning, not a runtime bug — but the Coverity job treats any new finding as a hard failure.

Implicated commit: 9f8df930 — "UCP/RNDV: Add rndv/get/mtype flow-control tests", Alma Mastbaum (branch add_throttling_to_rndv_fragment_requests, PR #11062, head [REDACTED:Hex High Entropy String])

File: test/gtest/ucp/rndv_frag_mpools.cc:17-32 (member declared at test/gtest/ucp/rndv_frag_mpools.h:75)

Suggested fix: Value-initialize the struct in the constructor's member-initializer list:

rndv_frag_mpools::rndv_frag_mpools(ucp_worker_h worker,
                                   ucs_memory_type_t mem_type) :
    m_worker(worker), m_fail_ops()   /* zero-initializes all function pointers */
{

(m_fail_ops() is valid C++11 value-initialization for a POD aggregate and silences UNINIT_CTOR. Equivalent alternatives: an in-class initializer ucs_mpool_ops_t m_fail_ops = {}; in the header, or memset(&m_fail_ops, 0, sizeof(m_fail_ops)); as the first statement.) Note the Coverity invocation already passes --checker-option UNINIT_CTOR:ctor_func:swap, so this checker is deliberately enabled — initializing the member is the right fix rather than suppressing it.

Related: PR #11062 — #11062

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id c9116e38-34b8-40e3-8380-c0535fbfdc64 in the triage console for the audit trail.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-ucx

svc-ucx commented Oct 19, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (Tests althca on worker 1) · commit 247506c5

TL;DR: The new gtest test_ucp_mmap.rndv_mpool_hash_growth fails on the althca node because it holds the only fragment of the (host, UNKNOWN, SHARED) rndv mpool and then asks that same pool for another fragment, which correctly returns UCS_ERR_NO_RESOURCE and trips ASSERT_UCS_OK. Fix the test: skip the already-held pool in the loop (or raise RNDV_FRAG_WORKER_MAX_MEM so the shared pool has ≥2 fragments).

Full analysis

Summary: tcp/test_ucp_mmap.rndv_mpool_hash_growth/1 <tcp,cuda_copy,rocm_copy/map_nb> failed (1 FAILED TEST, make: *** [test] Error 1), aborting the "althca on worker 1" job of Azure build 139806.

Root cause: Test-logic bug, not a library bug. The test is configured with RNDV_FRAG_SIZE=host:4K, RNDV_FRAG_ALLOC_COUNT=host:1, RNDV_FRAG_WORKER_MAX_MEM=8K (test_ucp_mmap.cc:1109-1112). With those settings ucp_proto_rndv_frag_max_elems() yields max_elems = 8K/4K = 2, and ucp_proto_rndv_frag_shared_elems() clamps the shared pool to ucs_min((unsigned)(max_elems*ratio), max_elems-1) → 1 fragment, leaving 1 for the reserved pool (src/ucp/rndv/proto_rndv.c:842-884).

The test then:

  1. takes first from the (HOST, UCS_SYS_DEVICE_ID_UNKNOWN, POOL_SHARED) pool — consuming its single-fragment quota (line 1131);
  2. loops over sys_devs × {SHARED, RESERVED} and ASSERT_UCS_OK(ucp_rndv_mpool_get(...)) for every combination (lines 1136-1143).

The first loop iteration hits sys_dev = UCS_SYS_DEVICE_ID_UNKNOWN, pool = SHARED — the exact pool whose only fragment is still held by first. ucp_rndv_mpool_get() takes the out_mp_get fast path, ucp_worker_mpool_get() returns NULL, and the function returns UCS_ERR_NO_RESOURCE (src/ucp/rndv/rndv.c:1229-1239) — correct quota behavior — so the ASSERT_UCS_OK fails.

This only reproduces on nodes with ≥2 TL system devices; everywhere else the test exits early via UCS_TEST_SKIP_R("not enough devices to create four pools") (line 1126-1128), which is why the test was never exercised until it landed on althca.

Implicated commit: 247506c5 — "UCP/CORE: Allocate rndv fragment mpools outside of the worker hash table", Alma Mastbaum (the PR HEAD commit; it added this test and the separately-allocated ucs_mpool_t* hash values).

File: test/gtest/ucp/test_ucp_mmap.cc:1136-1143 (assert at 1139), with quota logic at src/ucp/rndv/proto_rndv.c:868-884 and src/ucp/rndv/rndv.c:1229-1239.

Suggested fix: Don't re-request from the pool whose fragment is already held. Skip it in the loop:

for (ucs_sys_device_t sys_dev : sys_devs) {
    for (unsigned pool : {UCP_WORKER_RNDV_FRAG_POOL_SHARED,
                          UCP_WORKER_RNDV_FRAG_POOL_RESERVED}) {
        /* The only fragment of this pool is held by 'first' */
        if ((sys_dev == UCS_SYS_DEVICE_ID_UNKNOWN) &&
            (pool == UCP_WORKER_RNDV_FRAG_POOL_SHARED)) {
            continue;
        }
        ASSERT_UCS_OK(ucp_rndv_mpool_get(worker, UCS_MEMORY_TYPE_HOST,
                                         sys_dev, pool, &mdesc));
        ucs_mpool_put(mdesc);
    }
}

The hash still grows: the pre-existing (UNKNOWN, SHARED) entry plus the three created in the loop make 4 insertions, which is the khash growth point the test targets, so ASSERT_GT(kh_n_buckets(...), num_buckets) at line 1145 still holds. Alternatively, raise RNDV_FRAG_WORKER_MAX_MEM to 16K so shared_elems >= 2 and the loop's first get succeeds — but the explicit skip is clearer about intent and keeps the quota minimal.

Related: PR #11062 ("UCP/RNDV: Throttle rndv fragment requests"); same series as 5a8bdb4b (reserved-pool split) and 21d5bb87 (always keep a fragment for PUT/GET).

@amastbaum
amastbaum force-pushed the add_throttling_to_rndv_fragment_requests branch from 247506c to 58b3523 Compare October 19, 2026 09:20
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-ucx

svc-ucx commented Oct 19, 2026

Copy link
Copy Markdown

🤖 CI Triage Agent — UCX PR (Coverity coverity devel on coverity_rh7) · commit e11b44b8

TL;DR: The Coverity devel stage failed with 1 defect — UNINIT_CTOR on rndv_frag_mpools's constructor, because the new member m_fail_ops (a ucs_mpool_ops_t of function pointers) is never initialized in the constructor. Fix by value-initializing it in the member-init list (m_fail_ops{}) or memseting it in the ctor body.

Full analysis

Summary: cov-analyze reported nerrors=1 → the Azure job emitted ##[error]Coverity found 1 issues: /__w/1/s/test/gtest/ucp/rndv_frag_mpools.cc:56 Type: Uninitialized pointer field (UNINIT_CTOR), failing the pipeline (the compile/cov-build itself succeeded: "751 C/C++ compilation units (100%) successfully").

Root cause: rndv_frag_mpools::rndv_frag_mpools(ucp_worker_h, ucs_memory_type_t) only initializes m_worker in its member-init list. The class also has a by-value ucs_mpool_ops_t m_fail_ops; member (declared at test/gtest/ucp/rndv_frag_mpools.h:77) whose function-pointer fields chunk_alloc, chunk_release, obj_init, obj_cleanup, obj_str (declared src/ucs/datastruct/mpool.h:158-181) are left indeterminate when the constructor returns at line 56. It happens to be fully overwritten later in fail_alloc() (m_fail_ops = *mpool->data->ops;, line 110), but Coverity's UNINIT_CTOR checker (enabled via --all with --checker-option UNINIT_CTOR:ctor_func:swap) flags the constructor itself, and this CI job treats any non-zero defect count as a hard failure. This is new code introduced by this PR branch.

Implicated commit: 58b35234 / 21d5bb87 (Alma Mastbaum, 2026-10-19) on branch add_throttling_to_rndv_fragment_requests — m_fail_ops/fail_alloc() were added in the rndv_frag_mpools helper first created by 9f8df930 (Alma Mastbaum).

File: test/gtest/ucp/rndv_frag_mpools.cc:18-21 (constructor init list; defect reported at line 56) and test/gtest/ucp/rndv_frag_mpools.h:77

Suggested fix: Value-initialize the member in the constructor's init list so all function pointers are zeroed:

rndv_frag_mpools::rndv_frag_mpools(ucp_worker_h worker,
                                   ucs_memory_type_t mem_type) :
    m_worker(worker), m_fail_ops()   /* or m_fail_ops{} — C++11 is enabled */
{

(Equivalent alternatives: memset(&m_fail_ops, 0, sizeof(m_fail_ops)); as the first statement of the ctor body, or declare the member as ucs_mpool_ops_t m_fail_ops = {}; in the header.) Value-init is preferable to a Coverity suppression here since it also makes the object well-defined if restore_alloc()/~rndv_frag_mpools() ever run before fail_alloc().

Related: PR #11062 (the failing PR itself); same checker previously hit in #11868

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

ofirfarjun7
ofirfarjun7 previously approved these changes Oct 26, 2026
@ofirfarjun7
ofirfarjun7 requested a review from tvegas1 October 28, 2026 14:57
@jsack-ga jsack-ga added this to libcudf Oct 30, 2026
@jsack-ga jsack-ga moved this to Helps NeMo Curator in libcudf Oct 30, 2026
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

test/gtest/ucp/test_ucp_am.cc

ucp_am_send_nbx() can return NULL (immediate completion) or an error pointer, and ucp_request_check_status() dereferences req - 1. pls use is_request_completed() here, and guard the EXPECT_NE(UCS_INPROGRESS, ...) below the same way the ucp_request_release() call already does with UCS_PTR_IS_PTR().

                std::all_of(sreqs.begin(), sreqs.end(), [](void *req) {
                    return is_request_completed(req);
                })) {

src/ucp/rndv/rndv_mtype.inl

In ucp_proto_rndv_mtype_request_init(): if the reserved pool fails with UCS_ERR_NO_MEMORY (chunk alloc / mpool init failure) we skip the shared pool and abort the request, even when the shared pool has a free fragment that needs no allocation. why not fall back to shared on any reserved-pool failure, not only on UCS_ERR_NO_RESOURCE?

test/gtest/ucp/test_ucp_mmap.cc

minor: in the placeholder insertion loop in rndv_mpool_hash_growth, the NULL placeholders stay in worker->mpool_hash if any ASSERT_* returns early, and then ucp_worker_destroy_mpools() crashes on ucs_mpool_cleanup(NULL, 1) and hides the real failure. pls use EXPECT_* here, or skip NULL values in ucp_worker_destroy_mpools().

Residual coverage gap: no test exercises the fall-through case in finding 2 (reserved pool failing with UCS_ERR_NO_MEMORY while the shared pool still has a free fragment); rndv_mpool_allocation_failure only covers a single pool's return code.

Residual coverage gap: the else branch of the new ucp_proto_rndv_get_mtype_abort() (non-ppln: rkey destroy + ucp_proto_rndv_recv_complete_status()) is still unexercised — both peer-failure FC tests drive the ppln path only.

Residual coverage gap: all request-level throttle/reschedule coverage needs both ENABLE_STATS (the AM tests are inside #ifdef ENABLE_STATS) and a CUDA device (UCP_INSTANTIATE_TEST_CASE_GPU_AWARE); the host-only test_ucp_mmap cases cover mpool return codes but not the queue/wakeup cycle. Worth confirming a CI lane has both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants