1// RUN: %libomp-compile -Wl,--export-dynamic && %libomp-run
2
3// REQUIRES: linux
4
5// Test OpenMP 6.0 memory management routines.
6// Test host runtime's basic support with an emulated offload runtime.
7
8#include <stdlib.h>
9#include <omp.h>
10
11#define NUM_DEVICES 4
12
13//
14// Required offload runtime interfaces
15//
16extern int __tgt_get_num_devices(void) { return NUM_DEVICES; }
17
18extern int __tgt_get_mem_resources(int num_devices, const int *devices,
19 int host, omp_memspace_handle_t memspace,
20 int *resources) {
21 int i;
22 // We expect valid inputs within this test.
23 int num_resources = num_devices;
24 if (resources) {
25 // Simple resouce ID mapping example in the backend (=device ID).
26 // This does not represent any real backend.
27 for (i = 0; i < num_devices; i++)
28 resources[i] = devices[i];
29 }
30 return num_resources;
31}
32
33extern void *__tgt_omp_alloc(size_t size, omp_allocator_handle_t allocator) {
34 return malloc(size: size);
35}
36
37extern void __tgt_omp_free(void *ptr, omp_allocator_handle_t allocator) {
38 free(ptr: ptr);
39}
40
41// Code above is also used by the corresponding Fortran test
42
43#define CHECK_OR_RET_FAIL(Expr) \
44 do { \
45 if (!(Expr)) \
46 return EXIT_FAILURE; \
47 } while (0)
48
49// Test user-initialized allocator with the given memory space
50static int test_user_allocator(omp_memspace_handle_t ms) {
51 omp_allocator_handle_t al = omp_null_allocator;
52 al = omp_init_allocator(ms, 0, NULL);
53 CHECK_OR_RET_FAIL(al != omp_null_allocator);
54 void *m = omp_alloc(1024, al);
55 CHECK_OR_RET_FAIL(m != NULL);
56 omp_free(m, al);
57 omp_destroy_allocator(al);
58 return EXIT_SUCCESS;
59}
60
61static int test_allocator(omp_allocator_handle_t al) {
62 void *m = omp_alloc(1024, al);
63 CHECK_OR_RET_FAIL(m != NULL);
64 omp_free(m, al);
65 omp_destroy_allocator(al);
66 return EXIT_SUCCESS;
67}
68
69static int test_mem_space(void) {
70 int i, count;
71 int num_devices = omp_get_num_devices();
72 CHECK_OR_RET_FAIL(num_devices == NUM_DEVICES);
73
74 int *all_devices = (int *)malloc(size: sizeof(int) * num_devices);
75 for (i = 0; i < num_devices; i++)
76 all_devices[i] = i;
77
78 omp_memspace_handle_t predef = omp_default_mem_space;
79 omp_memspace_handle_t ms1 = omp_null_mem_space;
80 omp_memspace_handle_t ms2 = omp_null_mem_space;
81
82 // Test the following API routines.
83 // * omp_get_device_memspace
84 // * omp_get_device_and_host_memspace
85 // * omp_get_devices_memspace
86 // * omp_get_devices_and_host_memspace
87 // Test if runtime returns the same memory space handle for the same input.
88 // Test if we can use the memory space to intialize allocator.
89 for (i = 0; i < num_devices; i++) {
90 ms1 = omp_get_device_memspace(i, predef);
91 CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
92 ms2 = omp_get_device_memspace(i, predef);
93 CHECK_OR_RET_FAIL(ms1 == ms2);
94 CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
95 ms1 = ms2 = omp_null_mem_space;
96
97 ms1 = omp_get_device_and_host_memspace(i, predef);
98 CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
99 ms2 = omp_get_device_and_host_memspace(i, predef);
100 CHECK_OR_RET_FAIL(ms1 == ms2);
101 CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
102 ms1 = ms2 = omp_null_mem_space;
103
104 for (count = 1; i + count <= num_devices; count++) {
105 int *devices = &all_devices[i];
106 ms1 = omp_get_devices_memspace(count, devices, predef);
107 CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
108 ms2 = omp_get_devices_memspace(count, devices, predef);
109 CHECK_OR_RET_FAIL(ms1 == ms2);
110 CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
111 ms1 = ms2 = omp_null_mem_space;
112
113 ms1 = omp_get_devices_and_host_memspace(count, devices, predef);
114 CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
115 ms2 = omp_get_devices_and_host_memspace(count, devices, predef);
116 CHECK_OR_RET_FAIL(ms1 == ms2);
117 CHECK_OR_RET_FAIL(test_user_allocator(ms1) == EXIT_SUCCESS);
118 ms1 = ms2 = omp_null_mem_space;
119 }
120 }
121
122 // Test the following API routines.
123 // * omp_get_devices_all_memspace
124 // Test if runtime returns the same memory space handle for the same input.
125 ms1 = omp_get_devices_all_memspace(predef);
126 CHECK_OR_RET_FAIL(ms1 != omp_null_mem_space);
127 ms2 = omp_get_devices_all_memspace(predef);
128 CHECK_OR_RET_FAIL(ms1 == ms2);
129
130 free(ptr: all_devices);
131
132 return EXIT_SUCCESS;
133}
134
135static int test_mem_allocator(void) {
136 int i, count;
137 int num_devices = omp_get_num_devices();
138 CHECK_OR_RET_FAIL(num_devices == NUM_DEVICES);
139
140 int *all_devices = (int *)malloc(size: sizeof(int) * num_devices);
141 for (i = 0; i < num_devices; i++)
142 all_devices[i] = i;
143
144 omp_memspace_handle_t predef = omp_default_mem_space;
145 omp_allocator_handle_t al = omp_null_allocator;
146
147 // Test the following API routines.
148 // * omp_get_device_allocator
149 // * omp_get_device_and_host_allocator
150 // * omp_get_devices_allocator
151 // * omp_get_devices_and_host_allocator
152 for (i = 0; i < num_devices; i++) {
153 al = omp_get_device_allocator(i, predef);
154 CHECK_OR_RET_FAIL(al != omp_null_allocator);
155 CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
156 al = omp_null_allocator;
157
158 al = omp_get_device_and_host_allocator(i, predef);
159 CHECK_OR_RET_FAIL(al != omp_null_allocator);
160 CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
161 al = omp_null_allocator;
162
163 for (count = 1; i + count <= num_devices; count++) {
164 int *devices = &all_devices[i];
165 al = omp_get_devices_allocator(count, devices, predef);
166 CHECK_OR_RET_FAIL(al != omp_null_allocator);
167 CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
168 al = omp_null_allocator;
169
170 al = omp_get_devices_and_host_allocator(count, devices, predef);
171 CHECK_OR_RET_FAIL(al != omp_null_allocator);
172 CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
173 al = omp_null_allocator;
174 }
175 }
176
177 // Test the following API routines.
178 // * omp_get_devices_all_allocator
179 al = omp_get_devices_all_allocator(predef);
180 CHECK_OR_RET_FAIL(al != omp_null_allocator);
181 CHECK_OR_RET_FAIL(test_allocator(al) == EXIT_SUCCESS);
182
183 free(ptr: all_devices);
184
185 return EXIT_SUCCESS;
186}
187
188// Just test what we can expect from the emulated backend.
189static int test_sub_mem_space(void) {
190 int i;
191 omp_memspace_handle_t ms = omp_null_mem_space;
192 ms = omp_get_devices_all_memspace(omp_default_mem_space);
193 CHECK_OR_RET_FAIL(ms != omp_null_mem_space);
194 int num_resources = omp_get_memspace_num_resources(ms);
195 CHECK_OR_RET_FAIL(num_resources == NUM_DEVICES);
196
197 // Check if single-resource sub memspace is correctly returned.
198 for (i = 0; i < num_resources; i++) {
199 omp_memspace_handle_t sub = omp_get_submemspace(ms, 1, &i);
200 CHECK_OR_RET_FAIL(sub != omp_null_mem_space);
201 CHECK_OR_RET_FAIL(sub != ms);
202 int num_sub_resources = omp_get_memspace_num_resources(sub);
203 CHECK_OR_RET_FAIL(num_sub_resources == 1);
204 }
205
206 // Check if all-resrouce sub memspace is correctly returned.
207 int *resources = (int *)malloc(size: sizeof(int) * num_resources);
208 for (i = 0; i < num_resources; i++)
209 resources[i] = i;
210 omp_memspace_handle_t sub = omp_get_submemspace(ms, num_resources, resources);
211 CHECK_OR_RET_FAIL(sub != omp_null_mem_space);
212 CHECK_OR_RET_FAIL(sub == ms);
213
214 return EXIT_SUCCESS;
215}
216
217int main() {
218 int rc = test_mem_space();
219 CHECK_OR_RET_FAIL(rc == EXIT_SUCCESS);
220
221 rc = test_mem_allocator();
222 CHECK_OR_RET_FAIL(rc == EXIT_SUCCESS);
223
224 rc = test_sub_mem_space();
225 CHECK_OR_RET_FAIL(rc == EXIT_SUCCESS);
226
227 return rc;
228}
229

source code of openmp/runtime/test/api/omp60_memory_routines.c