diff options
author | Jan Schmidt <jan@centricular.com> | 2014-08-26 15:29:50 +1000 |
---|---|---|
committer | Jan Schmidt <jan@centricular.com> | 2014-08-26 15:32:02 +1000 |
commit | dfcc456c2b31deab21501e889c89bd168a50a411 (patch) | |
tree | ddc9bb43f1e270e59f77bb9b2c51cd66e76a04b9 | |
parent | 3c7cb2d3029628454eb22c7f4bc3451197462779 (diff) | |
download | orc-dfcc456c2b31deab21501e889c89bd168a50a411.tar.gz |
Add fallback CPU feature detection for Android
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.
-rw-r--r-- | orc/orccpu-arm.c | 143 |
1 files changed, 76 insertions, 67 deletions
diff --git a/orc/orccpu-arm.c b/orc/orccpu-arm.c index 9c32c98..0087c60 100644 --- a/orc/orccpu-arm.c +++ b/orc/orccpu-arm.c @@ -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; } |