Skip to content

[Feature/Performance] MetaX C500 OpenMPI backend staging experiments and follow-up items #32

Description

@Dayuxiaoshui

Problem Statement

MetaX C500 support is functional with the current OpenMPI backend, but the
backend moves accelerator buffers through host staging memory:

  1. device buffer -> host buffer
  2. MPI collective or point-to-point operation on host memory
  3. host buffer -> device buffer

This path is portable and useful as a bootstrap implementation, but the current
performance is limited by host staging overhead. The first experiment showed
that repeated host buffer allocation was a major avoidable cost for larger
messages.

Environment

  • Host: res-macloud-b01
  • Accelerator: 4 x MetaX C500 (XCORE1000, reported by macainfo)
  • MACA SDK: /opt/maca -> /opt/maca-3.7.0
  • mxcc: mxcc version 1.0.0 (d9102a1572)
  • OpenMPI: /opt/maca/ompi, mpirun (Open MPI) 4.1.6
  • CMake: 3.31.10
  • Backend/device configuration: WITH_METAX=ON, WITH_OMPI=ON

Manual build command used for reliable MetaX compilation:

export MACA_PATH=/opt/maca
export PATH="$MACA_PATH/ompi/bin:$PATH"
export LD_LIBRARY_PATH="$MACA_PATH/lib:$MACA_PATH/ompi/lib:$LD_LIBRARY_PATH"
export OMPI_CC="$PWD/scripts/devices/mxcc_wrapper.sh"
export OMPI_CXX="$PWD/scripts/devices/mxcc_wrapper.sh"

cmake -S . -B build-metax-fixed \
  -DCMAKE_BUILD_TYPE=Release \
  -DWITH_METAX=ON -DWITH_OMPI=ON \
  -DAUTO_DETECT_DEVICES=OFF -DAUTO_DETECT_BACKENDS=OFF \
  -DCMAKE_C_COMPILER="$MACA_PATH/ompi/bin/mpicc" \
  -DCMAKE_CXX_COMPILER="$MACA_PATH/ompi/bin/mpicxx"

cmake --build build-metax-fixed -j 8

Note: OpenMPI cannot initialize sockets inside the restricted sandbox used by
the agent, so runtime experiments were launched outside the sandbox.

Experiments

Correctness smoke tests

All internal examples passed on 2 ranks:

  • all_reduce
  • all_gather
  • all_to_all
  • broadcast
  • reduce
  • reduce_scatter
  • send_recv

Example command:

mpirun --allow-run-as-root -np 2 ./build-metax-fixed/examples/all_reduce

Observed all_reduce result:

Correct: YES
Expect:  3.00
Actual:  3.00

Microbenchmark

A new benchmark was added at examples/metax_bench.cc to compare:

  • copy_d2h: device-to-host copy
  • copy_h2d: host-to-device copy
  • copy_roundtrip: D2H + H2D
  • host_allreduce: host-only MPI_Allreduce
  • stage_reuse: manual D2H + MPI + H2D with reusable host buffers
  • stage_alloc: manual D2H + MPI + H2D with per-call malloc/free
  • infiniccl_allreduce: public InfiniCCL API path

Example command:

mpirun --allow-run-as-root -np 4 ./build-metax-fixed/examples/metax_bench \
  --elements 65536,262144,1048576,4194304 \
  --modes host_allreduce,stage_reuse,stage_alloc,infiniccl_allreduce \
  --warmup 5 --iters 20 --validate

Key Findings

Before host staging buffer reuse

infiniccl_allreduce was close to stage_alloc, which indicated that repeated
host buffer allocation was a major cost.

Case stage_reuse Original infiniccl_allreduce
2 ranks, 4 MB 3.36 ms 9.02 ms
2 ranks, 16 MB 12.78 ms 36.41 ms
4 ranks, 4 MB 4.89 ms 10.19 ms
4 ranks, 16 MB 17.57 ms 42.29 ms

After host staging buffer reuse

A reusable thread-local host staging buffer was added for the OpenMPI backend.
After the change, infiniccl_allreduce moved close to the stage_reuse
baseline.

