]> git.sesse.net Git - vlc/commitdiff
Linux: parse /proc/cpuinfo instead of playing fork tricks
authorRémi Denis-Courmont <remi@remlab.net>
Fri, 3 Feb 2012 16:36:04 +0000 (18:36 +0200)
committerRémi Denis-Courmont <remi@remlab.net>
Fri, 3 Feb 2012 16:42:30 +0000 (18:42 +0200)
src/Makefile.am
src/misc/cpu.c
src/posix/linux_cpu.c [new file with mode: 0644]

index 6dc33840fbe92d0259624a221d70706a125cfaa9..492dcde571ede640a30fcefb4ca66ac48c138f1b 100644 (file)
@@ -254,6 +254,7 @@ SOURCES_libvlc_linux = \
        posix/filesystem.c \
        posix/plugin.c \
        posix/thread.c \
+       posix/linux_cpu.c \
        posix/linux_specific.c \
        posix/rand.c \
        $(NULL)
index 7c28b25a2992a26dc1df34068eed0ac171f416c0..d4e762cce7899c0ddbca8bf43b274acd44cc47f7 100644 (file)
 
 #include <vlc_common.h>
 #include <vlc_cpu.h>
+#include "libvlc.h"
+
+#include <assert.h>
 
+#ifndef __linux__
 #include <sys/types.h>
 #ifndef WIN32
 #include <unistd.h>
 #else
 #include <errno.h>
 #endif
-#include <assert.h>
 
 #ifdef __APPLE__
 #include <sys/sysctl.h>
 #endif
 
-#include "libvlc.h"
-
 static uint32_t cpu_flags;
 
 #if defined (__i386__) || defined (__x86_64__) || defined (__powerpc__) \
@@ -284,45 +285,6 @@ void vlc_CPU_init (void)
     }
 out:
 
-#elif defined (__arm__)
-
-# if defined (__ARM_NEON__)
-    i_capabilities |= CPU_CAPABILITY_NEON;
-# elif defined (CAN_COMPILE_NEON)
-#  define NEED_RUNTIME_CPU_CHECK 1
-# endif
-
-# ifdef NEED_RUNTIME_CPU_CHECK
-#  if defined (__linux__)
-    FILE *info = fopen ("/proc/cpuinfo", "rt");
-    if (info != NULL)
-    {
-        char *line = NULL;
-        size_t linelen = 0;
-
-        while (getline (&line, &linelen, info) != -1)
-        {
-            const char *cap;
-
-            if (strncmp (line, "Features\t:", 10))
-                continue;
-
-            /* TODO: detect other CPU features when we use them */
-#   if defined (CAN_COMPILE_NEON) && !defined (__ARM_NEON__)
-                cap = strstr (line + 10, " neon");
-            if (cap != NULL && (cap[5] == '\0' || cap[5] == ' '))
-                i_capabilities |= CPU_CAPABILITY_NEON;
-#   endif
-            break;
-        }
-        fclose (info);
-        free (line);
-    }
-#  else
-#   warning Run-time CPU detection missing: optimizations disabled!
-#  endif
-# endif
-
 #elif defined( __powerpc__ ) || defined( __ppc__ ) || defined( __powerpc64__ ) \
     || defined( __ppc64__ )
 
@@ -363,6 +325,7 @@ unsigned vlc_CPU (void)
 #endif
     return cpu_flags;
 }
