Skip to content

test(net): add v11 plugin compat lazy-init unit test - #8633

Merged
nikitaxgusev merged 4 commits into
developfrom
users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test
Jul 24, 2026
Merged

nikitaxgusev merged 4 commits into
developfrom
users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test

Conversation

@nikitaxgusev

@nikitaxgusev nikitaxgusev commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

The NCCL v11 network-plugin compatibility layer must initialize lazily:
getNcclNet_v11() / getNcclCollNet_v11() should populate only the init
entry point of the public ncclNet_t / ncclCollNet_t vtable, and defer
wiring up every other entry point (devices, getProperties, listen, …)
until the plugin's init() callback has actually run. A v11 plugin is only
allowed to expose its per-device entry points after init(); populating the
vtable eagerly (the old direct-cast pattern) meant RCCL could call into an
uninitialized plugin.

The fix already landed on develop
(projects/rccl/src/plugin/net/net_v11.cc), but there was no test guarding
the behavior. This PR adds that regression test and wires it into CI.

Technical Details

  • New test projects/rccl/test/PluginCompatV11_test.cpp:
    • Defines an in-process mock v11 net/collnet plugin and exports it under the
      exact symbols the compat layer resolves via dlsym
      (ncclNetPlugin_v11 / ncclCollNetPlugin_v11), so no GPU or real
      network plugin is required
      .
    • Hands the compat layer a dlopen(NULL) handle and asserts the lazy-init
      contract:
      1. getNcclNet_v11() returns a non-null ncclNet_t*.
      2. Before init(): only ->init is set; every other entry point is
        nullptr.
      3. After ->init() succeeds: the remaining entry points become non-null.
    • Covers both the net and collnet compat layers.
  • projects/rccl/test/CMakeLists.txt:
    • Adds PluginCompatV11_test.cpp to the Debug-only
      rccl-UnitTestsFixturesDebug target — the test calls internal symbols
      (getNcclNet_v11) that have hidden visibility in Release builds, so it
      cannot live in the always-built rccl-UnitTests (that would break the
      Release link).
    • Exports only the two mock plugin symbols via
      --export-dynamic-symbol=ncclNetPlugin_v11 / =ncclCollNetPlugin_v11 (rather
      than the broad -rdynamic) so dlsym(dlopen(NULL)) can find them.
  • projects/rccl/tools/scripts/test_runner/configs/mi300x_mellanox_ib.json:
    • Registers the two tests as a plugin_compat_v11 gtest group
      (rccl-UnitTestsFixturesDebug, 1 GPU) so they run in the MI300X + Mellanox
      IB config.

JIRA ID

JIRA ID : AICOMRCCL-1532

Test Plan

Built and ran on an AMD MI350X (gfx950) node (Debug build):

bash install.sh -l -t --debug --prefix ~/rccl-install-1532
./build/debug/test/rccl-UnitTestsFixturesDebug --gtest_filter=PluginCompatV11*

Validity of the test was confirmed by temporarily reverting
getNcclNet_v11() to the old eager/direct-cast pattern and re-running. The
tests are also registered in the mi300x_mellanox_ib test-runner config so
they execute in CI.

Test Result

  • Fixed (current) code — PASS:
[==========] Running 2 tests from 1 test suite.
[ RUN      ] PluginCompatV11.NetLazyInitialization
[       OK ] PluginCompatV11.NetLazyInitialization (0 ms)
[ RUN      ] PluginCompatV11.CollNetLazyInitialization
[       OK ] PluginCompatV11.CollNetLazyInitialization (0 ms)
[  PASSED  ] 2 tests.
  • With getNcclNet_v11() reverted to the eager pattern — FAIL (the test
    catches the bug), failing exactly on the pre-init() null checks
    (devices / getProperties / listen / … set before init()).
    Restoring the fix returns the suite to PASS.

Submission Checklist

Copilot AI review requested due to automatic review settings July 15, 2026 18:10
@nikitaxgusev
nikitaxgusev requested a review from a team as a code owner July 15, 2026 18:10
@therock-pr-bot

therock-pr-bot Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
🌿 Branch Name ✅ Pass —
📝 PR Title/Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass PR does not contain code files — Unit Test auto-passed
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

@therock-pr-bot

Copy link
Copy Markdown

🚫 Please fix the failed policies before requesting reviews.

The following policy checks failed:

  • ❌ Unit Test

The Not ready to Review label has been added to this PR.
Once all policies pass, the label will be removed automatically.

Copilot AI 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.

Pull request overview

Adds a new regression unit test to guard the NCCL v11 network-plugin compatibility layer’s lazy-initialization contract, ensuring only ->init is populated before initialization and all other vtable entry points are deferred until after init() succeeds.

Changes:

  • Introduces an in-process mock v11 net/collnet plugin and validates pre-/post-init() vtable wiring behavior via GoogleTest.
  • Updates rccl-UnitTests build to include the new test source and exports executable symbols for dlsym(dlopen(NULL), ...) via -rdynamic.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
