Skip to content

Latest CXI opts - #1235

Closed
bcmIntc wants to merge 554 commits into
Sandia-OpenSHMEM:performancefrom
bcmIntc:performance
Closed

bcmIntc wants to merge 554 commits into
Sandia-OpenSHMEM:performancefrom
bcmIntc:performance

Conversation

@bcmIntc

@bcmIntc bcmIntc commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Performance Optimizations for CXI/Slingshot Systems

Summary

This PR adds performance optimizations targeting large-scale CXI/Slingshot systems (1000+ nodes, 104+ PPN):

  1. Huge page support - Use 2MB CXI ATU translations via MAP_HUGETLB
  2. Hierarchical barrier - Reduces NIC traffic for barrier-heavy workloads
  3. CXI fence and MR optimizations - Reduces latency and overhead
  4. Pipeline depth controls - Prevents TRS exhaustion and AMO incast at scale
  5. Put counter watermark - Optimizes per-call put_wait polling

All features are opt-in via runtime environment variables or configure flags.


1. Huge Page Support

Commit: 0ef65837 - symmetric heap: use anonymous MAP_HUGETLB for huge page allocation

Enables 2MB pages for symmetric heap allocation using anonymous MAP_HUGETLB. Requires --enable-ofi-mr=scalable (change from previous --enable-ofi-mr=basic default).

Why: CXI NIC's Address Translation Unit (ATU) performs virtual-to-physical translation for RDMA operations. With 4KB pages, the ATU cache thrashes on large jobs. 2MB pages reduce ATU pressure by 512×, improving cache hit rates.

Impact: CXI ATU telemetry shows improvement in 2MB translation usage (0% in baseline).

Implementation:

  • Uses MAP_HUGETLB | (21 << MAP_HUGE_SHIFT) for explicit 2MB page requests
  • Leverages kernel's nr_overcommit_hugepages for on-demand allocation
  • Graceful fallback: hugetlbfs → MAP_HUGETLB → madvise(MADV_HUGEPAGE) → 4KB pages
  • Modified mmap_alloc() in src/symmetric_heap_c.c

Requirements:

  • Configure: --enable-ofi-mr=scalable (registers entire heap as one region)
  • Runtime: export SHMEM_SYMMETRIC_HEAP_USE_HUGE_PAGES=1
  • System: echo 171000 | sudo tee /proc/sys/vm/nr_overcommit_hugepages

2. Pipeline Depth Controls

Commit: be191cd8 - transport/ofi: add put pipeline depth limit to prevent TRS exhaustion

Throttles outstanding put operations to prevent Transaction Request Slot (TRS) exhaustion on CXI NICs at large scale.

Why: Each outstanding RDMA operation consumes a TRS on the initiator NIC. At 1000+ nodes with high PPN, unconstrained put pipelines can exhaust the TRS pool, causing stalls and retries.

Impact: At 416 PEs with 2 NICs, reduced credit stalls by 98% (43,652 → 704). Critical for 1000+ node runs where TRS pressure compounds with PE count.

Implementation:

  • Polls pending put counter when pipeline reaches threshold
  • Only polls when SHMEM_OFI_PUT_PIPELINE_DEPTH > 0
  • Zero overhead when disabled (default)
  • Added in shmem_transport_put_nbi() in src/transport_ofi.c

Usage:

export SHMEM_OFI_PUT_PIPELINE_DEPTH=512   # Recommended for large-scale runs
export SHMEM_OFI_AMO_PIPELINE_DEPTH=4     # Throttles AMO incast at high PPN

Disabled by default (0). Enable for jobs with 1000+ nodes or evidence of TRS exhaustion (pct_retry_trs_put > 0 in CXI telemetry).


3. Put Counter Watermark

Commit: 9d2bf3e9 - transport/ofi: use put counter watermark for per-call put_wait

Optimizes shmem_transport_put_wait() by recording a watermark at each call site instead of polling from 0.

Why: Previous implementation polled pending_put_cntr from 0 on every put_wait() call, even when only a subset of puts needed to complete. At high operation rates, this causes unnecessary polling overhead.

