diff options
author | 2016-04-15 08:40:22 -0700 | |
---|---|---|
committer | 2016-04-15 08:40:23 -0700 | |
commit | 86498fbfcb93a9048bbe1c28cc0df40d8d0c96e9 (patch) | |
tree | a579fdee9a3cf330050dbe7fd0a3a25d49783693 /src/core/SkUtilsArm.cpp | |
parent | 2c7f24093a394ccbe54a7db60ba79af14682e7fa (diff) |
Revert of Move CPU feature detection to its own file. (patchset #7 id:120001 of https://codereview.chromium.org/1890483002/ )
Reason for revert:
many unexpected GM diffs across GPU+CPU configs on Windows (hopefully just text masks on GPU?). seems like we pick a different srcover variant in some places.
Original issue's description:
> Move CPU feature detection to its own file.
>
> - Moves CPU feature detection to its own file.
> - Cleans up some redundant feature detection scattered around core/ and opts/.
> - Can now detect a few new CPU features:
> * F16C -> Intel f16<->f32 instructions, added between AVX and AVX2
> * FMA -> Intel FMA instructions, added at the same time as AVX2
> * VFP_FP16 -> ARM f16<->f32 instructions, quite common
> * NEON_FMA -> ARM FMA instructions, also quite common
> * SSE and SSE3... why not?
>
> This new internal API makes it very cheap to do fine-grained runtime CPU
> feature detection. Redundant calls to SkCpu::Supports() should be eliminated
> and it's hoistable out of loops. It compiles away entirely when we have the
> appropriate instructions available at compile time.
>
> This means we can call it to guard even a little snippet of 1 or 2 instructions
> right where needed and let inlining hoist the check (if any at all) up to
> somewhere that doesn't hurt performance. I've explained how I made this work
> in the private section of the new header.
>
> Once this lands and bakes a bit, I'll start following up with CLs to use it more
> and to add a bunch of those little 1-2 instruction snippets we've been wanting,
> e.g. cvtps2ph, cvtph2ps, ptest, pmulld, pmovzxbd, blendvps, pshufb, roundps
> (for floor) on x86, and vcvt.f32.f16, vcvt.f16.f32 on ARM.
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1890483002
> CQ_EXTRA_TRYBOTS=client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot
>
> Committed: https://skia.googlesource.com/skia/+/872ea29357439f05b1f6995dd300fc054733e607
TBR=fmalita@chromium.org,herb@google.com,reed@google.com,mtklein@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:
Review URL: https://codereview.chromium.org/1892643003
Diffstat (limited to 'src/core/SkUtilsArm.cpp')
-rw-r--r-- | src/core/SkUtilsArm.cpp | 139 |
1 files changed, 138 insertions, 1 deletions
diff --git a/src/core/SkUtilsArm.cpp b/src/core/SkUtilsArm.cpp index c29938fdfc..bf98fed476 100644 --- a/src/core/SkUtilsArm.cpp +++ b/src/core/SkUtilsArm.cpp @@ -5,4 +5,141 @@ * found in the LICENSE file. */ -// This file no longer needs to exist, but it's still referenced by Chrome's GYP / GN builds. +#include "SkUtilsArm.h" + +#if SK_ARM_NEON_IS_DYNAMIC + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> + +#if defined(SK_BUILD_FOR_ANDROID) +# include <cpu-features.h> +#endif + +// A function used to determine at runtime if the target CPU supports +// the ARM NEON instruction set. This implementation is Linux-specific. +static bool sk_cpu_arm_check_neon(void) { + // If we fail any of the following, assume we don't have NEON instructions + // This allows us to return immediately in case of error. + bool result = false; + +// Use the Android NDK's cpu-features helper library to detect NEON at runtime. +// See http://crbug.com/164154 to see why this is needed in Chromium for Android. +#ifdef SK_BUILD_FOR_ANDROID + + result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; + +#else // SK_BUILD_FOR_ANDROID + + // There is no user-accessible CPUID instruction on ARM that we can use. + // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature. + // For example, here's a typical output (Nexus S running ICS 4.0.3): + /* + Processor : ARMv7 Processor rev 2 (v7l) + BogoMIPS : 994.65 + Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 + CPU implementer : 0x41 + CPU architecture: 7 + CPU variant : 0x2 + CPU part : 0xc08 + CPU revision : 2 + + Hardware : herring + Revision : 000b + Serial : 3833c77d6dc000ec + */ + char buffer[4096]; + + do { + // open /proc/cpuinfo + int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY)); + if (fd < 0) { + SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno)); + break; + } + + // Read the file. To simplify our search, we're going to place two + // sentinel '\n' characters: one at the start of the buffer, and one at + // the end. This means we reserve the first and last buffer bytes. + buffer[0] = '\n'; + int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2)); + close(fd); + + if (size < 0) { // should not happen + SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno)); + break; + } + + SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n", + size, buffer+1); + + // Compute buffer limit, and place final sentinel + char* buffer_end = buffer + 1 + size; + buffer_end[0] = '\n'; + + // Now, find a line that starts with "Features", i.e. look for + // '\nFeatures ' in our buffer. + const char features[] = "\nFeatures\t"; + const size_t features_len = sizeof(features)-1; + + char* line = (char*) memmem(buffer, buffer_end - buffer, + features, features_len); + if (line == nullptr) { // Weird, no Features line, bad kernel? + SkDebugf("Could not find a line starting with 'Features'" + "in /proc/cpuinfo ?\n"); + break; + } + + line += features_len; // Skip the "\nFeatures\t" prefix + + // Find the end of the current line + char* line_end = (char*) memchr(line, '\n', buffer_end - line); + if (line_end == nullptr) + line_end = buffer_end; + + // Now find an instance of 'neon' in the flags list. We want to + // ensure it's only 'neon' and not something fancy like 'noneon' + // so check that it follows a space. + const char neon[] = " neon"; + const size_t neon_len = sizeof(neon)-1; + const char* flag = (const char*) memmem(line, line_end - line, + neon, neon_len); + if (flag == nullptr) + break; + + // Ensure it is followed by a space or a newline. + if (flag[neon_len] != ' ' && flag[neon_len] != '\n') + break; + + // Fine, we support Arm NEON ! + result = true; + + } while (0); + +#endif // SK_BUILD_FOR_ANDROID + + if (result) { + SkDEBUGF(("Device supports ARM NEON instructions!\n")); + } else { + SkDEBUGF(("Device does NOT support ARM NEON instructions!\n")); + } + return result; +} + +static pthread_once_t sOnce; +static bool sHasArmNeon; + +// called through pthread_once() +void sk_cpu_arm_probe_features(void) { + sHasArmNeon = sk_cpu_arm_check_neon(); +} + +bool sk_cpu_arm_has_neon(void) { + pthread_once(&sOnce, sk_cpu_arm_probe_features); + return sHasArmNeon; +} + +#endif // SK_ARM_NEON_IS_DYNAMIC |