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

231 lines
7.1 KiB
C++

/*
* Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
*
* SPDX-License-Identifier: MIT
*/
#include <hip_test_common.hh>
#include <hip_test_process.hh>
/**
* @addtogroup hipIpcOpenMemHandle hipIpcOpenMemHandle
* @{
* @ingroup DeviceTest
* `hipIpcOpenMemHandle(void** devPtr, hipIpcMemHandle_t handle, unsigned int flags)` -
* Opens an interprocess memory handle exported from another process
* and returns a device pointer usable in the local process.
*/
/**
* Test Description
* ------------------------
* - Handle the attempt to open memory handle in the same process
* that has created it.
* -# When the process is the same
* - Expected output: return `hipErrorInvalidContext`
* Test source
* ------------------------
* - unit/device/hipIpcOpenMemHandle.cc
* Test requirements
* ------------------------
* - Host specific (LINUX)
* - HIP_VERSION >= 5.2
*/
HIP_TEST_CASE(Unit_hipIpcOpenMemHandle_Negative_Open_In_Creating_Process) {
hipDeviceptr_t ptr1, ptr2;
hipIpcMemHandle_t handle;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&ptr1), 1024));
HIP_CHECK(hipIpcGetMemHandle(&handle, reinterpret_cast<void*>(ptr1)));
HIP_CHECK_ERROR(
hipIpcOpenMemHandle(reinterpret_cast<void**>(&ptr2), handle, hipIpcMemLazyEnablePeerAccess),
hipErrorInvalidContext);
HIP_CHECK(hipFree(reinterpret_cast<void*>(ptr1)));
}
#if HT_LINUX
/**
* Test Description
* ------------------------
* - Checks that opening the same memory handle from a different context
* returns error
* -# When different context
* - Expected output: return `hipErrorInvalidResourceHandle`
* Test source
* ------------------------
* - unit/device/hipIpcOpenMemHandle.cc
* Test requirements
* ------------------------
* - Host specific (LINUX)
* - HIP_VERSION >= 5.2
*/
HIP_TEST_CASE(Unit_hipIpcOpenMemHandle_Negative_Open_In_Two_Contexts_Same_Device) {
int fd[2];
REQUIRE(pipe(fd) == 0);
// The fork must be performed before the runtime is initialized(so before any API that implicitly
// initializes it). The pipe in conjunction with wait is then used to impose total ordering
// between parent and child process. Because total ordering is imposed regular CATCH assertions
// should be safe to use
auto pid = fork();
REQUIRE(pid >= 0);
if (pid == 0) { // child
REQUIRE(close(fd[1]) == 0);
hipIpcMemHandle_t handle;
REQUIRE(read(fd[0], &handle, sizeof(handle)) >= 0);
REQUIRE(close(fd[0]) == 0);
hipDeviceptr_t ptr_child;
HIP_CHECK(hipIpcOpenMemHandle(reinterpret_cast<void**>(&ptr_child), handle,
hipIpcMemLazyEnablePeerAccess));
HIP_CHECK(hipInit(0));
hipCtx_t ctx;
HIP_CHECK(hipCtxCreate(&ctx, 0, 0));
hipDeviceptr_t ptr_child_ctx;
HIP_CHECK_ERROR(hipIpcOpenMemHandle(reinterpret_cast<void**>(&ptr_child_ctx), handle,
hipIpcMemLazyEnablePeerAccess),
hipErrorInvalidResourceHandle);
exit(0);
} else { // parent
REQUIRE(close(fd[0]) == 0);
hipDeviceptr_t ptr;
hipIpcMemHandle_t handle;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&ptr), 1024));
HIP_CHECK(hipIpcGetMemHandle(&handle, reinterpret_cast<void*>(ptr)));
REQUIRE(write(fd[1], &handle, sizeof(handle)) >= 0);
REQUIRE(close(fd[1]) == 0);
REQUIRE(wait(NULL) >= 0);
HIP_CHECK(hipFree(reinterpret_cast<void*>(ptr)));
}
}
#endif
constexpr int DATA_SIZE = 1024 * 1024;
constexpr size_t BYTE_SIZE = DATA_SIZE * sizeof(int);
constexpr int THREADS_PER_BLOCK = 512;
static __global__ void square_kernel(int* buf) {
int i = threadIdx.x + blockDim.x * blockIdx.x;
buf[i] = buf[i] * buf[i];
}
static std::string ipcHandleToHex(const hipIpcMemHandle_t& handle) {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (size_t i = 0; i < sizeof(handle.reserved); i++) {
oss << std::setw(2)
<< static_cast<unsigned>(static_cast<unsigned char>(handle.reserved[i]));
}
return oss.str();
}
static hipIpcMemHandle_t hexToIpcHandle(const std::string& hex_str) {
hipIpcMemHandle_t handle = {};
std::stringstream hex_ss(hex_str);
for (size_t i = 0; i < sizeof(handle.reserved); i++) {
std::string byte_str(2, '\0');
if (!hex_ss.read(&byte_str[0], 2)) break;
unsigned int byte_val = 0;
std::stringstream byte_ss;
byte_ss << std::hex << byte_str;
byte_ss >> byte_val;
handle.reserved[i] = static_cast<char>(static_cast<unsigned char>(byte_val));
}
return handle;
}
/**
* Test Description
* ------------------------
* - Parent process: allocates device memory, fills with i%1024,
* exports the IPC handle via environment variable, spawns a child
* process that squares the data through the shared handle, then
* validates the result.
* Test source
* ------------------------
* - unit/device/hipIpcOpenMemHandle.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 5.2
*/
HIP_TEST_CASE(Unit_hipIpcOpenMemHandle_Multiproc) {
int* d_buf;
HIP_CHECK(hipMalloc(&d_buf, BYTE_SIZE));
std::vector<int> h_buf(DATA_SIZE);
for (int i = 0; i < DATA_SIZE; i++) {
h_buf[i] = i % 1024;
}
HIP_CHECK(hipMemcpy(d_buf, h_buf.data(), BYTE_SIZE, hipMemcpyHostToDevice));
hipIpcMemHandle_t handle;
HIP_CHECK(hipIpcGetMemHandle(&handle, d_buf));
std::string hex = ipcHandleToHex(handle);
hip::SpawnProc child(getSelfExePath());
child.setEnv("HIP_IPC_HANDLE", hex);
REQUIRE(child.spawn("Unit_hipIpcOpenMemHandle_Multiproc_Child") == 0);
REQUIRE(child.wait() == 0);
HIP_CHECK(hipMemcpy(h_buf.data(), d_buf, BYTE_SIZE, hipMemcpyDeviceToHost));
for (int i = 0; i < DATA_SIZE; i++) {
int expected = (i % 1024) * (i % 1024);
REQUIRE(h_buf[i] == expected);
}
HIP_CHECK(hipFree(d_buf));
}
/**
* Test Description
* ------------------------
* - Child process: reads the IPC handle from the HIP_IPC_HANDLE
* environment variable, opens the shared device memory, squares
* each element via a kernel, validates the result, then closes
* the handle. Skipped when not launched by the parent test.
* Test source
* ------------------------
* - unit/device/hipIpcOpenMemHandle.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 5.2
*/
HIP_TEST_CASE(Unit_hipIpcOpenMemHandle_Multiproc_Child) {
const char* hex = std::getenv("HIP_IPC_HANDLE");
if (hex == nullptr || hex[0] == '\0') {
HIP_SKIP_TEST("This test must be launched by parent multiprocess test.");
}
hipIpcMemHandle_t handle = hexToIpcHandle(hex);
void* devPtr = nullptr;
HIP_CHECK(hipIpcOpenMemHandle(&devPtr, handle, hipIpcMemLazyEnablePeerAccess));
square_kernel<<<dim3(DATA_SIZE / THREADS_PER_BLOCK), dim3(THREADS_PER_BLOCK)>>>(
reinterpret_cast<int*>(devPtr));
HIP_CHECK(hipDeviceSynchronize());
std::vector<int> result(DATA_SIZE);
HIP_CHECK(hipMemcpy(result.data(), devPtr, BYTE_SIZE, hipMemcpyDeviceToHost));
for (int i = 0; i < DATA_SIZE; i++) {
int expected = (i % 1024) * (i % 1024);
REQUIRE(result[i] == expected);
}
HIP_CHECK(hipIpcCloseMemHandle(devPtr));
}
/**
* End doxygen group DeviceTest.
* @}
*/