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 | // |
16 | extern int __tgt_get_num_devices(void) { return NUM_DEVICES; } |
17 | |
18 | extern 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 | |
33 | extern void *__tgt_omp_alloc(size_t size, omp_allocator_handle_t allocator) { |
34 | return malloc(size: size); |
35 | } |
36 | |
37 | extern 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 |
50 | static 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 | |
61 | static 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 | |
69 | static 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 | |
135 | static 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. |
189 | static 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 | |
217 | int 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 | |