This patch adds documentation and DejaGNU test cases for GOMP_WAIT_POLICY, a new
GCC-specific environment variable extending OMP_WAIT_POLICY to support the
paravirtualized pv-barrier-sync policy (GOMP_WAIT_POLICY=pvsched), as well as
ACTIVE and PASSIVE wait policies.
The documentation in libgomp.texi describes the behavior of pv-barrier-sync:
when no phantom vCPUs are detected (phantom_average == 0), spinning is
maximized at barriers to achieve faster synchronization; as soon as host-side
vCPU contention is detected (phantom_average > 0), threads block immediately to
prevent wasting CPU cycles. The documentation also notes that initialization
errors or policy conflicts safely fall back to the default OMP_WAIT_POLICY.
The install documentation in install.texi notes the requirement for SystemTap
SDT
headers (sys/sdt.h) to build USDT tracing probes.
The test cases in libgomp/testsuite/libgomp.c/ verify:
- Parsing of active, passive, and pvsched policies.
- Case-insensitive parsing of policy keywords.
- Proper fallback to default wait policy on invalid values, device/mmap
initialization failures, or conflicting OMP_WAIT_POLICY settings.
gcc/ChangeLog:
* doc/install.texi: Document SystemTap SDT headers dependency
(sys/sdt.h) for libgomp USDT probes.
libgomp/ChangeLog:
* libgomp.texi: Add documentation for GOMP_WAIT_POLICY environment
variable and pv-barrier-sync policy.
* testsuite/libgomp.c/pvsched_wait_policy-1.c: New test.
* testsuite/libgomp.c/pvsched_wait_policy-2.c: New test.
* testsuite/libgomp.c/pvsched_wait_policy-3.c: New test.
* testsuite/libgomp.c/pvsched_wait_policy-4.c: New test.
* testsuite/libgomp.c/pvsched_wait_policy-5.c: New test.
---
gcc/doc/install.texi | 9 ++++
libgomp/libgomp.texi | 46 ++++++++++++++++++-
.../libgomp.c/pvsched_wait_policy-1.c | 20 ++++++++
.../libgomp.c/pvsched_wait_policy-2.c | 17 +++++++
.../libgomp.c/pvsched_wait_policy-3.c | 23 ++++++++++
.../libgomp.c/pvsched_wait_policy-4.c | 25 ++++++++++
.../libgomp.c/pvsched_wait_policy-5.c | 21 +++++++++
7 files changed, 160 insertions(+), 1 deletion(-)
create mode 100644 libgomp/testsuite/libgomp.c/pvsched_wait_policy-1.c
create mode 100644 libgomp/testsuite/libgomp.c/pvsched_wait_policy-2.c
create mode 100644 libgomp/testsuite/libgomp.c/pvsched_wait_policy-3.c
create mode 100644 libgomp/testsuite/libgomp.c/pvsched_wait_policy-4.c
create mode 100644 libgomp/testsuite/libgomp.c/pvsched_wait_policy-5.c
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 4e4c40edf84..159eb0cac04 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -491,6 +491,15 @@ Necessary to build GCC with zstd compression used for LTO
bytecode.
The library is searched in your default library patch search.
Alternatively, the @option{--with-zstd} configure option should be used.
+@item SystemTap SDT headers (@file{sys/sdt.h}), packaged as
+@samp{systemtap-sdt-dev} on Debian/Ubuntu or @samp{systemtap-sdt-devel}
+on Fedora/RHEL.
+
+Necessary to build libgomp's Userspace Statically Defined Tracing
+(USDT) probes, used by Phantom Tracker and other eBPF-based tooling to
+observe libgomp's OpenMP thread lifecycle and the pv-barrier-sync wait
+policy without relying on non-exported internal symbols.
+
@item Python3 modules
The complete list of Python3 modules broken down by GCC subcomponent
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index dd3e7de924c..8b7933198d0 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -4016,6 +4016,7 @@ variable is not set.
* GOMP_DEBUG:: Enable debugging output
* GOMP_STACKSIZE:: Set default thread stack size
* GOMP_SPINCOUNT:: Set the busy-wait spin count
+* GOMP_WAIT_POLICY:: Select the phantom-guided wait policy
* GOMP_RTEMS_THREAD_POOLS:: Set the RTEMS specific thread pools
* GOMP_REVERSE_OFFLOAD_THREADS:: Set the maximum number of host threads
@end menu
@@ -4690,7 +4691,50 @@ undefined, respectively; unless the @env{GOMP_SPINCOUNT}
is lower
or @env{OMP_WAIT_POLICY} is @code{PASSIVE}.
@item @emph{See also}:
-@ref{OMP_WAIT_POLICY}
+@ref{OMP_WAIT_POLICY}, @ref{GOMP_WAIT_POLICY}
+@end table
+
+
+
+@node GOMP_WAIT_POLICY
+@section @env{GOMP_WAIT_POLICY} -- Select the phantom-guided wait policy
+@cindex Environment Variable
+@cindex Implementation specific setting
+@table @asis
+@item @emph{Description}:
+GCC-specific extension of the OpenMP @env{OMP_WAIT_POLICY} ICV.
+libgomp's default spin/block behavior at barriers.
+
+When set to @code{PVSCHED}, @env{GOMP_WAIT_POLICY} enables
+@code{pv-barrier-sync}, a paravirtualized barrier synchronization
+policy: it overrides the normal fixed spin/block behavior so that a
+thread spins at every barrier and, on every spin iteration, checks a
+host-provided metric called @code{phantom_average} (a time-weighted
+average of how many of the guest's vCPUs were not actually running on
+a host pCPU during the last scheduler tick, published over shared
+memory via @code{/dev/guest_ivshmem}). As long as @code{phantom_average}
+is zero, the thread continues spinning, maximizing spinning during
+non-contended phases on the host to achieve faster synchronization at
+barriers. As soon as @code{phantom_average} becomes positive, indicating
+host-side vCPU contention, the thread blocks immediately instead of
+continuing to spin. Checking @code{phantom_average} is a plain
+shared-memory read, so it adds negligible overhead per iteration. If the
+shared-memory channel cannot be established (device unavailable), a warning is
+printed and libgomp falls back to the default @env{OMP_WAIT_POLICY}.
+
+@code{ACTIVE} and @code{PASSIVE} behave the same as the corresponding
+@env{OMP_WAIT_POLICY} values. Setting @env{OMP_WAIT_POLICY} and
+@env{GOMP_WAIT_POLICY} to conflicting values (one @code{ACTIVE} and
+the other @code{PASSIVE}) is an error; in case of such errors or
+initialization failures, execution safely falls back to the default
@env{OMP_WAIT_POLICY}.
+
+@item @emph{See also}:
+@ref{OMP_WAIT_POLICY}, @ref{GOMP_SPINCOUNT}
+
+@item @emph{Reference}:
+Himadri Chhaya-Shailesh,
+@uref{https://inria.hal.science/tel-05438117v2, Scheduler Guided OpenMP
+Execution in Cloud VMs} (PhD thesis)
@end table
diff --git a/libgomp/testsuite/libgomp.c/pvsched_wait_policy-1.c
b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-1.c
new file mode 100644
index 00000000000..1470fab6647
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-1.c
@@ -0,0 +1,20 @@
+/* Verify GOMP_WAIT_POLICY=active resolves to the active spin/throttle
+ constants in env.c's initialize_env(). */
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,-Bstatic,-lgomp,-Bdynamic" } */
+/* { dg-set-target-env-var GOMP_WAIT_POLICY "active" } */
+
+extern int gomp_pv_wait_policy;
+extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+
+int
+main (void)
+{
+ if (gomp_pv_wait_policy != 1)
+ __builtin_abort ();
+ if (gomp_spin_count_var != 30000000000ULL)
+ __builtin_abort ();
+ if (gomp_throttled_spin_count_var != 1000ULL)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/pvsched_wait_policy-2.c
b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-2.c
new file mode 100644
index 00000000000..8a716eb8ef1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-2.c
@@ -0,0 +1,17 @@
+/* Verify GOMP_WAIT_POLICY=passive resolves to a zero spin count. */
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,-Bstatic,-lgomp,-Bdynamic" } */
+/* { dg-set-target-env-var GOMP_WAIT_POLICY "passive" } */
+
+extern int gomp_pv_wait_policy;
+extern unsigned long long gomp_spin_count_var;
+
+int
+main (void)
+{
+ if (gomp_pv_wait_policy != 0)
+ __builtin_abort ();
+ if (gomp_spin_count_var != 0)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/pvsched_wait_policy-3.c
b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-3.c
new file mode 100644
index 00000000000..3cd78b3900c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-3.c
@@ -0,0 +1,23 @@
+/* Verify that conflicting OMP_WAIT_POLICY / GOMP_WAIT_POLICY settings
+ are handled by printing a conflict error and safely falling back to
+ the default wait policy (gomp_pv_wait_policy = -1, default spin counts). */
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,-Bstatic,-lgomp,-Bdynamic" } */
+/* { dg-set-target-env-var OMP_WAIT_POLICY "passive" } */
+/* { dg-set-target-env-var GOMP_WAIT_POLICY "active" } */
+/* { dg-output "Conflicting OMP_WAIT_POLICY and GOMP_WAIT_POLICY" } */
+
+extern int gomp_pv_wait_policy;
+extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+
+int
+main (void)
+{
+ if (gomp_pv_wait_policy != -1)
+ __builtin_abort ();
+ if (gomp_spin_count_var != 300000ULL)
+ __builtin_abort ();
+ if (gomp_throttled_spin_count_var != 100ULL)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/pvsched_wait_policy-4.c
b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-4.c
new file mode 100644
index 00000000000..8739fd9db9f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-4.c
@@ -0,0 +1,25 @@
+/* Verify GOMP_WAIT_POLICY parsing is case-insensitive: "PvSched" must
+ be recognized as the pvsched keyword. There's normally no
+ /dev/guest_ivshmem on a test machine, so gomp_pvsched_init() fails
+ and initialize_env() resets gomp_pv_wait_policy back to -1 - the
+ "Error initializing pvsched" message only appears if the keyword
+ was matched in the first place, which is what we're checking. */
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,-Bstatic,-lgomp,-Bdynamic" } */
+/* { dg-set-target-env-var GOMP_WAIT_POLICY "PvSched" } */
+/* { dg-output "Error initializing pvsched" } */
+
+extern int gomp_pv_wait_policy;
+extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+
+int
+main (void)
+{
+ if (gomp_pv_wait_policy != -1)
+ __builtin_abort ();
+ if (gomp_spin_count_var != 300000ULL)
+ __builtin_abort ();
+ if (gomp_throttled_spin_count_var != 100ULL)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/pvsched_wait_policy-5.c
b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-5.c
new file mode 100644
index 00000000000..d6d937ba1df
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pvsched_wait_policy-5.c
@@ -0,0 +1,21 @@
+/* Verify an unrecognized GOMP_WAIT_POLICY value is rejected and
+ safely falls back to the default wait policy. */
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,-Bstatic,-lgomp,-Bdynamic" } */
+/* { dg-set-target-env-var GOMP_WAIT_POLICY "bogus" } */
+/* { dg-output "Invalid value for environment variable GOMP_WAIT_POLICY" } */
+
+extern int gomp_pv_wait_policy;
+extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+
+int
+main (void)
+{
+ if (gomp_pv_wait_policy != -1)
+ __builtin_abort ();
+ if (gomp_spin_count_var != 300000ULL)
+ __builtin_abort ();
+ if (gomp_throttled_spin_count_var != 100ULL)
+ __builtin_abort ();
+ return 0;
+}
--
2.34.1