summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Turner <digit@google.com>2010-02-08 12:52:35 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2010-02-08 12:52:35 -0800
commite52f44d9506b56e610f81eecc4f6aaca390f7a8d (patch)
tree62ec8a31d41cbaf556f1c93b3485b8c7c9fd0f43
parent609329541ac4c23a2a21b7d493c594c1b3d0c438 (diff)
parent3b712fda34a3d7a71e6a4ba6ee495b178b2c1830 (diff)
downloadandroid_development-e52f44d9506b56e610f81eecc4f6aaca390f7a8d.tar.gz
android_development-e52f44d9506b56e610f81eecc4f6aaca390f7a8d.tar.bz2
android_development-e52f44d9506b56e610f81eecc4f6aaca390f7a8d.zip
am 3b712fda: Merge "Add \'cpufeatures\' library to perform runtime CPU family/features detection." into eclair
Merge commit '3b712fda34a3d7a71e6a4ba6ee495b178b2c1830' into eclair-plus-aosp * commit '3b712fda34a3d7a71e6a4ba6ee495b178b2c1830': Add 'cpufeatures' library to perform runtime CPU family/features detection.
-rw-r--r--ndk/docs/CHANGES.TXT8
-rw-r--r--ndk/docs/CPU-FEATURES.TXT92
-rw-r--r--ndk/sources/cpufeatures/Android.mk10
-rw-r--r--ndk/sources/cpufeatures/cpu-features.c219
-rw-r--r--ndk/sources/cpufeatures/cpu-features.h26
5 files changed, 355 insertions, 0 deletions
diff --git a/ndk/docs/CHANGES.TXT b/ndk/docs/CHANGES.TXT
index e36a82f50..f3d5cfb42 100644
--- a/ndk/docs/CHANGES.TXT
+++ b/ndk/docs/CHANGES.TXT
@@ -28,6 +28,14 @@ IMPORTANT CHANGES:
More details about ABIs is now available in docs/CPU-ARCH-ABIS.TXT
+- Added a new sample static library, named "cpufeatures" to detect
+ CPU Features at runtime. For now, this can be used to detect the
+ availability of ARM Advanced SIMD (a.k.a. NEON) instruction support
+ at runtime in order to provide optimized code paths for specific
+ operations.
+
+ See docs/CPU-FEATURES.TXT for details.
+
- GCC 4.4.0 is now used by default by the NDK. It generates better code than
GCC 4.2.1, which was used in previous releases. However, the compiler's C++
frontend is also a lot more pedantic regarding certain template constructs
diff --git a/ndk/docs/CPU-FEATURES.TXT b/ndk/docs/CPU-FEATURES.TXT
new file mode 100644
index 000000000..f69807c8a
--- /dev/null
+++ b/ndk/docs/CPU-FEATURES.TXT
@@ -0,0 +1,92 @@
+Android NDK CPU Features detection library:
+-------------------------------------------
+
+This NDK provides a small library named "cpufeatures" that can be used at
+runtime to detect the target device's CPU family and the optional features
+it supports.
+
+Usage:
+------
+
+The library is available from sources/cpufeatures. It provides an Android.mk
+build script that can be used to build it as a static library.
+
+To use it, you must:
+
+ * add 'cpufeatures' to your APP_MODULES list in your Application.mk
+
+ * include 'sources/cpufeatures/Android.mk' at the start or end of your
+ Android.mk file.
+
+ * add 'sources/cpufeatures' to your LOCAL_C_INCLUDES definition.
+
+ * add 'cpufeatures' to your LOCAL_STATIC_LIBRARIES definition when building
+ your final shared library.
+
+ your source code can then #include <cpu-features.h> to compile against it.
+
+Here is a simple example:
+
+<NDK>/apps/<appname>/Application.mk:
+ APP_PROJECT_PATH := <project-path>
+ APP_MODULES := <your-modules> cpufeatures
+
+<project-path>/jni/Android.mk:
+ LOCAL_PATH := $(call my-dir)
+
+ include $(CLEAR_VARS)
+ LOCAL_MODULE := <your-module-name>
+ LOCAL_C_INCLUDES += sources/cpufeatures
+ LOCAL_SRC_FILES := <your-source-files>
+ LOCAL_STATIC_LIBRARIES += cpufeatures
+ include $(BUILD_SHARED_LIBRARY)
+
+ include sources/cpufeature/Android.mk
+
+
+Features:
+---------
+
+Two functions are provided for now:
+
+ AndroidCpuFamily android_getCpuFamily();
+
+Returns the target device's CPU Family as an enum. For now, the only
+supported family is ANDROID_CPU_FAMILY_ARM.
+
+
+ uint64_t android_getCpuFeatures();
+
+Returns the set of optional features supported by the device's CPU.
+The result is a set of bit-flags, each corresponding to one CPU
+Family-specific optional feature.
+
+Currently, only the following flags are defined, for the ARM CPU Family:
+
+ ANDROID_CPU_ARM_FEATURE_ARMv7
+ Indicates that the device's CPU supports the ARMv7-A instruction
+ set as supported by the "armeabi-v7a" abi (see CPU-ARCH-ABIS.TXT).
+ This corresponds to Thumb-2 and VFPv3-D16 instructions.
+
+ ANDROID_CPU_ARM_FEATURE_VFPv3
+ Indicates that the device's CPU supports the VFPv3 hardware FPU
+ instruction set extension. Due to the definition of 'armeabi-v7a',
+ this will always be the case if ANDROID_CPU_ARM_FEATURE_ARMv7 is
+ returned.
+
+ Note that this corresponds to the minimum profile VFPv3-D16 that
+ only provides 16 hardware FP registers.
+
+ ANDROID_CPU_ARM_FEATURE_NEON
+ Indicates that the device's CPU supports the ARM Advanced SIMD
+ (a.k.a. NEON) vector instruction set extension. Note that ARM
+ mandates that such CPUs also implement VFPv3-D32, which provides
+ 32 hardware FP registers (shared with the NEON unit).
+
+
+Important Note:
+---------------
+
+The cpufeatures library will be updated to support more CPU families and
+optional features in the future. It is designed to work as-is on all
+official Android platform versions.
diff --git a/ndk/sources/cpufeatures/Android.mk b/ndk/sources/cpufeatures/Android.mk
new file mode 100644
index 000000000..49d479a88
--- /dev/null
+++ b/ndk/sources/cpufeatures/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+# If targetting ARM CPUs, build the ARMv7 detection
+# function. It will only be called by the main
+# library if we detect ARMv7 through a system property.
+#
+include $(CLEAR_VARS)
+LOCAL_MODULE := cpufeatures
+LOCAL_SRC_FILES := cpu-features.c
+include $(BUILD_STATIC_LIBRARY)
diff --git a/ndk/sources/cpufeatures/cpu-features.c b/ndk/sources/cpufeatures/cpu-features.c
new file mode 100644
index 000000000..d16563575
--- /dev/null
+++ b/ndk/sources/cpufeatures/cpu-features.c
@@ -0,0 +1,219 @@
+#include <sys/system_properties.h>
+#include <machine/cpu-features.h>
+#include <pthread.h>
+#include "cpu-features.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static pthread_once_t g_once;
+static AndroidCpuFamily g_cpuFamily;
+static uint64_t g_cpuFeatures;
+
+static const int android_cpufeatures_debug = 0;
+
+#define D(...) \
+ do { \
+ if (android_cpufeatures_debug) { \
+ printf(__VA_ARGS__); fflush(stdout); \
+ } \
+ } while (0)
+
+/* Read the content of /proc/cpuinfo into a user-provided buffer.
+ * Return the length of the data, or -1 on error. Does *not*
+ * zero-terminate the content. Will not read more
+ * than 'buffsize' bytes.
+ */
+static int
+read_file(const char* pathname, char* buffer, size_t buffsize)
+{
+ int fd, len;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ do {
+ len = read(fd, buffer, buffsize);
+ } while (len < 0 && errno == EINTR);
+
+ close(fd);
+
+ return len;
+}
+
+/* Extract the content of a the first occurence of a given field in
+ * the content of /proc/cpuinfo and return it as a heap-allocated
+ * string that must be freed by the caller.
+ *
+ * Return NULL if not found
+ */
+static char*
+extract_cpuinfo_field(char* buffer, int buflen, const char* field)
+{
+ int fieldlen = strlen(field);
+ char* bufend = buffer + buflen;
+ char* result = NULL;
+ int len, ignore;
+ const char *p, *q;
+
+ /* Look for first field occurence, and ensures it starts the line.
+ */
+ p = buffer;
+ bufend = buffer + buflen;
+ for (;;) {
+ p = memmem(p, bufend-p, field, fieldlen);
+ if (p == NULL)
+ goto EXIT;
+
+ if (p == buffer || p[-1] == '\n')
+ break;
+
+ p += fieldlen;
+ }
+
+ /* Skip to the first column followed by a space */
+ p += fieldlen;
+ p = memchr(p, ':', bufend-p);
+ if (p == NULL || p[1] != ' ')
+ goto EXIT;
+
+ /* Find the end of the line */
+ p += 2;
+ q = memchr(p, '\n', bufend-p);
+ if (q == NULL)
+ q = bufend;
+
+ /* Copy the line into a heap-allocated buffer */
+ len = q-p;
+ result = malloc(len+1);
+ if (result == NULL)
+ goto EXIT;
+
+ memcpy(result, p, len);
+ result[len] = '\0';
+
+EXIT:
+ return result;
+}
+
+
+/* Checks that a space-separated list of items contains one given 'item'.
+ * Returns 1 if found, 0 otherwise.
+ */
+static int
+has_list_item(const char* list, const char* item)
+{
+ const char* p = list;
+ int itemlen = strlen(item);
+
+ if (list == NULL)
+ return 0;
+
+ while (*p) {
+ const char* q;
+
+ /* skip spaces */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* find end of current list item */
+ q = p;
+ while (*q && *q != ' ' && *q != '\t')
+ q++;
+
+ if (itemlen == q-p && !memcmp(p, item, itemlen))
+ return 1;
+
+ /* skip to next item */
+ p = q;
+ }
+ return 0;
+}
+
+
+static void
+android_cpuInit(void)
+{
+ g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN;
+ g_cpuFeatures = 0;
+
+#ifdef __ARM_ARCH__
+ {
+ char cpuinfo[4096];
+ int cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo);
+ char* features = NULL;
+ char* architecture = NULL;
+
+ g_cpuFamily = ANDROID_CPU_FAMILY_ARM;
+
+ D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, cpuinfo_len, cpuinfo);
+
+ if (cpuinfo_len < 0) /* should not happen */ {
+ return;
+ }
+
+ /* Extract architecture from the "CPU Architecture" field,
+ * Which can be something like 5JTE, 7, or something else.
+ * We cannot rely on the 'Processor' field here.
+ */
+ {
+ char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture");
+
+ if (cpuArch != NULL) {
+ char* end;
+ long archNumber;
+
+ D("found cpuArch = '%s'\n", cpuArch);
+
+ /* read the initial decimal number, ignore the rest */
+ archNumber = strtol(cpuArch, &end, 10);
+
+ /* Here we assume that ARMv8 will be upwards compatible with v7
+ * in the future. Unfortunately, there is no 'Features' field to
+ * indicate that Thumb-2 is supported.
+ */
+ if (end > cpuArch && archNumber >= 7) {
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
+ }
+ free(cpuArch);
+ }
+ }
+
+ /* Extract the list of CPU features from 'Features' field */
+ {
+ char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features");
+
+ if (cpuFeatures != NULL) {
+
+ D("found cpuFeatures = '%s'\n", cpuFeatures);
+
+ if (has_list_item(cpuFeatures, "vfpv3"))
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+
+ if (has_list_item(cpuFeatures, "neon"))
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON;
+
+ free(cpuFeatures);
+ }
+ }
+ }
+#endif /* __ARM_ARCH__ */
+}
+
+
+AndroidCpuFamily
+android_getCpuFamily(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuFamily;
+}
+
+
+uint64_t
+android_getCpuFeatures(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuFeatures;
+}
diff --git a/ndk/sources/cpufeatures/cpu-features.h b/ndk/sources/cpufeatures/cpu-features.h
new file mode 100644
index 000000000..d5fa87694
--- /dev/null
+++ b/ndk/sources/cpufeatures/cpu-features.h
@@ -0,0 +1,26 @@
+#ifndef CPU_FEATURES_H
+#define CPU_FEATURES_H
+
+#include <stdint.h>
+
+typedef enum {
+ ANDROID_CPU_FAMILY_UNKNOWN = 0,
+ ANDROID_CPU_FAMILY_ARM,
+ ANDROID_CPU_FAMILY_X86,
+
+ ANDROID_CPU_FAMILY_MAX /* do not remove */
+
+} AndroidCpuFamily;
+
+/* Return family of the device's CPU */
+extern AndroidCpuFamily android_getCpuFamily(void);
+
+enum {
+ ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
+ ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
+ ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
+};
+
+extern uint64_t android_getCpuFeatures(void);
+
+#endif /* CPU_FEATURES_H */