projects/rccl/test/PluginCompatV11Tests.cpp Adds regression tests for v11 net/collnet compat-layer lazy initialization using in-process exported mock plugin symbols.
projects/rccl/test/CMakeLists.txt Includes the new test in rccl-UnitTests and adds -rdynamic so dlsym can resolve in-process plugin symbols.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread projects/rccl/test/CMakeLists.txt Resolved
@nikitaxgusev
nikitaxgusev force-pushed the users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test branch from ffaa5a2 to c884648 Compare July 15, 2026 18:20
@nikitaxgusev
nikitaxgusev force-pushed the users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test branch from c884648 to 983952e Compare July 15, 2026 18:52
@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

%RCCL_TEST_CONFIG
mi300x_mellanox_ib.json

@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

%RCCL_TEST_CONFIG
mi300x_mellanox_ib.json

@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

%RCCL_TEST_CONFIG
mi300x_mellanox_ib.json
SUITE=plugin_compat_v11
TEST_NAME=PluginCompatV11.*

1 similar comment
@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

%RCCL_TEST_CONFIG
mi300x_mellanox_ib.json
SUITE=plugin_compat_v11
TEST_NAME=PluginCompatV11.*

@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

%RCCL_TEST_CONFIG
mi300x_mellanox_ib.json
SUITE=plugin_compat_v11
TEST_NAME=PluginCompatV11.*

@nikitaxgusev
nikitaxgusev force-pushed the users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test branch 2 times, most recently from 278bc7a to a01bb82 Compare July 17, 2026 12:30
@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

%RCCL_TEST_CONFIG
mi300x_mellanox_ib.json
SUITE=plugin_compat_v11
TEST_NAME=PluginCompatV11.*

@nikitaxgusev

Copy link
Copy Markdown
Contributor Author

Checked manually

export LD_LIBRARY_PATH=~/rocm-systems-1532/projects/rccl/build/debug:$LD_LIBRARY_PATH
python3 test_runner.py --config configs/mi300x_mellanox_ib.json \
  --suite-name 'Plugin Compat v11 - Lazy Init' \
  --no-build --skip-mpi-check --verbose
----------------------
rccl-UnitTestsFixturesDebug --gtest_filter=PluginCompatV11.NetLazyInitialization      --gtest_output=json:...
rccl-UnitTestsFixturesDebug --gtest_filter=PluginCompatV11.CollNetLazyInitialization  --gtest_output=json:...
----------------------
NCCL INFO NET/Plugin: Loaded net plugin mock_v11_net (v11)
[       OK ] PluginCompatV11.NetLazyInitialization (221 ms)
NCCL INFO NET/Plugin: Loaded collnet plugin mock_v11_collnet (v11)
[       OK ] PluginCompatV11.CollNetLazyInitialization (232 ms)
Total Tests:   2
Passed:        2
Failed:        0
Skipped:       0
Timeout:       0
Exiting: Test run completed successfully   (exit=0)

@github-actions

Copy link
Copy Markdown
Contributor

RCCL Perf-Regression Gate: ✅ PASS

Mode: detect (reference vs candidate)
Thresholds (per-tier, calibrated): small 17.2% · mid 12.3% · large 12.9%
Keys compared: 0 · Confirmed regressions: 0 · Inconclusive: 0

Per-collective breakdown
group keys regressions inconclusive
all_gather_perf-d=bfloat16-default 0 0 0
all_gather_perf-d=float-default 0 0 0
all_reduce_perf-d=bfloat16-default 0 0 0
all_reduce_perf-d=float-default 0 0 0
broadcast_perf-d=bfloat16-default 0 0 0
broadcast_perf-d=float-default 0 0 0
reduce_scatter_perf-d=bfloat16-default 0 0 0
reduce_scatter_perf-d=float-default 0 0 0

Nikita Gusev added 3 commits July 22, 2026 09:44
Add PluginCompatV11_test.cpp, an in-process regression test for the NCCL
v11 network-plugin compat layer's lazy initialization: getNcclNet_v11() /
getNcclCollNet_v11() must populate only ncclNet.init and leave the remaining
entry points null until init() runs.

The test defines an in-process mock v11 net/collnet plugin exported under the
symbols the compat layer resolves via dlsym, so no GPU or real plugin is
required. It lives in the Debug-only rccl-UnitTestsFixturesDebug target since
it calls internal symbols (getNcclNet_v11) that are hidden in Release builds,
and exports the two mock symbols via --export-dynamic-symbol.

