Skip to content

[TENT] Opt-in deadline-aware NIC bandwidth arbitration (RFC #2792)#2794

Merged
catyans merged 9 commits into
kvcache-ai:mainfrom
catyans:feat/deadline-bw-arbitration-clean
Jul 14, 2026
Merged

[TENT] Opt-in deadline-aware NIC bandwidth arbitration (RFC #2792)#2794
catyans merged 9 commits into
kvcache-ai:mainfrom
catyans:feat/deadline-bw-arbitration-clean

Conversation

@catyans

@catyans catyans commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Implements the deadline-aware NIC bandwidth arbitration proposed in #2792.

Problem

TENT's QoS is vertical: SL/TC and priority tiers separate business classes. When flows in the same tier contend for one NIC, bandwidth was split without deadline awareness.

Design

Ordering acts at the per-NIC-path slice-post point: after slices are grouped by (local NIC → remote NIC), they are sorted most-urgent-first by predicted MLU immediately before submitSlices() reaches the QP budget.

  • bw_arbitration.h: pure, unit-testable urgency policy.
  • workers.cpp: opt-in wiring via transports/rdma/deadline_bw_arbitration (default false). The hot path reuses a thread_local scratch vector, so capacity is retained across calls rather than allocated for every arbitration.
  • tebench: native --deadline_us, --deadline_tight_threads, and --deadline_bw_arbitration flags, with aggregate tight/loose throughput reporting. The old custom transfer_engine_bench flags were removed.

Validation

bw_arbitration_test: 7/7 passed (deadline ordering, no-deadline, past-due, FIFO ties, zero-bandwidth, size weighting).

Two-node H20 / ConnectX RoCE, mlx5_bond_0, RDMA READ, 16 threads (4 tight + 12 loose), 1 MiB, three repeats:

Normal QP budget (MC_MAX_WR=256, batch=1)

arbitration total tight (4) loose (12)
off 48.626 GB/s 12.145 36.481
on 48.611 GB/s 12.204 36.407

No material change is expected here: synchronous batch=1 does not accumulate enough pending slices for arbitration.

Deliberate QP pressure (MC_MAX_WR=16, batch=32)

arbitration total tight (4) loose (12)
off 48.366 GB/s 12.090 36.276
on 96.660 GB/s 48.316 48.349

Across all three repeats, tight aggregate throughput rose by about 300%; total throughput did not regress. The total-throughput increase under this artificial low-WR setting indicates that urgency ordering also avoids QP under-utilization in this workload, so this result should not be interpreted as a general 2x bandwidth claim.

Notes

  • Opt-in and default-off.
  • Bandwidth estimate currently reuses configured default_bandwidth_gbps; live per-NIC EWMA can follow separately.
  • The benchmark migration and tests were built and run from this PR branch on the cluster.

Relates to #2792.

…i#2792)

Within a priority tier, when several flows contend for one NIC the bandwidth
is split blindly/equally today, with no way to give a flow about to miss its
deadline a larger share. This adds an opt-in, deadline-aware arbitration.

The ordering acts at the per-NIC-path slice-post point: after slices are
grouped by (local NIC -> remote NIC), they are sorted most-urgent-first by
predicted MLU (predicted transfer time / remaining deadline window, reusing
the MLU notion from kvcache-ai#2618) before submitSlices() hands them to the QP budget.
That is the point where same-tier flows actually contend for the shared NIC;
an earlier prototype that reordered at the priority-queue pop had no effect
because the QP budget, not the tier queue, is the contention point.

  * bw_arbitration.h: pure OrderByUrgency() policy (unit-testable, no RDMA
    deps) + PredictedMlu(). bw<=0 or no-deadline degrade to original order.
  * workers.cpp: opt-in wiring via transports/rdma/deadline_bw_arbitration
    (default false = byte-identical FIFO / equal split).
  * transfer_engine_bench: --deadline_us / --deadline_tight_threads to tag N
    threads as tight-deadline flows + per-flow tight/loose throughput report.
  * bw_arbitration_test: 7 cases (tighter-first, no-deadline-last, past-due,
    FIFO ties, zero-bandwidth no-op, size-weighting).

Measured (H20/ConnectX 200G RoCE, 2 nodes, 16 threads = 4 tight + 12 loose,
1 MB): tight flows 12.1 -> 44.6 GB/s (+269%), loose yield, total throughput
unchanged (48.4 GB/s). At light load it is a no-op, as intended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request implements deadline-aware NIC bandwidth arbitration within a priority tier (RFC #2792) to prioritize flows nearing their deadlines under NIC contention. It introduces the arbitration logic, integrates it as an opt-in feature in the RDMA transport worker's send path, and adds corresponding benchmark options and unit tests. Feedback on the changes highlights a performance concern in the hot path of asyncPostSend(), where multiple dynamic memory allocations are performed; using a thread_local scratch buffer is suggested to sort slices in-place and avoid heap fragmentation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread mooncake-transfer-engine/tent/src/transport/rdma/workers.cpp
@catyans

catyans commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Validation that the effect is the arbitration (not a thread/NIC-placement artifact) — swept the number of tight-deadline threads, arbitration on, 16 threads total, 1 MB:

tight threads tight total loose total
0 0 48.37 GB/s (no tight → all to loose)
1 11.23 37.17
4 44.63 3.75
8 48.33 0.03 (loose starved)

The share tracks which threads are tagged tight (the deadline_tight_threads knob), monotonically — a placement artifact wouldn't respond to the deadline tag. Total throughput stays 48.4 GB/s throughout (zero-sum reallocation, not manufactured bandwidth), and the on/off + config states are distinguishable in the logs (Loaded tent config from file).

Honest detail: a single tight flow tops out at ~11 GB/s (per-flow QP throughput ceiling), so tight=1 takes 11 and leaves the rest to loose rather than monopolizing — priority, not free bandwidth. tight≥4 saturates the NIC.

@codecov-commenter

codecov-commenter commented Jul 8, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 0% with 48 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mooncake-transfer-engine/benchmark/main.cpp 0.00% 34 Missing ⚠️
mooncake-transfer-engine/benchmark/utils.cpp 0.00% 14 Missing ⚠️

📢 Thoughts on this report? Let us know!

@alogfans

Copy link
Copy Markdown
Collaborator

Good contribution! Additionally, we prefer to use tebench instead of transfer_engine_bench, which is more flexible and easier for use.

@catyans

catyans commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the requested follow-ups:

  • migrated --deadline_us / --deadline_tight_threads and per-group reporting from transfer_engine_bench to tebench (8a1b9695)
  • added a native tebench --deadline_bw_arbitration A/B toggle (ac9a9cf3)
  • removed the old custom benchmark flags
  • eliminated per-call arbitration scratch allocations with reusable thread_local storage (c3d74adf)
  • built tebench, passed bw_arbitration_test 7/7, and reran 4-tight + 12-loose A/B on two H20/RoCE nodes (three repeats)

The PR body now contains both normal-QP and deliberately constrained-QP results. Under normal synchronous batch=1 load there is no accumulated slice backlog and therefore no material difference; under MC_MAX_WR=16, batch=32 pressure, tight aggregate throughput increases ~300% with no total-throughput regression.

# Conflicts:
#	mooncake-transfer-engine/tent/tests/CMakeLists.txt
@catyans

catyans commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

Merged current main and resolved the CMake conflict in fe3dea38 by retaining both bw_arbitration_test and main’s deadline_promotion_bench. Rebuilt the pure arbitration test on the backup Linux host: 7/7 passed. The PR is mergeable and CI is running.

@catyans

catyans commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator Author

@alogfans This has been addressed. The deadline workload was migrated from the old custom transfer_engine_bench flags to tebench:

  • added native tebench --deadline_us, --deadline_tight_threads, and --deadline_bw_arbitration
  • removed the old transfer_engine_bench deadline flags from the final diff
  • reran the 4-tight + 12-loose A/B on the H20/RoCE cluster with the tebench path
  • kept the hot path allocation-free by reusing thread_local arbitration scratch storage

The updated PR body contains the tebench validation results and the caveat for the constrained-QP run.

@alogfans alogfans left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

# Conflicts:
#	mooncake-transfer-engine/benchmark/tent_backend.cpp
@catyans

catyans commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

Merged latest main to resolve the merge conflict. The only manual conflict was in mooncake-transfer-engine/benchmark/tent_backend.cpp; the resolution keeps both fields set on each request: deadline_ns from this PR and intent_type from main.

Cluster validation:

  • node: lingjun-100 (8.130.214.133)
  • container: codex_mooncake_pr_eval
  • commit: bb1c9ddd
  • configured with WITH_TE=ON, USE_TENT=ON, BUILD_BENCHMARK=ON, USE_CUDA=OFF
  • command: cmake --build /root/mooncake-pr2794-build --target tebench -j 16
  • result: tebench built successfully.

@catyans
catyans merged commit 0be3166 into kvcache-ai:main Jul 14, 2026
27 checks passed
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.

3 participants