diff --git a/src/build/arm_neon.gypi b/src/build/arm_neon.gypi new file mode 100644 index 000000000..53c3b533b --- /dev/null +++ b/src/build/arm_neon.gypi @@ -0,0 +1,35 @@ +# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +# This file sets correct neon flags. Include it if you want to build +# source with neon intrinsics. +# To use this, create a gyp target with the following form: +# { +# 'target_name': 'my_lib', +# 'type': 'static_library', +# 'sources': [ +# 'foo.c', +# 'bar.cc', +# ], +# 'includes': ['path/to/this/gypi/file'], +# } + +{ + 'conditions': [ + ['OS=="android"', { + 'cflags!': [ + '-mfpu=vfpv3-d16', + ], + 'cflags': [ + '-mfpu=neon', + '-mfloat-abi=softfp', + '-flax-vector-conversions', + ], + }], + ], +} diff --git a/src/build/common.gypi b/src/build/common.gypi index d161b0cdf..9a9e68411 100644 --- a/src/build/common.gypi +++ b/src/build/common.gypi @@ -34,7 +34,6 @@ 'enable_video%': 1, # Selects fixed-point code where possible. - # TODO(andrew): we'd like to set this based on the target OS/architecture. 'prefer_fixed_point%': 0, # Enable data logging. Produces text files with data logged within engines @@ -46,6 +45,10 @@ 'build_libyuv%': 1, 'conditions': [ + ['OS=="android"', { + # On Android, we always prefer fixed_point to reduce CPU usage. + 'prefer_fixed_point%': 1, + }], ['build_with_chromium==1', { # Exclude pulse audio on Chromium since its prerequisites don't require # pulse audio. @@ -157,6 +160,9 @@ 'msvs_disabled_warnings!': [4189,], }], ['OS=="android"', { + # On android, we always perfer fixed_point to reduce cpu usage + 'prefer_fixed_point%': 1, + 'defines': [ 'WEBRTC_LINUX', 'WEBRTC_ANDROID', @@ -168,7 +174,6 @@ # with condition and event functions in system_wrappers. 'WEBRTC_CLOCK_TYPE_REALTIME', 'WEBRTC_THREAD_RR', - 'WEBRTC_ARM_INLINE_CALLS', 'WEBRTC_ANDROID_OPENSLES', ], }], diff --git a/src/modules/audio_processing/ns/ns.gypi b/src/modules/audio_processing/ns/ns.gypi index 147f7ead5..1dbbe6822 100644 --- a/src/modules/audio_processing/ns/ns.gypi +++ b/src/modules/audio_processing/ns/ns.gypi @@ -54,6 +54,33 @@ 'nsx_core.c', 'nsx_core.h', ], + 'conditions': [ + ['OS=="android"', { + 'dependencies': [ 'ns_neon', ], + 'defines': [ + 'WEBRTC_DETECT_ARM_NEON' + ], + }], + ], }, ], + 'conditions': [ + ['OS=="android"', { + 'targets': [ + { + 'target_name': 'ns_neon', + 'type': '<(library)', + 'includes': [ '../../../build/arm_neon.gypi', ], + 'dependencies': [ + '<(webrtc_root)/common_audio/common_audio.gyp:signal_processing', + ], + 'sources': [ + 'nsx_core_neon.c', + ], + }, + ], + }], + ], } + + diff --git a/src/modules/audio_processing/ns/nsx_core_neon.c b/src/modules/audio_processing/ns/nsx_core_neon.c index 2f85abd05..92daa75d9 100644 --- a/src/modules/audio_processing/ns/nsx_core_neon.c +++ b/src/modules/audio_processing/ns/nsx_core_neon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -15,7 +15,6 @@ // Update the noise estimation information. static void UpdateNoiseEstimateNeon(NsxInst_t* inst, int offset) { - int i = 0; const int16_t kExp2Const = 11819; // Q13 int16_t* ptr_noiseEstLogQuantile = NULL; int16_t* ptr_noiseEstQuantile = NULL; @@ -166,7 +165,8 @@ static void NoiseEstimationNeon(NsxInst_t* inst, int16x8_t tmp16x8_1; int16x8_t tmp16x8_2; int16x8_t tmp16x8_3; - int16x8_t tmp16x8_4; + // Initialize tmp16x8_4 to zero to avoid compilaton error. + int16x8_t tmp16x8_4 = vdupq_n_s16(0); int16x8_t tmp16x8_5; int32x4_t tmp32x4; @@ -499,7 +499,7 @@ static void SynthesisUpdateNeon(NsxInst_t* inst, int16_t gain_factor) { int16_t* ptr_real = &inst->real[0]; int16_t* ptr_syn = &inst->synthesisBuffer[0]; - int16_t* ptr_window = &inst->window[0]; + const int16_t* ptr_window = &inst->window[0]; // synthesis __asm__ __volatile__("vdup.16 d24, %0" : : "r"(gain_factor) : "d24"); @@ -647,7 +647,7 @@ static void AnalysisUpdateNeon(NsxInst_t* inst, } // Window data before FFT - int16_t* ptr_window = &inst->window[0]; + const int16_t* ptr_window = &inst->window[0]; ptr_out = &out[0]; ptr_ana = &inst->analysisBuffer[0]; for (; ptr_out < &out[inst->anaLen];) { diff --git a/src/system_wrappers/source/Android.mk b/src/system_wrappers/source/Android.mk index 49aed3124..08c682790 100644 --- a/src/system_wrappers/source/Android.mk +++ b/src/system_wrappers/source/Android.mk @@ -17,6 +17,8 @@ LOCAL_MODULE := libwebrtc_system_wrappers LOCAL_MODULE_TAGS := optional LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := \ + android/cpu-features.c \ + cpu_features_android.c \ map.cc \ sort.cc \ aligned_malloc.cc \ @@ -24,7 +26,6 @@ LOCAL_SRC_FILES := \ condition_variable.cc \ cpu_no_op.cc \ cpu_features.cc \ - cpu_features_arm.c \ cpu_info.cc \ critical_section.cc \ event.cc \ diff --git a/src/system_wrappers/source/android/cpu-features.c b/src/system_wrappers/source/android/cpu-features.c new file mode 100644 index 000000000..6a5cd8f1a --- /dev/null +++ b/src/system_wrappers/source/android/cpu-features.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#ifdef __arm__ +#include +#endif +#include +#include "cpu-features.h" +#include +#include +#include +#include + +static pthread_once_t g_once; +static AndroidCpuFamily g_cpuFamily; +static uint64_t g_cpuFeatures; +static int g_cpuCount; + +static const int android_cpufeatures_debug = 0; + +#ifdef __arm__ +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM +#elif defined __i386__ +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86 +#else +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN +#endif + +#define D(...) \ + do { \ + if (android_cpufeatures_debug) { \ + printf(__VA_ARGS__); fflush(stdout); \ + } \ + } while (0) + +#ifdef __i386__ +static __inline__ void x86_cpuid(int func, int values[4]) +{ + int a, b, c, d; + /* We need to preserve ebx since we're compiling PIC code */ + /* this means we can't use "=b" for the second output register */ + __asm__ __volatile__ ( \ + "push %%ebx\n" + "cpuid\n" \ + "mov %1, %%ebx\n" + "pop %%ebx\n" + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "a" (func) \ + ); + values[0] = a; + values[1] = b; + values[2] = c; + values[3] = d; +} +#endif + +/* 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; +} + +/* Count the number of occurences of a given field prefix in /proc/cpuinfo. + */ +static int +count_cpuinfo_field(char* buffer, int buflen, const char* field) +{ + int fieldlen = strlen(field); + const char* p = buffer; + const char* bufend = buffer + buflen; + const char* q; + int count = 0; + + for (;;) { + const char* q; + + p = memmem(p, bufend-p, field, fieldlen); + if (p == NULL) + break; + + /* Ensure that the field is at the start of a line */ + if (p > buffer && p[-1] != '\n') { + p += fieldlen; + continue; + } + + + /* skip any whitespace */ + q = p + fieldlen; + while (q < bufend && (*q == ' ' || *q == '\t')) + q++; + + /* we must have a colon now */ + if (q < bufend && *q == ':') { + count += 1; + q ++; + } + p = q; + } + + return count; +} + +/* Like strlen(), but for constant string literals */ +#define STRLEN_CONST(x) ((sizeof(x)-1) + + +/* 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) +{ + char cpuinfo[4096]; + int cpuinfo_len; + + g_cpuFamily = DEFAULT_CPU_FAMILY; + g_cpuFeatures = 0; + g_cpuCount = 1; + + cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo); + D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, + cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); + + if (cpuinfo_len < 0) /* should not happen */ { + return; + } + + /* Count the CPU cores, the value may be 0 for single-core CPUs */ + g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "processor"); + if (g_cpuCount == 0) { + g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "Processor"); + if (g_cpuCount == 0) { + g_cpuCount = 1; + } + } + + D("found cpuCount = %d\n", g_cpuCount); + +#ifdef __ARM_ARCH__ + { + char* features = NULL; + char* architecture = NULL; + + /* Extract architecture from the "CPU Architecture" field. + * The list is well-known, unlike the the output of + * the 'Processor' field which can vary greatly. + * + * See the definition of the 'proc_arch' array in + * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in + * same file. + */ + char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture"); + + if (cpuArch != NULL) { + char* end; + long archNumber; + int hasARMv7 = 0; + + 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) { + hasARMv7 = 1; + } + + /* Unfortunately, it seems that certain ARMv6-based CPUs + * report an incorrect architecture number of 7! + * + * See http://code.google.com/p/android/issues/detail?id=10812 + * + * We try to correct this by looking at the 'elf_format' + * field reported by the 'Processor' field, which is of the + * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for + * an ARMv6-one. + */ + if (hasARMv7) { + char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, + "Processor"); + if (cpuProc != NULL) { + D("found cpuProc = '%s'\n", cpuProc); + if (has_list_item(cpuProc, "(v6l)")) { + D("CPU processor and architecture mismatch!!\n"); + hasARMv7 = 0; + } + free(cpuProc); + } + } + + if (hasARMv7) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; + } + + /* The LDREX / STREX instructions are available from ARMv6 */ + if (archNumber >= 6) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; + } + + 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; + + else if (has_list_item(cpuFeatures, "vfpv3d16")) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; + + if (has_list_item(cpuFeatures, "neon")) { + /* Note: Certain kernels only report neon but not vfpv3 + * in their features list. However, ARM mandates + * that if Neon is implemented, so must be VFPv3 + * so always set the flag. + */ + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON | + ANDROID_CPU_ARM_FEATURE_VFPv3; + } + free(cpuFeatures); + } + } +#endif /* __ARM_ARCH__ */ + +#ifdef __i386__ + g_cpuFamily = ANDROID_CPU_FAMILY_X86; + + int regs[4]; + +/* According to http://en.wikipedia.org/wiki/CPUID */ +#define VENDOR_INTEL_b 0x756e6547 +#define VENDOR_INTEL_c 0x6c65746e +#define VENDOR_INTEL_d 0x49656e69 + + x86_cpuid(0, regs); + int vendorIsIntel = (regs[1] == VENDOR_INTEL_b && + regs[2] == VENDOR_INTEL_c && + regs[3] == VENDOR_INTEL_d); + + x86_cpuid(1, regs); + if ((regs[2] & (1 << 9)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; + } + if ((regs[2] & (1 << 23)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; + } + if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; + } +#endif +} + + +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; +} + + +int +android_getCpuCount(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuCount; +} diff --git a/src/system_wrappers/source/android/cpu-features.h b/src/system_wrappers/source/android/cpu-features.h new file mode 100644 index 000000000..f20c0bc4d --- /dev/null +++ b/src/system_wrappers/source/android/cpu-features.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// You can download Android source at +// http://source.android.com/source/downloading.html +// Original files are in ndk/sources/android/cpufeatures +// Revision is Change-Id: I9a0629efba36a6023f05e5f092e7addcc1b7d2a9 + +#ifndef CPU_FEATURES_H +#define CPU_FEATURES_H + +#include +#include + +__BEGIN_DECLS + +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), + ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3), +}; + +enum { + ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0), + ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1), + ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2), +}; + +extern uint64_t android_getCpuFeatures(void); + +/* Return the number of CPU cores detected on this device. */ +extern int android_getCpuCount(void); + +__END_DECLS + +#endif /* CPU_FEATURES_H */ diff --git a/src/system_wrappers/source/cpu_features_android.c b/src/system_wrappers/source/cpu_features_android.c new file mode 100644 index 000000000..7a4fa6ef2 --- /dev/null +++ b/src/system_wrappers/source/cpu_features_android.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "android/cpu-features.h" + +uint64_t WebRtc_GetCPUFeaturesARM(void) { + return android_getCpuFeatures(); +} diff --git a/src/system_wrappers/source/cpu_features_arm.c b/src/system_wrappers/source/cpu_features_arm.c deleted file mode 100644 index 106511852..000000000 --- a/src/system_wrappers/source/cpu_features_arm.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// This file is derived from Android's NDK package r7, located at -// /sources/android/cpufeatures/ (downloadable from -// http://developer.android.com/sdk/ndk/index.html). - -#include "cpu_features_wrapper.h" - -#include -#include -#include -#include -#include - -// Define CPU family. -typedef enum { - CPU_FAMILY_UNKNOWN = 0, - CPU_FAMILY_ARM, - CPU_FAMILY_X86, - CPU_FAMILY_MAX // Do not remove. -} CpuFamily; - -static pthread_once_t g_once; -static CpuFamily g_cpuFamily; -static uint64_t g_cpuFeatures; -static int g_cpuCount; - -static const int cpufeatures_debug = 0; - -#ifdef __arm__ -# define DEFAULT_CPU_FAMILY CPU_FAMILY_ARM -#elif defined __i386__ -# define DEFAULT_CPU_FAMILY CPU_FAMILY_X86 -#else -# define DEFAULT_CPU_FAMILY CPU_FAMILY_UNKNOWN -#endif - -#define D(...) \ - do { \ - if (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; -} - -/* Count the number of occurences of a given field prefix in /proc/cpuinfo. - */ -static int count_cpuinfo_field(char* buffer, int buflen, const char* field) { - int fieldlen = strlen(field); - const char* p = buffer; - const char* bufend = buffer + buflen; - const char* q; - int count = 0; - - for (;;) { - const char* q; - - p = memmem(p, bufend - p, field, fieldlen); - if (p == NULL) - break; - - /* Ensure that the field is at the start of a line */ - if (p > buffer && p[-1] != '\n') { - p += fieldlen; - continue; - } - - - /* skip any whitespace */ - q = p + fieldlen; - while (q < bufend && (*q == ' ' || *q == '\t')) - q++; - - /* we must have a colon now */ - if (q < bufend && *q == ':') { - count += 1; - q ++; - } - p = q; - } - - return count; -} - -/* Like strlen(), but for constant string literals */ -#define STRLEN_CONST(x) ((sizeof(x)-1) - - -/* 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 cpuInit(void) { - char cpuinfo[4096]; - int cpuinfo_len; - - g_cpuFamily = DEFAULT_CPU_FAMILY; - g_cpuFeatures = 0; - g_cpuCount = 1; - - cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo); - D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, - cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); - - if (cpuinfo_len < 0) { /* should not happen */ - return; - } - - /* Count the CPU cores, the value may be 0 for single-core CPUs */ - g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "processor"); - if (g_cpuCount == 0) { - g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "Processor"); - if (g_cpuCount == 0) { - g_cpuCount = 1; - } - } - - D("found cpuCount = %d\n", g_cpuCount); - -#ifdef __arm__ - { - char* features = NULL; - char* architecture = NULL; - - /* Extract architecture from the "CPU Architecture" field. - * The list is well-known, unlike the the output of - * the 'Processor' field which can vary greatly. - * - * See the definition of the 'proc_arch' array in - * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in - * same file. - */ - char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, - "CPU architecture"); - - if (cpuArch != NULL) { - char* end; - long archNumber; - int hasARMv7 = 0; - - 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) { - hasARMv7 = 1; - } - - /* Unfortunately, it seems that certain ARMv6-based CPUs - * report an incorrect architecture number of 7! - * - * We try to correct this by looking at the 'elf_format' - * field reported by the 'Processor' field, which is of the - * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for - * an ARMv6-one. - */ - if (hasARMv7) { - char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, - "Processor"); - if (cpuProc != NULL) { - D("found cpuProc = '%s'\n", cpuProc); - if (has_list_item(cpuProc, "(v6l)")) { - D("CPU processor and architecture mismatch!!\n"); - hasARMv7 = 0; - } - free(cpuProc); - } - } - - if (hasARMv7) { - g_cpuFeatures |= kCPUFeatureARMv7; - } - - /* The LDREX / STREX instructions are available from ARMv6 */ - if (archNumber >= 6) { - g_cpuFeatures |= kCPUFeatureLDREXSTREX; - } - - 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 |= kCPUFeatureVFPv3; - - else if (has_list_item(cpuFeatures, "vfpv3d16")) - g_cpuFeatures |= kCPUFeatureVFPv3; - - if (has_list_item(cpuFeatures, "neon")) { - /* Note: Certain kernels only report neon but not vfpv3 - * in their features list. However, ARM mandates - * that if Neon is implemented, so must be VFPv3 - * so always set the flag. - */ - g_cpuFeatures |= kCPUFeatureNEON | - kCPUFeatureVFPv3; - } - free(cpuFeatures); - } - } -#endif // __arm__ - -#ifdef __i386__ - g_cpuFamily = CPU_FAMILY_X86; -#endif -} - - -uint64_t WebRtc_GetCPUFeaturesARM(void) { - pthread_once(&g_once, cpuInit); - return g_cpuFeatures; -} diff --git a/src/system_wrappers/source/system_wrappers.gyp b/src/system_wrappers/source/system_wrappers.gyp index 8b6d63ec6..4a1b4fab6 100644 --- a/src/system_wrappers/source/system_wrappers.gyp +++ b/src/system_wrappers/source/system_wrappers.gyp @@ -57,6 +57,7 @@ 'condition_variable_win.cc', 'condition_variable_win.h', 'cpu.cc', + 'cpu_features_android.c', 'cpu_no_op.cc', 'cpu_info.cc', 'cpu_linux.cc', @@ -109,6 +110,9 @@ },{ 'sources!': [ 'data_log.cc', ], },], + ['OS=="android"', { + 'dependencies': [ 'cpu_features_android', ], + }], ['OS=="linux"', { 'link_settings': { 'libraries': [ '-lrt', ], @@ -150,6 +154,22 @@ }, ], # targets 'conditions': [ + ['OS=="android"', { + 'targets': [ + { + 'variables': { + # Treat this as third-party code. + 'chromium_code': 0, + }, + 'target_name': 'cpu_features_android', + 'type': '<(library)', + 'sources': [ + 'android/cpu-features.c', + 'android/cpu-features.h', + ], + }, + ], + }], ['build_with_chromium==0', { 'targets': [ { diff --git a/src/video_engine/main/test/android_test/jni/Android.mk b/src/video_engine/main/test/android_test/jni/Android.mk index 36ee2528d..c9c488b9a 100644 --- a/src/video_engine/main/test/android_test/jni/Android.mk +++ b/src/video_engine/main/test/android_test/jni/Android.mk @@ -166,6 +166,12 @@ LOCAL_SRC_FILES := \ $(MY_LIBS_PATH)/src/system_wrappers/source/libsystem_wrappers.a include $(PREBUILT_STATIC_LIBRARY) +include $(CLEAR_VARS) +LOCAL_MODULE := libcpu_features_android +LOCAL_SRC_FILES := \ + $(MY_LIBS_PATH)/src/system_wrappers/source/libcpu_features_android.a +include $(PREBUILT_STATIC_LIBRARY) + include $(CLEAR_VARS) LOCAL_MODULE := libaudio_device LOCAL_SRC_FILES := \ @@ -304,6 +310,7 @@ LOCAL_STATIC_LIBRARIES := \ libsignal_processing \ libapm_util \ libsystem_wrappers \ + libcpu_features_android \ libaudio_device \ librtp_rtcp \ libmedia_file \