Resolves AICOMRCCL-1532
Register the two PluginCompatV11 tests as a plugin_compat_v11 gtest group
(rccl-UnitTestsFixturesDebug, 1 GPU) so they run in the MI300X + Mellanox IB
test-runner config.
The compat-layer mock symbols are exported via --export-dynamic-symbol, not
-rdynamic; update the comment to match.
@nikitaxgusev
nikitaxgusev force-pushed the users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test branch from 64a8798 to 1d7490c Compare July 22, 2026 09:44
The plugin_compat_v11 test configuration had no matching test_suites entry, so the test_runner never enumerated the PluginCompatV11 lazy-init tests. Add the suite entry (Debug-only) so CI actually runs them.
@nikitaxgusev
nikitaxgusev force-pushed the users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test branch from 1d7490c to 9448042 Compare July 24, 2026 09:22
@nikitaxgusev
nikitaxgusev merged commit c7c3eb0 into develop Jul 24, 2026
28 of 36 checks passed
@nikitaxgusev
nikitaxgusev deleted the users/nikitaxgusev/AICOMRCCL-1532-plugin-v11-test branch July 24, 2026 18:57
amd-josnarlo pushed a commit that referenced this pull request Jul 28, 2026
## Motivation

The NCCL v11 network-plugin compatibility layer must initialize
**lazily**:
`getNcclNet_v11()` / `getNcclCollNet_v11()` should populate only the
`init`
entry point of the public `ncclNet_t` / `ncclCollNet_t` vtable, and
defer
wiring up every other entry point (`devices`, `getProperties`, `listen`,
…)
until the plugin's `init()` callback has actually run. A v11 plugin is
only
allowed to expose its per-device entry points after `init()`; populating
the
vtable eagerly (the old direct-cast pattern) meant RCCL could call into
an
uninitialized plugin.

The fix already landed on `develop`
(`projects/rccl/src/plugin/net/net_v11.cc`), but there was no test
guarding
the behavior. This PR adds that regression test and wires it into CI.

## Technical Details

- New test `projects/rccl/test/PluginCompatV11_test.cpp`:
- Defines an in-process mock v11 net/collnet plugin and exports it under
the
    exact symbols the compat layer resolves via `dlsym`
    (`ncclNetPlugin_v11` / `ncclCollNetPlugin_v11`), so **no GPU or real
    network plugin is required**.
- Hands the compat layer a `dlopen(NULL)` handle and asserts the
lazy-init
    contract:
    1. `getNcclNet_v11()` returns a non-null `ncclNet_t*`.
    2. Before `init()`: only `->init` is set; every other entry point is
       `nullptr`.
3. After `->init()` succeeds: the remaining entry points become
non-null.
  - Covers both the net and collnet compat layers.
- `projects/rccl/test/CMakeLists.txt`:
  - Adds `PluginCompatV11_test.cpp` to the **Debug-only**
`rccl-UnitTestsFixturesDebug` target — the test calls internal symbols
(`getNcclNet_v11`) that have hidden visibility in Release builds, so it
cannot live in the always-built `rccl-UnitTests` (that would break the
    Release link).
  - Exports only the two mock plugin symbols via
`--export-dynamic-symbol=ncclNetPlugin_v11 / =ncclCollNetPlugin_v11`
(rather
than the broad `-rdynamic`) so `dlsym`(`dlopen(NULL)`) can find them.
-
`projects/rccl/tools/scripts/test_runner/configs/mi300x_mellanox_ib.json`:
  - Registers the two tests as a `plugin_compat_v11` gtest group
(`rccl-UnitTestsFixturesDebug`, 1 GPU) so they run in the MI300X +
Mellanox
    IB config.

## JIRA ID

JIRA ID : AICOMRCCL-1532

## Test Plan

Built and ran on an AMD MI350X (gfx950) node (Debug build):

```
bash install.sh -l -t --debug --prefix ~/rccl-install-1532
./build/debug/test/rccl-UnitTestsFixturesDebug --gtest_filter=PluginCompatV11*
```

Validity of the test was confirmed by temporarily reverting
`getNcclNet_v11()` to the old eager/direct-cast pattern and re-running.
The
tests are also registered in the `mi300x_mellanox_ib` test-runner config
so
they execute in CI.

## Test Result

- Fixed (current) code — **PASS**:

```
[==========] Running 2 tests from 1 test suite.
[ RUN      ] PluginCompatV11.NetLazyInitialization
[       OK ] PluginCompatV11.NetLazyInitialization (0 ms)
[ RUN      ] PluginCompatV11.CollNetLazyInitialization
[       OK ] PluginCompatV11.CollNetLazyInitialization (0 ms)
[  PASSED  ] 2 tests.
```

- With `getNcclNet_v11()` reverted to the eager pattern — **FAIL** (the
test
  catches the bug), failing exactly on the pre-`init()` null checks
  (`devices` / `getProperties` / `listen` / … set before `init()`).
  Restoring the fix returns the suite to PASS.

## Submission Checklist

- [x] Look over the contributing guidelines at
https://github.com/ROCm/ROCm/blob/develop/CONTRIBUTING.md#pull-requests.
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.

5 participants