Support for OpenACC acc_on_device in offloading configurations.
[official-gcc.git] / libgomp / oacc-init.c
blob7298d9a13d1535dcf6e82fba554dd83b61485c44
1 /* OpenACC Runtime initialization routines
3 Copyright (C) 2013-2014 Free Software Foundation, Inc.
5 Contributed by Mentor Embedded.
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
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.
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.
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/>. */
29 #include "libgomp.h"
30 #include "libgomp_target.h"
31 #include "oacc-int.h"
32 #include "openacc.h"
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <strings.h>
36 #include <stdbool.h>
37 #include <stdio.h>
39 static gomp_mutex_t acc_device_lock;
41 /* The dispatch table for the current accelerator device. This is global, so
42 you can only have one type of device open at any given time in a program.
43 This is the "base" device in that several devices that use the same
44 dispatch table may be active concurrently: this one (the "zeroth") is used
45 for overall initialisation/shutdown, and other instances -- not necessarily
46 including this one -- may be opened and closed once the base device has
47 been initialized. */
48 struct gomp_device_descr const *base_dev;
50 #if defined HAVE_TLS || defined USE_EMUTLS
51 __thread struct goacc_thread *goacc_tls_data;
52 #else
53 pthread_key_t goacc_tls_key;
54 #endif
55 static pthread_key_t goacc_cleanup_key;
57 /* Current dispatcher, and how it was initialized */
58 static acc_device_t init_key = _ACC_device_hwm;
60 static struct goacc_thread *goacc_threads;
61 static gomp_mutex_t goacc_thread_lock;
63 /* An array of dispatchers for device types, indexed by the type. This array
64 only references "base" devices, and other instances of the same type are
65 found by simply indexing from each such device (which are stored linearly,
66 grouped by device in target.c:devices). */
67 static struct gomp_device_descr const *dispatchers[_ACC_device_hwm] = { 0 };
69 attribute_hidden void
70 goacc_register (struct gomp_device_descr const *disp)
72 /* Only register the 0th device here. */
73 if (disp->target_id != 0)
74 return;
76 gomp_mutex_lock (&acc_device_lock);
78 assert (acc_device_type (disp->type) != acc_device_none
79 && acc_device_type (disp->type) != acc_device_default
80 && acc_device_type (disp->type) != acc_device_not_host);
81 assert (!dispatchers[disp->type]);
82 dispatchers[disp->type] = disp;
84 gomp_mutex_unlock (&acc_device_lock);
87 static struct gomp_device_descr const *
88 resolve_device (acc_device_t d)
90 acc_device_t d_arg = d;
92 switch (d)
94 case acc_device_default:
96 if (goacc_device_type)
98 /* Lookup the named device. */
99 while (++d != _ACC_device_hwm)
100 if (dispatchers[d]
101 && !strcasecmp (goacc_device_type, dispatchers[d]->name)
102 && dispatchers[d]->get_num_devices_func () > 0)
103 goto found;
105 gomp_fatal ("device type %s not supported", goacc_device_type);
108 /* No default device specified, so start scanning for any non-host
109 device that is available. */
110 d = acc_device_not_host;
112 /* FALLTHROUGH */
114 case acc_device_not_host:
115 /* Find the first available device after acc_device_not_host. */
116 while (++d != _ACC_device_hwm)
117 if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
118 goto found;
119 if (d_arg == acc_device_default)
121 d = acc_device_host;
122 goto found;
124 gomp_fatal ("no device found");
125 break;
127 case acc_device_host:
128 break;
130 default:
131 if (d > _ACC_device_hwm)
132 gomp_fatal ("device %u out of range", (unsigned)d);
133 break;
135 found:
137 assert (d != acc_device_none
138 && d != acc_device_default
139 && d != acc_device_not_host);
141 return dispatchers[d];
144 /* This is called when plugins have been initialized, and serves to call
145 (indirectly) the target's device_init hook. Calling multiple times without
146 an intervening acc_shutdown_1 call is an error. */
148 static struct gomp_device_descr const *
149 acc_init_1 (acc_device_t d)
151 struct gomp_device_descr const *acc_dev;
153 acc_dev = resolve_device (d);
155 if (!acc_dev || acc_dev->get_num_devices_func () <= 0)
156 gomp_fatal ("device %u not supported", (unsigned)d);
158 if (acc_dev->is_initialized)
159 gomp_fatal ("device already active");
161 /* We need to remember what we were intialized as, to check shutdown etc. */
162 init_key = d;
164 gomp_init_device ((struct gomp_device_descr *) acc_dev);
166 return acc_dev;
169 static struct goacc_thread *
170 goacc_new_thread (void)
172 struct goacc_thread *thr = gomp_malloc (sizeof (struct gomp_thread));
174 #if defined HAVE_TLS || defined USE_EMUTLS
175 goacc_tls_data = thr;
176 #else
177 pthread_setspecific (goacc_tls_key, thr);
178 #endif
180 pthread_setspecific (goacc_cleanup_key, thr);
182 gomp_mutex_lock (&goacc_thread_lock);
183 thr->next = goacc_threads;
184 goacc_threads = thr;
185 gomp_mutex_unlock (&goacc_thread_lock);
187 return thr;
190 static void
191 goacc_destroy_thread (void *data)
193 struct goacc_thread *thr = data, *walk, *prev;
195 gomp_mutex_lock (&goacc_thread_lock);
197 if (thr)
199 if (base_dev && thr->target_tls)
201 base_dev->openacc.destroy_thread_data_func (thr->target_tls);
202 thr->target_tls = NULL;
205 assert (!thr->mapped_data);
207 /* Remove from thread list. */
208 for (prev = NULL, walk = goacc_threads; walk;
209 prev = walk, walk = walk->next)
210 if (walk == thr)
212 if (prev == NULL)
213 goacc_threads = walk->next;
214 else
215 prev->next = walk->next;
217 free (thr);
219 break;
222 assert (walk);
225 gomp_mutex_unlock (&goacc_thread_lock);
228 /* Open the ORD'th device of the currently-active type (base_dev must be
229 initialised before calling). If ORD is < 0, open the default-numbered
230 device (set by the ACC_DEVICE_NUM environment variable or a call to
231 acc_set_device_num), or leave any currently-opened device as is. "Opening"
232 consists of calling the device's open_device_func hook, and setting up
233 thread-local data (maybe allocating, then initializing with information
234 pertaining to the newly-opened or previously-opened device). */
236 static void
237 lazy_open (int ord)
239 struct goacc_thread *thr = goacc_thread ();
240 struct gomp_device_descr *acc_dev;
242 if (thr && thr->dev)
244 assert (ord < 0 || ord == thr->dev->target_id);
245 return;
248 assert (base_dev);
250 if (ord < 0)
251 ord = goacc_device_num;
253 /* The OpenACC 2.0 spec leaves the runtime's behaviour when an out-of-range
254 device is requested as implementation-defined (4.2 ACC_DEVICE_NUM).
255 We choose to raise an error in such a case. */
256 if (ord >= base_dev->get_num_devices_func ())
257 gomp_fatal ("device %u does not exist", ord);
259 if (!thr)
260 thr = goacc_new_thread ();
262 acc_dev = thr->dev = (struct gomp_device_descr *) &base_dev[ord];
264 assert (acc_dev->target_id == ord);
266 thr->saved_bound_dev = NULL;
267 thr->mapped_data = NULL;
269 if (!acc_dev->target_data)
270 acc_dev->target_data = acc_dev->openacc.open_device_func (ord);
272 thr->target_tls
273 = acc_dev->openacc.create_thread_data_func (acc_dev->target_data);
275 acc_dev->openacc.async_set_async_func (acc_async_sync);
277 if (!acc_dev->mem_map.is_initialized)
278 gomp_init_tables (acc_dev, &acc_dev->mem_map);
281 /* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
282 init/shutdown is per-process or per-thread. We choose per-process. */
284 void
285 acc_init (acc_device_t d)
287 if (!base_dev)
288 gomp_init_targets_once ();
290 gomp_mutex_lock (&acc_device_lock);
292 base_dev = acc_init_1 (d);
294 lazy_open (-1);
296 gomp_mutex_unlock (&acc_device_lock);
299 ialias (acc_init)
301 static void
302 acc_shutdown_1 (acc_device_t d)
304 struct goacc_thread *walk;
306 /* We don't check whether d matches the actual device found, because
307 OpenACC 2.0 (3.2.12) says the parameters to the init and this
308 call must match (for the shutdown call anyway, it's silent on
309 others). */
311 if (!base_dev)
312 gomp_fatal ("no device initialized");
313 if (d != init_key)
314 gomp_fatal ("device %u(%u) is initialized",
315 (unsigned) init_key, (unsigned) base_dev->type);
317 gomp_mutex_lock (&goacc_thread_lock);
319 /* Free target-specific TLS data and close all devices. */
320 for (walk = goacc_threads; walk != NULL; walk = walk->next)
322 if (walk->target_tls)
323 base_dev->openacc.destroy_thread_data_func (walk->target_tls);
325 walk->target_tls = NULL;
327 /* This would mean the user is shutting down OpenACC in the middle of an
328 "acc data" pragma. Likely not intentional. */
329 if (walk->mapped_data)
330 gomp_fatal ("shutdown in 'acc data' region");
332 if (walk->dev)
334 if (walk->dev->openacc.close_device_func (walk->dev->target_data) < 0)
335 gomp_fatal ("failed to close device");
337 walk->dev->target_data = NULL;
339 gomp_free_memmap (walk->dev);
341 walk->dev = NULL;
345 gomp_mutex_unlock (&goacc_thread_lock);
347 gomp_fini_device ((struct gomp_device_descr *) base_dev);
349 base_dev = NULL;
352 void
353 acc_shutdown (acc_device_t d)
355 gomp_mutex_lock (&acc_device_lock);
357 acc_shutdown_1 (d);
359 gomp_mutex_unlock (&acc_device_lock);
362 ialias (acc_shutdown)
364 /* This function is called after plugins have been initialized. It deals with
365 the "base" device, and is used to prepare the runtime for dealing with a
366 number of such devices (as implemented by some particular plugin). If the
367 argument device type D matches a previous call to the function, return the
368 current base device, else shut the old device down and re-initialize with
369 the new device type. */
371 static struct gomp_device_descr const *
372 lazy_init (acc_device_t d)
374 if (base_dev)
376 /* Re-initializing the same device, do nothing. */
377 if (d == init_key)
378 return base_dev;
380 acc_shutdown_1 (init_key);
383 assert (!base_dev);
385 return acc_init_1 (d);
388 /* Ensure that plugins are loaded, initialize and open the (default-numbered)
389 device. */
391 static void
392 lazy_init_and_open (acc_device_t d)
394 if (!base_dev)
395 gomp_init_targets_once ();
397 gomp_mutex_lock (&acc_device_lock);
399 base_dev = lazy_init (d);
401 lazy_open (-1);
403 gomp_mutex_unlock (&acc_device_lock);
407 acc_get_num_devices (acc_device_t d)
409 int n = 0;
410 struct gomp_device_descr const *acc_dev;
412 if (d == acc_device_none)
413 return 0;
415 if (!base_dev)
416 gomp_init_targets_once ();
418 acc_dev = resolve_device (d);
419 if (!acc_dev)
420 return 0;
422 n = acc_dev->get_num_devices_func ();
423 if (n < 0)
424 n = 0;
426 return n;
429 ialias (acc_get_num_devices)
431 void
432 acc_set_device_type (acc_device_t d)
434 lazy_init_and_open (d);
437 ialias (acc_set_device_type)
439 acc_device_t
440 acc_get_device_type (void)
442 acc_device_t res = acc_device_none;
443 const struct gomp_device_descr *dev;
445 if (base_dev)
446 res = acc_device_type (base_dev->type);
447 else
449 gomp_init_targets_once ();
451 dev = resolve_device (acc_device_default);
452 res = acc_device_type (dev->type);
455 assert (res != acc_device_default
456 && res != acc_device_not_host);
458 return res;
461 ialias (acc_get_device_type)
464 acc_get_device_num (acc_device_t d)
466 const struct gomp_device_descr *dev;
467 int num;
469 if (d >= _ACC_device_hwm)
470 gomp_fatal ("device %u out of range", (unsigned)d);
472 if (!base_dev)
473 gomp_init_targets_once ();
475 dev = resolve_device (d);
476 if (!dev)
477 gomp_fatal ("no devices of type %u", d);
479 /* We might not have called lazy_open for this host thread yet, in which case
480 the get_device_num_func hook will return -1. */
481 num = dev->openacc.get_device_num_func ();
482 if (num < 0)
483 num = goacc_device_num;
485 return num;
488 ialias (acc_get_device_num)
490 void
491 acc_set_device_num (int n, acc_device_t d)
493 const struct gomp_device_descr *dev;
494 int num_devices;
496 if (!base_dev)
497 gomp_init_targets_once ();
499 if ((int) d == 0)
501 int i;
503 /* A device setting of zero sets all device types on the system to use
504 the Nth instance of that device type. Only attempt it for initialized
505 devices though. */
506 for (i = acc_device_not_host + 1; i < _ACC_device_hwm; i++)
508 dev = resolve_device (d);
509 if (dev && dev->is_initialized)
510 dev->openacc.set_device_num_func (n);
513 /* ...and for future calls to acc_init/acc_set_device_type, etc. */
514 goacc_device_num = n;
516 else
518 struct goacc_thread *thr = goacc_thread ();
520 gomp_mutex_lock (&acc_device_lock);
522 base_dev = lazy_init (d);
524 num_devices = base_dev->get_num_devices_func ();
526 if (n >= num_devices)
527 gomp_fatal ("device %u out of range", n);
529 /* If we're changing the device number, de-associate this thread with
530 the device (but don't close the device, since it may be in use by
531 other threads). */
532 if (thr && thr->dev && n != thr->dev->target_id)
533 thr->dev = NULL;
535 lazy_open (n);
537 gomp_mutex_unlock (&acc_device_lock);
541 ialias (acc_set_device_num)
544 acc_on_device (acc_device_t dev)
546 struct goacc_thread *thr = goacc_thread ();
548 if (thr && thr->dev
549 && acc_device_type (thr->dev->type) == acc_device_host_nonshm)
550 return dev == acc_device_host_nonshm || dev == acc_device_not_host;
552 /* Just rely on the compiler builtin. */
553 return __builtin_acc_on_device (dev);
555 ialias (acc_on_device)
557 attribute_hidden void
558 goacc_runtime_initialize (void)
560 gomp_mutex_init (&acc_device_lock);
562 #if !(defined HAVE_TLS || defined USE_EMUTLS)
563 pthread_key_create (&goacc_tls_key, NULL);
564 #endif
566 pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
568 base_dev = NULL;
570 goacc_threads = NULL;
571 gomp_mutex_init (&goacc_thread_lock);
574 /* Compiler helper functions */
576 attribute_hidden void
577 goacc_save_and_set_bind (acc_device_t d)
579 struct goacc_thread *thr = goacc_thread ();
581 assert (!thr->saved_bound_dev);
583 thr->saved_bound_dev = thr->dev;
584 thr->dev = (struct gomp_device_descr *) dispatchers[d];
587 attribute_hidden void
588 goacc_restore_bind (void)
590 struct goacc_thread *thr = goacc_thread ();
592 thr->dev = thr->saved_bound_dev;
593 thr->saved_bound_dev = NULL;
596 /* This is called from any OpenACC support function that may need to implicitly
597 initialize the libgomp runtime. On exit all such initialization will have
598 been done, and both the global ACC_dev and the per-host-thread ACC_memmap
599 pointers will be valid. */
601 attribute_hidden void
602 goacc_lazy_initialize (void)
604 struct goacc_thread *thr = goacc_thread ();
606 if (thr && thr->dev)
607 return;
609 if (!base_dev)
610 lazy_init_and_open (acc_device_default);
611 else
613 gomp_mutex_lock (&acc_device_lock);
614 lazy_open (-1);
615 gomp_mutex_unlock (&acc_device_lock);