oacc-init.c revision 1.1.1.2.4.2 1 1.1 mrg /* OpenACC Runtime initialization routines
2 1.1 mrg
3 1.1.1.2.4.1 christos Copyright (C) 2013-2017 Free Software Foundation, Inc.
4 1.1 mrg
5 1.1 mrg Contributed by Mentor Embedded.
6 1.1 mrg
7 1.1 mrg This file is part of the GNU Offloading and Multi Processing Library
8 1.1 mrg (libgomp).
9 1.1 mrg
10 1.1 mrg Libgomp is free software; you can redistribute it and/or modify it
11 1.1 mrg under the terms of the GNU General Public License as published by
12 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
13 1.1 mrg any later version.
14 1.1 mrg
15 1.1 mrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 1.1 mrg more details.
19 1.1 mrg
20 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
21 1.1 mrg permissions described in the GCC Runtime Library Exception, version
22 1.1 mrg 3.1, as published by the Free Software Foundation.
23 1.1 mrg
24 1.1 mrg You should have received a copy of the GNU General Public License and
25 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
26 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 1.1 mrg <http://www.gnu.org/licenses/>. */
28 1.1 mrg
29 1.1 mrg #include "libgomp.h"
30 1.1 mrg #include "oacc-int.h"
31 1.1 mrg #include "openacc.h"
32 1.1 mrg #include <assert.h>
33 1.1 mrg #include <stdlib.h>
34 1.1 mrg #include <strings.h>
35 1.1 mrg #include <stdbool.h>
36 1.1 mrg #include <string.h>
37 1.1 mrg
38 1.1.1.2 mrg /* This lock is used to protect access to cached_base_dev, dispatchers and
39 1.1.1.2 mrg the (abstract) initialisation state of attached offloading devices. */
40 1.1.1.2 mrg
41 1.1 mrg static gomp_mutex_t acc_device_lock;
42 1.1 mrg
43 1.1 mrg /* A cached version of the dispatcher for the global "current" accelerator type,
44 1.1 mrg e.g. used as the default when creating new host threads. This is the
45 1.1 mrg device-type equivalent of goacc_device_num (which specifies which device to
46 1.1 mrg use out of potentially several of the same type). If there are several
47 1.1 mrg devices of a given type, this points at the first one. */
48 1.1 mrg
49 1.1 mrg static struct gomp_device_descr *cached_base_dev = NULL;
50 1.1 mrg
51 1.1 mrg #if defined HAVE_TLS || defined USE_EMUTLS
52 1.1 mrg __thread struct goacc_thread *goacc_tls_data;
53 1.1 mrg #else
54 1.1 mrg pthread_key_t goacc_tls_key;
55 1.1 mrg #endif
56 1.1 mrg static pthread_key_t goacc_cleanup_key;
57 1.1 mrg
58 1.1 mrg static struct goacc_thread *goacc_threads;
59 1.1 mrg static gomp_mutex_t goacc_thread_lock;
60 1.1 mrg
61 1.1 mrg /* An array of dispatchers for device types, indexed by the type. This array
62 1.1 mrg only references "base" devices, and other instances of the same type are
63 1.1 mrg found by simply indexing from each such device (which are stored linearly,
64 1.1 mrg grouped by device in target.c:devices). */
65 1.1 mrg static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
66 1.1 mrg
67 1.1 mrg attribute_hidden void
68 1.1 mrg goacc_register (struct gomp_device_descr *disp)
69 1.1 mrg {
70 1.1 mrg /* Only register the 0th device here. */
71 1.1 mrg if (disp->target_id != 0)
72 1.1 mrg return;
73 1.1 mrg
74 1.1 mrg gomp_mutex_lock (&acc_device_lock);
75 1.1 mrg
76 1.1 mrg assert (acc_device_type (disp->type) != acc_device_none
77 1.1 mrg && acc_device_type (disp->type) != acc_device_default
78 1.1 mrg && acc_device_type (disp->type) != acc_device_not_host);
79 1.1 mrg assert (!dispatchers[disp->type]);
80 1.1 mrg dispatchers[disp->type] = disp;
81 1.1 mrg
82 1.1 mrg gomp_mutex_unlock (&acc_device_lock);
83 1.1 mrg }
84 1.1 mrg
85 1.1 mrg /* OpenACC names some things a little differently. */
86 1.1 mrg
87 1.1 mrg static const char *
88 1.1 mrg get_openacc_name (const char *name)
89 1.1 mrg {
90 1.1 mrg if (strcmp (name, "nvptx") == 0)
91 1.1 mrg return "nvidia";
92 1.1 mrg else
93 1.1 mrg return name;
94 1.1 mrg }
95 1.1 mrg
96 1.1 mrg static const char *
97 1.1 mrg name_of_acc_device_t (enum acc_device_t type)
98 1.1 mrg {
99 1.1 mrg switch (type)
100 1.1 mrg {
101 1.1 mrg case acc_device_none: return "none";
102 1.1 mrg case acc_device_default: return "default";
103 1.1 mrg case acc_device_host: return "host";
104 1.1 mrg case acc_device_not_host: return "not_host";
105 1.1 mrg case acc_device_nvidia: return "nvidia";
106 1.1 mrg default: gomp_fatal ("unknown device type %u", (unsigned) type);
107 1.1 mrg }
108 1.1 mrg }
109 1.1 mrg
110 1.1.1.2 mrg /* ACC_DEVICE_LOCK must be held before calling this function. If FAIL_IS_ERROR
111 1.1.1.2 mrg is true, this function raises an error if there are no devices of type D,
112 1.1.1.2 mrg otherwise it returns NULL in that case. */
113 1.1.1.2 mrg
114 1.1 mrg static struct gomp_device_descr *
115 1.1.1.2 mrg resolve_device (acc_device_t d, bool fail_is_error)
116 1.1 mrg {
117 1.1 mrg acc_device_t d_arg = d;
118 1.1 mrg
119 1.1 mrg switch (d)
120 1.1 mrg {
121 1.1 mrg case acc_device_default:
122 1.1 mrg {
123 1.1 mrg if (goacc_device_type)
124 1.1 mrg {
125 1.1 mrg /* Lookup the named device. */
126 1.1 mrg while (++d != _ACC_device_hwm)
127 1.1 mrg if (dispatchers[d]
128 1.1 mrg && !strcasecmp (goacc_device_type,
129 1.1 mrg get_openacc_name (dispatchers[d]->name))
130 1.1 mrg && dispatchers[d]->get_num_devices_func () > 0)
131 1.1 mrg goto found;
132 1.1 mrg
133 1.1.1.2 mrg if (fail_is_error)
134 1.1.1.2 mrg {
135 1.1.1.2 mrg gomp_mutex_unlock (&acc_device_lock);
136 1.1.1.2 mrg gomp_fatal ("device type %s not supported", goacc_device_type);
137 1.1.1.2 mrg }
138 1.1.1.2 mrg else
139 1.1.1.2 mrg return NULL;
140 1.1 mrg }
141 1.1 mrg
142 1.1 mrg /* No default device specified, so start scanning for any non-host
143 1.1 mrg device that is available. */
144 1.1 mrg d = acc_device_not_host;
145 1.1 mrg }
146 1.1 mrg /* FALLTHROUGH */
147 1.1 mrg
148 1.1 mrg case acc_device_not_host:
149 1.1 mrg /* Find the first available device after acc_device_not_host. */
150 1.1 mrg while (++d != _ACC_device_hwm)
151 1.1 mrg if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
152 1.1 mrg goto found;
153 1.1 mrg if (d_arg == acc_device_default)
154 1.1 mrg {
155 1.1 mrg d = acc_device_host;
156 1.1 mrg goto found;
157 1.1 mrg }
158 1.1.1.2 mrg if (fail_is_error)
159 1.1.1.2 mrg {
160 1.1.1.2 mrg gomp_mutex_unlock (&acc_device_lock);
161 1.1.1.2 mrg gomp_fatal ("no device found");
162 1.1.1.2 mrg }
163 1.1.1.2 mrg else
164 1.1.1.2 mrg return NULL;
165 1.1 mrg break;
166 1.1 mrg
167 1.1 mrg case acc_device_host:
168 1.1 mrg break;
169 1.1 mrg
170 1.1 mrg default:
171 1.1 mrg if (d > _ACC_device_hwm)
172 1.1.1.2 mrg {
173 1.1.1.2 mrg if (fail_is_error)
174 1.1.1.2 mrg goto unsupported_device;
175 1.1.1.2 mrg else
176 1.1.1.2 mrg return NULL;
177 1.1.1.2 mrg }
178 1.1 mrg break;
179 1.1 mrg }
180 1.1 mrg found:
181 1.1 mrg
182 1.1 mrg assert (d != acc_device_none
183 1.1 mrg && d != acc_device_default
184 1.1 mrg && d != acc_device_not_host);
185 1.1 mrg
186 1.1.1.2 mrg if (dispatchers[d] == NULL && fail_is_error)
187 1.1.1.2 mrg {
188 1.1.1.2 mrg unsupported_device:
189 1.1.1.2 mrg gomp_mutex_unlock (&acc_device_lock);
190 1.1.1.2 mrg gomp_fatal ("device type %s not supported", name_of_acc_device_t (d));
191 1.1.1.2 mrg }
192 1.1.1.2 mrg
193 1.1 mrg return dispatchers[d];
194 1.1 mrg }
195 1.1 mrg
196 1.1.1.2 mrg /* Emit a suitable error if no device of a particular type is available, or
197 1.1.1.2 mrg the given device number is out-of-range. */
198 1.1.1.2 mrg static void
199 1.1.1.2 mrg acc_dev_num_out_of_range (acc_device_t d, int ord, int ndevs)
200 1.1.1.2 mrg {
201 1.1.1.2 mrg if (ndevs == 0)
202 1.1.1.2 mrg gomp_fatal ("no devices of type %s available", name_of_acc_device_t (d));
203 1.1.1.2 mrg else
204 1.1.1.2 mrg gomp_fatal ("device %u out of range", ord);
205 1.1.1.2 mrg }
206 1.1.1.2 mrg
207 1.1 mrg /* This is called when plugins have been initialized, and serves to call
208 1.1 mrg (indirectly) the target's device_init hook. Calling multiple times without
209 1.1.1.2 mrg an intervening acc_shutdown_1 call is an error. ACC_DEVICE_LOCK must be
210 1.1.1.2 mrg held before calling this function. */
211 1.1 mrg
212 1.1 mrg static struct gomp_device_descr *
213 1.1 mrg acc_init_1 (acc_device_t d)
214 1.1 mrg {
215 1.1 mrg struct gomp_device_descr *base_dev, *acc_dev;
216 1.1 mrg int ndevs;
217 1.1 mrg
218 1.1.1.2 mrg base_dev = resolve_device (d, true);
219 1.1 mrg
220 1.1 mrg ndevs = base_dev->get_num_devices_func ();
221 1.1 mrg
222 1.1.1.2 mrg if (ndevs <= 0 || goacc_device_num >= ndevs)
223 1.1.1.2 mrg acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
224 1.1 mrg
225 1.1 mrg acc_dev = &base_dev[goacc_device_num];
226 1.1 mrg
227 1.1.1.2 mrg gomp_mutex_lock (&acc_dev->lock);
228 1.1.1.2 mrg if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
229 1.1.1.2 mrg {
230 1.1.1.2 mrg gomp_mutex_unlock (&acc_dev->lock);
231 1.1.1.2 mrg gomp_fatal ("device already active");
232 1.1.1.2 mrg }
233 1.1 mrg
234 1.1 mrg gomp_init_device (acc_dev);
235 1.1.1.2 mrg gomp_mutex_unlock (&acc_dev->lock);
236 1.1 mrg
237 1.1 mrg return base_dev;
238 1.1 mrg }
239 1.1 mrg
240 1.1.1.2 mrg /* ACC_DEVICE_LOCK must be held before calling this function. */
241 1.1.1.2 mrg
242 1.1 mrg static void
243 1.1 mrg acc_shutdown_1 (acc_device_t d)
244 1.1 mrg {
245 1.1 mrg struct gomp_device_descr *base_dev;
246 1.1 mrg struct goacc_thread *walk;
247 1.1 mrg int ndevs, i;
248 1.1 mrg bool devices_active = false;
249 1.1 mrg
250 1.1 mrg /* Get the base device for this device type. */
251 1.1.1.2 mrg base_dev = resolve_device (d, true);
252 1.1.1.2 mrg
253 1.1.1.2 mrg ndevs = base_dev->get_num_devices_func ();
254 1.1 mrg
255 1.1.1.2 mrg /* Unload all the devices of this type that have been opened. */
256 1.1.1.2 mrg for (i = 0; i < ndevs; i++)
257 1.1.1.2 mrg {
258 1.1.1.2 mrg struct gomp_device_descr *acc_dev = &base_dev[i];
259 1.1 mrg
260 1.1.1.2 mrg gomp_mutex_lock (&acc_dev->lock);
261 1.1.1.2 mrg gomp_unload_device (acc_dev);
262 1.1.1.2 mrg gomp_mutex_unlock (&acc_dev->lock);
263 1.1.1.2 mrg }
264 1.1.1.2 mrg
265 1.1 mrg gomp_mutex_lock (&goacc_thread_lock);
266 1.1 mrg
267 1.1 mrg /* Free target-specific TLS data and close all devices. */
268 1.1 mrg for (walk = goacc_threads; walk != NULL; walk = walk->next)
269 1.1 mrg {
270 1.1 mrg if (walk->target_tls)
271 1.1 mrg base_dev->openacc.destroy_thread_data_func (walk->target_tls);
272 1.1 mrg
273 1.1 mrg walk->target_tls = NULL;
274 1.1 mrg
275 1.1 mrg /* This would mean the user is shutting down OpenACC in the middle of an
276 1.1 mrg "acc data" pragma. Likely not intentional. */
277 1.1 mrg if (walk->mapped_data)
278 1.1.1.2 mrg {
279 1.1.1.2 mrg gomp_mutex_unlock (&goacc_thread_lock);
280 1.1.1.2 mrg gomp_fatal ("shutdown in 'acc data' region");
281 1.1.1.2 mrg }
282 1.1 mrg
283 1.1 mrg /* Similarly, if this happens then user code has done something weird. */
284 1.1 mrg if (walk->saved_bound_dev)
285 1.1.1.2 mrg {
286 1.1.1.2 mrg gomp_mutex_unlock (&goacc_thread_lock);
287 1.1.1.2 mrg gomp_fatal ("shutdown during host fallback");
288 1.1.1.2 mrg }
289 1.1 mrg
290 1.1 mrg if (walk->dev)
291 1.1 mrg {
292 1.1 mrg gomp_mutex_lock (&walk->dev->lock);
293 1.1 mrg gomp_free_memmap (&walk->dev->mem_map);
294 1.1 mrg gomp_mutex_unlock (&walk->dev->lock);
295 1.1 mrg
296 1.1 mrg walk->dev = NULL;
297 1.1 mrg walk->base_dev = NULL;
298 1.1 mrg }
299 1.1 mrg }
300 1.1 mrg
301 1.1 mrg gomp_mutex_unlock (&goacc_thread_lock);
302 1.1 mrg
303 1.1 mrg /* Close all the devices of this type that have been opened. */
304 1.1.1.2.4.1 christos bool ret = true;
305 1.1 mrg for (i = 0; i < ndevs; i++)
306 1.1 mrg {
307 1.1 mrg struct gomp_device_descr *acc_dev = &base_dev[i];
308 1.1.1.2 mrg gomp_mutex_lock (&acc_dev->lock);
309 1.1.1.2 mrg if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
310 1.1 mrg {
311 1.1 mrg devices_active = true;
312 1.1.1.2.4.1 christos ret &= acc_dev->fini_device_func (acc_dev->target_id);
313 1.1.1.2 mrg acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
314 1.1 mrg }
315 1.1.1.2 mrg gomp_mutex_unlock (&acc_dev->lock);
316 1.1 mrg }
317 1.1 mrg
318 1.1.1.2.4.1 christos if (!ret)
319 1.1.1.2.4.1 christos gomp_fatal ("device finalization failed");
320 1.1.1.2.4.1 christos
321 1.1 mrg if (!devices_active)
322 1.1 mrg gomp_fatal ("no device initialized");
323 1.1 mrg }
324 1.1 mrg
325 1.1 mrg static struct goacc_thread *
326 1.1 mrg goacc_new_thread (void)
327 1.1 mrg {
328 1.1.1.2.4.1 christos struct goacc_thread *thr = gomp_malloc (sizeof (struct goacc_thread));
329 1.1 mrg
330 1.1 mrg #if defined HAVE_TLS || defined USE_EMUTLS
331 1.1 mrg goacc_tls_data = thr;
332 1.1 mrg #else
333 1.1 mrg pthread_setspecific (goacc_tls_key, thr);
334 1.1 mrg #endif
335 1.1 mrg
336 1.1 mrg pthread_setspecific (goacc_cleanup_key, thr);
337 1.1 mrg
338 1.1 mrg gomp_mutex_lock (&goacc_thread_lock);
339 1.1 mrg thr->next = goacc_threads;
340 1.1 mrg goacc_threads = thr;
341 1.1 mrg gomp_mutex_unlock (&goacc_thread_lock);
342 1.1 mrg
343 1.1 mrg return thr;
344 1.1 mrg }
345 1.1 mrg
346 1.1 mrg static void
347 1.1 mrg goacc_destroy_thread (void *data)
348 1.1 mrg {
349 1.1 mrg struct goacc_thread *thr = data, *walk, *prev;
350 1.1 mrg
351 1.1 mrg gomp_mutex_lock (&goacc_thread_lock);
352 1.1 mrg
353 1.1 mrg if (thr)
354 1.1 mrg {
355 1.1 mrg struct gomp_device_descr *acc_dev = thr->dev;
356 1.1 mrg
357 1.1 mrg if (acc_dev && thr->target_tls)
358 1.1 mrg {
359 1.1 mrg acc_dev->openacc.destroy_thread_data_func (thr->target_tls);
360 1.1 mrg thr->target_tls = NULL;
361 1.1 mrg }
362 1.1 mrg
363 1.1 mrg assert (!thr->mapped_data);
364 1.1 mrg
365 1.1 mrg /* Remove from thread list. */
366 1.1 mrg for (prev = NULL, walk = goacc_threads; walk;
367 1.1 mrg prev = walk, walk = walk->next)
368 1.1 mrg if (walk == thr)
369 1.1 mrg {
370 1.1 mrg if (prev == NULL)
371 1.1 mrg goacc_threads = walk->next;
372 1.1 mrg else
373 1.1 mrg prev->next = walk->next;
374 1.1 mrg
375 1.1 mrg free (thr);
376 1.1 mrg
377 1.1 mrg break;
378 1.1 mrg }
379 1.1 mrg
380 1.1 mrg assert (walk);
381 1.1 mrg }
382 1.1 mrg
383 1.1 mrg gomp_mutex_unlock (&goacc_thread_lock);
384 1.1 mrg }
385 1.1 mrg
386 1.1 mrg /* Use the ORD'th device instance for the current host thread (or -1 for the
387 1.1 mrg current global default). The device (and the runtime) must be initialised
388 1.1 mrg before calling this function. */
389 1.1 mrg
390 1.1 mrg void
391 1.1 mrg goacc_attach_host_thread_to_device (int ord)
392 1.1 mrg {
393 1.1 mrg struct goacc_thread *thr = goacc_thread ();
394 1.1 mrg struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
395 1.1 mrg int num_devices;
396 1.1 mrg
397 1.1 mrg if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
398 1.1 mrg return;
399 1.1 mrg
400 1.1 mrg if (ord < 0)
401 1.1 mrg ord = goacc_device_num;
402 1.1 mrg
403 1.1 mrg /* Decide which type of device to use. If the current thread has a device
404 1.1 mrg type already (e.g. set by acc_set_device_type), use that, else use the
405 1.1 mrg global default. */
406 1.1 mrg if (thr && thr->base_dev)
407 1.1 mrg base_dev = thr->base_dev;
408 1.1 mrg else
409 1.1 mrg {
410 1.1 mrg assert (cached_base_dev);
411 1.1 mrg base_dev = cached_base_dev;
412 1.1 mrg }
413 1.1 mrg
414 1.1 mrg num_devices = base_dev->get_num_devices_func ();
415 1.1 mrg if (num_devices <= 0 || ord >= num_devices)
416 1.1.1.2 mrg acc_dev_num_out_of_range (acc_device_type (base_dev->type), ord,
417 1.1.1.2 mrg num_devices);
418 1.1 mrg
419 1.1 mrg if (!thr)
420 1.1 mrg thr = goacc_new_thread ();
421 1.1 mrg
422 1.1 mrg thr->base_dev = base_dev;
423 1.1 mrg thr->dev = acc_dev = &base_dev[ord];
424 1.1 mrg thr->saved_bound_dev = NULL;
425 1.1 mrg thr->mapped_data = NULL;
426 1.1 mrg
427 1.1 mrg thr->target_tls
428 1.1 mrg = acc_dev->openacc.create_thread_data_func (ord);
429 1.1 mrg
430 1.1 mrg acc_dev->openacc.async_set_async_func (acc_async_sync);
431 1.1 mrg }
432 1.1 mrg
433 1.1 mrg /* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
434 1.1 mrg init/shutdown is per-process or per-thread. We choose per-process. */
435 1.1 mrg
436 1.1 mrg void
437 1.1 mrg acc_init (acc_device_t d)
438 1.1 mrg {
439 1.1.1.2.4.1 christos gomp_init_targets_once ();
440 1.1 mrg
441 1.1 mrg gomp_mutex_lock (&acc_device_lock);
442 1.1 mrg
443 1.1 mrg cached_base_dev = acc_init_1 (d);
444 1.1 mrg
445 1.1 mrg gomp_mutex_unlock (&acc_device_lock);
446 1.1 mrg
447 1.1 mrg goacc_attach_host_thread_to_device (-1);
448 1.1 mrg }
449 1.1 mrg
450 1.1 mrg ialias (acc_init)
451 1.1 mrg
452 1.1 mrg void
453 1.1 mrg acc_shutdown (acc_device_t d)
454 1.1 mrg {
455 1.1.1.2 mrg gomp_init_targets_once ();
456 1.1.1.2 mrg
457 1.1 mrg gomp_mutex_lock (&acc_device_lock);
458 1.1 mrg
459 1.1 mrg acc_shutdown_1 (d);
460 1.1 mrg
461 1.1 mrg gomp_mutex_unlock (&acc_device_lock);
462 1.1 mrg }
463 1.1 mrg
464 1.1 mrg ialias (acc_shutdown)
465 1.1 mrg
466 1.1 mrg int
467 1.1 mrg acc_get_num_devices (acc_device_t d)
468 1.1 mrg {
469 1.1 mrg int n = 0;
470 1.1 mrg struct gomp_device_descr *acc_dev;
471 1.1 mrg
472 1.1 mrg if (d == acc_device_none)
473 1.1 mrg return 0;
474 1.1 mrg
475 1.1 mrg gomp_init_targets_once ();
476 1.1 mrg
477 1.1.1.2 mrg gomp_mutex_lock (&acc_device_lock);
478 1.1.1.2 mrg acc_dev = resolve_device (d, false);
479 1.1.1.2 mrg gomp_mutex_unlock (&acc_device_lock);
480 1.1.1.2 mrg
481 1.1 mrg if (!acc_dev)
482 1.1 mrg return 0;
483 1.1 mrg
484 1.1 mrg n = acc_dev->get_num_devices_func ();
485 1.1 mrg if (n < 0)
486 1.1 mrg n = 0;
487 1.1 mrg
488 1.1 mrg return n;
489 1.1 mrg }
490 1.1 mrg
491 1.1 mrg ialias (acc_get_num_devices)
492 1.1 mrg
493 1.1 mrg /* Set the device type for the current thread only (using the current global
494 1.1 mrg default device number), initialising that device if necessary. Also set the
495 1.1 mrg default device type for new threads to D. */
496 1.1 mrg
497 1.1 mrg void
498 1.1 mrg acc_set_device_type (acc_device_t d)
499 1.1 mrg {
500 1.1 mrg struct gomp_device_descr *base_dev, *acc_dev;
501 1.1 mrg struct goacc_thread *thr = goacc_thread ();
502 1.1 mrg
503 1.1.1.2.4.1 christos gomp_init_targets_once ();
504 1.1 mrg
505 1.1.1.2.4.1 christos gomp_mutex_lock (&acc_device_lock);
506 1.1 mrg
507 1.1.1.2 mrg cached_base_dev = base_dev = resolve_device (d, true);
508 1.1 mrg acc_dev = &base_dev[goacc_device_num];
509 1.1 mrg
510 1.1.1.2 mrg gomp_mutex_lock (&acc_dev->lock);
511 1.1.1.2 mrg if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
512 1.1 mrg gomp_init_device (acc_dev);
513 1.1.1.2 mrg gomp_mutex_unlock (&acc_dev->lock);
514 1.1 mrg
515 1.1 mrg gomp_mutex_unlock (&acc_device_lock);
516 1.1 mrg
517 1.1 mrg /* We're changing device type: invalidate the current thread's dev and
518 1.1 mrg base_dev pointers. */
519 1.1 mrg if (thr && thr->base_dev != base_dev)
520 1.1 mrg {
521 1.1 mrg thr->base_dev = thr->dev = NULL;
522 1.1 mrg if (thr->mapped_data)
523 1.1 mrg gomp_fatal ("acc_set_device_type in 'acc data' region");
524 1.1 mrg }
525 1.1 mrg
526 1.1 mrg goacc_attach_host_thread_to_device (-1);
527 1.1 mrg }
528 1.1 mrg
529 1.1 mrg ialias (acc_set_device_type)
530 1.1 mrg
531 1.1 mrg acc_device_t
532 1.1 mrg acc_get_device_type (void)
533 1.1 mrg {
534 1.1 mrg acc_device_t res = acc_device_none;
535 1.1 mrg struct gomp_device_descr *dev;
536 1.1 mrg struct goacc_thread *thr = goacc_thread ();
537 1.1 mrg
538 1.1 mrg if (thr && thr->base_dev)
539 1.1 mrg res = acc_device_type (thr->base_dev->type);
540 1.1 mrg else
541 1.1 mrg {
542 1.1 mrg gomp_init_targets_once ();
543 1.1 mrg
544 1.1.1.2 mrg gomp_mutex_lock (&acc_device_lock);
545 1.1.1.2 mrg dev = resolve_device (acc_device_default, true);
546 1.1.1.2 mrg gomp_mutex_unlock (&acc_device_lock);
547 1.1 mrg res = acc_device_type (dev->type);
548 1.1 mrg }
549 1.1 mrg
550 1.1 mrg assert (res != acc_device_default
551 1.1 mrg && res != acc_device_not_host);
552 1.1 mrg
553 1.1 mrg return res;
554 1.1 mrg }
555 1.1 mrg
556 1.1 mrg ialias (acc_get_device_type)
557 1.1 mrg
558 1.1 mrg int
559 1.1 mrg acc_get_device_num (acc_device_t d)
560 1.1 mrg {
561 1.1 mrg const struct gomp_device_descr *dev;
562 1.1 mrg struct goacc_thread *thr = goacc_thread ();
563 1.1 mrg
564 1.1 mrg if (d >= _ACC_device_hwm)
565 1.1.1.2 mrg gomp_fatal ("unknown device type %u", (unsigned) d);
566 1.1 mrg
567 1.1.1.2.4.1 christos gomp_init_targets_once ();
568 1.1 mrg
569 1.1.1.2 mrg gomp_mutex_lock (&acc_device_lock);
570 1.1.1.2 mrg dev = resolve_device (d, true);
571 1.1.1.2 mrg gomp_mutex_unlock (&acc_device_lock);
572 1.1 mrg
573 1.1 mrg if (thr && thr->base_dev == dev && thr->dev)
574 1.1 mrg return thr->dev->target_id;
575 1.1 mrg
576 1.1 mrg return goacc_device_num;
577 1.1 mrg }
578 1.1 mrg
579 1.1 mrg ialias (acc_get_device_num)
580 1.1 mrg
581 1.1 mrg void
582 1.1 mrg acc_set_device_num (int ord, acc_device_t d)
583 1.1 mrg {
584 1.1 mrg struct gomp_device_descr *base_dev, *acc_dev;
585 1.1 mrg int num_devices;
586 1.1 mrg
587 1.1.1.2.4.1 christos gomp_init_targets_once ();
588 1.1 mrg
589 1.1 mrg if (ord < 0)
590 1.1 mrg ord = goacc_device_num;
591 1.1 mrg
592 1.1 mrg if ((int) d == 0)
593 1.1 mrg /* Set whatever device is being used by the current host thread to use
594 1.1 mrg device instance ORD. It's unclear if this is supposed to affect other
595 1.1 mrg host threads too (OpenACC 2.0 (3.2.4) acc_set_device_num). */
596 1.1 mrg goacc_attach_host_thread_to_device (ord);
597 1.1 mrg else
598 1.1 mrg {
599 1.1 mrg gomp_mutex_lock (&acc_device_lock);
600 1.1 mrg
601 1.1.1.2 mrg cached_base_dev = base_dev = resolve_device (d, true);
602 1.1 mrg
603 1.1 mrg num_devices = base_dev->get_num_devices_func ();
604 1.1 mrg
605 1.1.1.2 mrg if (num_devices <= 0 || ord >= num_devices)
606 1.1.1.2 mrg acc_dev_num_out_of_range (d, ord, num_devices);
607 1.1 mrg
608 1.1 mrg acc_dev = &base_dev[ord];
609 1.1 mrg
610 1.1.1.2 mrg gomp_mutex_lock (&acc_dev->lock);
611 1.1.1.2 mrg if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
612 1.1 mrg gomp_init_device (acc_dev);
613 1.1.1.2 mrg gomp_mutex_unlock (&acc_dev->lock);
614 1.1 mrg
615 1.1 mrg gomp_mutex_unlock (&acc_device_lock);
616 1.1 mrg
617 1.1 mrg goacc_attach_host_thread_to_device (ord);
618 1.1 mrg }
619 1.1 mrg
620 1.1 mrg goacc_device_num = ord;
621 1.1 mrg }
622 1.1 mrg
623 1.1 mrg ialias (acc_set_device_num)
624 1.1 mrg
625 1.1.1.2 mrg /* For -O and higher, the compiler always attempts to expand acc_on_device, but
626 1.1.1.2 mrg if the user disables the builtin, or calls it via a pointer, we'll need this
627 1.1.1.2 mrg version.
628 1.1 mrg
629 1.1.1.2 mrg Compile this with optimization, so that the compiler expands
630 1.1.1.2 mrg this, rather than generating infinitely recursive code. */
631 1.1 mrg
632 1.1.1.2 mrg int __attribute__ ((__optimize__ ("O2")))
633 1.1.1.2 mrg acc_on_device (acc_device_t dev)
634 1.1.1.2 mrg {
635 1.1.1.2 mrg return __builtin_acc_on_device (dev);
636 1.1 mrg }
637 1.1 mrg
638 1.1 mrg ialias (acc_on_device)
639 1.1 mrg
640 1.1 mrg attribute_hidden void
641 1.1 mrg goacc_runtime_initialize (void)
642 1.1 mrg {
643 1.1 mrg gomp_mutex_init (&acc_device_lock);
644 1.1 mrg
645 1.1 mrg #if !(defined HAVE_TLS || defined USE_EMUTLS)
646 1.1 mrg pthread_key_create (&goacc_tls_key, NULL);
647 1.1 mrg #endif
648 1.1 mrg
649 1.1 mrg pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
650 1.1 mrg
651 1.1 mrg cached_base_dev = NULL;
652 1.1 mrg
653 1.1 mrg goacc_threads = NULL;
654 1.1 mrg gomp_mutex_init (&goacc_thread_lock);
655 1.1 mrg
656 1.1 mrg /* Initialize and register the 'host' device type. */
657 1.1 mrg goacc_host_init ();
658 1.1 mrg }
659 1.1 mrg
660 1.1.1.2.4.2 martin static void __attribute__((destructor))
661 1.1.1.2.4.2 martin goacc_runtime_deinitialize (void)
662 1.1.1.2.4.2 martin {
663 1.1.1.2.4.2 martin #if !(defined HAVE_TLS || defined USE_EMUTLS)
664 1.1.1.2.4.2 martin pthread_key_delete (goacc_tls_key);
665 1.1.1.2.4.2 martin #endif
666 1.1.1.2.4.2 martin pthread_key_delete (goacc_cleanup_key);
667 1.1.1.2.4.2 martin }
668 1.1.1.2.4.2 martin
669 1.1 mrg /* Compiler helper functions */
670 1.1 mrg
671 1.1 mrg attribute_hidden void
672 1.1 mrg goacc_save_and_set_bind (acc_device_t d)
673 1.1 mrg {
674 1.1 mrg struct goacc_thread *thr = goacc_thread ();
675 1.1 mrg
676 1.1 mrg assert (!thr->saved_bound_dev);
677 1.1 mrg
678 1.1 mrg thr->saved_bound_dev = thr->dev;
679 1.1 mrg thr->dev = dispatchers[d];
680 1.1 mrg }
681 1.1 mrg
682 1.1 mrg attribute_hidden void
683 1.1 mrg goacc_restore_bind (void)
684 1.1 mrg {
685 1.1 mrg struct goacc_thread *thr = goacc_thread ();
686 1.1 mrg
687 1.1 mrg thr->dev = thr->saved_bound_dev;
688 1.1 mrg thr->saved_bound_dev = NULL;
689 1.1 mrg }
690 1.1 mrg
691 1.1 mrg /* This is called from any OpenACC support function that may need to implicitly
692 1.1 mrg initialize the libgomp runtime, either globally or from a new host thread.
693 1.1 mrg On exit "goacc_thread" will return a valid & populated thread block. */
694 1.1 mrg
695 1.1 mrg attribute_hidden void
696 1.1 mrg goacc_lazy_initialize (void)
697 1.1 mrg {
698 1.1 mrg struct goacc_thread *thr = goacc_thread ();
699 1.1 mrg
700 1.1 mrg if (thr && thr->dev)
701 1.1 mrg return;
702 1.1 mrg
703 1.1 mrg if (!cached_base_dev)
704 1.1 mrg acc_init (acc_device_default);
705 1.1 mrg else
706 1.1 mrg goacc_attach_host_thread_to_device (-1);
707 1.1 mrg }
708