[vlc-commits] [Git][videolan/vlc][master] 7 commits: linux: detect <sys/auxv.h>

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Thu Feb 24 01:35:14 UTC 2022



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
b2a48016 by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
linux: detect <sys/auxv.h>

This is necessary for Linux-specific getauxval() and associated flags.
In this case, VLC needs AT_HWCAP (and probably AT_HWCAP2 going forward)
to detect CPU features on most architectures.

- - - - -
ea93bcb8 by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
compat: Linux getauxval() replacement

This was added over a decade ago, but 🤷...

- - - - -
f383f00f by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
linux: use getauxval() for AArch64 CPU detection

- - - - -
4aea7124 by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
linux: use getauxval() for AArch32 CPU detection

- - - - -
e75a33e4 by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
linux: use getauxval() for POWER CPU detection

- - - - -
d7b1f8e2 by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
linux: use getauxval() for RISC-V CPU detection

- - - - -
13ab2516 by Rémi Denis-Courmont at 2022-02-23T21:10:16+00:00
linux: simplify CPU detection macros

Only x86 still uses the flaky procfs parsing.

- - - - -


4 changed files:

- + compat/getauxval.c
- configure.ac
- include/vlc_fixups.h
- src/linux/cpu.c


Changes:

=====================================
compat/getauxval.c
=====================================
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * getauxval.c: Linux getauxval() replacement
+ *****************************************************************************
+ * Copyright © 2022 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+
+extern char **environ;
+
+unsigned long getauxval(unsigned long type)
+{
+	const unsigned long *auxv;
+	size_t i = 0;
+
+	while (environ[i++] != NULL);
+
+	auxv = (const void *)&environ[i];
+
+	for (i = 0; auxv[i]; i += 2)
+		if (auxv[i] == type)
+			return auxv[i + 1];
+
+	return 0;
+}


=====================================
configure.ac
=====================================
@@ -734,6 +734,7 @@ dnl Check for non-standard system calls
 case "$SYS" in
   "linux")
     AC_CHECK_FUNCS([eventfd vmsplice sched_getaffinity recvmmsg memfd_create])
+    AC_REPLACE_FUNCS([getauxval])
     ;;
   "mingw32")
     AC_CHECK_FUNCS([_lock_file])
@@ -965,7 +966,7 @@ dnl  BSD
 AC_CHECK_HEADERS([netinet/tcp.h netinet/udplite.h sys/param.h sys/mount.h])
 
 dnl  GNU/Linux
-AC_CHECK_HEADERS([features.h getopt.h linux/dccp.h linux/magic.h sys/eventfd.h])
+AC_CHECK_HEADERS([features.h getopt.h linux/dccp.h linux/magic.h sys/auxv.h sys/eventfd.h])
 
 dnl  MacOS
 AC_CHECK_HEADERS([xlocale.h])


