Repository navigation
fix(rccl): honor abortFlag in DDA waits so revoke can complete - #11245
Conversation
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🚫 Please fix the failed policies before requesting reviews. The following policy checks failed:
The |
e6a2877 to
eb8e08a
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new DDA revoke MPI test currently queries HIP device properties for device 0 instead of the rank’s assigned/current device, which can cause incorrect skip/pass behavior under non-trivial device assignment.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR ensures ncclCommRevoke can reliably unblock in-flight DDA collectives by sampling comm->abortFlagDev inside DDA LL/LL128 wait loops and inside the Fabric/IPC GPU barriers, then adds MPI tests/config entries to specifically exercise the DDA LL one-shot and two-shot paths on gfx1250.
Changes:
- Add a shared device helper (
dda_abort.h) and threadcomm->abortFlagDevthrough DDA LL/LL128 kernels and wait primitives to break out of peer-flag spins when revoked. - Update DDA Fabric/IPC GPU barrier implementations to poll
abortFlagDevduring CAS-based waits. - Add new MPI revoke+shrink tests that assert DDA LL one-shot/two-shot path selection via log “needles”, and register them in MI455 test-runner configs.
File summaries
| File | Description |
|---|---|
| projects/rccl/tools/scripts/test_runner/configs/mi455_ainic_roce.json | Register new DDA revoke MPI test cases in the MI455 RoCE suite config. |
| projects/rccl/tools/scripts/test_runner/configs/mi455_ainic_roce_func.json | Register new DDA revoke MPI test cases in the MI455 RoCE functional suite config. |
| projects/rccl/test/RevokeMPITests.cpp | Add RevokeDdaMPITest cases that force DDA LL one-shot/two-shot selection and then revoke+shrink. |
| projects/rccl/src/CMakeLists.txt | Add new DDA abort header to the source list. |
| projects/rccl/src/algorithms/dda/device/dda_abort.h | Introduce device-side abort-flag polling helpers for DDA kernels/barriers. |
| projects/rccl/src/algorithms/dda/device/CollCommon.h | Add LL line wait helper that aborts based on abortFlagDev. |
| projects/rccl/src/algorithms/dda/device/CollCommon_ll128.h | Add LL128 flag/poll helpers that abort based on abortFlagDev. |
| projects/rccl/src/algorithms/dda/reduce_scatter/reduce_scatter_dda_fabric_ll.h | Thread abort flag into LL reduce-scatter waits and exit cleanly on revoke. |
| projects/rccl/src/algorithms/dda/reduce_scatter/reduce_scatter_dda_fabric_ll128.h | Thread abort flag into LL128 reduce-scatter waits and exit cleanly on revoke. |
| projects/rccl/src/algorithms/dda/reduce_scatter/dda_reduce_scatter_fabric_ll.cu | Pass comm->abortFlagDev into LL reduce-scatter kernel launches. |
| projects/rccl/src/algorithms/dda/reduce_scatter/dda_reduce_scatter_fabric_ll128.cu | Pass comm->abortFlagDev into LL128 reduce-scatter kernel launches. |
| projects/rccl/src/algorithms/dda/all_reduce/all_reduce_dda_ll.h | Thread abort flag into LL all-reduce waits and exit cleanly on revoke. |
| projects/rccl/src/algorithms/dda/all_reduce/all_reduce_dda_ll_twoshot.h | Thread abort flag into LL two-shot all-reduce waits and exit cleanly on revoke. |
| projects/rccl/src/algorithms/dda/all_reduce/all_reduce_dda_fabric_ll128.h | Thread abort flag into LL128 all-reduce waits and exit cleanly on revoke. |
| projects/rccl/src/algorithms/dda/all_reduce/dda_all_reduce_fabric_ll.cu | Pass comm->abortFlagDev into LL all-reduce (one-shot + two-shot) launches. |
| projects/rccl/src/algorithms/dda/all_reduce/dda_all_reduce_fabric_ll128.cu | Pass comm->abortFlagDev into LL128 all-reduce launches. |
| projects/rccl/src/algorithms/dda/all_gather/all_gather_dda_fabric_ll.h | Thread abort flag into LL all-gather waits to avoid hangs on revoke. |
| projects/rccl/src/algorithms/dda/all_gather/all_gather_dda_fabric_ll128.h | Thread abort flag into LL128 all-gather waits/polls to avoid hangs on revoke. |
| projects/rccl/src/algorithms/dda/all_gather/dda_all_gather_fabric_ll.cu | Pass comm->abortFlagDev into LL all-gather launches. |
| projects/rccl/src/algorithms/dda/all_gather/dda_all_gather_fabric_ll128.cu | Pass comm->abortFlagDev into LL128 all-gather launches. |
| projects/rccl/src/algorithms/dda/alltoall/alltoall_dda_fabric_ll.h | Thread abort flag into LL all-to-all waits to avoid hangs on revoke. |
| projects/rccl/src/algorithms/dda/alltoall/alltoall_dda_fabric_ll128.h | Thread abort flag into LL128 all-to-all waits to avoid hangs on revoke. |
| projects/rccl/src/algorithms/dda/alltoall/dda_alltoall_fabric_ll.cu | Pass comm->abortFlagDev into LL all-to-all launches. |
| projects/rccl/src/algorithms/dda/alltoall/dda_alltoall_fabric_ll128.cu | Pass comm->abortFlagDev into LL128 all-to-all launches. |
| projects/rccl/src/algorithms/dda/ipc/ipc_gpu_barrier.h | Add abort-aware spinning to IPC GPU barrier flag CAS loops. |
| projects/rccl/src/algorithms/dda/ipc/ipc_gpu_barrier.cu | Plumb abort flag through IPC barrier construction. |
| projects/rccl/src/algorithms/dda/ipc/ipc_init.cu | Pass comm->abortFlagDev into IPC barrier init. |
| projects/rccl/src/algorithms/dda/fabric/fabric_gpu_barrier.h | Add abort-aware spinning to fabric GPU barrier flag operations. |
| projects/rccl/src/algorithms/dda/fabric/fabric_gpu_barrier.cu | Plumb abort flag through fabric barrier construction. |
| projects/rccl/src/algorithms/dda/fabric/fabric_init.cu | Pass comm->abortFlagDev into fabric barrier init. |
Review details
- Files reviewed: 30/30 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
ARGUS
Bottom line: Worth settling before approval: new abortFlag wait-loop coverage is AllReduce-LL only, leaving LL128/AllGather/AllToAll/ReduceScatter/barrier abort paths untested.
Comment @argus review to re-run, or @argus re-review after pushing.
b4b375d to
dc248f8
Compare
There was a problem hiding this comment.
ARGUS
Findings
1 finding(s) that fall outside the diff and could not be anchored to a line
projects/rccl/CHANGELOG.md:23(Low) No CHANGELOG entry for a user-visible revoke hang fix
Bottom line: The device-side abort plumbing traces clean on every path checked. Worth settling before approval: the two new tests still cover only AllReduce LL, so every other converted wait loop stays unexercised.
Comment @argus review to re-run, or @argus re-review after pushing.
Skip due to NCCL defect. Fix: ROCm/rocm-systems#11245
|
This pull request has been inactive for 25 days and will be marked as stale. If you would like to keep this PR open, please:
This PR will be automatically closed in 5 days if no further activity occurs. |
dc248f8 to
bf55109
Compare
|
@cppccppccppc @sunguobao PTAL |
There was a problem hiding this comment.
ARGUS
Bottom line: Worth settling before approval: the DDA barrier's abort exit leaves CAS mailbox flags set and nothing re-zeroes them (fabric_gpu_barrier.h:94). All seven earlier threads are still open.
Comment @argus review to re-run, or @argus re-review after pushing.
|
Re the Argus review summary (CHANGELOG): added a "Resolved issues" entry under RCCL 2.32.3 for the abort/revoke hang in DDA collectives, in 3166b4c. |
There was a problem hiding this comment.
ARGUS
This PR changes 1,067 lines across 39 files. A change this size is hard to review
well, for a person and for this bot alike: reviewers lose the thread, defects hide in the
volume, and the feedback arrives too late to be cheap to act on. Splitting it into a
stacked pull request
gives each piece a reviewable diff and keeps the history. This review covers the whole change
regardless.
Bottom line: Worth settling before approval: kDisableLL also turns off the LL128 tier, so the three new LL128 cases always skip and those kernels get no coverage.
Comment @argus review to re-run, or @argus re-review after pushing.
There was a problem hiding this comment.
ARGUS
This PR changes 1,139 lines across 38 files. A change this size is hard to review
well, for a person and for this bot alike: reviewers lose the thread, defects hide in the
volume, and the feedback arrives too late to be cheap to act on. Splitting it into a
stacked pull request
gives each piece a reviewable diff and keeps the history. This review covers the whole change
regardless.
Bottom line: Worth settling before approval: the new abortFlag_ member and 3-argument mailbox calls in ipc_gpu_barrier.h break the rccl-UnitTestsFixtures build (DdaIpcGpuBarrierOrderingTests.cpp:52 static_assert, 2-argument calls at :93-106).
Comment @argus review to re-run, or @argus re-review after pushing.
44ef618 to
134defe
Compare
rcclGetCollImplInfo reports the LL128 tier, not the one-/two-shot variant, so lowering RCCL_DDA_LL128_ONESHOT_THRESHOLD below the test size made IncompleteCollective_DdaLl128OneShot rerun the two-shot kernel and left the one-shot kernel's abort wait without a case. Skip unless the threshold is at its default.
The ddaLaunch checks in the DDA revoke/shrink and abort helpers were rank-local ASSERT_EQs. A launch failure on one rank returned from the test on that rank alone while its peers carried on into the next MPI_Barrier or hipStreamSynchronize and hung. Collect each launch result, default it to success on ranks that do not launch, and check it with ASSERT_MPI_EQ so every rank fails together. For the child launch, vote before the stream sync so the surviving ranks do not block waiting on a peer that never launched.
…tests After ncclCommRevoke or ncclCommAbort the DDA revoke and abort helpers called hipStreamSynchronize directly. If abortFlag failed to break a DDA wait, the kernel spun forever and the job hung with no diagnostic. Use DdaFabricMPI::waitStreamBounded with abortJobUnlessAllRanksDrained so a stuck kernel or a sticky stream error is reported and the MPI job is aborted on every rank.
ncclCommAbort was checked with a rank-local ASSERT_EQ. A failure on one rank returned from the test while its peers blocked in the all-rank drain vote that follows. Check it with ASSERT_MPI_EQ, as the other revoke and grow abort tests do, so every rank fails together.
…All polls The abort exit in the fabric LL/LL128 AllGather and AlltoAll gather loops is a break rather than the ddaSetLLEpoch-and-return used elsewhere. Note why at each site: the poll is the outermost loop, so the epoch bump below still runs, and in the LL128 AllGather every thread must reach the trailing __syncthreads.
An early return per unrolled wait bloated the kernel; skip the remaining waits instead and still bump the LL epoch.
An abort can leave ranks with different DDA LL epochs and unconsumed barrier mailbox slots, so a later DDA collective on the parent could hang or return a peer's stale data. Disqualify DDA on that comm in rcclDdaEnabled; restoring DDA there needs a cross-rank resync.
DDA kernels, wait helpers and the Fabric/IPC GPU barriers took comm->abortFlagDev as a bare const uint32_t*. Wrap it in DdaAbortSignal, passed by value, with isSet() and spinTick() replacing ddaAbortFlagSet and ddaAbortSpinTick, so the abort state has its own type at every launch and wait site. The struct holds one pointer, so the kernel ABI is unchanged.
With the sticky abort, a thread that gave up waiting in phase 2 still published acc0/acc1 to every peer under the current epoch flag, with zeros in place of the missing peers. A peer that had not aborted yet and already held its phase-1 inputs accepted those partial sums in phase 3 and finished with wrong data. Skip the publish once aborted; peers then either read a correct reduced shard or keep waiting until they abort too.
DdaFabricMPITestFixture.hpp, DdaReduceScatterLL128MPITests.cpp and DdaFabricSimpleMPITests.cpp each had their own copy, two of them still querying device 0. Use DdaMPITestHelpers::isGfx1250Device(), which checks the current device.
Every lane of ddaLL128PollWire loads the same abort flag in the same instruction, so the lanes already leave the loop together without __any().
Equivalent to the early return inside the loop, and reads like the other DDA wait helpers.
A barrier wait that gave up on abort let the kernel signal its next barrier anyway. A late peer that was not aborted could then pair its earlier flag with that signal, pass the barrier, and read a shard this rank never finished, returning ncclSuccess with wrong data. Keep a sticky aborted_ flag in IpcGpuBarrier and FabricGpuBarrier, shared across the signaling lanes with a wave vote, and skip every later signal in the kernel once it is set. Fabric cliques larger than a wave fall back to __syncthreads_or.
Per review, make the per-launch DDA kernel argument a general parameter struct so later values can be added without another kernel argument. dda_abort.h becomes dda_kernel_params.h, the kernel and barrier members become params / params_, and the methods become aborted() and abortSpinTick(). No behavior change.
…cannot run DDA, CE 2-shot and GIN-SDMA return from the collective impl before ncclEnqueueCheck, which is where a revoked comm is rejected. Once revoke can complete with DDA barrier flags left unconsumed, a collective issued on the revoked parent would run DDA again and could pass a barrier early. Divert revoked comms through enqueue so they get ncclInvalidUsage.
…nd the revoked parent - DdaIpcGpuBarrierOrdering.AbortedBarrierStaysSilent fails if a barrier that gave up on abort still signals the next one. - RevokeDdaIpcMPITest.IncompleteCollective_DdaIpcAllReduceTree reaches the three-barrier tree kernel; ShrinkAbort_DisablesDdaOnParent now also runs on the 8-rank DDA IPC parent. - The DDA revoke helper checks that the revoked parent rejects the same DDA collective with ncclInvalidUsage. - The DDA fabric mock comm carries a non-null abortFlagDev, so the launcher tests can tell the flag was forwarded.
…fix mi455 LL128 descriptions
7bb78ac to
43304ae
Compare
Resolve against #11245 (abortFlag in DDA waits): both LL128 one-shot poll sites use the abort-aware ddaLL128PollWire and update the LL epoch before returning, the word-per-lane LL128 kernel uses ddaLL128WaitFlag, and the test drops its copies of the two-shot helpers now in DdaMPITestHelpers.hpp.
TheRock Submodule Bump ActivityNewest first
|
Skip due to NCCL defect. Fix: ROCm/rocm-systems#11245 (cherry picked from commit 64843f1) Signed-off-by: pablo-garay <pablo-garay@users.noreply.github.com>
Skip due to NCCL defect. Fix: ROCm/rocm-systems#11245 (cherry picked from commit 64843f1) Signed-off-by: pablo-garay <pablo-garay@users.noreply.github.com>
Motivation
ncclCommRevokeandncclCommAbortsetabortFlagso in-flight kernels can drain. Generic device primitives already sample that flag, but the standalone DDA kernels did not.On gfx1250, an incomplete DDA collective (for example, a rank that never launches its AllReduce) left the other ranks spinning on peer flags or barrier mailboxes that would never arrive. Revoke and abort then hung in stream sync (
RevokeMPITest.IncompleteCollective_Revoke_Shrink_Collective). DDA IPC on gfx942/gfx950 has the same shape inIpcGpuBarrier.Technical Details
Every DDA wait now polls
comm->abortFlagDev, at the same cadence ascheckAbort(kDdaSpinsBeforeCheckAbort, in the newdda_kernel_params.h). This covers the LL and LL128 flag waits in AllReduce (one-shot and two-shot), AllGather, ReduceScatter and AlltoAll, and the fabric and IPC GPU barriers. Launchers pass adda::common::DdaKernelParamsby value to the kernels, wait helpers and barriers. It holds the abort flag today, and later per-launch values go there rather than as extra kernel arguments.On abort a wait gives up rather than returning early from the kernel where that would skip shared work: polls
breakso the LL epoch update and__syncthreadsstill run. The LL two-shot AllReduce uses a sticky abort, skipping the remaining waits once the flag is seen, because an early return after each unrolled wait nearly doubled the 8-rank kernel and slowed the single-node two-shot path. A thread that has aborted does not publish its phase-2 sums, which are partial, so a peer that has not seen the abort cannot accept them as the reduced shard.IpcGpuBarrierandFabricGpuBarrierkeep a stickyaborted_for the rest of the kernel. Once a signaling lane gives up a put or a wait, the block signals no later barrier, so a late peer cannot pair its earlier flag with this block's next one and read a two-shot shard this rank never finished. The signaling lanes all sit in wave 0, so they share the result through__any;FabricGpuBarrieruses__syncthreads_orwhen the clique is wider than one wave. This replaces a load of the pinned-host abort flag before every put.DDA stays enabled when revoke is used, because revoke has to stop kernels that are already running. A collective issued on a revoked comm is rejected: DDA, CE 2-shot and GIN-SDMA return from the collective before
ncclEnqueueCheck, sorcclCollectiveMustUseEnqueuePathnow sends a revoked comm through enqueue, which returnsncclInvalidUsageasnccl.hdocuments. Without this, a collective on the revoked parent would run DDA again on mailboxes left with unconsumed flags.A parent comm shrunk with
NCCL_SHRINK_ABORTstops using DDA (comm->ddaDisabledAfterAbort, checked inrcclDdaEnabled). The abort can leave ranks with different LL epochs and unconsumed barrier mailbox slots, so a later DDA collective on that parent could hang or return a peer's stale data. The shrunk child does not share the parent's resources and is not affected.Tests (the MPI cases are in
RevokeMPITests.cpp):RevokeDdaMPITest.IncompleteCollective_*(11 cases, gfx1250): one rank skips a DDA collective, the rest revoke and shrink. They cover LL and LL128 one-shot and two-shot AllReduce, the VMM barrier, and LL/LL128 AllGather, ReduceScatter and AlltoAll. Each case first confirms throughrcclGetCollImplInfothat the intended DDA path is selected, and after the revoke checks that the same collective on the revoked parent returnsncclInvalidUsage.RevokeDdaIpcMPITest.IncompleteCollective_DdaIpc*(5 cases, gfx942/gfx950, 8 ranks): the same pattern for DDA IPC AllReduce (flat and the three-barrier tree kernel), AllGather, ReduceScatter and AlltoAll.AbortDdaMPITest.IncompleteCollective_*(5 cases): the same pattern withncclCommAbort, for LL one-shot and two-shot AllReduce, and AllGather, ReduceScatter and AlltoAll LL.ShrinkAbort_DisablesDdaOnParentin bothRevokeDdaMPITestandRevokeDdaIpcMPITest: afterNCCL_SHRINK_ABORT, the parent no longer selects DDA and the child's AllReduce succeeds.DdaIpcGpuBarrierOrdering.AbortedBarrierStaysSilent(one GPU): a barrier that gave up on abort must not signal the next one after late peers drain the first. It fails with the stickyaborted_removed.Rcclwrap.EnqueueGuards_RevokedForcesEnqueue: a revoked comm takes the enqueue path.comm->abortFlagDevreaches the kernel; the mock comm now carries a non-null flag so the check can fail.Launch, abort and stream-drain results are voted across ranks, and post-revoke waits are bounded, so a failure on one rank fails every rank instead of hanging. The test runner configs for MI300, MI355X and MI455 include the new cases.
Known gaps
These are out of scope for this PR and tracked as follow-ups:
ncclCommRevokeandNCCL_SHRINK_ABORTwith a stuck DDA kernel. Both setabortFlag, sync onlyhostStreamanddeviceStream, then clear the flag (commRevokeAsyncandncclCommShrink). DDA kernels run on the user stream, whichdeviceStreamis not ordered after outside graph capture, so a stuck kernel that does not poll the flag inside that window keeps spinning. In practice the window is long enough for the poll (everykDdaSpinsBeforeCheckAbortspins), which is why the revoke tests pass, but it is not guaranteed. Native single-stream kernels and NCCL upstream have the same window.ncclCommAbortleaves the flag set and is not affected.NCCL_SHRINK_ABORT. Turning it back on needs a cross-rank resync of the LL epochs and barrier mailboxes.ncclCommRevokeorNCCL_SHRINK_ABORTclearsabortFlagnever sees the abort, and hangs if a peer is missing.Issue Tracking
JIRA ID: ROCM-33096 (gfx1250, DDA fabric), ROCM-32381 (gfx942, DDA IPC).
Test Plan
Run each
RevokeDdaMPITestcase in its own process, as the runner configs do. In one process the first case cachesRCCL_DDA_LLand the LL sub-thresholds, so laterMpiEnvGuards have no effect and some cases skip.AbortDdaMPITest.*sets no overrides and can run in one process.mpirun -np 4 ./rccl-UnitTestsMPI --gtest_filter=<case>for eachRevokeDdaMPITest,RevokeMPITestandRevokeNonBlockingMPITestcase in therevoke_mpi_tests_4rankgroup (for example--gtest_filter=RevokeDdaMPITest.IncompleteCollective_DdaVmmBarrier), and--gtest_filter='AbortDdaMPITest.*'.mpirun -np 8 --host <nodeA>:4,<nodeB>:4 ...).mpirun -np 8 ./rccl-UnitTestsMPI --gtest_filter=RevokeDdaIpcMPITest.<case>, one per process, on 8 gfx942/gfx950 GPUs, plus the revoke, shrink, abort and grow suites ofmi300x_mellanox_ib.json../rccl-UnitTestsFixtures --gtest_filter='DdaIpcGpuBarrierOrdering.*'and./rccl-UnitTestsFixturesDebug --gtest_filter='Rcclwrap.EnqueueGuards_*'.rccl-UnitTestsMicroDdaCollandrccl-UnitTestsMicroDda.-c 1) for AllReduce, AllGather, ReduceScatter and AlltoAll on one and two nodes, plus two-node AlltoAll and ReduceScatter withRCCL_DDA_LL128_THRESHOLD=67108864.NCCL_DEBUG_SUBSYS=COLLlogs confirm the DDA path at each size.RCCL_DDA_LL_ONESHOT_THRESHOLD=0).Test Result
gfx942, DDA IPC (8x MI300X, one node, ROCm 7.13.0 rc2, DebugFast,
7bb78ac42da):mi300x_mellanox_ib.json: 62 pass, 2 fail and 19 skip on this hardware, including everyRevokeDdaIpcMPITest.IncompleteCollective_*case andDdaIpcGpuBarrierOrdering.*.RevokeDdaIpcMPITest.ShrinkAbort_DisablesDdaOnParent, added after that run, passes on its own. The 2 failures areSymAbort_Kernel.LLAllToAll_AbortReleasesKernelandSymAbort_Kernel.LsaBarrier_AbortReleasesKernel, which time out in communicator setup on develop as well.Rcclwrap.EnqueueGuards_*passes. With the sticky barrier abort or the revoked-comm divert reverted,AbortedBarrierStaysSilent,EnqueueGuards_RevokedForcesEnqueueand the IPC AllReduce revoke cases fail.rccl-UnitTestsMicroDdapasses 51 of 51.rccl-UnitTestsMicroDdaCollpasses 266; 5 LL128 eligibility tests fail on develop as well, after Tuning Infra Improvement #12386 removed theRCCL_DDA_LLgate from LL128 eligibility.cc2700e596d, rccl-tests-c 1reports 0 wrong values for all four collectives on DDA IPC, and performance againstcc2700e596dis within noise from 1 KB to 8 MB (3 reps).gfx1250, DDA fabric (4 GPUs per node,
ctheliosp-rck-g02-j11-12alone and withj11-11, one MNNVL fabric clique):65410fcff30(the barrier fix, before the revoked-comm divert and the new tests), 80 of 86 cases in the revoke, shrink and abort suites pass on one and two nodes. Of the 6 failures, 3 two-node cases did not start (ORTE was unable to reliably start one or more daemons), 2 are theSymAbort_Kerneltimeouts above, and 1 is a staleSymCheckMode_Registrationfilter name in the mi455 config on develop. rccl-tests-c 1reports 0 wrong values in every run that completed.7bb78ac42dais not yet tested on gfx1250: the nodes moved to a new ROCm build mid-run and are now in use. Results to follow.dfb3f8c9e28(median latency, 2% threshold with non-overlapping ranges):134defe6cc6, AllReduce forced onto the LL two-shot kernel is 3–6% slower (about 1–1.4 µs) from 64 KB to 2 MB, on one and two nodes. At default thresholds this kernel is used at 2 MB only.8fecb7a64bb), the LL two-shot AllReduce is within -1.5% to +0.2% of134defe6cc6at every size from 64 KB to 2 MB, on one node (4 ranks, 5 reps) and two nodes (8 ranks, 3 reps).Submission Checklist