CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
326 lines
13 KiB
C++
326 lines
13 KiB
C++
/*************************************************************************
|
|
* Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
* See LICENSE.txt for license information
|
|
************************************************************************/
|
|
|
|
// Unit tests for the bootstrap bidirectional AllGather gating contract.
|
|
//
|
|
// Socket bidir is on by default (NCCL_BOOTSTRAP_BIDIR_ALLGATHER=1); net OOB and
|
|
// net bidir are off by default. The helper `bootstrapBidirEnabled(nranks, kind)`
|
|
// in src/bootstrap.cc is the single source of truth that bootstrapInit,
|
|
// bootstrapAllGather and bootstrapClose all consult; if its contract drifts the
|
|
// runtime quietly diverges between setup and teardown, hence these tests pin it.
|
|
//
|
|
// Each case runs in an isolated process (via RUN_ISOLATED_TEST_WITH_ENV) because
|
|
// NCCL_PARAM caches the env value on first read for the lifetime of the process,
|
|
// so the only way to re-evaluate is to fork a fresh child.
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "common/ProcessIsolatedTestRunner.hpp"
|
|
#include "bootstrap.h" // bootstrapBidirEnabled — single source of truth for the
|
|
// signature; if it drifts we get a compile error here, not
|
|
// a deferred linker error against librccl.so.
|
|
|
|
namespace RcclUnitTesting {
|
|
|
|
constexpr int kKindSocket = 0;
|
|
constexpr int kKindNet = 1;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Tiny-comm short-circuit: nranks<3 is below the bidir threshold (one ring step
|
|
// is degenerate at N==2 and undefined at N<2). Independent of any env var.
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, TinyNranks_ReturnsFalse_Default)
|
|
{
|
|
RUN_ISOLATED_TEST(
|
|
"BootstrapBidir.TinyNranks_ReturnsFalse_Default",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(0, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(2, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(0, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(2, kKindNet));
|
|
}
|
|
);
|
|
}
|
|
|
|
TEST(BootstrapBidir, TinyNranks_ReturnsFalse_EvenWithBidirForcedOn)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.TinyNranks_ReturnsFalse_EvenWithBidirForcedOn",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(0, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(2, kKindSocket));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_ALLGATHER", "1"},
|
|
{"NCCL_OOB_NET_ENABLE", "0"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Branch 1 default: with no env vars set, the socket bidir path is selected for
|
|
// any nranks>=3. This is the headline behavioural change the branch introduces.
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, SocketBidir_OnByDefault)
|
|
{
|
|
RUN_ISOLATED_TEST(
|
|
"BootstrapBidir.SocketBidir_OnByDefault",
|
|
[]()
|
|
{
|
|
// Span the realistic nranks range: small (3, 8), 2-node 8ppn (16),
|
|
// mid-scale (128), large (1024) - all should resolve to "on".
|
|
EXPECT_TRUE(bootstrapBidirEnabled(3, kKindSocket));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(8, kKindSocket));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(16, kKindSocket));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(128, kKindSocket));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(1024, kKindSocket));
|
|
}
|
|
);
|
|
}
|
|
|
|
TEST(BootstrapBidir, NetBidir_OffByDefault)
|
|
{
|
|
RUN_ISOLATED_TEST(
|
|
"BootstrapBidir.NetBidir_OffByDefault",
|
|
[]()
|
|
{
|
|
// Net OOB is off by default, so net bidir is unconditionally off
|
|
// regardless of nranks (the !netOn guard fires first).
|
|
EXPECT_FALSE(bootstrapBidirEnabled(8, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1024, kKindNet));
|
|
}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Off-switch: BIDIR_ALLGATHER=0 must produce the legacy unidir socket path
|
|
// regardless of scale (and regardless of the threshold knob).
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, SocketBidir_ExplicitOff_DisablesEverywhere)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.SocketBidir_ExplicitOff_DisablesEverywhere",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(8, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1024, kKindSocket));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_ALLGATHER", "0"}}
|
|
);
|
|
}
|
|
|
|
// Threshold knob applies only to the net path; for socket it must have no effect
|
|
// (the helper short-circuits on the on/off semantics before consulting threshold).
|
|
TEST(BootstrapBidir, SocketBidir_ThresholdKnob_HasNoEffect)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.SocketBidir_ThresholdKnob_HasNoEffect",
|
|
[]()
|
|
{
|
|
// Threshold absurdly above any realistic nranks: still on.
|
|
EXPECT_TRUE(bootstrapBidirEnabled(8, kKindSocket));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(128, kKindSocket));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "1000000"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Net OOB shadow: enabling net OOB transport must immediately disable the socket
|
|
// bidir path (the dispatcher in bootstrapAllGather picks the net path instead).
|
|
// This is the !netOn clause in bootstrapBidirEnabled(., kind=0).
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, NetOob_ShadowsSocketBidir)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetOob_ShadowsSocketBidir",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(8, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1024, kKindSocket));
|
|
},
|
|
{{"NCCL_OOB_NET_ENABLE", "1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_ALLGATHER", "1"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Net bidir requires net OOB. With OOB_NET_ENABLE=0, BIDIR_NET=1 must still
|
|
// resolve to false: there is no second QP pair to drive Ring1 over.
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, NetBidir_WithoutNetOob_ReturnsFalse)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetBidir_WithoutNetOob_ReturnsFalse",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1024, kKindNet));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_NET", "1"},
|
|
{"NCCL_OOB_NET_ENABLE", "0"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Net bidir on (explicit): both knobs must be set; nranks threshold is bypassed
|
|
// when the user has explicitly opted in (BIDIR_NET=1 vs the auto value -1).
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, NetBidir_ExplicitOn_BypassesThreshold)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetBidir_ExplicitOn_BypassesThreshold",
|
|
[]()
|
|
{
|
|
// Threshold absurdly above the asked nranks; explicit =1 must still
|
|
// win because it short-circuits before threshold logic.
|
|
EXPECT_TRUE(bootstrapBidirEnabled(8, kKindNet));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(128, kKindNet));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_NET", "1"},
|
|
{"NCCL_OOB_NET_ENABLE", "1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "1000000"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Net bidir auto-threshold: BIDIR_NET=-1 (auto) + OOB_NET_ENABLE=1 with the
|
|
// default threshold 128 must (a) be off below threshold, (b) on at and above it.
|
|
// This protects the regression matrix: small comms shouldn't pay net-bidir setup
|
|
// cost, but >=128 ranks should benefit.
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, NetBidir_AutoThreshold_BelowAndAbove)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetBidir_AutoThreshold_BelowAndAbove",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(8, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(64, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(127, kKindNet));
|
|
EXPECT_TRUE (bootstrapBidirEnabled(128, kKindNet));
|
|
EXPECT_TRUE (bootstrapBidirEnabled(1024, kKindNet));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_NET", "-1"},
|
|
{"NCCL_OOB_NET_ENABLE", "1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "128"}}
|
|
);
|
|
}
|
|
|
|
TEST(BootstrapBidir, NetBidir_AutoThreshold_CustomValue)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetBidir_AutoThreshold_CustomValue",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(63, kKindNet));
|
|
EXPECT_TRUE (bootstrapBidirEnabled(64, kKindNet));
|
|
EXPECT_TRUE (bootstrapBidirEnabled(65, kKindNet));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_NET", "-1"},
|
|
{"NCCL_OOB_NET_ENABLE", "1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "64"}}
|
|
);
|
|
}
|
|
|
|
// Threshold==0 disables the auto path entirely (never crosses the gate).
|
|
TEST(BootstrapBidir, NetBidir_AutoThreshold_Zero_DisablesAuto)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetBidir_AutoThreshold_Zero_DisablesAuto",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1024, kKindNet));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_NET", "-1"},
|
|
{"NCCL_OOB_NET_ENABLE", "1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "0"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// BIDIR_NET explicit-zero: even when net OOB is enabled, BIDIR_NET=0 must
|
|
// short-circuit (the `v == 0` branch in bootstrapBidirEnabled's kind==1 arm).
|
|
// Other tests only cover BIDIR_NET=1 / -1.
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, NetBidir_ExplicitZero_With_NetOob_DisablesNet)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetBidir_ExplicitZero_With_NetOob_DisablesNet",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindNet));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(1024, kKindNet));
|
|
},
|
|
{{"NCCL_BOOTSTRAP_BIDIR_NET", "0"},
|
|
{"NCCL_OOB_NET_ENABLE", "1"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Net OOB auto path: NCCL_OOB_NET_ENABLE=-1 + threshold gates the underlying
|
|
// bootstrapNetEnabledEffective helper. Without this case the auto (`v == -1`)
|
|
// branch and the `thr > 0 && nranks >= thr` short-circuit inside
|
|
// bootstrapNetEnabledEffective stay at zero hits in coverage.
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, NetOob_Auto_Threshold_BelowAndAbove_GatesSocketShadow)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetOob_Auto_Threshold_BelowAndAbove_GatesSocketShadow",
|
|
[]()
|
|
{
|
|
// Below threshold: net OOB is auto-off, so socket bidir is allowed.
|
|
EXPECT_TRUE (bootstrapBidirEnabled(64, kKindSocket));
|
|
// At/above threshold: net OOB auto-on, which shadows socket bidir.
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, kKindSocket));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(256, kKindSocket));
|
|
},
|
|
{{"NCCL_OOB_NET_ENABLE", "-1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "128"}}
|
|
);
|
|
}
|
|
|
|
TEST(BootstrapBidir, NetOob_Auto_Threshold_Zero_KeepsNetOff)
|
|
{
|
|
RUN_ISOLATED_TEST_WITH_ENV(
|
|
"BootstrapBidir.NetOob_Auto_Threshold_Zero_KeepsNetOff",
|
|
[]()
|
|
{
|
|
// thr==0 makes the auto-net-on path fail (never crosses), so socket
|
|
// bidir is allowed unconditionally — covers the false branch of the
|
|
// `thr > 0 && ...` short-circuit in bootstrapNetEnabledEffective.
|
|
EXPECT_TRUE(bootstrapBidirEnabled(8, kKindSocket));
|
|
EXPECT_TRUE(bootstrapBidirEnabled(1024, kKindSocket));
|
|
},
|
|
{{"NCCL_OOB_NET_ENABLE", "-1"},
|
|
{"NCCL_BOOTSTRAP_BIDIR_THRESHOLD", "0"}}
|
|
);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Unknown 'kind' values must return false (defensive default for any future
|
|
// caller that adds a third transport without updating this gate).
|
|
// -----------------------------------------------------------------------------
|
|
TEST(BootstrapBidir, UnknownKind_ReturnsFalse)
|
|
{
|
|
RUN_ISOLATED_TEST(
|
|
"BootstrapBidir.UnknownKind_ReturnsFalse",
|
|
[]()
|
|
{
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, 2));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, -1));
|
|
EXPECT_FALSE(bootstrapBidirEnabled(128, 99));
|
|
}
|
|
);
|
|
}
|
|
|
|
} // namespace RcclUnitTesting
|