OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 |
| 7 #include "CPU.h" |
| 8 |
| 9 #if CPU(ARM_NEON_OPTIONAL) |
| 10 |
| 11 #include "wtf/Assertions.h" |
| 12 #include <pthread.h> |
| 13 |
| 14 #if OS(ANDROID) |
| 15 #include <cpu-features.h> |
| 16 #elif OS(LINUX) |
| 17 #include <errno.h> |
| 18 #include <fcntl.h> |
| 19 #include <string.h> |
| 20 #include <unistd.h> |
| 21 #endif |
| 22 |
| 23 static pthread_once_t sOnce; |
| 24 static bool sHasArmNeon; |
| 25 |
| 26 // A function used to determine at runtime if the target CPU supports |
| 27 // the ARM NEON instruction set. This implementation is Linux and Android specif
ic. |
| 28 static bool checkNEON(void) |
| 29 { |
| 30 // If we fail any of the following, assume we don't have NEON instructions |
| 31 // This allows us to return immediately in case of error. |
| 32 bool result = false; |
| 33 |
| 34 #if OS(ANDROID) |
| 35 // Use the Android NDK's cpu-features helper library to detect NEON at runti
me. |
| 36 // See http://crbug.com/164154 for skia to see why this is needed in Chromiu
m for Android. |
| 37 result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; |
| 38 #elif OS(LINUX) |
| 39 // There is no user-accessible CPUID instruction on ARM that we can use. |
| 40 // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature. |
| 41 // For example, here's a typical output (Nexus S running ICS 4.0.3): |
| 42 /* |
| 43 Processor : ARMv7 Processor rev 2 (v7l) |
| 44 BogoMIPS : 994.65 |
| 45 Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 |
| 46 CPU implementer : 0x41 |
| 47 CPU architecture: 7 |
| 48 CPU variant : 0x2 |
| 49 CPU part : 0xc08 |
| 50 CPU revision : 2 |
| 51 |
| 52 Hardware : herring |
| 53 Revision : 000b |
| 54 Serial : 3833c77d6dc000ec |
| 55 */ |
| 56 char buffer[4096]; |
| 57 |
| 58 do { |
| 59 // open /proc/cpuinfo |
| 60 int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY)); |
| 61 if (fd < 0) { |
| 62 WTF_LOG_ERROR("Could not open /proc/cpuinfo: %s", strerror(errno)); |
| 63 break; |
| 64 } |
| 65 |
| 66 // Read the file. To simplify our search, we're going to place two |
| 67 // sentinel '\n' characters: one at the start of the buffer, and one at |
| 68 // the end. This means we reserve the first and last buffer bytes. |
| 69 buffer[0] = '\n'; |
| 70 int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2)); |
| 71 close(fd); |
| 72 |
| 73 if (size < 0) { |
| 74 WTF_LOG_ERROR("Could not read /proc/cpuinfo: %s", strerror(errno)); |
| 75 break; |
| 76 } |
| 77 |
| 78 WTF_LOG(CPU, "START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo", size, buff
er+1); |
| 79 |
| 80 // Compute buffer limit, and place final sentinel |
| 81 char* bufferEnd = buffer + 1 + size; |
| 82 bufferEnd[0] = '\n'; |
| 83 |
| 84 // Now, find a line that starts with "Features", i.e. look for |
| 85 // '\nFeatures ' in our buffer. |
| 86 const char features[] = "\nFeatures\t"; |
| 87 const size_t featuresLength = sizeof(features)-1; |
| 88 |
| 89 char* line = (char*) memmem(buffer, bufferEnd - buffer, features, featur
esLength); |
| 90 if (!line) { |
| 91 WTF_LOG(CPU, "Could not find a line starting with 'Features' in /pro
c/cpuinfo ?"); |
| 92 break; |
| 93 } |
| 94 |
| 95 // Skip the "\nFeatures\t" prefix |
| 96 line += featuresLength; |
| 97 |
| 98 // Find the end of the current line |
| 99 char* lineEnd = (char*) memchr(line, '\n', bufferEnd - line); |
| 100 if (!lineEnd) |
| 101 lineEnd = bufferEnd; |
| 102 |
| 103 // Now find an instance of 'neon' in the flags list. We want to |
| 104 // ensure it's only 'neon' and not something fancy like 'noneon' |
| 105 // so check that it follows a space. |
| 106 const char neon[] = " neon"; |
| 107 const size_t neonLength = sizeof(neon)-1; |
| 108 const char* flag = (const char*) memmem(line, lineEnd - line, neon, neon
Length); |
| 109 if (!flag) |
| 110 break; |
| 111 |
| 112 // Ensure it is followed by a space or a newline. |
| 113 if (flag[neonLength] != ' ' && flag[neonLength] != '\n') |
| 114 break; |
| 115 |
| 116 // Fine, we support Arm NEON ! |
| 117 result = true; |
| 118 |
| 119 } while (0); |
| 120 #endif // OS(ANDROID) |
| 121 |
| 122 if (result) |
| 123 WTF_LOG(CPU, "Device supports ARM NEON instructions!\n"); |
| 124 else |
| 125 WTF_LOG(CPU, "Device does NOT support ARM NEON instructions!\n"); |
| 126 return result; |
| 127 } |
| 128 |
| 129 // called through pthread_once() |
| 130 void probeNEONFeature(void) |
| 131 { |
| 132 sHasArmNeon = checkNEON(); |
| 133 } |
| 134 |
| 135 bool isSupportedNEON(void) |
| 136 { |
| 137 pthread_once(&sOnce, probeNEONFeature); |
| 138 return sHasArmNeon; |
| 139 } |
| 140 #endif |
OLD | NEW |