Impact: Reduces poll iterations in put_wait() by only waiting for puts issued since the last wait call, not all puts since initialization.

Implementation:

  • Stores pending_put_cntr value at start of wait
  • Polls until counter advances past watermark
  • Modified shmem_transport_put_wait() in src/transport_ofi.c

4. CXI Hybrid MR Descriptor Mode

Commit: 5e08a9e2 - transport/ofi: enable CXI hybrid local MR descriptor mode (squashed)

Enables CXI provider's hybrid MR descriptor mode via FI_CXI_DOM_OPS_3 to skip redundant internal memory registration lookups.

Why: Without hybrid mode, CXI provider performs internal MR cache lookup on every fi_write()/fi_writemsg() call even when the buffer is already registered. Each lookup adds latency to RDMA puts.

Impact: Drops per-call overhead on put data path by trusting non-NULL desc parameter and skipping provider's internal registration walk.

Implementation:

  • Calls enable_hybrid_mr_desc(true) after fi_domain() creation
  • Gated by SHMEM_OFI_CXI_HYBRID_MR_DESC=true (default)
  • Mirrors struct fi_cxi_dom_ops locally (no rdma/fi_cxi_ext.h dependency)
  • Refactored provider checks into shmem_transport_ofi_check_provider() helper
  • Modified src/transport_ofi.c, added declarations to src/transport_ofi.h

5. CXI Fence Optimization

Commit: 87f6ebfb - transport/ofi: skip put_quiet in fence for CXI provider

Skips redundant put_quiet poll in shmem_transport_fence() for CXI provider.

Why: CXI maintains per-EP FIFO ordering with FI_DELIVERY_COMPLETE, so subsequent operations already see prior puts at the target. Polling pending_put_cntr in put_quiet() is redundant and adds ~1-2µs latency per fence.

Impact: ~1-2µs improvement in put_signal_nbi() and barrier operations that call shmem_transport_fence().

Implementation:

  • Checks shmem_transport_ofi_check_provider("cxi") in fence path
  • Preserves existing behavior for non-CXI providers (tcp, verbs, opx, sockets)
  • Modified shmem_transport_fence() in src/transport_ofi.h

6. Hierarchical Barrier

Commits: 99d340d9, a726303d - barrier: three-phase hierarchical barrier via XPMEM + NIC dissemination

Three-phase barrier: intranode gather/fanout via XPMEM CPU atomics, internode dissemination via NIC (node roots only).

Why: Traditional barriers send messages from every PE across the NIC. At 104+ PPN, this creates massive NIC contention. Hierarchical approach keeps intranode traffic on CPU, reducing network traffic by ~90% for barrier-heavy workloads.

Impact: For 1000 nodes × 104 PPN, reduces barrier NIC messages from 108,160 to ~1,000.

Requirements:

  • Configure: --enable-hierarchical-barrier --with-xpmem
  • Runtime: export SHMEM_BARRIER_ALGORITHM=auto (auto-enables at ≥2 local PEs)

Additional Changes

  • Zero max_buffered_send - Let provider advertise instead of hardcoding
  • Improved OFI transport wait - Better polling logic

Configuration

Build:

../configure --enable-ofi-mr=scalable --enable-mr-endpoint \
  --enable-hierarchical-barrier --with-xpmem --disable-nonfetch-amo

# Note: Previous default was --enable-ofi-mr=basic
# Change to scalable is required for huge page optimization

Runtime:

# Huge pages (before running workload on all nodes):
pbsdsh -- bash -c 'echo 171000 | sudo tee /proc/sys/vm/nr_overcommit_hugepages'

# SOS environment:
export SHMEM_SYMMETRIC_HEAP_USE_HUGE_PAGES=1
export SHMEM_SYMMETRIC_SIZE=3G
export SHMEM_BARRIER_ALGORITHM=auto
export SHMEM_OFI_PROVIDER=cxi