=====================================
include/vlc_fixups.h
=====================================
@@ -503,6 +503,11 @@ void *lfind( const void *key, const void *base, size_t *nmemb,
 void tdestroy( void *root, void (*free_node)(void *nodep) );
 #endif
 
+/* sys/auxv.h */
+#ifndef HAVE_GETAUXVAL
+unsigned long getauxval(unsigned long);
+#endif
+
 /* Random numbers */
 #ifndef HAVE_NRAND48
 double erand48 (unsigned short subi[3]);


=====================================
src/linux/cpu.c
=====================================
@@ -24,82 +24,79 @@
 
 #include <stdio.h>
 #include <string.h>
+#ifdef HAVE_SYS_AUXV_H
+# include <sys/auxv.h>
+#endif
+#ifndef AT_HWCAP /* ancient libc, fallback to kernel header */
+# include <linux/auxvec.h>
+#endif
 #include <vlc_common.h>
 #include <vlc_cpu.h>
 
-#undef CPU_FLAGS
-#if defined (__arm__) || defined (__aarch64__)
-# define CPU_FLAGS "Features"
-
-#elif defined (__i386__) || defined (__x86_64__)
-# define CPU_FLAGS "flags"
-
-#elif defined (__powerpc__) || defined (__powerpc64__)
-# define CPU_FLAGS "cpu"
-
-#elif defined (__riscv)
-# include <vlc_strings.h>
-# define CPU_FLAGS "isa"
-
-static unsigned vlc_CPU_RV_isa_parse(const char *isa)
+#if defined (__aarch64__)
+unsigned vlc_CPU_raw(void)
 {
-    unsigned caps = 0;
-    int c;
-
-    if (vlc_ascii_tolower((unsigned char)isa[0]) != 'r'
-     || vlc_ascii_tolower((unsigned char)isa[1]) != 'v')
-        return 0;
-
-    isa += 2;
-
-    if (strncmp(isa, "32", 2) == 0 || strncmp(isa, "64", 2) == 0)
-        isa += 2;
-    else if (strncmp(isa, "128", 3) == 0)
-        isa += 3;
-    else
-        return 0;
-
-    while ((c = vlc_ascii_tolower((unsigned char)*isa)) != '\0') {
-        size_t extlen = 1;
+    unsigned int flags = 0;
+    const unsigned long hwcap = getauxval(AT_HWCAP);
+    //const unsigned long hwcap2 = getauxval(AT_HWCAP2); // TODO: SVE2
+
+    /* HWCAP_FP (HAVE_FPU) is statically assumed. */
+# ifdef HWCAP_ASIMD
+    if (hwcap & HWCAP_ASIMD)
+        flags |= VLC_CPU_ARM_NEON;
+# endif
+# ifdef HWCAP_SVE
+    if (hwcap & HWCAP_SVE)
+        flags |= VLC_CPU_ARM_SVE;
+# endif
+    return flags;
+}
 
-        switch (c) {
-            case '_':
-                break;
+#elif defined (__arm__)
+/* On AArch32, glibc's <bits/hwcap.h> uses different HWCAP names than the
+ * kernel and other libc's. Include the kernel header manually. */
+# include <asm/hwcap.h>
 
-            case 'z':
-            case 's':
-            case 'h':
-            case 'x':
-                extlen = 1 + strcspn(isa + 1, "_");
-                break;
+unsigned vlc_CPU_raw(void)
+{
+    unsigned int flags = 0;
+    const unsigned long hwcap = getauxval(AT_HWCAP);
+
+    /* TLS implies ARMv6, Thumb-EE and VFP imply ARMv7 */
+    if (hwcap & (HWCAP_TLS|HWCAP_THUMBEE|HWCAP_VFP))
+        flags |= VLC_CPU_ARMv6; /* SIMD */
+    if (hwcap & HWCAP_NEON)
+        flags |= VLC_CPU_ARM_NEON; /* Advanced SIMD */
+    return flags;
+}
 
-            default:
-                if (((unsigned)(c - 'a')) > 'y')
-                    return 0;
+#elif defined (__powerpc__) /* both 32- and 64-bit */
+unsigned vlc_CPU_raw(void)
+{
+    const unsigned long hwcap = getauxval(AT_HWCAP);
+    unsigned int flags = 0;
 
-                while (isa[extlen] && ((unsigned)(isa[extlen] - '0')) < 10)
-                    extlen++;
+    if (hwcap & PPC_FEATURE_HAS_ALTIVEC)
+        flags |= VLC_CPU_ALTIVEC;
 
-                if (vlc_ascii_tolower(isa[extlen]) == 'p') {
-                    extlen++;
+    return flags;
+}
 
-                    while (isa[extlen] && ((unsigned)(isa[extlen] - '0')) < 10)
-                        extlen++;
-                }
-        }
+#elif defined (__riscv)
+# define HWCAP_RV(letter) (1LU << ((letter) - 'A'))
 
-        /* TODO: Zve extensions */
-        if (c == 'v')
-            caps |= VLC_CPU_RV_V;
+unsigned vlc_CPU_raw(void)
+{
+    const unsigned long hwcap = getauxval(AT_HWCAP);
+    unsigned int flags = 0;
 
-        isa += extlen;
-    }
+    if (hwcap & HWCAP_RV('V'))
+        flags |= VLC_CPU_RV_V;
 
-    return caps;
+    return flags;
 }
-#endif
 
-#ifdef CPU_FLAGS
+#elif defined (__i386__) || defined (__x86_64__)
 unsigned vlc_CPU_raw(void)
 {
     FILE *info = fopen ("/proc/cpuinfo", "rte");
@@ -115,34 +112,16 @@ unsigned vlc_CPU_raw(void)
         char *p, *cap;
         uint_fast32_t core_caps = 0;
 
-#if defined (__arm__)
-        unsigned ver;
-        if (sscanf (line, "Processor\t: ARMv%u", &ver) >= 1 && ver >= 6)
-            core_caps |= VLC_CPU_ARMv6;
-#endif
-        if (strncmp (line, CPU_FLAGS, strlen (CPU_FLAGS)))
+        if (strncmp(line, "flags", 5))
             continue;
 
-        p = line + strlen(CPU_FLAGS);
+        p = line + 5;
         p += strspn(p, "\t");
         if (*p != ':')
             continue;
 
-#if defined (__riscv)
-        p += strspn(p, "\t ");
-        core_caps = vlc_CPU_RV_isa_parse(p);
-#else
         while ((cap = strsep (&p, " ")) != NULL)
         {
-#if defined (__arm__) || defined (__aarch64__)
-            if (!strcmp (cap, "neon"))
-                core_caps |= VLC_CPU_ARM_NEON;
-# if defined (__aarch64__)
-            if (!strcmp (cap, "sve"))
-                core_caps |= VLC_CPU_ARM_SVE;
-# endif
-
-#elif defined (__i386__) || defined (__x86_64__)
             if (!strcmp (cap, "mmx"))
                 core_caps |= VLC_CPU_MMX;
             if (!strcmp (cap, "sse"))
@@ -169,13 +148,7 @@ unsigned vlc_CPU_raw(void)
                 core_caps |= VLC_CPU_XOP;
             if (!strcmp (cap, "fma4"))
                 core_caps |= VLC_CPU_FMA4;
-
-#elif defined (__powerpc__) || defined (__powerpc64__)
-            if (!strcmp (cap, "altivec supported"))
-                core_caps |= VLC_CPU_ALTIVEC;
-#endif
         }
-#endif
 
         /* Take the intersection of capabilities of each processor */
         all_caps &= core_caps;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1cd55cbad268ea90db8028c759fa046c4ffe0800...13ab251675dfa32269ffa47adb809315a76388e5

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1cd55cbad268ea90db8028c759fa046c4ffe0800...13ab251675dfa32269ffa47adb809315a76388e5
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list