[PATCH v2 3/3] devtools/cocci: add script to find empty spinloops
Stephen Hemminger
stephen at networkplumber.org
Mon Apr 13 18:45:31 CEST 2026
This script finds and fixes many variations of the pattern:
while (!atomic(&flag));
to add a rte_pause() to the loop.
This type of loop was causing failures in the standalone atomic
tests on high core system. The script generalizes that to find other
places with the same problem.
Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
---
devtools/cocci/fix_empty_spinloops.cocci | 165 +++++++++++++++++++++++
1 file changed, 165 insertions(+)
create mode 100644 devtools/cocci/fix_empty_spinloops.cocci
diff --git a/devtools/cocci/fix_empty_spinloops.cocci b/devtools/cocci/fix_empty_spinloops.cocci
new file mode 100644
index 0000000000..ff64b30eac
--- /dev/null
+++ b/devtools/cocci/fix_empty_spinloops.cocci
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Find and fix empty spin loops that should call rte_pause()
+//
+// Empty spin loops waste CPU cycles and can cause performance issues.
+// This script finds various forms of busy-wait loops and adds rte_pause()
+// to give hints to the CPU and reduce power consumption.
+
+// Rule 1: Handle rte_atomic*_read() variants
+ at fix_atomic_read@
+expression ptr, val;
+@@
+
+(
+- while (rte_atomic16_read(ptr) == val);
++ while (rte_atomic16_read(ptr) == val)
++ rte_pause();
+|
+- while (rte_atomic16_read(ptr) != val);
++ while (rte_atomic16_read(ptr) != val)
++ rte_pause();
+|
+- while (rte_atomic32_read(ptr) == val);
++ while (rte_atomic32_read(ptr) == val)
++ rte_pause();
+|
+- while (rte_atomic32_read(ptr) != val);
++ while (rte_atomic32_read(ptr) != val)
++ rte_pause();
+|
+- while (rte_atomic64_read(ptr) == val);
++ while (rte_atomic64_read(ptr) == val)
++ rte_pause();
+|
+- while (rte_atomic64_read(ptr) != val);
++ while (rte_atomic64_read(ptr) != val)
++ rte_pause();
+)
+
+// Rule 2: Handle rte_atomic*_read() with comparison operators
+ at fix_atomic_cmp@
+expression ptr, val;
+@@
+
+(
+- while (rte_atomic16_read(ptr) < val);
++ while (rte_atomic16_read(ptr) < val)
++ rte_pause();
+|
+- while (rte_atomic16_read(ptr) > val);
++ while (rte_atomic16_read(ptr) > val)
++ rte_pause();
+|
+- while (rte_atomic32_read(ptr) < val);
++ while (rte_atomic32_read(ptr) < val)
++ rte_pause();
+|
+- while (rte_atomic32_read(ptr) > val);
++ while (rte_atomic32_read(ptr) > val)
++ rte_pause();
+|
+- while (rte_atomic64_read(ptr) < val);
++ while (rte_atomic64_read(ptr) < val)
++ rte_pause();
+|
+- while (rte_atomic64_read(ptr) > val);
++ while (rte_atomic64_read(ptr) > val)
++ rte_pause();
+)
+
+// Rule 3: Handle C11 atomics with rte_atomic_load_explicit()
+ at fix_c11_atomic@
+expression ptr, order, val;
+@@
+
+(
+- while (rte_atomic_load_explicit(ptr, order) == val);
++ while (rte_atomic_load_explicit(ptr, order) == val)
++ rte_pause();
+|
+- while (rte_atomic_load_explicit(ptr, order) != val);
++ while (rte_atomic_load_explicit(ptr, order) != val)
++ rte_pause();
+|
+- while (rte_atomic_load_explicit(ptr, order) < val);
++ while (rte_atomic_load_explicit(ptr, order) < val)
++ rte_pause();
+|
+- while (rte_atomic_load_explicit(ptr, order) > val);
++ while (rte_atomic_load_explicit(ptr, order) > val)
++ rte_pause();
+)
+
+// Rule 4: Handle __atomic_load_n() directly
+ at fix_gcc_atomic@
+expression ptr, order, val;
+@@
+
+(
+- while (__atomic_load_n(ptr, order) == val);
++ while (__atomic_load_n(ptr, order) == val)
++ rte_pause();
+|
+- while (__atomic_load_n(ptr, order) != val);
++ while (__atomic_load_n(ptr, order) != val)
++ rte_pause();
+|
+- while (__atomic_load_n(ptr, order) < val);
++ while (__atomic_load_n(ptr, order) < val)
++ rte_pause();
+|
+- while (__atomic_load_n(ptr, order) > val);
++ while (__atomic_load_n(ptr, order) > val)
++ rte_pause();
+)
+
+// Rule 5: Handle volatile variable reads (simple dereference)
+ at fix_volatile@
+expression E;
+identifier v;
+@@
+
+(
+- while (*v == E);
++ while (*v == E)
++ rte_pause();
+|
+- while (*v != E);
++ while (*v != E)
++ rte_pause();
+|
+- while (*v < E);
++ while (*v < E)
++ rte_pause();
+|
+- while (*v > E);
++ while (*v > E)
++ rte_pause();
+|
+- while (v == E);
++ while (v == E)
++ rte_pause();
+|
+- while (v != E);
++ while (v != E)
++ rte_pause();
+)
+
+// Rule 6: Handle negated conditions
+ at fix_negated@
+expression ptr, val;
+@@
+
+(
+- while (!rte_atomic32_read(ptr));
++ while (!rte_atomic32_read(ptr))
++ rte_pause();
+|
+- while (!rte_atomic64_read(ptr));
++ while (!rte_atomic64_read(ptr))
++ rte_pause();
+|
+- while (!rte_atomic_load_explicit(ptr, val));
++ while (!rte_atomic_load_explicit(ptr, val))
++ rte_pause();
+)
--
2.53.0
More information about the dev
mailing list