Files
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

160 lines
6.1 KiB
C++

// Copyright (c) Advanced Micro Devices, Inc.
// SPDX-License-Identifier: MIT
/**
* Exercises all 9 rocSHMEM host-stream APIs in a minimal 2-PE program.
*
* Every PE calls every API so that rocprofiler-systems tracing captures all
* nine rocm_rocshmem_api spans:
*
* barrier_all_on_stream quiet_on_stream sync_all_on_stream
* putmem_on_stream getmem_on_stream
* putmem_signal_on_stream signal_wait_until_on_stream
* broadcastmem_on_stream alltoallmem_on_stream
*
* Launch with: mpirun -np 2 rocshmem
*/
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <hip/hip_runtime.h>
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
namespace
{
bool
check_hip(hipError_t err, const char* file, int line)
{
if(err == hipSuccess) return true;
fprintf(stderr, "[HIP error] %s:%d — %s\n", file, line, hipGetErrorString(err));
return false;
}
} // namespace
#define CHECK_HIP(cmd) \
do \
{ \
if(!check_hip((cmd), __FILE__, __LINE__)) return 1; \
} while(0)
int
main()
{
// Guard: verify at least one GPU is accessible before committing to
// rocshmem_init(). On systems where rocSHMEM is installed but the GPU
// does not support it, rocshmem_init() may call abort(); this early check
// provides a clean exit (code 2) that the test framework converts to a
// skip rather than a failure.
int num_devices = 0;
hipError_t hip_dev_err = hipGetDeviceCount(&num_devices);
if(hip_dev_err != hipSuccess || num_devices == 0)
{
fprintf(stderr, "rocshmem: no GPU available (%s) — skipping\n",
hipGetErrorString(hip_dev_err != hipSuccess ? hip_dev_err
: hipErrorNoDevice));
return 2;
}
// rocSHMEM requires hipSetDevice() to be called BEFORE rocshmem_init()
// so that the MPI PE is bound to its GPU before the symmetric heap is
// allocated on that device. Use OMPI_COMM_WORLD_LOCAL_RANK (set by
// Open MPI before any process code runs) to pick the right device.
const char* local_rank_env = getenv("OMPI_COMM_WORLD_LOCAL_RANK");
const int local_rank = local_rank_env ? atoi(local_rank_env) : 0;
CHECK_HIP(hipSetDevice(local_rank % num_devices));
rocshmem_init();
const int me = rocshmem_my_pe();
const int npes = rocshmem_n_pes();
const int peer = (me + 1) % npes;
hipStream_t stream = nullptr;
CHECK_HIP(hipStreamCreate(&stream));
// Symmetric buffers:
// src — DATA_BYTES bytes sent by this PE
// dst — npes * DATA_BYTES bytes for receives (alltoall needs npes slots)
// sig — one uint64_t signal word per PE
constexpr size_t DATA_BYTES = 64;
auto* src = static_cast<uint8_t*>(rocshmem_malloc(DATA_BYTES));
auto* dst = static_cast<uint8_t*>(rocshmem_malloc(npes * DATA_BYTES));
auto* sig = static_cast<uint64_t*>(rocshmem_malloc(sizeof(uint64_t)));
if(src == nullptr || dst == nullptr || sig == nullptr)
{
fprintf(stderr, "rocshmem: symmetric heap allocation failed\n");
return 1;
}
memset(src, me, DATA_BYTES);
memset(dst, 0, npes * DATA_BYTES);
*sig = 0;
// ------------------------------------------------------------------
// 1. barrier_all_on_stream — global fence before any transfers
rocshmem_barrier_all_on_stream(stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 2. sync_all_on_stream — lightweight global synchronisation
rocshmem_sync_all_on_stream(stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 3. putmem_on_stream — each PE writes DATA_BYTES into its peer's dst
rocshmem_putmem_on_stream(dst, src, DATA_BYTES, peer, stream);
rocshmem_barrier_all_on_stream(stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 4. getmem_on_stream — each PE reads DATA_BYTES from its peer's src
rocshmem_getmem_on_stream(dst, src, DATA_BYTES, peer, stream);
rocshmem_barrier_all_on_stream(stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 5. putmem_signal_on_stream — write data and set remote signal atomically.
// Each PE targets its peer: after the put the peer's sig word is 1.
// 6. signal_wait_until_on_stream — each PE waits for its own sig word to
// be set to 1 by its peer.
// The stream sync after step 5 guarantees the put (and its network
// transmission) is initiated before the wait is enqueued on the stream.
*sig = 0;
rocshmem_barrier_all_on_stream(stream);
CHECK_HIP(hipStreamSynchronize(stream));
rocshmem_putmem_signal_on_stream(dst, src, DATA_BYTES, sig, /*signal_value=*/1,
ROCSHMEM_SIGNAL_SET, peer, stream);
CHECK_HIP(hipStreamSynchronize(stream));
rocshmem_signal_wait_until_on_stream(sig, ROCSHMEM_CMP_EQ, /*cmp_value=*/1, stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 7. broadcastmem_on_stream — PE 0 broadcasts DATA_BYTES to all PEs
rocshmem_broadcastmem_on_stream(ROCSHMEM_TEAM_WORLD, dst, src, DATA_BYTES,
/*pe_root=*/0, stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 8. alltoallmem_on_stream — each PE contributes DATA_BYTES; dst must be
// at least npes * DATA_BYTES (allocated above)
rocshmem_alltoallmem_on_stream(ROCSHMEM_TEAM_WORLD, dst, src, DATA_BYTES, stream);
CHECK_HIP(hipStreamSynchronize(stream));
// 9. quiet_on_stream — ensure all outstanding remote operations are complete
rocshmem_quiet_on_stream(stream);
CHECK_HIP(hipStreamSynchronize(stream));
// ------------------------------------------------------------------
printf("[PE %d/%d] rocshmem: all 9 host-stream APIs completed\n", me, npes);
rocshmem_free(src);
rocshmem_free(dst);
rocshmem_free(sig);
CHECK_HIP(hipStreamDestroy(stream));
rocshmem_finalize();
return 0;
}