The attached 2 patches, add a new cpu-supports module,
and updates the crc-x86_64 module to use it.
This ensures that any users of the crc-x86_64 module
will honor the GLIBC_TUNABLES environment variable.
Specifically it will allow disabling of the hardware acceleration
used by crc-x86_64 using:
export GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX
Note this is a general mechanism provided by glibc
to tune hardware acceleration within glibc and also
determines what libs are loaded with its dynamic dispatch mechanism:
On my "x86-64-v3" system for example:
$ ld.so --help | grep -B1 x86-64-v
Subdirectories of glibc-hwcaps directories, in priority order:
x86-64-v4
x86-64-v3 (supported, searched)
x86-64-v2 (supported, searched)
$ ld.so --help | GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX \
grep -B1 x86-64-v
Subdirectories of glibc-hwcaps directories, in priority order:
x86-64-v4
x86-64-v3 (supported, searched)
x86-64-v2 (supported, searched)
This module will also be used by coreutils to ensure
its various uses of __builtin_cpu_supports() are similarly gated.
cheers,
Padraig
From d17ad4582cd2d918f368c175eb1060383646cb66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Fri, 12 Sep 2025 18:01:08 +0100
Subject: [PATCH 2/2] crc-x86_64: honor GLIBC_TUNABLES to disable acceleration
* modules/crc-x86_64: Depend on cpu-supports
* lib/crc.c: Call the cpu_supports() wrapper that honors glibc hwcaps.
---
lib/crc.c | 9 +++++----
modules/crc-x86_64 | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/lib/crc.c b/lib/crc.c
index 319a23715b..6847764d50 100644
--- a/lib/crc.c
+++ b/lib/crc.c
@@ -22,6 +22,7 @@
#include "endian.h"
#ifdef GL_CRC_X86_64_PCLMUL
+#include "cpu-supports.h"
#include "crc-x86_64.h"
static bool pclmul_enabled = false;
static bool pclmul_checked = false;
@@ -118,8 +119,8 @@ crc32_update_no_xor (uint32_t crc, const char *buf, size_t len)
#ifdef GL_CRC_X86_64_PCLMUL
if (!pclmul_checked)
{
- pclmul_enabled = (0 < __builtin_cpu_supports ("pclmul")
- && 0 < __builtin_cpu_supports ("avx"));
+ pclmul_enabled = (cpu_supports ("pclmul")
+ && cpu_supports ("avx"));
pclmul_checked = true;
}
@@ -200,8 +201,8 @@ crc32_update_no_xor (uint32_t crc, const char *buf, size_t len)
#ifdef GL_CRC_X86_64_PCLMUL
if (!pclmul_checked)
{
- pclmul_enabled = (0 < __builtin_cpu_supports ("pclmul")
- && 0 < __builtin_cpu_supports ("avx"));
+ pclmul_enabled = (cpu_supports ("pclmul")
+ && cpu_supports ("avx"));
pclmul_checked = true;
}
diff --git a/modules/crc-x86_64 b/modules/crc-x86_64
index 4ce70a99c6..2de91341f0 100644
--- a/modules/crc-x86_64
+++ b/modules/crc-x86_64
@@ -7,6 +7,7 @@ lib/crc-x86_64-pclmul.c
m4/crc-x86_64.m4
Depends-on:
+cpu-supports
stdint-h
crc
--
2.50.1
From f06f9fd7789e430c75a0f0fc0c573f9ff82f6b00 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Fri, 12 Sep 2025 16:55:45 +0100
Subject: [PATCH 1/2] cpu-supports: a module to honor
GLIBC_TUNABLES=glibc.cpu.hwcaps
This functionality is useful to allow better test coverage at least,
and may be useful for users to tune their environment,
avoiding CPU throttling for example.
* lib/cpu-supports.h (cpu_supports): A new wrapper that
checks that the GLIBC_TUNABLES environment variable allows
the hardware feature, before checking with __builtin_cpu_supports().
(gcc_feature_to_glibc_hwcap): A helper that will resolve
at compile time with standard optimizations enabled.
* lib/cpu-supports.c (hwcap_allowed): Query the GLIBC_TUNABLES
environment variable (read once per process), to see if the
passed GLIBC_HWCAP is allowed.
* modules/cpu-supports: New module definition.
---
lib/cpu-supports.c | 50 +++++++++++++++++++++++++++++++++++
lib/cpu-supports.h | 63 ++++++++++++++++++++++++++++++++++++++++++++
modules/cpu-supports | 27 +++++++++++++++++++
3 files changed, 140 insertions(+)
create mode 100644 lib/cpu-supports.c
create mode 100644 lib/cpu-supports.h
create mode 100644 modules/cpu-supports
diff --git a/lib/cpu-supports.c b/lib/cpu-supports.c
new file mode 100644
index 0000000000..47f7031c9c
--- /dev/null
+++ b/lib/cpu-supports.c
@@ -0,0 +1,50 @@
+#include <config.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu-supports.h"
+
+extern bool
+hwcap_allowed (char const* glibc_hwcap)
+{
+ if (! glibc_hwcap)
+ return true;
+
+ /* Match how GLIBC parses tunables as indicated with:
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=... ld.so --list-tunables | grep hwcaps */
+ static char const *GLIBC_TUNABLES;
+ if (! GLIBC_TUNABLES)
+ { /* Cache glibc.cpu.hwcaps once per process. */
+ if ((GLIBC_TUNABLES = getenv ("GLIBC_TUNABLES")))
+ {
+ char const *tunables_start = GLIBC_TUNABLES;
+ char const *last_hwcaps;
+ while ((last_hwcaps = strstr (GLIBC_TUNABLES, "glibc.cpu.hwcaps=")))
+ GLIBC_TUNABLES = last_hwcaps + sizeof "glibc.cpu.hwcaps=" - 1;
+ if (GLIBC_TUNABLES == tunables_start) /* No match. */
+ GLIBC_TUNABLES = "";
+ }
+ else
+ GLIBC_TUNABLES = "";
+ }
+
+ assert (GLIBC_TUNABLES);
+
+ if (! *GLIBC_TUNABLES)
+ return true;
+
+ char const *sentinel = strchr (GLIBC_TUNABLES, ':');
+ if (! sentinel)
+ sentinel = GLIBC_TUNABLES + strlen (GLIBC_TUNABLES);
+ char const *cap = GLIBC_TUNABLES;
+ while ((cap = strstr (cap, glibc_hwcap)) && cap < sentinel)
+ { /* Check it's not a partial match. */
+ cap += strlen (glibc_hwcap);
+ if (*cap == ',' || *cap == ':' || *cap == '\0')
+ return false; /* Feature disabled. */
+ /* glibc hwcaps can't have '-' in name so ok to search from here. */
+ }
+
+ return true;
+}
diff --git a/lib/cpu-supports.h b/lib/cpu-supports.h
new file mode 100644
index 0000000000..2743f273bf
--- /dev/null
+++ b/lib/cpu-supports.h
@@ -0,0 +1,63 @@
+/* Support routines to query GLIBC_TUNABLES=glibc.cpu.hwcaps
+
+ Copyright 2025 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include "attribute.h"
+
+#ifndef _CPU_SUPPORTS_H
+# define _CPU_SUPPORTS_H
+
+# define cpu_supports(feature) \
+ (hwcap_allowed (gcc_feature_to_glibc_hwcap (feature)) \
+ && __builtin_cpu_supports (feature))
+
+# ifndef STREQ
+# define STREQ(a, b) (strcmp (a, b) == 0)
+# endif
+
+/* Return the glibc.cpu.hwcaps setting (prepended with "-"),
+ corresponding to the passed gcc _builtin_cpu_supports(FEATURE).
+ Supported hwcaps can be identified from the bit_cpu_* defines
+ in GLIBC's sysdeps/x86/include/cpu-features.h
+ Note this mapping should resolve at compile time. */
+ATTRIBUTE_PURE
+static inline char const*
+gcc_feature_to_glibc_hwcap (char const* feature)
+{
+ char const* hwcap = nullptr;
+
+ if (0);
+# if defined __x86_64__
+ else if (STREQ (feature, "avx")) hwcap = "-AVX";
+ else if (STREQ (feature, "avx2")) hwcap = "-AVX2";
+ else if (STREQ (feature, "avx512bw")) hwcap = "-AVX512BW";
+ else if (STREQ (feature, "avx512f")) hwcap = "-AVX512F";
+ else if (STREQ (feature, "pclmul")) hwcap = "-PCLMULQDQ";
+ else if (STREQ (feature, "vpclmulqdq")) hwcap = "-VPCLMULQDQ";
+# elif defined __aarch64__
+ else if (STREQ (feature, "pmull")) hwcap "-PMULL";
+# endif
+
+ return hwcap;
+}
+
+/* Support GLIBC's interface to disable features using:
+ export GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F,-AVX2,-AVX,-PMULL
+ Return true if the HWCAP is allowed. */
+extern bool hwcap_allowed (char const* glibc_hwcap);
+
+#endif /* _CPU_SUPPORTS_H */
diff --git a/modules/cpu-supports b/modules/cpu-supports
new file mode 100644
index 0000000000..62b2600bf6
--- /dev/null
+++ b/modules/cpu-supports
@@ -0,0 +1,27 @@
+Description:
+A wrapper for __builtin_cpu_supports to also check GLIBC_TUNABLES
+
+Files:
+lib/cpu-supports.h
+lib/cpu-supports.c
+
+Depends-on:
+assert
+attribute
+bool
+c99
+inline
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += cpu-supports.c
+
+Include:
+"cpu-supports.h"
+
+License:
+GPL
+
+Maintainer:
+all
--
2.50.1