[OpenMP] Add omp_pause_resource* API
Add omp_pause_resource and omp_pause_resource_all API and enum, plus stub for
internal implementation. Implemented callable helper function to do local pause,
and added basic functionality for hard and soft pause.
Patch by Terry Wilmarth
Differential Revision: https://reviews.llvm.org/D55078
git-svn-id: https://llvm.org/svn/llvm-project/openmp/trunk@351372 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/runtime/src/dllexports b/runtime/src/dllexports
index 9885f87..f0f2ee6 100644
--- a/runtime/src/dllexports
+++ b/runtime/src/dllexports
@@ -406,6 +406,7 @@
# USED FOR 4.5 __kmpc_critical_with_hint 270
__kmpc_get_target_offload 271
__kmpc_omp_reg_task_with_affinity 272
+ __kmpc_pause_resource 273
%endif
%endif
@@ -554,6 +555,8 @@
ompc_get_affinity_format 753
ompc_display_affinity 754
ompc_capture_affinity 755
+ omp_pause_resource 756
+ omp_pause_resource_all 757
OMP_NULL_ALLOCATOR DATA
omp_default_mem_alloc DATA
diff --git a/runtime/src/include/50/omp.h.var b/runtime/src/include/50/omp.h.var
index 872b8f5..09c8cda 100644
--- a/runtime/src/include/50/omp.h.var
+++ b/runtime/src/include/50/omp.h.var
@@ -249,6 +249,15 @@
extern void __KAI_KMPC_CONVENTION omp_display_affinity(char const *);
extern size_t __KAI_KMPC_CONVENTION omp_capture_affinity(char *, size_t, char const *);
+ /* OpenMP 5.0 Pause Resources */
+ typedef enum omp_pause_resource_t {
+ omp_pause_resume = 0,
+ omp_pause_soft = 1,
+ omp_pause_hard = 2
+ } omp_pause_resource_t;
+ extern int __KAI_KMPC_CONVENTION omp_pause_resource(omp_pause_resource_t, int);
+ extern int __KAI_KMPC_CONVENTION omp_pause_resource_all(omp_pause_resource_t);
+
# undef __KAI_KMPC_CONVENTION
# undef __KMP_IMP
diff --git a/runtime/src/include/50/omp_lib.f.var b/runtime/src/include/50/omp_lib.f.var
index bebb6e9..2c534e2 100644
--- a/runtime/src/include/50/omp_lib.f.var
+++ b/runtime/src/include/50/omp_lib.f.var
@@ -36,6 +36,8 @@
integer, parameter :: omp_control_tool_result_kind = omp_integer_kind
integer, parameter :: omp_allocator_kind = int_ptr_kind()
+ integer, parameter :: omp_pause_resource_kind = omp_integer_kind
+
end module omp_lib_kinds
module omp_lib
@@ -83,6 +85,10 @@
integer (kind=omp_allocator_kind), parameter :: omp_pteam_mem_alloc = 7
integer (kind=omp_allocator_kind), parameter :: omp_thread_mem_alloc = 8
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_resume = 0
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_soft = 1
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_hard = 2
+
interface
! ***
@@ -283,6 +289,19 @@
integer (kind=omp_integer_kind) omp_get_device_num
end function omp_get_device_num
+ function omp_pause_resource(kind, device_num)
+ use omp_lib_kinds
+ integer (kind=omp_pause_resource_kind) kind
+ integer (kind=omp_integer_kind) device_num
+ integer (kind=omp_integer_kind) omp_pause_resource
+ end function omp_pause_resource
+
+ function omp_pause_resource_all(kind)
+ use omp_lib_kinds
+ integer (kind=omp_pause_resource_kind) kind
+ integer (kind=omp_integer_kind) omp_pause_resource_all
+ end function omp_pause_resource_all
+
subroutine omp_init_lock(svar)
!DIR$ IF(__INTEL_COMPILER.GE.1400)
!DIR$ attributes known_intrinsic :: omp_init_lock
@@ -621,6 +640,9 @@
!dec$ attributes alias:'OMP_GET_INITIAL_DEVICE' :: omp_get_initial_device
!dec$ attributes alias:'OMP_GET_MAX_TASK_PRIORITY' :: omp_get_max_task_priority
!dec$ attributes alias:'OMP_GET_DEVICE_NUM' :: omp_get_device_num
+!dec$ attributes alias:'OMP_PAUSE_RESOURCE' :: omp_pause_resource
+!dec$ attributes alias:'OMP_PAUSE_RESOURCE_ALL' :: omp_pause_resource_all
+
!dec$ attributes alias:'OMP_CONTROL_TOOL' :: omp_control_tool
!dec$ attributes alias:'OMP_SET_AFFINITY_FORMAT' :: omp_set_affinity_format
!dec$ attributes alias:'OMP_GET_AFFINITY_FORMAT' :: omp_get_affinity_format
@@ -708,6 +730,9 @@
!dec$ attributes alias:'_OMP_GET_INITIAL_DEVICE' :: omp_get_initial_device
!dec$ attributes alias:'_OMP_GET_MAX_TASK_PRIORTY' :: omp_get_max_task_priority
!dec$ attributes alias:'_OMP_GET_DEVICE_NUM' :: omp_get_device_num
+!dec$ attributes alias:'_OMP_PAUSE_RESOURCE' :: omp_pause_resource
+!dec$ attributes alias:'_OMP_PAUSE_RESOURCE_ALL' :: omp_pause_resource_all
+
!dec$ attributes alias:'_OMP_CONTROL_TOOL' :: omp_control_tool
!dec$ attributes alias:'_OMP_SET_AFFINITY_FORMAT' :: omp_set_affinity_format
!dec$ attributes alias:'_OMP_GET_AFFINITY_FORMAT' :: omp_get_affinity_format
@@ -798,6 +823,9 @@
!dec$ attributes alias:'omp_get_initial_device_'::omp_get_initial_device
!dec$ attributes alias:'omp_get_max_task_priority_'::omp_get_max_task_priority
!dec$ attributes alias:'omp_get_device_num_'::omp_get_device_num
+!dec$ attributes alias:'omp_pause_resource_' :: omp_pause_resource
+!dec$ attributes alias:'omp_pause_resource_all_' :: omp_pause_resource_all
+
!dec$ attributes alias:'omp_set_affinity_format_' :: omp_set_affinity_format
!dec$ attributes alias:'omp_get_affinity_format_' :: omp_get_affinity_format
!dec$ attributes alias:'omp_display_affinity_' :: omp_display_affinity
@@ -887,6 +915,9 @@
!dec$ attributes alias:'_omp_get_initial_device_'::omp_get_initial_device
!dec$ attributes alias:'_omp_get_max_task_priorty_'::omp_get_max_task_priority
!dec$ attributes alias:'_omp_get_device_num_'::omp_get_device_num
+!dec$ attributes alias:'_omp_pause_resource_' :: omp_pause_resource
+!dec$ attributes alias:'_omp_pause_resource_all_' :: omp_pause_resource_all
+
!dec$ attributes alias:'_omp_init_lock_'::omp_init_lock
!dec$ attributes alias:'_omp_init_lock_with_hint_'::omp_init_lock_with_hint
!dec$ attributes alias:'_omp_destroy_lock_'::omp_destroy_lock
diff --git a/runtime/src/include/50/omp_lib.f90.var b/runtime/src/include/50/omp_lib.f90.var
index e0233de..a1c0128 100644
--- a/runtime/src/include/50/omp_lib.f90.var
+++ b/runtime/src/include/50/omp_lib.f90.var
@@ -33,6 +33,8 @@
integer, parameter :: omp_control_tool_result_kind = omp_integer_kind
integer, parameter :: omp_allocator_kind = c_intptr_t
+ integer, parameter :: omp_pause_resource_kind = omp_integer_kind
+
end module omp_lib_kinds
module omp_lib
@@ -97,6 +99,10 @@
integer (kind=omp_allocator_kind), parameter :: omp_pteam_mem_alloc = 7
integer (kind=omp_allocator_kind), parameter :: omp_thread_mem_alloc = 8
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_resume = 0
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_soft = 1
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_hard = 2
+
interface
! ***
@@ -299,6 +305,19 @@
integer (kind=omp_integer_kind) omp_get_device_num
end function omp_get_device_num
+ function omp_pause_resource(kind, device_num) bind(c)
+ use omp_lib_kinds
+ integer (kind=omp_pause_resource_kind), value :: kind
+ integer (kind=omp_integer_kind), value :: device_num
+ integer (kind=omp_integer_kind) omp_pause_resource
+ end function omp_pause_resource
+
+ function omp_pause_resource_all(kind) bind(c)
+ use omp_lib_kinds
+ integer (kind=omp_pause_resource_kind), value :: kind
+ integer (kind=omp_integer_kind) omp_pause_resource_all
+ end function omp_pause_resource_all
+
subroutine omp_init_lock(svar) bind(c)
!DIR$ IF(__INTEL_COMPILER.GE.1400)
!DIR$ attributes known_intrinsic :: omp_init_lock
diff --git a/runtime/src/include/50/omp_lib.h.var b/runtime/src/include/50/omp_lib.h.var
index 605b410..fe6716b 100644
--- a/runtime/src/include/50/omp_lib.h.var
+++ b/runtime/src/include/50/omp_lib.h.var
@@ -41,6 +41,7 @@
parameter(omp_control_tool_result_kind=omp_integer_kind)
integer omp_allocator_kind
parameter(omp_allocator_kind=int_ptr_kind())
+ integer, parameter :: omp_pause_resource_kind = omp_integer_kind
integer(kind=omp_integer_kind)openmp_version
parameter(openmp_version=@LIBOMP_OMP_YEAR_MONTH@)
@@ -137,6 +138,10 @@
integer(kind=omp_allocator_kind)omp_thread_mem_alloc
parameter(omp_thread_mem_alloc=8)
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_resume = 0
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_soft = 1
+ integer (kind=omp_pause_resource_kind), parameter :: omp_pause_hard = 2
+
interface
! ***
@@ -332,6 +337,19 @@
integer (kind=omp_integer_kind) omp_get_device_num
end function omp_get_device_num
+ function omp_pause_resource(kind, device_num) bind(c)
+ import
+ integer (kind=omp_pause_resource_kind), value :: kind
+ integer (kind=omp_integer_kind), value :: device_num
+ integer (kind=omp_integer_kind) omp_pause_resource
+ end function omp_pause_resource
+
+ function omp_pause_resource_all(kind) bind(c)
+ import
+ integer (kind=omp_pause_resource_kind), value :: kind
+ integer (kind=omp_integer_kind) omp_pause_resource_all
+ end function omp_pause_resource_all
+
subroutine omp_init_lock(svar) bind(c)
!DIR$ IF(__INTEL_COMPILER.GE.1400)
!DIR$ attributes known_intrinsic :: omp_init_lock
@@ -652,6 +670,8 @@
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_initial_device
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_num_devices
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_device_num
+!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_pause_resource
+!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_pause_resource_all
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_num_teams
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_team_num
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_init_lock
@@ -731,6 +751,8 @@
!$omp declare target(omp_get_initial_device )
!$omp declare target(omp_get_num_devices )
!$omp declare target(omp_get_device_num )
+!$omp declare target(omp_pause_resource )
+!$omp declare target(omp_pause_resource_all )
!$omp declare target(omp_get_num_teams )
!$omp declare target(omp_get_team_num )
!$omp declare target(omp_init_lock )
diff --git a/runtime/src/kmp.h b/runtime/src/kmp.h
index 599cbf2..8c0913c 100644
--- a/runtime/src/kmp.h
+++ b/runtime/src/kmp.h
@@ -3467,6 +3467,10 @@
extern void __kmp_reap_worker(kmp_info_t *th);
extern void __kmp_terminate_thread(int gtid);
+extern int __kmp_try_suspend_mx(kmp_info_t *th);
+extern void __kmp_lock_suspend_mx(kmp_info_t *th);
+extern void __kmp_unlock_suspend_mx(kmp_info_t *th);
+
extern void __kmp_suspend_32(int th_gtid, kmp_flag_32 *flag);
extern void __kmp_suspend_64(int th_gtid, kmp_flag_64 *flag);
extern void __kmp_suspend_oncore(int th_gtid, kmp_flag_oncore *flag);
@@ -4007,6 +4011,33 @@
#define KMP_DEVICE_ALL -11 // This is libomptarget's "all devices".
#endif // OMP_40_ENABLED
+#if OMP_50_ENABLED
+// OMP Pause Resource
+
+// The following enum is used both to set the status in __kmp_pause_status, and
+// as the internal equivalent of the externally-visible omp_pause_resource_t.
+typedef enum kmp_pause_status_t {
+ kmp_not_paused = 0, // status is not paused, or, requesting resume
+ kmp_soft_paused = 1, // status is soft-paused, or, requesting soft pause
+ kmp_hard_paused = 2 // status is hard-paused, or, requesting hard pause
+} kmp_pause_status_t;
+
+// This stores the pause state of the runtime
+extern kmp_pause_status_t __kmp_pause_status;
+extern int __kmpc_pause_resource(kmp_pause_status_t level);
+extern int __kmp_pause_resource(kmp_pause_status_t level);
+// Soft resume sets __kmp_pause_status, and wakes up all threads.
+extern void __kmp_resume_if_soft_paused();
+// Hard resume simply resets the status to not paused. Library will appear to
+// be uninitialized after hard pause. Let OMP constructs trigger required
+// initializations.
+static inline void __kmp_resume_if_hard_paused() {
+ if (__kmp_pause_status == kmp_hard_paused) {
+ __kmp_pause_status = kmp_not_paused;
+ }
+}
+#endif // OMP_50_ENABLED
+
#ifdef __cplusplus
}
#endif
diff --git a/runtime/src/kmp_csupport.cpp b/runtime/src/kmp_csupport.cpp
index 61d4a93..b5f65fa 100644
--- a/runtime/src/kmp_csupport.cpp
+++ b/runtime/src/kmp_csupport.cpp
@@ -485,6 +485,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
this_thr = __kmp_threads[global_tid];
serial_team = this_thr->th.th_serial_team;
@@ -696,6 +700,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
if (__kmp_env_consistency_check) {
if (loc == 0) {
KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
@@ -744,6 +752,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
if (KMP_MASTER_GTID(global_tid)) {
KMP_COUNT_BLOCK(OMP_MASTER);
KMP_PUSH_PARTITIONED_TIMER(OMP_master);
@@ -834,6 +846,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
#if USE_ITT_BUILD
__kmp_itt_ordered_prep(gtid);
// TODO: ordered_wait_id
@@ -1590,6 +1606,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
if (__kmp_env_consistency_check)
__kmp_check_barrier(global_tid, ct_barrier, loc);
@@ -1648,6 +1668,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
if (__kmp_env_consistency_check) {
if (loc == 0) {
KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
@@ -3366,6 +3390,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
// check correctness of reduce block nesting
#if KMP_USE_DYNAMIC_LOCK
if (__kmp_env_consistency_check)
@@ -3586,6 +3614,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
// check correctness of reduce block nesting
#if KMP_USE_DYNAMIC_LOCK
if (__kmp_env_consistency_check)
@@ -4159,6 +4191,13 @@
}
return __kmp_target_offload;
}
+
+int __kmpc_pause_resource(kmp_pause_status_t level) {
+ if (!__kmp_init_serial) {
+ return 1; // Can't pause if runtime is not initialized
+ }
+ return __kmp_pause_resource(level);
+}
#endif // OMP_50_ENABLED
// end of file //
diff --git a/runtime/src/kmp_dispatch.cpp b/runtime/src/kmp_dispatch.cpp
index 1090e9d..b957c56 100644
--- a/runtime/src/kmp_dispatch.cpp
+++ b/runtime/src/kmp_dispatch.cpp
@@ -740,6 +740,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
#if INCLUDE_SSC_MARKS
SSC_MARK_DISPATCH_INIT();
#endif
diff --git a/runtime/src/kmp_dispatch_hier.h b/runtime/src/kmp_dispatch_hier.h
index 8277eaa..48b164e 100644
--- a/runtime/src/kmp_dispatch_hier.h
+++ b/runtime/src/kmp_dispatch_hier.h
@@ -924,6 +924,10 @@
KMP_DEBUG_ASSERT(new_chunks);
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
th = __kmp_threads[gtid];
team = th->th.th_team;
active = !team->t.t_serialized;
diff --git a/runtime/src/kmp_ftn_entry.h b/runtime/src/kmp_ftn_entry.h
index c08e31b..09be9ba 100644
--- a/runtime/src/kmp_ftn_entry.h
+++ b/runtime/src/kmp_ftn_entry.h
@@ -1332,6 +1332,42 @@
// Compiler/libomptarget will handle this if called inside target.
int FTN_STDCALL FTN_GET_DEVICE_NUM(void) KMP_WEAK_ATTRIBUTE;
int FTN_STDCALL FTN_GET_DEVICE_NUM(void) { return KMP_HOST_DEVICE; }
+
+// Compiler will ensure that this is only called from host in sequential region
+int FTN_STDCALL FTN_PAUSE_RESOURCE(kmp_pause_status_t kind, int device_num) {
+#ifdef KMP_STUB
+ return 1; // just fail
+#else
+ if (device_num == KMP_HOST_DEVICE)
+ return __kmpc_pause_resource(kind);
+ else {
+#if !KMP_OS_WINDOWS
+ int (*fptr)(kmp_pause_status_t, int);
+ if ((*(void **)(&fptr) = dlsym(RTLD_DEFAULT, "tgt_pause_resource")))
+ return (*fptr)(kind, device_num);
+ else
+#endif
+ return 1; // just fail if there is no libomptarget
+ }
+#endif
+}
+
+// Compiler will ensure that this is only called from host in sequential region
+int FTN_STDCALL FTN_PAUSE_RESOURCE_ALL(kmp_pause_status_t kind) {
+#ifdef KMP_STUB
+ return 1; // just fail
+#else
+ int fails = 0;
+#if !KMP_OS_WINDOWS
+ int (*fptr)(kmp_pause_status_t, int);
+ if ((*(void **)(&fptr) = dlsym(RTLD_DEFAULT, "tgt_pause_resource")))
+ fails = (*fptr)(kind, KMP_DEVICE_ALL); // pause devices
+#endif
+ fails += __kmpc_pause_resource(kind); // pause host
+ return fails;
+#endif
+}
+
#endif // OMP_50_ENABLED
// GCC compatibility (versioned symbols)
@@ -1435,6 +1471,8 @@
#if OMP_50_ENABLED
// OMP_5.0 versioned symbols
// KMP_VERSION_SYMBOL(FTN_GET_DEVICE_NUM, 50, "OMP_5.0");
+// KMP_VERSION_SYMBOL(FTN_PAUSE_RESOURCE, 50, "OMP_5.0");
+// KMP_VERSION_SYMBOL(FTN_PAUSE_RESOURCE_ALL, 50, "OMP_5.0");
#endif
#endif // KMP_USE_VERSION_SYMBOLS
diff --git a/runtime/src/kmp_ftn_os.h b/runtime/src/kmp_ftn_os.h
index 776db39..33f1309 100644
--- a/runtime/src/kmp_ftn_os.h
+++ b/runtime/src/kmp_ftn_os.h
@@ -142,6 +142,8 @@
#define FTN_GET_AFFINITY_FORMAT omp_get_affinity_format
#define FTN_DISPLAY_AFFINITY omp_display_affinity
#define FTN_CAPTURE_AFFINITY omp_capture_affinity
+#define FTN_PAUSE_RESOURCE omp_pause_resource
+#define FTN_PAUSE_RESOURCE_ALL omp_pause_resource_all
#endif
#endif /* KMP_FTN_PLAIN */
@@ -271,6 +273,8 @@
#define FTN_GET_AFFINITY_FORMAT omp_get_affinity_format_
#define FTN_DISPLAY_AFFINITY omp_display_affinity_
#define FTN_CAPTURE_AFFINITY omp_capture_affinity_
+#define FTN_PAUSE_RESOURCE omp_pause_resource_
+#define FTN_PAUSE_RESOURCE_ALL omp_pause_resource_all_
#endif
#endif /* KMP_FTN_APPEND */
@@ -400,6 +404,8 @@
#define FTN_GET_AFFINITY_FORMAT OMP_GET_AFFINITY_FORMAT
#define FTN_DISPLAY_AFFINITY OMP_DISPLAY_AFFINITY
#define FTN_CAPTURE_AFFINITY OMP_CAPTURE_AFFINITY
+#define FTN_PAUSE_RESOURCE OMP_PAUSE_RESOURCE
+#define FTN_PAUSE_RESOURCE_ALL OMP_PAUSE_RESOURCE_ALL
#endif
#endif /* KMP_FTN_UPPER */
@@ -529,6 +535,8 @@
#define FTN_GET_AFFINITY_FORMAT OMP_GET_AFFINITY_FORMAT_
#define FTN_DISPLAY_AFFINITY OMP_DISPLAY_AFFINITY_
#define FTN_CAPTURE_AFFINITY OMP_CAPTURE_AFFINITY_
+#define FTN_PAUSE_RESOURCE OMP_PAUSE_RESOURCE_
+#define FTN_PAUSE_RESOURCE_ALL OMP_PAUSE_RESOURCE_ALL_
#endif
#endif /* KMP_FTN_UAPPEND */
diff --git a/runtime/src/kmp_global.cpp b/runtime/src/kmp_global.cpp
index 5f38009..37903a6 100644
--- a/runtime/src/kmp_global.cpp
+++ b/runtime/src/kmp_global.cpp
@@ -533,5 +533,9 @@
#if OMP_50_ENABLED
kmp_target_offload_kind_t __kmp_target_offload = tgt_default;
-#endif
+
+// OMP Pause Resources
+kmp_pause_status_t __kmp_pause_status = kmp_not_paused;
+#endif // OMP_50_ENABLED
+
// end of file //
diff --git a/runtime/src/kmp_gsupport.cpp b/runtime/src/kmp_gsupport.cpp
index c1f9bdd..33b0ebe 100644
--- a/runtime/src/kmp_gsupport.cpp
+++ b/runtime/src/kmp_gsupport.cpp
@@ -120,6 +120,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
// 3rd parameter == FALSE prevents kmp_enter_single from pushing a
// workshare when USE_CHECKS is defined. We need to avoid the push,
// as there is no corresponding GOMP_single_end() call.
@@ -168,6 +172,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
// If this is the first thread to enter, return NULL. The generated code will
// then call GOMP_single_copy_end() for this thread only, with the
// copyprivate data pointer as an argument.
diff --git a/runtime/src/kmp_runtime.cpp b/runtime/src/kmp_runtime.cpp
index 0db3761..821012b 100644
--- a/runtime/src/kmp_runtime.cpp
+++ b/runtime/src/kmp_runtime.cpp
@@ -752,6 +752,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
th = __kmp_threads[gtid];
team = th->th.th_team;
status = 0;
@@ -1189,6 +1193,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
this_thr = __kmp_threads[global_tid];
serial_team = this_thr->th.th_serial_team;
@@ -1492,6 +1500,10 @@
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
+#if OMP_50_ENABLED
+ __kmp_resume_if_soft_paused();
+#endif
+
/* setup current data */
master_th = __kmp_threads[gtid]; // AC: potentially unsafe, not in sync with
// shutdown
@@ -5851,7 +5863,6 @@
gtid = thread->th.th_info.ds.ds_gtid;
if (!is_root) {
-
if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
/* Assume the threads are at the fork barrier here */
KA_TRACE(
@@ -6272,8 +6283,10 @@
// OM: Removed Linux* OS restriction to fix the crash on OS X* (DPD200239966)
// and Windows(DPD200287443) that occurs when using critical sections from
// foreign threads.
- KA_TRACE(10, ("__kmp_internal_end_thread: exiting T#%d\n", gtid_req));
- return;
+ if (__kmp_pause_status != kmp_hard_paused) {
+ KA_TRACE(10, ("__kmp_internal_end_thread: exiting T#%d\n", gtid_req));
+ return;
+ }
#endif
/* synchronize the termination process */
__kmp_acquire_bootstrap_lock(&__kmp_initz_lock);
@@ -6920,6 +6933,10 @@
__kmp_do_middle_initialize();
}
+#if OMP_50_ENABLED
+ __kmp_resume_if_hard_paused();
+#endif
+
/* begin initialization */
KA_TRACE(10, ("__kmp_parallel_initialize: enter\n"));
KMP_ASSERT(KMP_UBER_GTID(gtid));
@@ -8190,3 +8207,82 @@
kmp_int32 __kmp_get_reduce_method(void) {
return ((__kmp_entry_thread()->th.th_local.packed_reduction_method) >> 8);
}
+
+#if OMP_50_ENABLED
+
+// Soft pause sets up threads to ignore blocktime and just go to sleep.
+// Spin-wait code checks __kmp_pause_status and reacts accordingly.
+void __kmp_soft_pause() { __kmp_pause_status = kmp_soft_paused; }
+
+// Hard pause shuts down the runtime completely. Resume happens naturally when
+// OpenMP is used subsequently.
+void __kmp_hard_pause() {
+ __kmp_pause_status = kmp_hard_paused;
+ __kmp_internal_end_thread(-1);
+}
+
+// Soft resume sets __kmp_pause_status, and wakes up all threads.
+void __kmp_resume_if_soft_paused() {
+ if (__kmp_pause_status == kmp_soft_paused) {
+ __kmp_pause_status = kmp_not_paused;
+
+ for (int gtid = 1; gtid < __kmp_threads_capacity; ++gtid) {
+ kmp_info_t *thread = __kmp_threads[gtid];
+ if (thread) { // Wake it if sleeping
+ kmp_flag_64 fl(&thread->th.th_bar[bs_forkjoin_barrier].bb.b_go, thread);
+ if (fl.is_sleeping())
+ fl.resume(gtid);
+ else if (__kmp_try_suspend_mx(thread)) { // got suspend lock
+ __kmp_unlock_suspend_mx(thread); // unlock it; it won't sleep
+ } else { // thread holds the lock and may sleep soon
+ do { // until either the thread sleeps, or we can get the lock
+ if (fl.is_sleeping()) {
+ fl.resume(gtid);
+ break;
+ } else if (__kmp_try_suspend_mx(thread)) {
+ __kmp_unlock_suspend_mx(thread);
+ break;
+ }
+ } while (1);
+ }
+ }
+ }
+ }
+}
+
+// This function is called via __kmpc_pause_resource. Returns 0 if successful.
+// TODO: add warning messages
+int __kmp_pause_resource(kmp_pause_status_t level) {
+ if (level == kmp_not_paused) { // requesting resume
+ if (__kmp_pause_status == kmp_not_paused) {
+ // error message about runtime not being paused, so can't resume
+ return 1;
+ } else {
+ KMP_DEBUG_ASSERT(__kmp_pause_status == kmp_soft_paused ||
+ __kmp_pause_status == kmp_hard_paused);
+ __kmp_pause_status = kmp_not_paused;
+ return 0;
+ }
+ } else if (level == kmp_soft_paused) { // requesting soft pause
+ if (__kmp_pause_status != kmp_not_paused) {
+ // error message about already being paused
+ return 1;
+ } else {
+ __kmp_soft_pause();
+ return 0;
+ }
+ } else if (level == kmp_hard_paused) { // requesting hard pause
+ if (__kmp_pause_status != kmp_not_paused) {
+ // error message about already being paused
+ return 1;
+ } else {
+ __kmp_hard_pause();
+ return 0;
+ }
+ } else {
+ // error message about invalid level
+ return 1;
+ }
+}
+
+#endif // OMP_50_ENABLED
diff --git a/runtime/src/kmp_tasking.cpp b/runtime/src/kmp_tasking.cpp
index 7292ed1..084583e 100644
--- a/runtime/src/kmp_tasking.cpp
+++ b/runtime/src/kmp_tasking.cpp
@@ -2839,7 +2839,7 @@
threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
KMP_DEBUG_ASSERT(threads_data != NULL);
- if ((__kmp_tasking_mode == tskm_task_teams) &&
+ if (__kmp_tasking_mode == tskm_task_teams &&
(__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME)) {
// Release any threads sleeping at the barrier, so that they can steal
// tasks and execute them. In extra barrier mode, tasks do not sleep
diff --git a/runtime/src/kmp_wait_release.h b/runtime/src/kmp_wait_release.h
index dd56c88..5cd7b9a 100644
--- a/runtime/src/kmp_wait_release.h
+++ b/runtime/src/kmp_wait_release.h
@@ -268,12 +268,20 @@
// Setup for waiting
KMP_INIT_YIELD(spins);
- if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
+ if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME
+#if OMP_50_ENABLED
+ || __kmp_pause_status == kmp_soft_paused
+#endif
+ ) {
#if KMP_USE_MONITOR
// The worker threads cannot rely on the team struct existing at this point.
// Use the bt values cached in the thread struct instead.
#ifdef KMP_ADJUST_BLOCKTIME
- if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
+ if (
+#if OMP_50_ENABLED
+ __kmp_pause_status == kmp_soft_paused ||
+#endif
+ (__kmp_zero_bt && !this_thr->th.th_team_bt_set))
// Force immediate suspend if not set by user and more threads than
// available procs
hibernate = 0;
@@ -296,7 +304,13 @@
th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
hibernate - __kmp_global.g.g_time.dt.t_value));
#else
- hibernate_goal = KMP_NOW() + this_thr->th.th_team_bt_intervals;
+#if OMP_50_ENABLED
+ if (__kmp_pause_status == kmp_soft_paused) {
+ // Force immediate suspend
+ hibernate_goal = KMP_NOW();
+ } else
+#endif
+ hibernate_goal = KMP_NOW() + this_thr->th.th_team_bt_intervals;
poll_count = 0;
#endif // KMP_USE_MONITOR
}
@@ -389,7 +403,11 @@
#endif
// Don't suspend if KMP_BLOCKTIME is set to "infinite"
- if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
+ if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME
+#if OMP_50_ENABLED
+ && __kmp_pause_status != kmp_soft_paused
+#endif
+ )
continue;
// Don't suspend if there is a likelihood of new tasks being spawned.
@@ -405,7 +423,14 @@
continue;
#endif
+#if OMP_50_ENABLED
+ if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
+ __kmp_pause_status != kmp_soft_paused)
+ continue;
+#endif
+
KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
+
#if KMP_OS_UNIX
if (final_spin)
KMP_ATOMIC_ST_REL(&this_thr->th.th_blocking, false);
diff --git a/runtime/src/z_Linux_util.cpp b/runtime/src/z_Linux_util.cpp
index aa0302c..eb6c3c0 100644
--- a/runtime/src/z_Linux_util.cpp
+++ b/runtime/src/z_Linux_util.cpp
@@ -1414,6 +1414,21 @@
}
}
+// return true if lock obtained, false otherwise
+int __kmp_try_suspend_mx(kmp_info_t *th) {
+ return (pthread_mutex_trylock(&th->th.th_suspend_mx.m_mutex) == 0);
+}
+
+void __kmp_lock_suspend_mx(kmp_info_t *th) {
+ int status = pthread_mutex_lock(&th->th.th_suspend_mx.m_mutex);
+ KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
+}
+
+void __kmp_unlock_suspend_mx(kmp_info_t *th) {
+ int status = pthread_mutex_unlock(&th->th.th_suspend_mx.m_mutex);
+ KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
+}
+
/* This routine puts the calling thread to sleep after setting the
sleep bit for the indicated flag variable to true. */
template <class C>
@@ -1437,7 +1452,15 @@
/* TODO: shouldn't this use release semantics to ensure that
__kmp_suspend_initialize_thread gets called first? */
old_spin = flag->set_sleeping();
-
+#if OMP_50_ENABLED
+ if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
+ __kmp_pause_status != kmp_soft_paused) {
+ flag->unset_sleeping();
+ status = pthread_mutex_unlock(&th->th.th_suspend_mx.m_mutex);
+ KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
+ return;
+ }
+#endif
KF_TRACE(5, ("__kmp_suspend_template: T#%d set sleep bit for spin(%p)==%x,"
" was %x\n",
th_gtid, flag->get(), flag->load(), old_spin));
diff --git a/runtime/src/z_Windows_NT_util.cpp b/runtime/src/z_Windows_NT_util.cpp
index f3d667f..8b8891a 100644
--- a/runtime/src/z_Windows_NT_util.cpp
+++ b/runtime/src/z_Windows_NT_util.cpp
@@ -159,6 +159,10 @@
EnterCriticalSection(&mx->cs);
}
+int __kmp_win32_mutex_trylock(kmp_win32_mutex_t *mx) {
+ return TryEnterCriticalSection(&mx->cs);
+}
+
void __kmp_win32_mutex_unlock(kmp_win32_mutex_t *mx) {
LeaveCriticalSection(&mx->cs);
}
@@ -300,6 +304,18 @@
}
}
+int __kmp_try_suspend_mx(kmp_info_t *th) {
+ return __kmp_win32_mutex_trylock(&th->th.th_suspend_mx);
+}
+
+void __kmp_lock_suspend_mx(kmp_info_t *th) {
+ __kmp_win32_mutex_lock(&th->th.th_suspend_mx);
+}
+
+void __kmp_unlock_suspend_mx(kmp_info_t *th) {
+ __kmp_win32_mutex_unlock(&th->th.th_suspend_mx);
+}
+
/* This routine puts the calling thread to sleep after setting the
sleep bit for the indicated flag variable to true. */
template <class C>
@@ -321,6 +337,14 @@
/* TODO: shouldn't this use release semantics to ensure that
__kmp_suspend_initialize_thread gets called first? */
old_spin = flag->set_sleeping();
+#if OMP_50_ENABLED
+ if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
+ __kmp_pause_status != kmp_soft_paused) {
+ flag->unset_sleeping();
+ __kmp_win32_mutex_unlock(&th->th.th_suspend_mx);
+ return;
+ }
+#endif
KF_TRACE(5, ("__kmp_suspend_template: T#%d set sleep bit for flag's"
" loc(%p)==%d\n",
diff --git a/runtime/test/api/omp_pause_resource.c b/runtime/test/api/omp_pause_resource.c
new file mode 100644
index 0000000..32c1120
--- /dev/null
+++ b/runtime/test/api/omp_pause_resource.c
@@ -0,0 +1,58 @@
+// RUN: %libomp-compile-and-run
+#include <stdio.h>
+#include "omp_testsuite.h"
+
+int test_omp_pause_resource() {
+ int fails, nthreads, my_dev;
+
+ fails = 0;
+ nthreads = 0;
+ my_dev = omp_get_initial_device();
+
+#pragma omp parallel
+#pragma omp single
+ nthreads = omp_get_num_threads();
+
+ if (omp_pause_resource(omp_pause_soft, my_dev))
+ fails++;
+
+#pragma omp parallel shared(nthreads)
+#pragma omp single
+ nthreads = omp_get_num_threads();
+
+ if (nthreads == 0)
+ fails++;
+ if (omp_pause_resource(omp_pause_hard, my_dev))
+ fails++;
+ nthreads = 0;
+
+#pragma omp parallel shared(nthreads)
+#pragma omp single
+ nthreads = omp_get_num_threads();
+
+ if (nthreads == 0)
+ fails++;
+ if (omp_pause_resource_all(omp_pause_soft))
+ fails++;
+ nthreads = 0;
+
+#pragma omp parallel shared(nthreads)
+#pragma omp single
+ nthreads = omp_get_num_threads();
+
+ if (nthreads == 0)
+ fails++;
+ return fails == 0;
+}
+
+int main() {
+ int i;
+ int num_failed = 0;
+
+ for (i = 0; i < REPETITIONS; i++) {
+ if (!test_omp_pause_resource()) {
+ num_failed++;
+ }
+ }
+ return num_failed;
+}