llvm-project/openmp/runtime/test/api/omp60_memory_routines.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

229 lines
7.5 KiB
C
Raw Normal View History

// RUN: %libomp-compile -Wl,--export-dynamic && %libomp-run
// REQUIRES: linux
// Test OpenMP 6.0 memory management routines.
// Test host runtime's basic support with an emulated offload runtime.
#include <stdlib.h>
#include <omp.h>
#define NUM_DEVICES 4
//
// Required offload runtime interfaces
//
extern int __tgt_get_num_devices(void) { return NUM_DEVICES; }
extern int __tgt_get_mem_resources(int num_devices, const int *devices,
int host, omp_memspace_handle_t memspace,
int *resources) {
int i;
// We expect valid inputs within this test.
int num_resources = num_devices;
if (resources) {
// Simple resouce ID mapping example in the backend (=device ID).
// This does not represent any real backend.
for (i = 0; i < num_devices; i++)
resources[i] = devices[i];
}
return num_resources;
}
extern void *__tgt_omp_alloc(size_t size, omp_allocator_handle_t allocator) {
return malloc(size);
}
extern void __tgt_omp_free(void *ptr, omp_allocator_handle_t allocator) {
free(ptr);
}
// Code above is also used by the corresponding Fortran test
#define CHECK_OR_RET_FAIL(Expr) \
do { \
if (!(Expr)) \
return EXIT_FAILURE; \
} while (0)
// Test user-initialized allocator with the given memory space
static int test_user_allocator(omp_memspace_handle_t ms) {
omp_allocator_handle_t al = omp_null_allocator;
al = omp_init_allocator(ms, 0, NULL);
CHECK_OR_RET_FAIL(al != omp_null_allocator);
void *m = omp_alloc(1024, al);
CHECK_OR_RET_FAIL(m != NULL);
omp_free(m, al);
omp_destroy_allocator(al);
return EXIT_SUCCESS;
}
static int test_allocator(omp_allocator_handle_t al) {
void *m = omp_alloc(1024, al);
CHECK_OR_RET_FAIL(m != NULL);
omp_free(m, al);
omp_destroy_allocator(al);
return EXIT_SUCCESS;
}
static int test_mem_space(void) {
int i, count;
int num_devices = omp_get_num_devices();
CHECK_OR_RET_FAIL(num_devices == NUM_DEVICES);
int *all_devices = (int *)malloc(sizeof(int) * num_devices);
for (i = 0; i < num_devices; i++)
all_devices[i] = i;
omp_memspace_handle_t predef = omp_default_mem_space;
omp_memspace_handle_t ms1 = omp_null_mem_space;
omp_memspace_handle_t ms2 = omp_null_mem_space;
// Test the following API routines.
// * omp_get_device_memspace
// * omp_get_device_and_host_memspace
// * omp_get_devices_memspace
// * omp_get_devices_and_host_memspace
// Test if runtime returns the same memory space handle for the same input.
// Test if we can use the memory space to intialize allocator.
for (i = 0; i < num_devices; i++) {
ms1 = omp_get_device_memspace(i, predef);
CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
ms2 = omp_get_device_memspace(i, predef);
CHECK_OR_RET_FAIL(ms1 == ms2);
CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
ms1 = ms2 = omp_null_mem_space;
ms1 = omp_get_device_and_host_memspace(i, predef);
CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
ms2 = omp_get_device_and_host_memspace(i, predef);
CHECK_OR_RET_FAIL(ms1 == ms2);
CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
ms1 = ms2 = omp_null_mem_space;
for (count = 1; i + count <= num_devices; count++) {
int *devices = &all_devices[i];
ms1 = omp_get_devices_memspace(count, devices, predef);
CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
ms2 = omp_get_devices_memspace(count, devices, predef);
CHECK_OR_RET_FAIL(ms1 == ms2);
CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
ms1 = ms2 = omp_null_mem_space;
ms1 = omp_get_devices_and_host_memspace(count, devices, predef);
CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
ms2 = omp_get_devices_and_host_memspace(count, devices, predef);
CHECK_OR_RET_FAIL(ms1 == ms2);
CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
ms1 = ms2 = omp_null_mem_space;
}
}
// Test the following API routines.
// * omp_get_devices_all_memspace
// Test if runtime returns the same memory space handle for the same input.
ms1 = omp_get_devices_all_memspace(predef);
CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
ms2 = omp_get_devices_all_memspace(predef);
CHECK_OR_RET_FAIL(ms1 == ms2);
free(all_devices);
return EXIT_SUCCESS;
}
static int test_mem_allocator(void) {
int i, count;
int num_devices = omp_get_num_devices();
CHECK_OR_RET_FAIL(num_devices == NUM_DEVICES);
int *all_devices = (int *)malloc(sizeof(int) * num_devices);
for (i = 0; i < num_devices; i++)
all_devices[i] = i;
omp_memspace_handle_t predef = omp_default_mem_space;
omp_allocator_handle_t al = omp_null_allocator;
// Test the following API routines.
// * omp_get_device_allocator
// * omp_get_device_and_host_allocator
// * omp_get_devices_allocator
// * omp_get_devices_and_host_allocator
for (i = 0; i < num_devices; i++) {
al = omp_get_device_allocator(i, predef);
CHECK_OR_RET_FAIL(al != omp_null_allocator);
CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
al = omp_null_allocator;
al = omp_get_device_and_host_allocator(i, predef);
CHECK_OR_RET_FAIL(al != omp_null_allocator);
CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
al = omp_null_allocator;
for (count = 1; i + count <= num_devices; count++) {
int *devices = &all_devices[i];
al = omp_get_devices_allocator(count, devices, predef);
CHECK_OR_RET_FAIL(al != omp_null_allocator);
CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
al = omp_null_allocator;
al = omp_get_devices_and_host_allocator(count, devices, predef);
CHECK_OR_RET_FAIL(al != omp_null_allocator);
CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
al = omp_null_allocator;
}
}
// Test the following API routines.
// * omp_get_devices_all_allocator
al = omp_get_devices_all_allocator(predef);
CHECK_OR_RET_FAIL(al != omp_null_allocator);
CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
free(all_devices);
return EXIT_SUCCESS;
}
// Just test what we can expect from the emulated backend.
static int test_sub_mem_space(void) {
int i;
omp_memspace_handle_t ms = omp_null_mem_space;
ms = omp_get_devices_all_memspace(omp_default_mem_space);
CHECK_OR_RET_FAIL(ms != omp_null_mem_space);
int num_resources = omp_get_memspace_num_resources(ms);
CHECK_OR_RET_FAIL(num_resources == NUM_DEVICES);
// Check if single-resource sub memspace is correctly returned.
for (i = 0; i < num_resources; i++) {
omp_memspace_handle_t sub = omp_get_submemspace(ms, 1, &i);
CHECK_OR_RET_FAIL(sub != omp_null_mem_space);
CHECK_OR_RET_FAIL(sub != ms);
int num_sub_resources = omp_get_memspace_num_resources(sub);
CHECK_OR_RET_FAIL(num_sub_resources == 1);
}
// Check if all-resrouce sub memspace is correctly returned.
int *resources = (int *)malloc(sizeof(int) * num_resources);
for (i = 0; i < num_resources; i++)
resources[i] = i;
omp_memspace_handle_t sub = omp_get_submemspace(ms, num_resources, resources);
CHECK_OR_RET_FAIL(sub != omp_null_mem_space);
CHECK_OR_RET_FAIL(sub == ms);
return EXIT_SUCCESS;
}
int main() {
int rc = test_mem_space();
CHECK_OR_RET_FAIL(rc == EXIT_SUCCESS);
rc = test_mem_allocator();
CHECK_OR_RET_FAIL(rc == EXIT_SUCCESS);
rc = test_sub_mem_space();
CHECK_OR_RET_FAIL(rc == EXIT_SUCCESS);
return rc;
}