Add fallback CPU feature detection for Android
authorJan Schmidt <jan@centricular.com>
Tue, 26 Aug 2014 05:29:50 +0000 (15:29 +1000)
committerJan Schmidt <jan@centricular.com>
Tue, 26 Aug 2014 05:32:02 +0000 (15:32 +1000)
On Android, /proc/self/auxv might not be readable (except
when debuggable=true in the build, annoyingly), so do what
the android cpufeatures detection code does and fall back to
/proc/cpuinfo string matching.

Without this, release builds run really slowly, due to ORC always
doing emulation.

orc/orccpu-arm.c

index 9c32c98..0087c60 100644 (file)
@@ -71,6 +71,7 @@ orc_check_neon_proc_auxv (void)
 
   fd = open("/proc/self/auxv", O_RDONLY);
   if (fd < 0) {
+    ORC_LOG ("Failed to open /proc/self/auxv");
     return 0;
   }
 
@@ -99,39 +100,7 @@ orc_check_neon_proc_auxv (void)
 }
 #endif
 
-#ifdef unused
-static void
-orc_cpu_arm_getflags_cpuinfo (char *cpuinfo)
-{
-  char *cpuinfo_flags;
-  char **flags;
-  char **f;
-
-  cpuinfo_flags = get_cpuinfo_line(cpuinfo, "Features");
-  if (cpuinfo_flags == NULL) {
-    free (cpuinfo);
-    return;
-  }
-
-  flags = strsplit(cpuinfo_flags, ' ');
-  for (f = flags; *f; f++) {
-#if 0
-    if (strcmp (*f, "edsp") == 0) {
-      ORC_DEBUG ("cpu feature %s", *f);
-      orc_cpu_flags |= ORC_CPU_FLAG_EDSP;
-    }
-    if (strcmp (*f, "vfp") == 0) {
-      ORC_DEBUG ("cpu feature %s", *f);
-      orc_cpu_flags |= ORC_CPU_FLAG_VFP;
-    }
-#endif
-
-    free (*f);
-  }
-  free (flags);
-  free (cpuinfo_flags);
-}
-
+#ifdef ANDROID
 static char *
 get_proc_cpuinfo (void)
 {
@@ -160,56 +129,96 @@ get_proc_cpuinfo (void)
 
   return cpuinfo;
 }
-#endif
 
-unsigned long
-orc_arm_get_cpu_flags (void)
+static char *
+get_cpuinfo_line (char *cpuinfo, const char *tag)
 {
-  unsigned long neon_flags = 0;
+  char *flags;
+  char *end;
+  char *colon;
 
-#ifdef __linux__
-  neon_flags = orc_check_neon_proc_auxv ();
-#endif
-#ifdef unused
-#ifdef __linux__
-  int arm_implementer = 0;
+  flags = strstr(cpuinfo,tag);
+  if (flags == NULL) return NULL;
+
+  end = strchr(flags, '\n');
+  if (end == NULL) return NULL;
+  colon = strchr (flags, ':');
+  if (colon == NULL) return NULL;
+  colon++;
+  if(colon >= end) return NULL;
+
+  return _strndup (colon, end-colon);
+}
+
+static unsigned long
+orc_cpu_arm_getflags_cpuinfo ()
+{
+  unsigned long ret = 0;
   char *cpuinfo;
-  char *s;
+  char *cpuinfo_line;
+  char **flags;
+  char **f;
 
   cpuinfo = get_proc_cpuinfo();
-  if (cpuinfo == NULL) return;
+  if (cpuinfo == NULL) {
+    ORC_DEBUG ("Failed to read /proc/cpuinfo");
+    return 0;
+  }
+
+  cpuinfo_line = get_cpuinfo_line(cpuinfo, "CPU architecture");
+  if (cpuinfo_line) {
+    int arm_arch = strtoul (cpuinfo_line, NULL, 0);
+    if (arm_arch >= 8L) {
+      /* Armv8 always supports these, but they won't be listed
+       * in the CPU info optional features */
+      ret = ORC_TARGET_ARM_EDSP | ORC_TARGET_NEON_NEON;
+      goto out;
+    }
 
-  s = get_cpuinfo_line(cpuinfo, "CPU implementer");
-  if (s) {
-    arm_implementer = strtoul (s, NULL, 0);
-    free(s);
+    free(cpuinfo_line);
   }
 
-  switch(arm_implementer) {
-    case 0x69: /* Intel */
-    case 0x41: /* ARM */
-      /* ARM chips are known to not have timestamping available from 
-       * user space */
-      break;
-    default:
-      break;
+  cpuinfo_line = get_cpuinfo_line(cpuinfo, "Features");
+  if (cpuinfo_line == NULL) {
+    free (cpuinfo);
+    return 0;
   }
 
-#if 0
-  s = get_cpuinfo_line(cpuinfo, "CPU architecture");
-  if (s) {
-    int arm_arch;
-    arm_arch = strtoul (s, NULL, 0);
-    if (arm_arch >= 6)
-      orc_cpu_flags |= ORC_CPU_FLAG_ARM6;
-    free(s);
+  flags = strsplit(cpuinfo_line, ' ');
+  for (f = flags; *f; f++) {
+    if (strcmp (*f, "edsp") == 0)
+      ret |= ORC_TARGET_ARM_EDSP;
+    else if (strcmp (*f, "neon") == 0)
+      ret |= ORC_TARGET_NEON_NEON;
+    free (*f);
   }
-#endif
 
-  orc_cpu_arm_getflags_cpuinfo (cpuinfo);
+  free (flags);
+
+out:
+  free (cpuinfo_line);
   free (cpuinfo);
+
+  return ret;
+}
 #endif
+
+unsigned long
+orc_arm_get_cpu_flags (void)
+{
+  unsigned long neon_flags = 0;
+
+#ifdef __linux__
+  neon_flags = orc_check_neon_proc_auxv ();
 #endif
+#ifdef ANDROID
+  if (!neon_flags) {
+    /* On ARM, /proc/self/auxv might not be accessible.
+     * Fall back to /proc/cpuinfo */
+    neon_flags = orc_cpu_arm_getflags_cpuinfo ();
+  }
+#endif
+
   if (orc_compiler_flag_check ("-neon")) {
     neon_flags &= ~ORC_TARGET_NEON_NEON;
   }