+#endif
 
 void vlc_CPU_dump (vlc_object_t *obj)
 {
diff --git a/src/posix/linux_cpu.c b/src/posix/linux_cpu.c
new file mode 100644 (file)
index 0000000..63f184e
--- /dev/null
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ * linux_cpu.c: CPU detection code for Linux
+ *****************************************************************************
+ * Copyright (C) 2012 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 <stdio.h>
+#include <string.h>
+#include <vlc_common.h>
+#include <vlc_cpu.h>
+
+#undef CPU_FLAGS
+#if defined (__arm__)
+# define CPU_FLAGS "Features\t:"
+
+#elif defined (__i386__) || defined (__x86_64__)
+# define CPU_FLAGS "flags\t\t:"
+
+#elif defined (__powerpc__) || defined (__powerpc64__)
+# define CPU_FLAGS "cpu\t\t:"
+
+#endif
+
+#ifdef CPU_FLAGS
+static uint32_t cpu_flags = 0;
+
+static void vlc_CPU_init (void)
+{
+    FILE *info = fopen ("/proc/cpuinfo", "rt");
+    if (info == NULL)
+        return;
+
+    char *line = NULL;
+    size_t linelen = 0;
+    uint_fast32_t all_caps = 0xFFFFFFFF;
+
+    while (getline (&line, &linelen, info) != -1)
+    {
+        if (strncmp (line, CPU_FLAGS, strlen (CPU_FLAGS)))
+            continue;
+
+        char *p = line, *cap;
+        uint_fast32_t core_caps = 0;
+
+        while ((cap = strsep (&p, " ")) != NULL)
+        {
+#if defined (__arm__)
+# ifndef __ARM_NEON__
+            if (!strcmp (cap, "neon"))
+                core_caps |= CPU_CAPABILITY_NEON;
+# endif
+
+#elif defined (__i386__) || defined (__x86_64__)
+# ifndef __MMX__
+            if (!strcmp (cap, "mmx"))
+                core_caps |= CPU_CAPABILITY_MMX;
+# endif
+# ifndef __SSE__
+            if (!strcmp (cap, "sse"))
+                core_caps |= CPU_CAPABILITY_SSE | CPU_CAPABILITY_MMXEXT;
+            if (!strcmp (cap, "mmxext"))
+                core_caps |= CPU_CAPABILITY_MMXEXT;
+# endif
+# ifndef __SSE2__
+            if (!strcmp (cap, "sse2"))
+                core_caps |= CPU_CAPABILITY_SSE2;
+# endif
+# ifndef __SSE3__
+            if (!strcmp (cap, "pni"))
+                core_caps |= CPU_CAPABILITY_SSE3;
+# endif
+# ifndef __SSSE3__
+            if (!strcmp (cap, "ssse3"))
+                core_caps |= CPU_CAPABILITY_SSSE3;
+# endif
+# ifndef __SSE4_1__
+            if (!strcmp (cap, "sse4_1"))
+                core_caps |= CPU_CAPABILITY_SSE4_1;
+# endif
+# ifndef __SSE4_2__
+            if (!strcmp (cap, "sse4_2"))
+                core_caps |= CPU_CAPABILITY_SSE4_1;
+# endif
+# ifndef __3dNOW__
+            if (!strcmp (cap, "3dnow"))
+                core_caps |= CPU_CAPABILITY_3DNOW;
+# endif
+
+#elif defined (__powerpc__) || defined (__powerpc64__)
+            if (!strcmp (cap, "altivec supported"))
+                core_caps |= CPU_CAPABILITY_ALTIVEC;
+#endif
+        }
+
+        /* Take the intersection of capabilities of each processor */
+        all_caps &= core_caps;
+    }
+    fclose (info);
+    free (line);
+
+    if (all_caps == 0xFFFFFFFF) /* Error parsing of cpuinfo? */
+        all_caps = 0; /* Do not assume any capability! */
+
+    /* Always enable capabilities that were forced during compilation */
+#if defined (__arm__)
+# ifdef __ARM_NEON__
+    all_caps |= CPU_CAPABILITY_NEON;
+# endif
+
+#elif defined (__i386__) || defined (__x86_64__)
+# ifdef __MMX__
+    all_caps |= CPU_CAPABILITY_MMX;
+# endif
+# ifdef __SSE__
+    all_caps |= CPU_CAPABILITY_SSE | CPU_CAPABILITY_MMXEXT;
+# endif
+# ifdef __SSE2__
+    all_caps |= CPU_CAPABILITY_SSE2;
+# endif
+# ifdef __SSE3__
+    all_caps |= CPU_CAPABILITY_SSE3;
+# endif
+# ifdef __SSSE3__
+    all_caps |= CPU_CAPABILITY_SSSE3;
+# endif
+# ifdef __SSE4_1__
+    all_caps |= CPU_CAPABILITY_SSE4_1;
+# endif
+# ifdef __SSE4_2__
+    all_caps |= CPU_CAPABILITY_SSE4_2;
+# endif
+# ifdef __3dNOW__
+    all_caps |= CPU_CAPABILITY_3DNOW;
+# endif
+
+#endif
+    cpu_flags = all_caps;
+}
+
+unsigned vlc_CPU (void)
+{
+    static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+    pthread_once (&once, vlc_CPU_init);
+    return cpu_flags;
+}
+#else /* CPU_FLAGS */
+unsigned vlc_CPU (void)
+{
+    return 0;
+}
+#endif