1 /* OpenACC Runtime Library Definitions.
3 Copyright (C) 2013-2019 Free Software Foundation, Inc.
5 Contributed by Mentor Embedded.
7 This file is part of the GNU Offloading and Multi Processing Library
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)
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
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.
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/>. */
35 static struct goacc_thread
*
36 get_goacc_thread (void)
38 struct goacc_thread
*thr
= goacc_thread ();
40 if (!thr
|| !thr
->dev
)
41 gomp_fatal ("no device active");
47 validate_async_val (int async
)
49 if (!async_valid_p (async
))
50 gomp_fatal ("invalid async-argument: %d", async
);
52 if (async
== acc_async_sync
)
55 if (async
== acc_async_noval
)
59 /* TODO: we reserve 0 for acc_async_noval before we can clarify the
60 semantics of "default_async". */
63 __builtin_unreachable ();
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.
70 Unless CREATE, this will not generate any OpenACC Profiling Interface
73 attribute_hidden
struct goacc_asyncqueue
*
74 lookup_goacc_asyncqueue (struct goacc_thread
*thr
, bool create
, int async
)
76 async
= validate_async_val (async
);
80 struct goacc_asyncqueue
*ret_aq
= NULL
;
81 struct gomp_device_descr
*dev
= thr
->dev
;
83 gomp_mutex_lock (&dev
->openacc
.async
.lock
);
86 && (async
>= dev
->openacc
.async
.nasyncqueue
87 || !dev
->openacc
.async
.asyncqueue
[async
]))
90 if (async
>= dev
->openacc
.async
.nasyncqueue
)
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;
101 if (!dev
->openacc
.async
.asyncqueue
[async
])
103 dev
->openacc
.async
.asyncqueue
[async
] = dev
->openacc
.async
.construct_func ();
105 if (!dev
->openacc
.async
.asyncqueue
[async
])
107 gomp_mutex_unlock (&dev
->openacc
.async
.lock
);
108 gomp_fatal ("async %d creation failed", async
);
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
;
118 ret_aq
= dev
->openacc
.async
.asyncqueue
[async
];
121 gomp_mutex_unlock (&dev
->openacc
.async
.lock
);
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. */
129 attribute_hidden
struct goacc_asyncqueue
*
130 get_goacc_asyncqueue (int async
)
132 struct goacc_thread
*thr
= get_goacc_thread ();
133 return lookup_goacc_asyncqueue (thr
, true, async
);
137 acc_async_test (int async
)
139 struct goacc_thread
*thr
= goacc_thread ();
141 if (!thr
|| !thr
->dev
)
142 gomp_fatal ("no device active");
144 goacc_aq aq
= lookup_goacc_asyncqueue (thr
, false, async
);
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
);
153 prof_info
.async
= async
;
154 prof_info
.async_queue
= prof_info
.async
;
157 int res
= thr
->dev
->openacc
.async
.test_func (aq
);
161 thr
->prof_info
= NULL
;
162 thr
->api_info
= NULL
;
169 acc_async_test_all (void)
171 struct goacc_thread
*thr
= get_goacc_thread ();
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
);
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
))
185 gomp_mutex_unlock (&thr
->dev
->openacc
.async
.lock
);
189 thr
->prof_info
= NULL
;
190 thr
->api_info
= NULL
;
199 struct goacc_thread
*thr
= get_goacc_thread ();
201 goacc_aq aq
= lookup_goacc_asyncqueue (thr
, false, async
);
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
);
210 prof_info
.async
= async
;
211 prof_info
.async_queue
= prof_info
.async
;
214 if (!thr
->dev
->openacc
.async
.synchronize_func (aq
))
215 gomp_fatal ("wait on %d failed", async
);
219 thr
->prof_info
= NULL
;
220 thr
->api_info
= NULL
;
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
)
229 acc_async_wait (int async
)
236 acc_wait_async (int async1
, int async2
)
238 struct goacc_thread
*thr
= get_goacc_thread ();
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? */
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
);
251 prof_info
.async
= async2
;
252 prof_info
.async_queue
= prof_info
.async
;
255 goacc_aq aq2
= lookup_goacc_asyncqueue (thr
, true, async2
);
256 /* An async queue is always synchronized with itself. */
262 if (!thr
->dev
->openacc
.async
.serialize_func (aq1
, aq2
))
263 gomp_fatal ("ordering of async ids %d and %d failed", async1
, async2
);
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
);
276 thr
->prof_info
= NULL
;
277 thr
->api_info
= NULL
;
284 struct goacc_thread
*thr
= goacc_thread ();
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
);
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
);
298 thr
->prof_info
= NULL
;
299 thr
->api_info
= NULL
;
303 gomp_fatal ("wait all failed");
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
)
311 acc_async_wait_all (void)
318 acc_wait_all_async (int async
)
320 struct goacc_thread
*thr
= get_goacc_thread ();
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
);
327 prof_info
.async
= async
;
328 prof_info
.async_queue
= prof_info
.async
;
331 goacc_aq waiting_queue
= lookup_goacc_asyncqueue (thr
, true, async
);
334 gomp_mutex_lock (&thr
->dev
->openacc
.async
.lock
);
335 for (goacc_aq_list l
= thr
->dev
->openacc
.async
.active
; l
; l
= l
->next
)
338 ret
&= thr
->dev
->openacc
.async
.serialize_func (l
->aq
, waiting_queue
);
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
);
344 gomp_mutex_unlock (&thr
->dev
->openacc
.async
.lock
);
348 thr
->prof_info
= NULL
;
349 thr
->api_info
= NULL
;
353 gomp_fatal ("wait all async(%d) failed", async
);
356 attribute_hidden
void
357 goacc_async_free (struct gomp_device_descr
*devicep
,
358 struct goacc_asyncqueue
*aq
, void *ptr
)
363 devicep
->openacc
.async
.queue_callback_func (aq
, free
, ptr
);
366 /* This function initializes the asyncqueues for the device specified by
367 DEVICEP. TODO DEVICEP must be locked on entry, and remains locked on
370 attribute_hidden
void
371 goacc_init_asyncqueues (struct gomp_device_descr
*devicep
)
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
);
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. */
382 attribute_hidden
bool
383 goacc_fini_asyncqueues (struct gomp_device_descr
*devicep
)
386 gomp_mutex_lock (&devicep
->openacc
.async
.lock
);
387 if (devicep
->openacc
.async
.nasyncqueue
> 0)
390 for (goacc_aq_list l
= devicep
->openacc
.async
.active
; l
; l
= next
)
392 ret
&= devicep
->openacc
.async
.destruct_func (l
->aq
);
396 free (devicep
->openacc
.async
.asyncqueue
);
397 devicep
->openacc
.async
.nasyncqueue
= 0;
398 devicep
->openacc
.async
.asyncqueue
= NULL
;
399 devicep
->openacc
.async
.active
= NULL
;
401 gomp_mutex_unlock (&devicep
->openacc
.async
.lock
);
402 gomp_mutex_destroy (&devicep
->openacc
.async
.lock
);