Index: libomptarget/src/interface.cpp =================================================================== --- libomptarget/src/interface.cpp +++ libomptarget/src/interface.cpp @@ -21,6 +21,40 @@ #include #include +static inline void checkOffloadResult(int rc) { + if (rc == OFFLOAD_SUCCESS) { + HasSuccessfulRuns = true; + } else { // if (rc == OFFLOAD_FAIL) + if (!HasSuccessfulRuns) { + fprintf(stderr, "WARNING: Target offload failure, falling back to the " + "host\n"); + HostFallback = true; + } else { + fprintf(stderr, "WARNING: Target offload failure after offload success, " + "terminating application due to possible inconsistent state of data" + "\n"); + exit(OFFLOAD_FAIL); + } + } +} + +#define CHECK_HOST_FALLBACK_DATA() \ + { \ + if (HostFallback) { \ + DP("Execution has fallen back to the host, ignoring \"target data\", " \ + "\"target enter/exit data\" or \"target update\"\n"); \ + return; \ + } \ + } +#define CHECK_HOST_FALLBACK_TARGET() \ + { \ + if (HostFallback) { \ + DP("Execution has fallen back to the host, returning immediately from " \ + "__tgt_target call\n"); \ + return OFFLOAD_FAIL; \ + } \ + } + //////////////////////////////////////////////////////////////////////////////// /// adds a target shared library to the target execution image EXTERN void __tgt_register_lib(__tgt_bin_desc *desc) { @@ -260,6 +294,7 @@ /// and passes the data to the device. EXTERN void __tgt_target_data_begin(int64_t device_id, int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) { + CHECK_HOST_FALLBACK_DATA(); DP("Entering data begin region for device %ld with %d mappings\n", device_id, arg_num); @@ -310,6 +345,7 @@ /// created by the last __tgt_target_data_begin. EXTERN void __tgt_target_data_end(int64_t device_id, int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) { + CHECK_HOST_FALLBACK_DATA(); DP("Entering data end region with %d mappings\n", arg_num); // No devices available? @@ -362,6 +398,7 @@ EXTERN void __tgt_target_data_update(int64_t device_id, int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) { + CHECK_HOST_FALLBACK_DATA(); DP("Entering data update with %d mappings\n", arg_num); // No devices available? @@ -391,6 +428,7 @@ EXTERN int __tgt_target(int64_t device_id, void *host_ptr, int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) { + CHECK_HOST_FALLBACK_TARGET(); DP("Entering target region with entry point " DPxMOD " and device Id %ld\n", DPxPTR(host_ptr), device_id); @@ -421,6 +459,7 @@ cleanup_map(new_arg_num, new_args_base, new_args, new_arg_sizes, new_arg_types, arg_num, args_base); + checkOffloadResult(rc); return rc; } @@ -438,6 +477,7 @@ EXTERN int __tgt_target_teams(int64_t device_id, void *host_ptr, int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types, int32_t team_num, int32_t thread_limit) { + CHECK_HOST_FALLBACK_TARGET(); DP("Entering target region with entry point " DPxMOD " and device Id %ld\n", DPxPTR(host_ptr), device_id); @@ -469,6 +509,7 @@ cleanup_map(new_arg_num, new_args_base, new_args, new_arg_sizes, new_arg_types, arg_num, args_base); + checkOffloadResult(rc); return rc; } Index: libomptarget/src/omptarget.cpp =================================================================== --- libomptarget/src/omptarget.cpp +++ libomptarget/src/omptarget.cpp @@ -25,6 +25,14 @@ int DebugLevel = 0; #endif // OMPTARGET_DEBUG +// Variables that control the behavior of libomptarget in case of offload +// failure. It is OK to always fail (we can safely fall back to the host, since +// data on the host is up to date). It is not OK to succeed at first and then +// fail, as the most up to date data might be on the device, so falling back to +// the host is not guaranteed to yield correct results. +bool HasSuccessfulRuns = false; +bool HostFallback = false; + /// Map global data and execute pending ctors static int InitLibrary(DeviceTy& Device) { /* Index: libomptarget/src/private.h =================================================================== --- libomptarget/src/private.h +++ libomptarget/src/private.h @@ -46,4 +46,7 @@ #define DP(...) {} #endif // OMPTARGET_DEBUG +extern bool HasSuccessfulRuns; +extern bool HostFallback; + #endif Index: libomptarget/src/rtl.cpp =================================================================== --- libomptarget/src/rtl.cpp +++ libomptarget/src/rtl.cpp @@ -45,6 +45,13 @@ } #endif // OMPTARGET_DEBUG + // Parse environment variable LIBOMPTARGET_FORCE_TERMINATION + if (char *envStr = getenv("LIBOMPTARGET_FORCE_TERMINATION")) { + // Pretend that we have had a successful target execution already in order + // to force the library terminate the application. + HasSuccessfulRuns = std::stoi(envStr) > 0; + } + // Parse environment variable OMP_TARGET_OFFLOAD (if set) char *envStr = getenv("OMP_TARGET_OFFLOAD"); if (envStr && !strcmp(envStr, "DISABLED")) {