Case Optimized infiniccl_allreduce
2 ranks, 4 MB 3.47 ms
2 ranks, 16 MB 12.74 ms
4 ranks, 4 MB 4.45 ms
4 ranks, 16 MB 16.69 ms

This is roughly a 2x-3x improvement for large AllReduce messages compared with
the original implementation.

Changes Made During Investigation

Build and documentation

  • Removed late mutation of CMAKE_C_COMPILER and CMAKE_CXX_COMPILER from the
    MetaX branch in top-level CMakeLists.txt.
  • Updated scripts/build.sh to detect MetaX and use MACA OpenMPI wrappers with
    OMPI_CC/OMPI_CXX pointing to scripts/devices/mxcc_wrapper.sh.
  • Made scripts/build.sh tolerate a read-only ~/.bashrc.
  • Documented the MetaX + OpenMPI manual build path in README.md.
  • Ignored build-* directories.

Runtime/backend

  • Added src/ompi/staging_buffer.h.
  • Replaced per-call host staging malloc/free in the OpenMPI backend with
    reusable thread-local staging buffers.
  • Applied the staging buffer reuse to:
    • AllReduce
    • AllGather
    • AllToAll
    • Broadcast
    • Reduce
    • ReduceScatter
    • Send
    • Recv
  • Added examples/metax_bench.cc for repeatable MetaX/OpenMPI experiments.

Remaining Issues

1. OpenMPI backend is still host-staging based

The current path still copies data through host memory. Buffer reuse removes a
large allocation overhead, but it does not remove the D2H/H2D copies.

Follow-up options:

  • Investigate MACA/MCCL backend support for native accelerator collectives.
  • Investigate whether MACA OpenMPI supports GPU-aware MPI for MetaX buffers.
  • Add an optional direct device-buffer MPI path if supported and safe.

2. Staging buffers are pageable host memory

The reusable buffers currently use std::malloc. Copy bandwidth may improve if
MACA provides pinned/page-locked host allocation APIs.

Follow-up options:

  • Check MACA runtime support for pinned host memory.
  • Add a staging allocator abstraction with normal malloc fallback.
  • Benchmark pageable vs pinned host staging.

3. ReduceScatter still needs separate analysis

Correctness passes, but reduce_scatter did not show the same clear timing
improvement as AllReduce in the example-level test. It should be investigated
separately with a benchmark mode that matches the exact ReduceScatter data
layout and counts.

Follow-up options:

  • Extend metax_bench with reduce_scatter modes.
  • Compare MPI_Reduce_scatter_block against alternative decompositions.
  • Check if count, buffer size, or MPI algorithm selection is dominating.

4. MPI errors abort the process

INFINI_CHECK_MPI currently aborts on MPI errors. This is harsh for a library
API that otherwise returns ReturnStatus.

Follow-up options:

  • Convert MPI error handling to return ReturnStatus.
  • Include MPI error strings in logs.
  • Keep abort behavior only under an explicit debug/fail-fast option.

5. Device binding is OpenMPI-specific

MetaX device selection currently relies on OMPI_COMM_WORLD_LOCAL_RANK.

Follow-up options:

  • Add fallbacks for common MPI/PMI local-rank environment variables.
  • Query MetaX device count and validate selected device IDs.
  • Consider modulo mapping or explicit devlist behavior for oversubscription.

6. Reusable staging buffer retention needs policy

The new thread-local staging buffers keep the largest capacity seen by each
thread. This is good for repeated collectives but can retain large host memory
after a single large operation.

Follow-up options:

  • Add an upper bound or shrink policy.
  • Add an environment variable for staging buffer cache size.
  • Add communicator-level or backend-level cleanup hooks if needed.

Proposed Next Steps

  1. Keep the reusable host staging buffer optimization; it gives a clear
    improvement with low API risk.
  2. Extend metax_bench to cover all_gather, all_to_all, broadcast,
    reduce, reduce_scatter, send, and recv.
  3. Add pinned host staging support if MACA exposes a suitable API.
  4. Investigate MCCL or GPU-aware MPI support as the higher-ceiling path.
  5. Harden error handling and device binding before larger multi-node testing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions