]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgomp/oacc-async.c
Daily bump.
[thirdparty/gcc.git] / libgomp / oacc-async.c
1 /* OpenACC Runtime Library Definitions.
2
3 Copyright (C) 2013-2019 Free Software Foundation, Inc.
4
5 Contributed by Mentor Embedded.
6
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
9
10 Libgomp is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
14
15 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
23
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
28
29 #include <assert.h>
30 #include <string.h>
31 #include "openacc.h"
32 #include "libgomp.h"
33 #include "oacc-int.h"
34
35 static struct goacc_thread *
36 get_goacc_thread (void)
37 {
38 struct goacc_thread *thr = goacc_thread ();
39
40 if (!thr || !thr->dev)
41 gomp_fatal ("no device active");
42
43 return thr;
44 }
45
46 static int
47 validate_async_val (int async)
48 {
49 if (!async_valid_p (async))
50 gomp_fatal ("invalid async-argument: %d", async);
51
52 if (async == acc_async_sync)
53 return -1;
54
55 if (async == acc_async_noval)
56 return 0;
57
58 if (async >= 0)
59 /* TODO: we reserve 0 for acc_async_noval before we can clarify the
60 semantics of "default_async". */
61 return 1 + async;
62 else
63 __builtin_unreachable ();
64 }
65
66 /* Return the asyncqueue to be used for OpenACC async-argument ASYNC. This
67 might return NULL if no asyncqueue is to be used. Otherwise, if CREATE,
68 create the asyncqueue if it doesn't exist yet.
69
70 Unless CREATE, this will not generate any OpenACC Profiling Interface
71 events. */
72
73 attribute_hidden struct goacc_asyncqueue *
74 lookup_goacc_asyncqueue (struct goacc_thread *thr, bool create, int async)
75 {
76 async = validate_async_val (async);
77 if (async < 0)
78 return NULL;
79
80 struct goacc_asyncqueue *ret_aq = NULL;
81 struct gomp_device_descr *dev = thr->dev;
82
83 gomp_mutex_lock (&dev->openacc.async.lock);
84
85 if (!create
86 && (async >= dev->openacc.async.nasyncqueue
87 || !dev->openacc.async.asyncqueue[async]))
88 goto end;
89
90 if (async >= dev->openacc.async.nasyncqueue)
91 {
92 int diff = async + 1 - dev->openacc.async.nasyncqueue;
93 dev->openacc.async.asyncqueue
94 = gomp_realloc (dev->openacc.async.asyncqueue,
95 sizeof (goacc_aq) * (async + 1));
96 memset (dev->openacc.async.asyncqueue + dev->openacc.async.nasyncqueue,
97 0, sizeof (goacc_aq) * diff);
98 dev->openacc.async.nasyncqueue = async + 1;
99 }
100
101 if (!dev->openacc.async.asyncqueue[async])
102 {
103 dev->openacc.async.asyncqueue[async] = dev->openacc.async.construct_func ();
104
105 if (!dev->openacc.async.asyncqueue[async])
106 {
107 gomp_mutex_unlock (&dev->openacc.async.lock);
108 gomp_fatal ("async %d creation failed", async);
109 }
110
111 /* Link new async queue into active list. */
112 goacc_aq_list n = gomp_malloc (sizeof (struct goacc_asyncqueue_list));
113 n->aq = dev->openacc.async.asyncqueue[async];
114 n->next = dev->openacc.async.active;
115 dev->openacc.async.active = n;
116 }
117
118 ret_aq = dev->openacc.async.asyncqueue[async];
119
120 end:
121 gomp_mutex_unlock (&dev->openacc.async.lock);
122 return ret_aq;
123 }
124
125 /* Return the asyncqueue to be used for OpenACC async-argument ASYNC. This
126 might return NULL if no asyncqueue is to be used. Otherwise, create the
127 asyncqueue if it doesn't exist yet. */
128
129 attribute_hidden struct goacc_asyncqueue *
130 get_goacc_asyncqueue (int async)
131 {
132 struct goacc_thread *thr = get_goacc_thread ();
133 return lookup_goacc_asyncqueue (thr, true, async);
134 }
135
136 int
137 acc_async_test (int async)
138 {
139 struct goacc_thread *thr = goacc_thread ();
140
141 if (!thr || !thr->dev)
142 gomp_fatal ("no device active");
143
144 goacc_aq aq = lookup_goacc_asyncqueue (thr, false, async);
145 if (!aq)
146 return 1;
147
148 acc_prof_info prof_info;
149 acc_api_info api_info;
150 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
151 if (profiling_p)
152 {
153 prof_info.async = async;
154 prof_info.async_queue = prof_info.async;
155 }
156
157 int res = thr->dev->openacc.async.test_func (aq);
158
159 if (profiling_p)
160 {
161 thr->prof_info = NULL;
162 thr->api_info = NULL;
163 }
164
165 return res;
166 }
167
168 int
169 acc_async_test_all (void)
170 {
171 struct goacc_thread *thr = get_goacc_thread ();
172
173 acc_prof_info prof_info;
174 acc_api_info api_info;
175 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
176
177 int ret = 1;
178 gomp_mutex_lock (&thr->dev->openacc.async.lock);
179 for (goacc_aq_list l = thr->dev->openacc.async.active; l; l = l->next)
180 if (!thr->dev->openacc.async.test_func (l->aq))
181 {
182 ret = 0;
183 break;
184 }
185 gomp_mutex_unlock (&thr->dev->openacc.async.lock);
186
187 if (profiling_p)
188 {
189 thr->prof_info = NULL;
190 thr->api_info = NULL;
191 }
192
193 return ret;
194 }
195
196 void
197 acc_wait (int async)
198 {
199 struct goacc_thread *thr = get_goacc_thread ();
200
201 goacc_aq aq = lookup_goacc_asyncqueue (thr, false, async);
202 if (!aq)
203 return;
204
205 acc_prof_info prof_info;
206 acc_api_info api_info;
207 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
208 if (profiling_p)
209 {
210 prof_info.async = async;
211 prof_info.async_queue = prof_info.async;
212 }
213
214 if (!thr->dev->openacc.async.synchronize_func (aq))
215 gomp_fatal ("wait on %d failed", async);
216
217 if (profiling_p)
218 {
219 thr->prof_info = NULL;
220 thr->api_info = NULL;
221 }
222 }
223
224 /* acc_async_wait is an OpenACC 1.0 compatibility name for acc_wait. */
225 #ifdef HAVE_ATTRIBUTE_ALIAS
226 strong_alias (acc_wait, acc_async_wait)
227 #else
228 void
229 acc_async_wait (int async)
230 {
231 acc_wait (async);
232 }
233 #endif
234
235 void
236 acc_wait_async (int async1, int async2)
237 {
238 struct goacc_thread *thr = get_goacc_thread ();
239
240 goacc_aq aq1 = lookup_goacc_asyncqueue (thr, false, async1);
241 /* TODO: Is this also correct for acc_async_sync, assuming that in this case,
242 we'll always be synchronous anyways? */
243 if (!aq1)
244 return;
245
246 acc_prof_info prof_info;
247 acc_api_info api_info;
248 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
249 if (profiling_p)
250 {
251 prof_info.async = async2;
252 prof_info.async_queue = prof_info.async;
253 }
254
255 goacc_aq aq2 = lookup_goacc_asyncqueue (thr, true, async2);
256 /* An async queue is always synchronized with itself. */
257 if (aq1 == aq2)
258 goto out_prof;
259
260 if (aq2)
261 {
262 if (!thr->dev->openacc.async.serialize_func (aq1, aq2))
263 gomp_fatal ("ordering of async ids %d and %d failed", async1, async2);
264 }
265 else
266 {
267 /* TODO: Local thread synchronization.
268 Necessary for the "async2 == acc_async_sync" case, or can just skip? */
269 if (!thr->dev->openacc.async.synchronize_func (aq1))
270 gomp_fatal ("wait on %d failed", async1);
271 }
272
273 out_prof:
274 if (profiling_p)
275 {
276 thr->prof_info = NULL;
277 thr->api_info = NULL;
278 }
279 }
280
281 void
282 acc_wait_all (void)
283 {
284 struct goacc_thread *thr = goacc_thread ();
285
286 acc_prof_info prof_info;
287 acc_api_info api_info;
288 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
289
290 bool ret = true;
291 gomp_mutex_lock (&thr->dev->openacc.async.lock);
292 for (goacc_aq_list l = thr->dev->openacc.async.active; l; l = l->next)
293 ret &= thr->dev->openacc.async.synchronize_func (l->aq);
294 gomp_mutex_unlock (&thr->dev->openacc.async.lock);
295
296 if (profiling_p)
297 {
298 thr->prof_info = NULL;
299 thr->api_info = NULL;
300 }
301
302 if (!ret)
303 gomp_fatal ("wait all failed");
304 }
305
306 /* acc_async_wait_all is an OpenACC 1.0 compatibility name for acc_wait_all. */
307 #ifdef HAVE_ATTRIBUTE_ALIAS
308 strong_alias (acc_wait_all, acc_async_wait_all)
309 #else
310 void
311 acc_async_wait_all (void)
312 {
313 acc_wait_all ();
314 }
315 #endif
316
317 void
318 acc_wait_all_async (int async)
319 {
320 struct goacc_thread *thr = get_goacc_thread ();
321
322 acc_prof_info prof_info;
323 acc_api_info api_info;
324 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
325 if (profiling_p)
326 {
327 prof_info.async = async;
328 prof_info.async_queue = prof_info.async;
329 }
330
331 goacc_aq waiting_queue = lookup_goacc_asyncqueue (thr, true, async);
332
333 bool ret = true;
334 gomp_mutex_lock (&thr->dev->openacc.async.lock);
335 for (goacc_aq_list l = thr->dev->openacc.async.active; l; l = l->next)
336 {
337 if (waiting_queue)
338 ret &= thr->dev->openacc.async.serialize_func (l->aq, waiting_queue);
339 else
340 /* TODO: Local thread synchronization.
341 Necessary for the "async2 == acc_async_sync" case, or can just skip? */
342 ret &= thr->dev->openacc.async.synchronize_func (l->aq);
343 }
344 gomp_mutex_unlock (&thr->dev->openacc.async.lock);
345
346 if (profiling_p)
347 {
348 thr->prof_info = NULL;
349 thr->api_info = NULL;
350 }
351
352 if (!ret)
353 gomp_fatal ("wait all async(%d) failed", async);
354 }
355
356 attribute_hidden void
357 goacc_async_free (struct gomp_device_descr *devicep,
358 struct goacc_asyncqueue *aq, void *ptr)
359 {
360 if (!aq)
361 free (ptr);
362 else
363 devicep->openacc.async.queue_callback_func (aq, free, ptr);
364 }
365
366 /* This function initializes the asyncqueues for the device specified by
367 DEVICEP. TODO DEVICEP must be locked on entry, and remains locked on
368 return. */
369
370 attribute_hidden void
371 goacc_init_asyncqueues (struct gomp_device_descr *devicep)
372 {
373 devicep->openacc.async.nasyncqueue = 0;
374 devicep->openacc.async.asyncqueue = NULL;
375 devicep->openacc.async.active = NULL;
376 gomp_mutex_init (&devicep->openacc.async.lock);
377 }
378
379 /* This function finalizes the asyncqueues for the device specified by DEVICEP.
380 TODO DEVICEP must be locked on entry, and remains locked on return. */
381
382 attribute_hidden bool
383 goacc_fini_asyncqueues (struct gomp_device_descr *devicep)
384 {
385 bool ret = true;
386 gomp_mutex_lock (&devicep->openacc.async.lock);
387 if (devicep->openacc.async.nasyncqueue > 0)
388 {
389 goacc_aq_list next;
390 for (goacc_aq_list l = devicep->openacc.async.active; l; l = next)
391 {
392 ret &= devicep->openacc.async.destruct_func (l->aq);
393 next = l->next;
394 free (l);
395 }
396 free (devicep->openacc.async.asyncqueue);
397 devicep->openacc.async.nasyncqueue = 0;
398 devicep->openacc.async.asyncqueue = NULL;
399 devicep->openacc.async.active = NULL;
400 }
401 gomp_mutex_unlock (&devicep->openacc.async.lock);
402 gomp_mutex_destroy (&devicep->openacc.async.lock);
403 return ret;
404 }