2015-02-22 Arnaud Charlet <charlet@adacore.com>
[official-gcc.git] / libgomp / oacc-init.c
blob166eb553a6c07ec91db821d7c4f6b94dec86f683
1 /* OpenACC Runtime initialization routines
3 Copyright (C) 2013-2015 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 "oacc-int.h"
31 #include "openacc.h"
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <stdbool.h>
36 #include <string.h>
38 static gomp_mutex_t acc_device_lock;
40 /* The dispatch table for the current accelerator device. This is global, so
41 you can only have one type of device open at any given time in a program.
42 This is the "base" device in that several devices that use the same
43 dispatch table may be active concurrently: this one (the "zeroth") is used
44 for overall initialisation/shutdown, and other instances -- not necessarily
45 including this one -- may be opened and closed once the base device has
46 been initialized. */
47 struct gomp_device_descr *base_dev;
49 #if defined HAVE_TLS || defined USE_EMUTLS
50 __thread struct goacc_thread *goacc_tls_data;
51 #else
52 pthread_key_t goacc_tls_key;
53 #endif
54 static pthread_key_t goacc_cleanup_key;
56 /* Current dispatcher, and how it was initialized */
57 static acc_device_t init_key = _ACC_device_hwm;
59 static struct goacc_thread *goacc_threads;
60 static gomp_mutex_t goacc_thread_lock;
62 /* An array of dispatchers for device types, indexed by the type. This array
63 only references "base" devices, and other instances of the same type are
64 found by simply indexing from each such device (which are stored linearly,
65 grouped by device in target.c:devices). */
66 static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
68 attribute_hidden void
69 goacc_register (struct gomp_device_descr *disp)
71 /* Only register the 0th device here. */
72 if (disp->target_id != 0)
73 return;
75 gomp_mutex_lock (&acc_device_lock);
77 assert (acc_device_type (disp->type) != acc_device_none
78 && acc_device_type (disp->type) != acc_device_default
79 && acc_device_type (disp->type) != acc_device_not_host);
80 assert (!dispatchers[disp->type]);
81 dispatchers[disp->type] = disp;
83 gomp_mutex_unlock (&acc_device_lock);
86 /* OpenACC names some things a little differently. */
88 static const char *
89 get_openacc_name (const char *name)
91 if (strcmp (name, "nvptx") == 0)
92 return "nvidia";
93 else
94 return name;
97 static struct gomp_device_descr *
98 resolve_device (acc_device_t d)
100 acc_device_t d_arg = d;
102 switch (d)
104 case acc_device_default:
106 if (goacc_device_type)
108 /* Lookup the named device. */
109 while (++d != _ACC_device_hwm)
110 if (dispatchers[d]
111 && !strcasecmp (goacc_device_type,
112 get_openacc_name (dispatchers[d]->name))
113 && dispatchers[d]->get_num_devices_func () > 0)
114 goto found;
116 gomp_fatal ("device type %s not supported", goacc_device_type);
119 /* No default device specified, so start scanning for any non-host
120 device that is available. */
121 d = acc_device_not_host;
123 /* FALLTHROUGH */
125 case acc_device_not_host:
126 /* Find the first available device after acc_device_not_host. */
127 while (++d != _ACC_device_hwm)
128 if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
129 goto found;
130 if (d_arg == acc_device_default)
132 d = acc_device_host;
133 goto found;
135 gomp_fatal ("no device found");
136 break;
138 case acc_device_host:
139 break;
141 default:
142 if (d > _ACC_device_hwm)
143 gomp_fatal ("device %u out of range", (unsigned)d);
144 break;
146 found:
148 assert (d != acc_device_none
149 && d != acc_device_default
150 && d != acc_device_not_host);
152 return dispatchers[d];
155 /* This is called when plugins have been initialized, and serves to call
156 (indirectly) the target's device_init hook. Calling multiple times without
157 an intervening acc_shutdown_1 call is an error. */
159 static struct gomp_device_descr *
160 acc_init_1 (acc_device_t d)
162 struct gomp_device_descr *acc_dev;
164 acc_dev = resolve_device (d);
166 if (!acc_dev || acc_dev->get_num_devices_func () <= 0)
167 gomp_fatal ("device %u not supported", (unsigned)d);
169 if (acc_dev->is_initialized)
170 gomp_fatal ("device already active");
172 /* We need to remember what we were intialized as, to check shutdown etc. */
173 init_key = d;
175 gomp_init_device (acc_dev);
177 return acc_dev;
180 static struct goacc_thread *
181 goacc_new_thread (void)
183 struct goacc_thread *thr = gomp_malloc (sizeof (struct gomp_thread));
185 #if defined HAVE_TLS || defined USE_EMUTLS
186 goacc_tls_data = thr;
187 #else
188 pthread_setspecific (goacc_tls_key, thr);
189 #endif
191 pthread_setspecific (goacc_cleanup_key, thr);
193 gomp_mutex_lock (&goacc_thread_lock);
194 thr->next = goacc_threads;
195 goacc_threads = thr;
196 gomp_mutex_unlock (&goacc_thread_lock);
198 return thr;
201 static void
202 goacc_destroy_thread (void *data)
204 struct goacc_thread *thr = data, *walk, *prev;
206 gomp_mutex_lock (&goacc_thread_lock);
208 if (thr)
210 if (base_dev && thr->target_tls)
212 base_dev->openacc.destroy_thread_data_func (thr->target_tls);
213 thr->target_tls = NULL;
216 assert (!thr->mapped_data);
218 /* Remove from thread list. */
219 for (prev = NULL, walk = goacc_threads; walk;
220 prev = walk, walk = walk->next)
221 if (walk == thr)
223 if (prev == NULL)
224 goacc_threads = walk->next;
225 else
226 prev->next = walk->next;
228 free (thr);
230 break;
233 assert (walk);
236 gomp_mutex_unlock (&goacc_thread_lock);
239 /* Open the ORD'th device of the currently-active type (base_dev must be
240 initialised before calling). If ORD is < 0, open the default-numbered
241 device (set by the ACC_DEVICE_NUM environment variable or a call to
242 acc_set_device_num), or leave any currently-opened device as is. "Opening"
243 consists of calling the device's open_device_func hook, and setting up
244 thread-local data (maybe allocating, then initializing with information
245 pertaining to the newly-opened or previously-opened device). */
247 static void
248 lazy_open (int ord)
250 struct goacc_thread *thr = goacc_thread ();
251 struct gomp_device_descr *acc_dev;
253 if (thr && thr->dev)
255 assert (ord < 0 || ord == thr->dev->target_id);
256 return;
259 assert (base_dev);
261 if (ord < 0)
262 ord = goacc_device_num;
264 /* The OpenACC 2.0 spec leaves the runtime's behaviour when an out-of-range
265 device is requested as implementation-defined (4.2 ACC_DEVICE_NUM).
266 We choose to raise an error in such a case. */
267 if (ord >= base_dev->get_num_devices_func ())
268 gomp_fatal ("device %u does not exist", ord);
270 if (!thr)
271 thr = goacc_new_thread ();
273 acc_dev = thr->dev = &base_dev[ord];
275 assert (acc_dev->target_id == ord);
277 thr->saved_bound_dev = NULL;
278 thr->mapped_data = NULL;
280 if (!acc_dev->openacc.target_data)
281 acc_dev->openacc.target_data = acc_dev->openacc.open_device_func (ord);
283 thr->target_tls
284 = acc_dev->openacc.create_thread_data_func (acc_dev->openacc.target_data);
286 acc_dev->openacc.async_set_async_func (acc_async_sync);
288 struct gomp_memory_mapping *mem_map = &acc_dev->mem_map;
289 gomp_mutex_lock (&mem_map->lock);
290 if (!mem_map->is_initialized)
291 gomp_init_tables (acc_dev, mem_map);
292 gomp_mutex_unlock (&mem_map->lock);
295 /* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
296 init/shutdown is per-process or per-thread. We choose per-process. */
298 void
299 acc_init (acc_device_t d)
301 if (!base_dev)
302 gomp_init_targets_once ();
304 gomp_mutex_lock (&acc_device_lock);
306 base_dev = acc_init_1 (d);
308 lazy_open (-1);
310 gomp_mutex_unlock (&acc_device_lock);
313 ialias (acc_init)
315 static void
316 acc_shutdown_1 (acc_device_t d)
318 struct goacc_thread *walk;
320 /* We don't check whether d matches the actual device found, because
321 OpenACC 2.0 (3.2.12) says the parameters to the init and this
322 call must match (for the shutdown call anyway, it's silent on
323 others). */
325 if (!base_dev)
326 gomp_fatal ("no device initialized");
327 if (d != init_key)
328 gomp_fatal ("device %u(%u) is initialized",
329 (unsigned) init_key, (unsigned) base_dev->type);
331 gomp_mutex_lock (&goacc_thread_lock);
333 /* Free target-specific TLS data and close all devices. */
334 for (walk = goacc_threads; walk != NULL; walk = walk->next)
336 if (walk->target_tls)
337 base_dev->openacc.destroy_thread_data_func (walk->target_tls);
339 walk->target_tls = NULL;
341 /* This would mean the user is shutting down OpenACC in the middle of an
342 "acc data" pragma. Likely not intentional. */
343 if (walk->mapped_data)
344 gomp_fatal ("shutdown in 'acc data' region");
346 if (walk->dev)
348 void *target_data = walk->dev->openacc.target_data;
349 if (walk->dev->openacc.close_device_func (target_data) < 0)
350 gomp_fatal ("failed to close device");
352 walk->dev->openacc.target_data = target_data = NULL;
354 struct gomp_memory_mapping *mem_map = &walk->dev->mem_map;
355 gomp_mutex_lock (&mem_map->lock);
356 gomp_free_memmap (mem_map);
357 gomp_mutex_unlock (&mem_map->lock);
359 walk->dev = NULL;
363 gomp_mutex_unlock (&goacc_thread_lock);
365 gomp_fini_device (base_dev);
367 base_dev = NULL;
370 void
371 acc_shutdown (acc_device_t d)
373 gomp_mutex_lock (&acc_device_lock);
375 acc_shutdown_1 (d);
377 gomp_mutex_unlock (&acc_device_lock);
380 ialias (acc_shutdown)
382 /* This function is called after plugins have been initialized. It deals with
383 the "base" device, and is used to prepare the runtime for dealing with a
384 number of such devices (as implemented by some particular plugin). If the
385 argument device type D matches a previous call to the function, return the
386 current base device, else shut the old device down and re-initialize with
387 the new device type. */
389 static struct gomp_device_descr *
390 lazy_init (acc_device_t d)
392 if (base_dev)
394 /* Re-initializing the same device, do nothing. */
395 if (d == init_key)
396 return base_dev;
398 acc_shutdown_1 (init_key);
401 assert (!base_dev);
403 return acc_init_1 (d);
406 /* Ensure that plugins are loaded, initialize and open the (default-numbered)
407 device. */
409 static void
410 lazy_init_and_open (acc_device_t d)
412 if (!base_dev)
413 gomp_init_targets_once ();
415 gomp_mutex_lock (&acc_device_lock);
417 base_dev = lazy_init (d);
419 lazy_open (-1);
421 gomp_mutex_unlock (&acc_device_lock);
425 acc_get_num_devices (acc_device_t d)
427 int n = 0;
428 const struct gomp_device_descr *acc_dev;
430 if (d == acc_device_none)
431 return 0;
433 if (!base_dev)
434 gomp_init_targets_once ();
436 acc_dev = resolve_device (d);
437 if (!acc_dev)
438 return 0;
440 n = acc_dev->get_num_devices_func ();
441 if (n < 0)
442 n = 0;
444 return n;
447 ialias (acc_get_num_devices)
449 void
450 acc_set_device_type (acc_device_t d)
452 lazy_init_and_open (d);
455 ialias (acc_set_device_type)
457 acc_device_t
458 acc_get_device_type (void)
460 acc_device_t res = acc_device_none;
461 const struct gomp_device_descr *dev;
463 if (base_dev)
464 res = acc_device_type (base_dev->type);
465 else
467 gomp_init_targets_once ();
469 dev = resolve_device (acc_device_default);
470 res = acc_device_type (dev->type);
473 assert (res != acc_device_default
474 && res != acc_device_not_host);
476 return res;
479 ialias (acc_get_device_type)
482 acc_get_device_num (acc_device_t d)
484 const struct gomp_device_descr *dev;
485 int num;
487 if (d >= _ACC_device_hwm)
488 gomp_fatal ("device %u out of range", (unsigned)d);
490 if (!base_dev)
491 gomp_init_targets_once ();
493 dev = resolve_device (d);
494 if (!dev)
495 gomp_fatal ("no devices of type %u", d);
497 /* We might not have called lazy_open for this host thread yet, in which case
498 the get_device_num_func hook will return -1. */
499 num = dev->openacc.get_device_num_func ();
500 if (num < 0)
501 num = goacc_device_num;
503 return num;
506 ialias (acc_get_device_num)
508 void
509 acc_set_device_num (int n, acc_device_t d)
511 const struct gomp_device_descr *dev;
512 int num_devices;
514 if (!base_dev)
515 gomp_init_targets_once ();
517 if ((int) d == 0)
519 int i;
521 /* A device setting of zero sets all device types on the system to use
522 the Nth instance of that device type. Only attempt it for initialized
523 devices though. */
524 for (i = acc_device_not_host + 1; i < _ACC_device_hwm; i++)
526 dev = resolve_device (d);
527 if (dev && dev->is_initialized)
528 dev->openacc.set_device_num_func (n);
531 /* ...and for future calls to acc_init/acc_set_device_type, etc. */
532 goacc_device_num = n;
534 else
536 struct goacc_thread *thr = goacc_thread ();
538 gomp_mutex_lock (&acc_device_lock);
540 base_dev = lazy_init (d);
542 num_devices = base_dev->get_num_devices_func ();
544 if (n >= num_devices)
545 gomp_fatal ("device %u out of range", n);
547 /* If we're changing the device number, de-associate this thread with
548 the device (but don't close the device, since it may be in use by
549 other threads). */
550 if (thr && thr->dev && n != thr->dev->target_id)
551 thr->dev = NULL;
553 lazy_open (n);
555 gomp_mutex_unlock (&acc_device_lock);
559 ialias (acc_set_device_num)
562 acc_on_device (acc_device_t dev)
564 struct goacc_thread *thr = goacc_thread ();
566 if (thr && thr->dev
567 && acc_device_type (thr->dev->type) == acc_device_host_nonshm)
568 return dev == acc_device_host_nonshm || dev == acc_device_not_host;
570 /* Just rely on the compiler builtin. */
571 return __builtin_acc_on_device (dev);
574 ialias (acc_on_device)
576 attribute_hidden void
577 goacc_runtime_initialize (void)
579 gomp_mutex_init (&acc_device_lock);
581 #if !(defined HAVE_TLS || defined USE_EMUTLS)
582 pthread_key_create (&goacc_tls_key, NULL);
583 #endif
585 pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
587 base_dev = NULL;
589 goacc_threads = NULL;
590 gomp_mutex_init (&goacc_thread_lock);
593 /* Compiler helper functions */
595 attribute_hidden void
596 goacc_save_and_set_bind (acc_device_t d)
598 struct goacc_thread *thr = goacc_thread ();
600 assert (!thr->saved_bound_dev);
602 thr->saved_bound_dev = thr->dev;
603 thr->dev = dispatchers[d];
606 attribute_hidden void
607 goacc_restore_bind (void)
609 struct goacc_thread *thr = goacc_thread ();
611 thr->dev = thr->saved_bound_dev;
612 thr->saved_bound_dev = NULL;
615 /* This is called from any OpenACC support function that may need to implicitly
616 initialize the libgomp runtime. On exit all such initialization will have
617 been done, and both the global ACC_dev and the per-host-thread ACC_memmap
618 pointers will be valid. */
620 attribute_hidden void
621 goacc_lazy_initialize (void)
623 struct goacc_thread *thr = goacc_thread ();
625 if (thr && thr->dev)
626 return;
628 if (!base_dev)
629 lazy_init_and_open (acc_device_default);
630 else
632 gomp_mutex_lock (&acc_device_lock);
633 lazy_open (-1);
634 gomp_mutex_unlock (&acc_device_lock);