aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libgomp/env.c60
-rw-r--r--libgomp/libgomp.h8
-rw-r--r--libgomp/libgomp.texi25
-rw-r--r--libgomp/target.c45
4 files changed, 130 insertions, 8 deletions
diff --git a/libgomp/env.c b/libgomp/env.c
index d730c48..f305b14 100644
--- a/libgomp/env.c
+++ b/libgomp/env.c
@@ -75,6 +75,8 @@ struct gomp_task_icv gomp_global_icv = {
unsigned long gomp_max_active_levels_var = gomp_supported_active_levels;
bool gomp_cancel_var = false;
+enum gomp_target_offload_t gomp_target_offload_var
+ = GOMP_TARGET_OFFLOAD_DEFAULT;
int gomp_max_task_priority_var = 0;
#ifndef HAVE_SYNC_BUILTINS
gomp_mutex_t gomp_managed_threads_lock;
@@ -374,6 +376,48 @@ parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
return false;
}
+static void
+parse_target_offload (const char *name, enum gomp_target_offload_t *offload)
+{
+ const char *env;
+ bool found = false;
+ enum gomp_target_offload_t new_offload;
+
+ env = getenv (name);
+ if (env == NULL)
+ return;
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (strncasecmp (env, "default", 7) == 0)
+ {
+ env += 7;
+ found = true;
+ new_offload = GOMP_TARGET_OFFLOAD_DEFAULT;
+ }
+ else if (strncasecmp (env, "mandatory", 9) == 0)
+ {
+ env += 9;
+ found = true;
+ new_offload = GOMP_TARGET_OFFLOAD_MANDATORY;
+ }
+ else if (strncasecmp (env, "disabled", 8) == 0)
+ {
+ env += 8;
+ found = true;
+ new_offload = GOMP_TARGET_OFFLOAD_DISABLED;
+ }
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (found && *env == '\0')
+ {
+ *offload = new_offload;
+ return;
+ }
+
+ gomp_error ("Invalid value for environment variable OMP_TARGET_OFFLOAD");
+}
+
/* Parse environment variable set to a boolean or list of omp_proc_bind_t
enum values. Return true if one was present and it was successfully
parsed. */
@@ -1334,6 +1378,21 @@ handle_omp_display_env (unsigned long stacksize, int wait_policy)
}
fputs ("'\n", stderr);
+ fputs (" OMP_TARGET_OFFLOAD = '", stderr);
+ switch (gomp_target_offload_var)
+ {
+ case GOMP_TARGET_OFFLOAD_DEFAULT:
+ fputs ("DEFAULT", stderr);
+ break;
+ case GOMP_TARGET_OFFLOAD_MANDATORY:
+ fputs ("MANDATORY", stderr);
+ break;
+ case GOMP_TARGET_OFFLOAD_DISABLED:
+ fputs ("DISABLED", stderr);
+ break;
+ }
+ fputs ("'\n", stderr);
+
if (verbose)
{
fputs (" GOMP_CPU_AFFINITY = ''\n", stderr);
@@ -1366,6 +1425,7 @@ initialize_env (void)
parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
parse_boolean ("OMP_DISPLAY_AFFINITY", &gomp_display_affinity_var);
parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
+ parse_target_offload ("OMP_TARGET_OFFLOAD", &gomp_target_offload_var);
parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
true);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 9d26de2..da7ac03 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -434,6 +434,13 @@ struct gomp_task_icv
struct target_mem_desc *target_data;
};
+enum gomp_target_offload_t
+{
+ GOMP_TARGET_OFFLOAD_DEFAULT,
+ GOMP_TARGET_OFFLOAD_MANDATORY,
+ GOMP_TARGET_OFFLOAD_DISABLED
+};
+
#define gomp_supported_active_levels INT_MAX
extern struct gomp_task_icv gomp_global_icv;
@@ -442,6 +449,7 @@ extern gomp_mutex_t gomp_managed_threads_lock;
#endif
extern unsigned long gomp_max_active_levels_var;
extern bool gomp_cancel_var;
+extern enum gomp_target_offload_t gomp_target_offload_var;
extern int gomp_max_task_priority_var;
extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
extern unsigned long gomp_available_cpus, gomp_managed_threads;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index a888613..7c6d5fd 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -1381,6 +1381,7 @@ beginning with @env{GOMP_} are GNU extensions.
* OMP_PLACES:: Specifies on which CPUs the theads should be placed
* OMP_STACKSIZE:: Set default thread stack size
* OMP_SCHEDULE:: How threads are scheduled
+* OMP_TARGET_OFFLOAD:: Controls offloading behaviour
* OMP_THREAD_LIMIT:: Set the maximum number of threads
* OMP_WAIT_POLICY:: How waiting threads are handled
* GOMP_CPU_AFFINITY:: Bind threads to specific CPUs
@@ -1654,6 +1655,30 @@ dynamic scheduling and a chunk size of 1 is used.
+@node OMP_TARGET_OFFLOAD
+@section @env{OMP_TARGET_OFFLOAD} -- Controls offloading behaviour
+@cindex Environment Variable
+@cindex Implementation specific setting
+@table @asis
+@item @emph{Description}:
+Specifies the behaviour with regard to offloading code to a device. This
+variable can be set to one of three values - @code{MANDATORY}, @code{DISABLED}
+or @code{DEFAULT}.
+
+If set to @code{MANDATORY}, the program will terminate with an error if
+the offload device is not present or is not supported. If set to
+@code{DISABLED}, then offloading is disabled and all code will run on the
+host. If set to @code{DEFAULT}, the program will try offloading to the
+device first, then fall back to running code on the host if it cannot.
+
+If undefined, then the program will behave as if @code{DEFAULT} was set.
+
+@item @emph{Reference}:
+@uref{https://www.openmp.org, OpenMP specification v5.0}, Section 6.17
+@end table
+
+
+
@node OMP_THREAD_LIMIT
@section @env{OMP_THREAD_LIMIT} -- Set the maximum number of threads
@cindex Environment Variable
diff --git a/libgomp/target.c b/libgomp/target.c
index ab7ac9b..bb643b3 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -116,7 +116,14 @@ resolve_device (int device_id)
}
if (device_id < 0 || device_id >= gomp_get_num_devices ())
- return NULL;
+ {
+ if (gomp_target_offload_var == GOMP_TARGET_OFFLOAD_MANDATORY
+ && device_id != GOMP_DEVICE_HOST_FALLBACK)
+ gomp_fatal ("OMP_TARGET_OFFLOAD is set to MANDATORY, "
+ "but device not found");
+
+ return NULL;
+ }
gomp_mutex_lock (&devices[device_id].lock);
if (devices[device_id].state == GOMP_DEVICE_UNINITIALIZED)
@@ -124,6 +131,12 @@ resolve_device (int device_id)
else if (devices[device_id].state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devices[device_id].lock);
+
+ if (gomp_target_offload_var == GOMP_TARGET_OFFLOAD_MANDATORY
+ && device_id != GOMP_DEVICE_HOST_FALLBACK)
+ gomp_fatal ("OMP_TARGET_OFFLOAD is set to MANDATORY, "
+ "but device is finalized");
+
return NULL;
}
gomp_mutex_unlock (&devices[device_id].lock);
@@ -1997,9 +2010,16 @@ gomp_unload_device (struct gomp_device_descr *devicep)
/* Host fallback for GOMP_target{,_ext} routines. */
static void
-gomp_target_fallback (void (*fn) (void *), void **hostaddrs)
+gomp_target_fallback (void (*fn) (void *), void **hostaddrs,
+ struct gomp_device_descr *devicep)
{
struct gomp_thread old_thr, *thr = gomp_thread ();
+
+ if (gomp_target_offload_var == GOMP_TARGET_OFFLOAD_MANDATORY
+ && devicep != NULL)
+ gomp_fatal ("OMP_TARGET_OFFLOAD is set to MANDATORY, but device cannot "
+ "be used for offloading");
+
old_thr = *thr;
memset (thr, '\0', sizeof (*thr));
if (gomp_places_list)
@@ -2107,7 +2127,7 @@ GOMP_target (int device, void (*fn) (void *), const void *unused,
/* All shared memory devices should use the GOMP_target_ext function. */
|| devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM
|| !(fn_addr = gomp_get_target_fn_addr (devicep, fn)))
- return gomp_target_fallback (fn, hostaddrs);
+ return gomp_target_fallback (fn, hostaddrs, devicep);
struct target_mem_desc *tgt_vars
= gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false,
@@ -2243,7 +2263,7 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
tgt_align, tgt_size);
}
}
- gomp_target_fallback (fn, hostaddrs);
+ gomp_target_fallback (fn, hostaddrs, devicep);
return;
}
@@ -2276,9 +2296,15 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
/* Host fallback for GOMP_target_data{,_ext} routines. */
static void
-gomp_target_data_fallback (void)
+gomp_target_data_fallback (struct gomp_device_descr *devicep)
{
struct gomp_task_icv *icv = gomp_icv (false);
+
+ if (gomp_target_offload_var == GOMP_TARGET_OFFLOAD_MANDATORY
+ && devicep != NULL)
+ gomp_fatal ("OMP_TARGET_OFFLOAD is set to MANDATORY, but device cannot "
+ "be used for offloading");
+
if (icv->target_data)
{
/* Even when doing a host fallback, if there are any active
@@ -2302,7 +2328,7 @@ GOMP_target_data (int device, const void *unused, size_t mapnum,
if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
|| (devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM))
- return gomp_target_data_fallback ();
+ return gomp_target_data_fallback (devicep);
struct target_mem_desc *tgt
= gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false,
@@ -2321,7 +2347,7 @@ GOMP_target_data_ext (int device, size_t mapnum, void **hostaddrs,
if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
|| devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
- return gomp_target_data_fallback ();
+ return gomp_target_data_fallback (devicep);
struct target_mem_desc *tgt
= gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true,
@@ -2617,7 +2643,7 @@ gomp_target_task_fn (void *data)
|| (devicep->can_run_func && !devicep->can_run_func (fn_addr)))
{
ttask->state = GOMP_TARGET_TASK_FALLBACK;
- gomp_target_fallback (ttask->fn, ttask->hostaddrs);
+ gomp_target_fallback (ttask->fn, ttask->hostaddrs, devicep);
return false;
}
@@ -3258,6 +3284,9 @@ gomp_target_init (void)
num_devices = 0;
devices = NULL;
+ if (gomp_target_offload_var == GOMP_TARGET_OFFLOAD_DISABLED)
+ return;
+
cur = OFFLOAD_PLUGINS;
if (*cur)
do