# CXI provider optimizations:
export FI_CXI_RX_MATCH_MODE=hybrid
export FI_MR_CACHE_MONITOR=userfaultfd

# Pipeline controls (recommended for large-scale runs):
export SHMEM_OFI_PUT_PIPELINE_DEPTH=512
export SHMEM_OFI_AMO_PIPELINE_DEPTH=4

Testing

Validated on:

  • NERSC Perlmutter (CXI/Slingshot interconnect, 1 NIC per node)
  • Borealis cluster (8 NICs per node, multi-rail configuration)

Telemetry confirms:

  • Most ATU translations using 2MB pages
  • 98% reduction in credit stalls with pipeline controls
  • Hierarchical barrier reduces NIC traffic for high-PPN jobs

Compatibility

  • Backward compatible: All optimizations are opt-in via environment variables
  • Graceful degradation: Falls back to 4KB pages if huge pages unavailable
  • Provider-specific: CXI optimizations automatically detected at runtime
  • Platform support: Linux only (uses #ifdef __linux__ guards where needed)

kholland-intel and others added 30 commits November 10, 2022 17:02
…ed_tests

Added configury option to enable deprecated tests
…rrier

Add support for a SHMEMX_NO_BARRIER hint
* test: unit test for ctx_get_team

* Updated based on Dave's comment
…updating intel dates

Signed-off-by: tmh97 <thuber@udel.edu>
…e_corrections

Moving Cornelis License from bottom to top, adding to transport_ofi, …
…strides

Teams: support negative strides, adds a unit test
Instead of zeroing caps, we will set them to a relevant subset of the p_info->caps.
Instead of zeroing caps, we will set them to a relevant subset of the p_info->caps.
kphuphanwoe and others added 12 commits August 27, 2025 11:54
Issue Sandia-OpenSHMEM#1185

If SHMEM_SYMMETRIC_SIZE contains invalid characters, return error.

Signed-off-by: Kitibodee Phuphanwoe <kitibodee.ph@ksu.ac.th>
Do not force hard polling when XPMEM is enabled.
This conflicts with counter based polling when used with OFI transport.

Issue Sandia-OpenSHMEM#1217

Signed-off-by: Mark F. Brown <mark.f.brown@intel.com>
Replaced complex polling with simpler OFI counter wait

Issue Sandia-OpenSHMEM#1217

Signed-off-by: Mark F. Brown <mark.f.brown@intel.com>
Issue Sandia-OpenSHMEM#1221

Signed-off-by: Mark F. Brown <mark.f.brown@intel.com>
Let the provider advertise its natural inject_size rather than
requiring it to be at least sizeof(long double). The returned
inject_size is adopted immediately after fi_getinfo.
Adds --enable-hierarchical-barrier, a three-phase barrier that keeps
intranode traffic off the NIC by using CPU atomics over XPMEM for
gather/fanout and restricts NIC puts to the internode phase (node roots
only).

Phase 1 (intranode gather): local PEs signal up a k-ary tree. Each PE
writes to its OWN up-slot in local_pSync; the parent reads each child's
slot individually. Slots are padded to one cache line (HIER_SLOT_STRIDE=8
longs, 64 bytes) so no two PEs share a line, eliminating the MESI
serialization that would occur if all children wrote to a single counter.
Signal values increment monotonically via hier_sense, avoiding explicit
slot resets between calls (sense alternation).

Phase 2 (internode dissemination): node roots run a put-based binary
dissemination across the NIC. After each round the slot is reset via a
CPU store rather than a self-put, saving ceil(log2(N_nodes)) NIC
round-trips per barrier (12 at 4096 nodes).

Phase 3 (intranode fanout): node root CPU-stores an ack into each child's
down-slot; children relay down the k-ary tree with reset-before-signal
ordering. Down-slots are in the upper half of local_pSync, laid out with
the same per-PE cache-line padding as up-slots.

AUTO selection activates when local PE count >= SHMEM_HIER_BARRIER_THRESHOLD
(default 2). Also selectable via SHMEM_BARRIER_ALGORITHM=hierarchical.

New infrastructure:
- src/shr_transport.h  — XPMEM CPU pointer mapping; self-access returns
  the address directly without an XPMEM lookup
- src/runtime_util.c  — global hostname exchange so each PE can identify
  its node root
- configure.ac  — --enable-hierarchical-barrier requires --with-xpmem and
  a network transport
Bug: Static global hier_sense caused signal mismatch when PEs
participated in different barrier teams. Only PEs in the active set
incremented hier_sense, causing divergence on the next TEAM_WORLD
barrier (PEs that skipped the subset barrier had stale sense values).

Fix: Move hier_sense to shmem_internal_team_t. For TEAM_WORLD barriers
(PE_start=0, PE_stride=1, PE_size=num_pes), use team-local state.
For subset barriers (rare), use static fallback to avoid full
team-parameter refactor.

All PEs in TEAM_WORLD now stay synchronized across interleaved
team/subset barrier sequences.
When SYMMETRIC_HEAP_USE_HUGE_PAGES is enabled but no hugetlbfs mount is
configured, use anonymous MAP_HUGETLB with explicit 2MB page size instead
of falling back to transparent huge pages (THP).

This allows the kernel's nr_overcommit_hugepages mechanism to dynamically
allocate surplus huge pages on demand without requiring pre-reserved
HugePages_Total. Anonymous MAP_HUGETLB with (21 << MAP_HUGE_SHIFT)
explicitly requests 2MB pages, matching the CXI provider's behavior.

When used with scalable MR mode (--enable-ofi-mr=scalable), this enables
the CXI NIC's ATU to use 2MB page translations (derivative1) instead of
4KB base pages, significantly improving ATU cache hit rates.

Fallback to THP via madvise(MADV_HUGEPAGE) still occurs if MAP_HUGETLB
fails, ensuring compatibility across different kernel configurations.

Formatting

symmetric heap: change hugetlbfs file warning to debug message

Change the hugetlbfs file open failure from RAISE_WARN_STR to DEBUG_MSG
since the fallback to anonymous MAP_HUGETLB works correctly. The warning
was misleading because huge pages were still being allocated successfully
via the anonymous MAP_HUGETLB path.

symmetric heap: fix huge page allocation bugs and improve fallback handling

- Fix double free: set directory/file_name to NULL after freeing
- Fix size bug: preserve original bytes, only use hugetlbfs_bytes for file path
- Fix fallback: use NULL address hint after MAP_HUGETLB failure
- Add debug visibility: log which allocation path succeeded
- Change hugetlbfs warnings to debug messages (fallback works correctly)

symmetric heap: fix munmap size mismatch and preserve requested_base in fallbacks

- Fix Issue 1 (munmap size mismatch): add size_t *mapped_bytes out-parameter
  to mmap_alloc(). On the hugetlbfs success path the mapping is rounded up to
  a huge-page boundary (hugetlbfs_bytes > bytes); the previous code passed the
  original unrounded size to munmap and transport registration (OFI, Portals4,
  UCX, XPMEM), leaking the tail pages from the huge-page pool. mmap_alloc now
  reports the actual mapped size, and shmem_internal_symmetric_init updates
  shmem_internal_heap_length accordingly so munmap, registration, and bounds
  checks all use the correct extent.

- Fix Issue 2 (requested_base dropped on fallback): both THP fallback paths
  (ftruncate failure and MAP_HUGETLB failure) previously used mmap(NULL, ...)
  unconditionally. This discards the requested_base hint (data segment + 2 GB,
  1 GB-aligned) that is required for --enable-remote-virtual-addressing to
  maintain symmetric virtual addresses across PEs. The fallbacks now first
  attempt mmap(requested_base, ...) and only resort to mmap(NULL, ...) if
  that also fails. Remove the incorrect comment claiming requested_base will
  not work after MAP_HUGETLB failure.
Cray SHMEM caps in-flight SHEAP puts at 512, which prevents the NIC's TRS
(Transaction Resource) pool from exhausting under AMO+put contention.
SOS had no such limit, causing mst_stalled_waiting_put_crdts to reach
333M+ on the initiator while Cray shows 0.

Add SHMEM_OFI_PUT_PIPELINE_DEPTH (default 512, 0=unlimited) which throttles
RDMA put issue rate by checking pending-completed against the limit before
each fi_write/fi_writemsg call.  The inject path (fi_inject_write) is exempt
since inject does not consume TRS slots.

Throttle points: put_large (fi_write), put_nb bounce-buffer path (fi_writemsg).
The signal operation retains its existing fence-based ordering.

transport/ofi: default OFI_PUT_PIPELINE_DEPTH to 0 (disabled)

The nail benchmark's dependent put pattern (1 put per AMO) never reaches
the 512 limit, so the throttle added overhead (fi_cntr_read on every RDMA
put) with no benefit.  Default to 0 (disabled) until a workload that
actually benefits from it is identified.  Enable with
SHMEM_OFI_PUT_PIPELINE_DEPTH=512 to match Cray SHMEM behavior.

transport/ofi: add SHMEM_OFI_AMO_PIPELINE_DEPTH for incast throttling

At high PPN (e.g. 128), all PEs simultaneously fire fetching AMOs to the
same target PE.  This saturates the target NIC's TRS pool and causes
mst_stalled_waiting_put_crdts on all initiators despite only one put per
AMO being in flight.

Cray SHMEM addresses this with incast throttling — "every 0 atomics at
128 PPN" — pacing each PE's AMO issue rate so the target NIC is not
overwhelmed.

Add SHMEM_OFI_AMO_PIPELINE_DEPTH (default 0=disabled) which limits
in-flight fetching AMOs per context.  The throttle is in
fetch_atomic_nbi (the CXI path under ENABLE_MR_ENDPOINT), the only
fetching AMO code path active on Perlmutter.

At 128 PPN with ~512 NIC TRS slots, a value of 4 leaves each PE a fair
share.  Enable with:
  SHMEM_OFI_AMO_PIPELINE_DEPTH=4 srun ...
Previously, shmem_long_put for sizes > bounce_buffer_size routed through
put_large which set *completion=1, causing shmem_internal_put_wait to call
shmem_transport_put_quiet — a global drain of every in-flight put on the
context.  Under the Nail benchmark's AMO+put pattern, this serialized the
entire pipeline at sizes >= 16KB: each put waited for all prior puts and
implicitly any in-progress AMOs sharing the context.

Replace the count-based completion semantic with a counter watermark.
put_large now records pending_put_cntr immediately after issuing all
fragments; put_wait spins fi_cntr_read(put_cntr) until it reaches that
specific watermark.  This satisfies the OpenSHMEM "source buffer reusable
on return" contract for blocking puts without forcing global ordering.

The inject and bounce-buffer paths are unaffected: inject completes
synchronously inside fi_inject_write, and bounce buffers memcpy the source
before issue, so neither path needs to set the watermark — *completion
stays 0 and put_wait is a no-op for them, as before.
Cray SHMEM's startup log shows it calls FI_CXI_DOM_OPS_3 enable_hybrid_mr_desc
right after fi_domain(); SOS does not.  Without it, the CXI provider performs
internal memory registration on every fi_write/fi_writemsg/fi_fetch_atomicmsg
call where the desc field is non-NULL — even if the buffer is already in a
provider-registered region.  Each MR cache lookup adds latency to large RDMA
puts.

With hybrid mode enabled, the provider trusts a non-NULL desc and skips its
internal registration walk, dropping per-call overhead on the put data path.

The call must occur before any endpoints are created — the docstring warns
that endpoints inherit the domain's hybrid-MR status only at creation time.

Implementation does not include rdma/fi_cxi_ext.h; instead, it mirrors the
needed fields of struct fi_cxi_dom_ops locally so the build does not require
CXI headers.  fi_open_ops() returns -FI_ENOSYS on non-CXI providers; that
case is silently ignored.

Gated by SHMEM_OFI_CXI_HYBRID_MR_DESC=true (default), so it can be disabled
for A/B testing without rebuilding.


transport/ofi: print CXI hybrid MR desc status from PE 0

Promote the hybrid MR desc enable result from DEBUG_MSG (silent unless
SHMEM_DEBUG=1) to fprintf(stderr) on PE 0 only, so we can verify whether
the call actually took effect on each run.  Also reports when the env var
disables it, when the provider doesn't support dom_ops_v3 (non-CXI), and
when the call returned an error.


transport/ofi: refactor provider checks into shmem_transport_ofi_check_provider()

Replace hardcoded provider name comparisons with a centralized helper
function. This provides:

- Single source of truth for provider name storage
- Consistent comparison logic across all provider checks
- Easy addition of new provider-specific optimizations
- Better code maintainability

Changed:
- Replaced global `shmem_transport_ofi_is_cxi` with static
  `shmem_transport_ofi_prov_name` pointer
- Added `shmem_transport_ofi_check_provider(const char *name)` helper
- Updated fence CXI check to use new function
- Set provider name once in query_for_fabric()

No functional change - same CXI fence optimization behavior.
CXI maintains per-EP FIFO ordering, so FI_TRANSMIT_COMPLETE already
guarantees subsequent operations see prior puts at the target. Polling
pending_put_cntr in shmem_transport_put_quiet() is redundant and adds
~1-2µs latency.

Skip put_quiet when prov_name == "cxi". Other providers (tcp, verbs,
opx, sockets) require explicit put_quiet to ensure remote visibility
before fence returns, so preserve existing behavior for non-CXI.

This is safe because:
1. put_signal_nbi already uses FI_DELIVERY_COMPLETE for the signal write
2. Explicit fence (put_quiet or FI_FENCE flag) orders signal after data
3. CXI FIFO ordering means TRANSMIT_COMPLETE is sufficient for correctness

Expected benefit: ~1-2µs improvement in put_signal_nbi and barrier
operations that call shmem_transport_fence().
@bcmIntc bcmIntc self-assigned this Jun 10, 2026
bcmIntc added 11 commits June 11, 2026 04:15
- collectives: use malloc instead of alloca for PE arrays at scale (prevents
  stack overflow when PE_size reaches 100K+)
- runtime-pmi/pmi2: add NULL check for location_array (prevents segfault)
- shmem_comm: use put_quiet instead of unreliable completion watermark in
  copy_self (guarantees visibility across all put paths: inject, bounce, large)
Revert to put_quiet approach after analysis showed put_wait is insufficient.
The inject path (small copies) has no counter event, so put_wait with
completion=0 would return immediately and leave heterogeneous memory (FI_HMEM)
writes unordered, causing a data race.

put_quiet drains all pending puts and provides the NIC-level ordering
fence needed to guarantee dest is visible in heterogeneous memory (FI_HMEM)
before returning. More conservative than put_wait but correct for all paths.
The extern declaration in transport_ofi.h conflicted with static inline
definition in transport_ofi.c. Since this is a trivial 3-line function
called from an inline function in the header, inline the check directly
rather than calling through a function pointer.

Fixes build error: static declaration follows non-static declaration
- Remove 'static' from shmem_transport_ofi_prov_name declaration to match
  extern declaration in header
- Remove unused 'len' variable in shmem_internal_atomicv, compute inline in assert

Fixes:
- error: static declaration follows non-static declaration
- warning: unused variable 'len'
- collectives: remove unused tree_parent_shr and my_up_slot variables
- collectives: add __attribute__((unused)) to cpu_atomic_load_long
- transport_ofi: remove unused check_provider function (inlined in header)

The check_provider function was replaced by an inline check in commit 33da5805
to avoid linkage conflicts, so the function definition is no longer needed.
- collectives: remove unused tree_parent_shr variable (parent not used in current implementation)
- collectives: keep my_up_raw (used for atomic stores) but remove unused my_up_slot
- collectives: add __attribute__((unused)) to cpu_atomic_load_long (utility for future use)
- strdup provider name so pointer remains valid after fi_freeinfo
- free provider name in shmem_transport_fini
- gate hybrid MR descriptor setup on CXI provider check to avoid spurious warnings
- fix check_provider to use strcmp (exact match) instead of strncmp
- move per-fragment throttle inside loop to enforce pipeline depth per fragment
shmem_shr_transport_ptr() is XPMEM-only — the hierarchical barrier uses
direct pointer mapping for intranode atomics, which CMA cannot provide
(process_vm_writev/readv are bulk copy, not pointer-mapped). Accepting
--with-cma as sufficient caused a silent runtime crash at the first
barrier with RAISE_ERROR_MSG("No path to peer").

Change the configure check from (xpmem OR cma) to (xpmem required) so
CMA-only builds fail at configure time with a clear error message.
Also update the --help text accordingly.
Add comprehensive project documentation in my_claude_state/:
- CLAUDE.md: technical guide for development
- docs/architecture.md: architectural decisions and patterns
- docs/open-issues.md: current issues and resolved items
- docs/session-handoff.md: session continuity information
- docs/todo.md: task tracking and priorities

Update terminology throughout to clarify FI_HMEM:
- "GPU memory ordering" → "Heterogeneous Memory Ordering (FI_HMEM)"
- Clarify this is an optional feature (--enable-ofi-hmem)
- Note standard builds use memcpy() and are unaffected
- Emphasize Perlmutter configuration does not use FI_HMEM

Documentation maintained as work progresses per project conventions.
Update copy_self implementation comment to use "heterogeneous memory
(FI_HMEM)" instead of "GPU" for accuracy. This matches libfabric's
FI_HMEM terminology for device-attached memory (GPUs, accelerators).

No functional changes - comment-only update.
bcmIntc added 3 commits June 11, 2026 09:10
Before this fix, SHMEM_SYMMETRIC_HEAP_USE_HUGE_PAGES only controlled
tier 1 (hugetlbfs file mapping). Tiers 2 (anonymous MAP_HUGETLB) and 3
(THP via madvise) were attempted in error paths even when the flag was
explicitly set to 0, making it impossible to test with regular pages only.

New behavior:
- SHMEM_SYMMETRIC_HEAP_USE_HUGE_PAGES=1: Try all tiers (1→2→3→4)
- SHMEM_SYMMETRIC_HEAP_USE_HUGE_PAGES=0: Skip to tier 4 (regular pages)

Allocation strategy when USE_HUGE_PAGES enabled:
  Tier 1: hugetlbfs file mapping (static pool)
  Tier 2: anonymous MAP_HUGETLB (static + overcommit pools)
  Tier 3: THP via madvise (best-effort promotion)
  Tier 4: regular 4KB pages (fallback)

When disabled, skips directly to tier 4.

This makes the env var name match its actual behavior and allows
controlled testing with/without huge pages.
Update documentation to reflect:
- Huge page gating fix (commit 676f1a8): all tiers now properly
  controlled by SHMEM_SYMMETRIC_HEAP_USE_HUGE_PAGES flag
- Detailed explanation of tiered fallback strategy and interaction
  with nr_overcommit_hugepages on Cray systems
- Impact on CXI MR/ATU performance (2MB pages vs 4KB)
- Current session progress: FI_HMEM terminology updates, git history
  rewrite, new commits since last handoff
- Updated HEAD commit references and branch status

Documentation maintained as work progresses per project conventions.
The condition "if (ret == MAP_FAILED || fd == 0)" was incorrect because
fd is always zeroed after the tier 1 block (cleanup happens on both
success and failure). This caused successful tier 1 allocations to
incorrectly fall through to tier 2.

Fix: Test only ret == MAP_FAILED, which correctly identifies when tier 1
failed and fallback is needed.

Also restore RAISE_WARN_MSG for madvise failure (was incorrectly changed
to DEBUG_MSG in previous commit).
@bcmIntc bcmIntc closed this Jun 11, 2026
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.

8 participants