Use no-SIMD engine version when needed

If the CPU does not support the required SIMD instructions, use the
stockfish_nosimd engine version instead.
This commit is contained in:
Peter Osterlund
2020-09-13 20:03:11 +02:00
parent fe9689e5f2
commit 82e1eb2e0e
27 changed files with 4265 additions and 11 deletions

View File

@@ -1,14 +1,6 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include src/main/cpp/nativeutil/Android.mk
LOCAL_MODULE := nativeutil
LOCAL_SRC_FILES := nativeutil.cpp
include $(BUILD_SHARED_LIBRARY)
include src/main/cpp/stockfish/Android.mk include src/main/cpp/stockfish/Android.mk
include src/main/cpp/gtb/Android.mk include src/main/cpp/gtb/Android.mk
include src/main/cpp/rtb/Android.mk include src/main/cpp/rtb/Android.mk

View File

@@ -1,4 +1,3 @@
APP_PLATFORM := android-14
APP_ABI := all APP_ABI := all
APP_STL := c++_static APP_STL := c++_static
APP_OPTIM := release APP_OPTIM := release

View File

@@ -0,0 +1,34 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
UTIL_SRC_FILES := nativeutil.cpp
CPU_FEATS := cpu_features
CPU_FEATS_SRC_FILES += $(CPU_FEATS)/src/filesystem.c \
$(CPU_FEATS)/src/stack_line_reader.c \
$(CPU_FEATS)/src/string_view.c \
$(CPU_FEATS)/src/hwcaps.c \
$(CPU_FEATS)/src/unix_features_aggregator.c
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
UTIL_SRC_FILES += $(CPU_FEATS_SRC_FILES) $(CPU_FEATS)/src/cpuinfo_arm.c
endif
#ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
# UTIL_SRC_FILES += $(CPU_FEATS_SRC_FILES) $(CPU_FEATS)/src/cpuinfo_aarch64.c
#endif
ifeq ($(TARGET_ARCH_ABI),x86)
UTIL_SRC_FILES += $(CPU_FEATS_SRC_FILES) $(CPU_FEATS)/src/cpuinfo_x86.c
endif
#ifeq ($(TARGET_ARCH_ABI),x86_64)
# UTIL_SRC_FILES += $(CPU_FEATS_SRC_FILES) $(CPU_FEATS)/src/cpuinfo_x86.c
#endif
LOCAL_MODULE := nativeutil
LOCAL_SRC_FILES := $(UTIL_SRC_FILES)
LOCAL_CFLAGS := -I$(LOCAL_PATH)/$(CPU_FEATS)/include \
-I$(LOCAL_PATH)/$(CPU_FEATS)/include/internal \
-DHAVE_DLFCN_H=1 -DSTACK_LINE_READER_BUFFER_SIZE=1024 \
-fPIC -s
LOCAL_LDFLAGS := -fPIC -s
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,230 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
For files in the `ndk_compat` folder:
--------------------------------------------------------------------------------
Copyright (C) 2010 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@@ -0,0 +1,174 @@
# cpu_features [![Build Status](https://travis-ci.org/google/cpu_features.svg?branch=master)](https://travis-ci.org/google/cpu_features) [![Build status](https://ci.appveyor.com/api/projects/status/46d1owsj7n8dsylq/branch/master?svg=true)](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master)
A cross-platform C library to retrieve CPU features (such as available
instructions) at runtime.
## Table of Contents
- [Design Rationale](#rationale)
- [Code samples](#codesample)
- [Running sample code](#usagesample)
- [What's supported](#support)
- [Android NDK's drop in replacement](#ndk)
- [License](#license)
- [Build with cmake](#cmake)
<a name="rationale"></a>
## Design Rationale
- **Simple to use.** See the snippets below for examples.
- **Extensible.** Easy to add missing features or architectures.
- **Compatible with old compilers** and available on many architectures so it
can be used widely. To ensure that cpu_features works on as many platforms
as possible, we implemented it in a highly portable version of C: C99.
- **Sandbox-compatible.** The library uses a variety of strategies to cope
with sandboxed environments or when `cpuid` is unavailable. This is useful
when running integration tests in hermetic environments.
- **Thread safe, no memory allocation, and raises no exceptions.**
cpu_features is suitable for implementing fundamental libc functions like
`malloc`, `memcpy`, and `memcmp`.
- **Unit tested.**
<a name="codesample"></a>
### Checking features at runtime
Here's a simple example that executes a codepath if the CPU supports both the
AES and the SSE4.2 instruction sets:
```c
#include "cpuinfo_x86.h"
static const X86Features features = GetX86Info().features;
void Compute(void) {
if (features.aes && features.sse4_2) {
// Run optimized code.
} else {
// Run standard code.
}
}
```
### Caching for faster evaluation of complex checks
If you wish, you can read all the features at once into a global variable, and
then query for the specific features you care about. Below, we store all the ARM
features and then check whether AES and NEON are supported.
```c
#include <stdbool.h>
#include "cpuinfo_arm.h"
static const ArmFeatures features = GetArmInfo().features;
static const bool has_aes_and_neon = features.aes && features.neon;
// use has_aes_and_neon.
```
This is a good approach to take if you're checking for combinations of features
when using a compiler that is slow to extract individual bits from bit-packed
structures.
### Checking compile time flags
The following code determines whether the compiler was told to use the AVX
instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
```c
#include <stdbool.h>
#include "cpuinfo_x86.h"
static const X86Features features = GetX86Info().features;
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
// use has_avx.
```
`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to
use AVX and 0 otherwise, combining compile time and runtime knowledge.
### Rejecting poor hardware implementations based on microarchitecture
On x86, the first incarnation of a feature in a microarchitecture might not be
the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve
the underlying microarchitecture so you can decide whether to use it.
Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction
set&mdash;but only if it's not Sandy Bridge.
```c
#include <stdbool.h>
#include "cpuinfo_x86.h"
static const X86Info info = GetX86Info();
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
// use has_fast_avx.
```
This feature is currently available only for x86 microarchitectures.
<a name="usagesample"></a>
### Running sample code
Building `cpu_features` brings a small executable to test the library.
```shell
% ./build/list_cpu_features
arch : x86
brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz
family : 6 (0x06)
model : 45 (0x2D)
stepping : 7 (0x07)
uarch : INTEL_SNB
flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
```
```shell
% ./build/list_cpu_features --json
{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
```
<a name="support"></a>
## What's supported
| | x86³ | ARM | AArch64 | MIPS⁴ | POWER |
|---------|:----:|:-------:|:-------:|:------:|:-------:|
| Android | yes² | yes¹ | yes¹ | yes¹ | N/A |
| iOS | N/A | not yet | not yet | N/A | N/A |
| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ |
| MacOs | yes² | N/A | not yet | N/A | no |
| Windows | yes² | not yet | not yet | N/A | N/A |
1. **Features revealed from Linux.** We gather data from several sources
depending on availability:
+ from glibc's
[getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html)
+ by parsing `/proc/self/auxv`
+ by parsing `/proc/cpuinfo`
2. **Features revealed from CPU.** features are retrieved by using the `cpuid`
instruction.
3. **Microarchitecture detection.** On x86 some features are not always
implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the
microarchitecture allows the client to reject particular microarchitectures.
4. All flavors of Mips are supported, little and big endian as well as 32/64
bits.
<a name="ndk"></a>
## Android NDK's drop in replacement
[cpu_features](https://github.com/google/cpu_features) is now officially
supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h)
, see [ndk_compat](ndk_compat) folder for details.
<a name="license"></a>
## License
The cpu_features library is licensed under the terms of the Apache license.
See [LICENSE](LICENSE) for more information.
<a name="cmake"></a>
## Build with CMake
Please check the [CMake build instructions](cmake/README.md).

View File

@@ -0,0 +1,54 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef enum {
CPU_FEATURE_CACHE_NULL = 0,
CPU_FEATURE_CACHE_DATA = 1,
CPU_FEATURE_CACHE_INSTRUCTION = 2,
CPU_FEATURE_CACHE_UNIFIED = 3,
CPU_FEATURE_CACHE_TLB = 4,
CPU_FEATURE_CACHE_DTLB = 5,
CPU_FEATURE_CACHE_STLB = 6,
CPU_FEATURE_CACHE_PREFETCH = 7
} CacheType;
typedef struct {
int level;
CacheType cache_type;
int cache_size; // Cache size in bytes
int ways; // Associativity, 0 undefined, 0xFF fully associative
int line_size; // Cache line size in bytes
int tlb_entries; // number of entries for TLB
int partitioning; // number of lines per sector
} CacheLevelInfo;
// Increase this value if more cache levels are needed.
#ifndef CPU_FEATURES_MAX_CACHE_LEVEL
#define CPU_FEATURES_MAX_CACHE_LEVEL 10
#endif
typedef struct {
int size;
CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL];
} CacheInfo;
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_

View File

@@ -0,0 +1,212 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
////////////////////////////////////////////////////////////////////////////////
// Architectures
////////////////////////////////////////////////////////////////////////////////
#if defined(__pnacl__) || defined(__CLR_VER)
#define CPU_FEATURES_ARCH_VM
#endif
#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM)
#define CPU_FEATURES_ARCH_X86_32
#endif
#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM)
#define CPU_FEATURES_ARCH_X86_64
#endif
#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64)
#define CPU_FEATURES_ARCH_X86
#endif
#if (defined(__arm__) || defined(_M_ARM))
#define CPU_FEATURES_ARCH_ARM
#endif
#if defined(__aarch64__)
#define CPU_FEATURES_ARCH_AARCH64
#endif
#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM))
#define CPU_FEATURES_ARCH_ANY_ARM
#endif
#if defined(__mips64)
#define CPU_FEATURES_ARCH_MIPS64
#endif
#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__
#define CPU_FEATURES_ARCH_MIPS32
#endif
#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64)
#define CPU_FEATURES_ARCH_MIPS
#endif
#if defined(__powerpc__)
#define CPU_FEATURES_ARCH_PPC
#endif
////////////////////////////////////////////////////////////////////////////////
// Os
////////////////////////////////////////////////////////////////////////////////
#if defined(__linux__)
#define CPU_FEATURES_OS_LINUX_OR_ANDROID
#endif
#if defined(__ANDROID__)
#define CPU_FEATURES_OS_ANDROID
#endif
#if (defined(_WIN64) || defined(_WIN32))
#define CPU_FEATURES_OS_WINDOWS
#endif
////////////////////////////////////////////////////////////////////////////////
// Compilers
////////////////////////////////////////////////////////////////////////////////
#if defined(__clang__)
#define CPU_FEATURES_COMPILER_CLANG
#endif
#if defined(__GNUC__) && !defined(__clang__)
#define CPU_FEATURES_COMPILER_GCC
#endif
#if defined(_MSC_VER)
#define CPU_FEATURES_COMPILER_MSC
#endif
////////////////////////////////////////////////////////////////////////////////
// Cpp
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
#define CPU_FEATURES_START_CPP_NAMESPACE \
namespace cpu_features { \
extern "C" {
#define CPU_FEATURES_END_CPP_NAMESPACE \
} \
}
#else
#define CPU_FEATURES_START_CPP_NAMESPACE
#define CPU_FEATURES_END_CPP_NAMESPACE
#endif
////////////////////////////////////////////////////////////////////////////////
// Compiler flags
////////////////////////////////////////////////////////////////////////////////
// Use the following to check if a feature is known to be available at
// compile time. See README.md for an example.
#if defined(CPU_FEATURES_ARCH_X86)
#if defined(__AES__)
#define CPU_FEATURES_COMPILED_X86_AES 1
#else
#define CPU_FEATURES_COMPILED_X86_AES 0
#endif // defined(__AES__)
#if defined(__F16C__)
#define CPU_FEATURES_COMPILED_X86_F16C 1
#else
#define CPU_FEATURES_COMPILED_X86_F16C 0
#endif // defined(__F16C__)
#if defined(__BMI__)
#define CPU_FEATURES_COMPILED_X86_BMI 1
#else
#define CPU_FEATURES_COMPILED_X86_BMI 0
#endif // defined(__BMI__)
#if defined(__BMI2__)
#define CPU_FEATURES_COMPILED_X86_BMI2 1
#else
#define CPU_FEATURES_COMPILED_X86_BMI2 0
#endif // defined(__BMI2__)
#if (defined(__SSE__) || (_M_IX86_FP >= 1))
#define CPU_FEATURES_COMPILED_X86_SSE 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE 0
#endif
#if (defined(__SSE2__) || (_M_IX86_FP >= 2))
#define CPU_FEATURES_COMPILED_X86_SSE2 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE2 0
#endif
#if defined(__SSE3__)
#define CPU_FEATURES_COMPILED_X86_SSE3 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE3 0
#endif // defined(__SSE3__)
#if defined(__SSSE3__)
#define CPU_FEATURES_COMPILED_X86_SSSE3 1
#else
#define CPU_FEATURES_COMPILED_X86_SSSE3 0
#endif // defined(__SSSE3__)
#if defined(__SSE4_1__)
#define CPU_FEATURES_COMPILED_X86_SSE4_1 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE4_1 0
#endif // defined(__SSE4_1__)
#if defined(__SSE4_2__)
#define CPU_FEATURES_COMPILED_X86_SSE4_2 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE4_2 0
#endif // defined(__SSE4_2__)
#if defined(__AVX__)
#define CPU_FEATURES_COMPILED_X86_AVX 1
#else
#define CPU_FEATURES_COMPILED_X86_AVX 0
#endif // defined(__AVX__)
#if defined(__AVX2__)
#define CPU_FEATURES_COMPILED_X86_AVX2 1
#else
#define CPU_FEATURES_COMPILED_X86_AVX2 0
#endif // defined(__AVX2__)
#endif // defined(CPU_FEATURES_ARCH_X86)
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
#if defined(__ARM_NEON__)
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1
#else
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0
#endif // defined(__ARM_NEON__)
#endif // defined(CPU_FEATURES_ARCH_ANY_ARM)
#if defined(CPU_FEATURES_ARCH_MIPS)
#if defined(__mips_msa)
#define CPU_FEATURES_COMPILED_MIPS_MSA 1
#else
#define CPU_FEATURES_COMPILED_MIPS_MSA 0
#endif // defined(__mips_msa)
#endif // defined(CPU_FEATURES_ARCH_MIPS)
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_

View File

@@ -0,0 +1,120 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
#include "cpu_features_macros.h"
#include "cpu_features_cache_info.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int fp : 1; // Floating-point.
int asimd : 1; // Advanced SIMD.
int evtstrm : 1; // Generic timer generated events.
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
int atomics : 1; // Armv8.1 atomic instructions.
int fphp : 1; // Half-precision floating point support.
int asimdhp : 1; // Advanced SIMD half-precision support.
int cpuid : 1; // Access to certain ID registers.
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
int jscvt : 1; // Support for JavaScript conversion.
int fcma : 1; // Floating point complex numbers.
int lrcpc : 1; // Support for weaker release consistency.
int dcpop : 1; // Data persistence writeback.
int sha3 : 1; // Hardware-accelerated SHA3.
int sm3 : 1; // Hardware-accelerated SM3.
int sm4 : 1; // Hardware-accelerated SM4.
int asimddp : 1; // Dot product instruction.
int sha512 : 1; // Hardware-accelerated SHA512.
int sve : 1; // Scalable Vector Extension.
int asimdfhm : 1; // Additional half-precision instructions.
int dit : 1; // Data independent timing.
int uscat : 1; // Unaligned atomics support.
int ilrcpc : 1; // Additional support for weaker release consistency.
int flagm : 1; // Flag manipulation instructions.
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
int sb : 1; // Speculation barrier.
int paca : 1; // Address authentication.
int pacg : 1; // Generic authentication.
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
} Aarch64Features;
typedef struct {
Aarch64Features features;
int implementer;
int variant;
int part;
int revision;
} Aarch64Info;
Aarch64Info GetAarch64Info(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
AARCH64_FP,
AARCH64_ASIMD,
AARCH64_EVTSTRM,
AARCH64_AES,
AARCH64_PMULL,
AARCH64_SHA1,
AARCH64_SHA2,
AARCH64_CRC32,
AARCH64_ATOMICS,
AARCH64_FPHP,
AARCH64_ASIMDHP,
AARCH64_CPUID,
AARCH64_ASIMDRDM,
AARCH64_JSCVT,
AARCH64_FCMA,
AARCH64_LRCPC,
AARCH64_DCPOP,
AARCH64_SHA3,
AARCH64_SM3,
AARCH64_SM4,
AARCH64_ASIMDDP,
AARCH64_SHA512,
AARCH64_SVE,
AARCH64_ASIMDFHM,
AARCH64_DIT,
AARCH64_USCAT,
AARCH64_ILRCPC,
AARCH64_FLAGM,
AARCH64_SSBS,
AARCH64_SB,
AARCH64_PACA,
AARCH64_PACG,
AARCH64_LAST_,
} Aarch64FeaturesEnum;
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
Aarch64FeaturesEnum value);
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_AARCH64)
#error "Including cpuinfo_aarch64.h from a non-aarch64 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_

View File

@@ -0,0 +1,117 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
#include <stdint.h> // uint32_t
#include "cpu_features_macros.h"
#include "cpu_features_cache_info.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int swp : 1; // SWP instruction (atomic read-modify-write)
int half : 1; // Half-word loads and stores
int thumb : 1; // Thumb (16-bit instruction set)
int _26bit : 1; // "26 Bit" Model (Processor status register folded into program counter)
int fastmult : 1; // 32x32->64-bit multiplication
int fpa : 1; // Floating point accelerator
int vfp : 1; // Vector Floating Point.
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all others above)
int java : 1; // Jazelle (Java bytecode accelerator)
int iwmmxt : 1; // Intel Wireless MMX Technology.
int crunch : 1; // MaverickCrunch coprocessor
int thumbee : 1; // ThumbEE
int neon : 1; // Advanced SIMD.
int vfpv3 : 1; // VFP version 3
int vfpv3d16 : 1; // VFP version 3 with 16 D-registers
int tls : 1; // TLS register
int vfpv4 : 1; // VFP version 4 with fast context switching
int idiva : 1; // SDIV and UDIV hardware division in ARM mode.
int idivt : 1; // SDIV and UDIV hardware division in Thumb mode.
int vfpd32 : 1; // VFP with 32 D-registers
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on 32-bit architecture)
int evtstrm : 1; // kernel event stream using generic architected timer
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
// Make sure to update ArmFeaturesEnum below if you add a field here.
} ArmFeatures;
typedef struct {
ArmFeatures features;
int implementer;
int architecture;
int variant;
int part;
int revision;
} ArmInfo;
// TODO(user): Add macros to know which features are present at compile
// time.
ArmInfo GetArmInfo(void);
// Compute CpuId from ArmInfo.
uint32_t GetArmCpuId(const ArmInfo* const info);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
ARM_SWP,
ARM_HALF,
ARM_THUMB,
ARM_26BIT,
ARM_FASTMULT,
ARM_FPA,
ARM_VFP,
ARM_EDSP,
ARM_JAVA,
ARM_IWMMXT,
ARM_CRUNCH,
ARM_THUMBEE,
ARM_NEON,
ARM_VFPV3,
ARM_VFPV3D16,
ARM_TLS,
ARM_VFPV4,
ARM_IDIVA,
ARM_IDIVT,
ARM_VFPD32,
ARM_LPAE,
ARM_EVTSTRM,
ARM_AES,
ARM_PMULL,
ARM_SHA1,
ARM_SHA2,
ARM_CRC32,
ARM_LAST_,
} ArmFeaturesEnum;
int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value);
const char* GetArmFeaturesEnumName(ArmFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_ARM)
#error "Including cpuinfo_arm.h from a non-arm target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_

View File

@@ -0,0 +1,214 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
// The field names are based on the short name provided in the wikipedia tables.
typedef struct {
int fpu : 1;
int tsc : 1;
int cx8 : 1;
int clfsh : 1;
int mmx : 1;
int aes : 1;
int erms : 1;
int f16c : 1;
int fma4 : 1;
int fma3 : 1;
int vaes : 1;
int vpclmulqdq : 1;
int bmi1 : 1;
int hle : 1;
int bmi2 : 1;
int rtm : 1;
int rdseed : 1;
int clflushopt : 1;
int clwb : 1;
int sse : 1;
int sse2 : 1;
int sse3 : 1;
int ssse3 : 1;
int sse4_1 : 1;
int sse4_2 : 1;
int sse4a : 1;
int avx : 1;
int avx2 : 1;
int avx512f : 1;
int avx512cd : 1;
int avx512er : 1;
int avx512pf : 1;
int avx512bw : 1;
int avx512dq : 1;
int avx512vl : 1;
int avx512ifma : 1;
int avx512vbmi : 1;
int avx512vbmi2 : 1;
int avx512vnni : 1;
int avx512bitalg : 1;
int avx512vpopcntdq : 1;
int avx512_4vnniw : 1;
int avx512_4vbmi2 : 1;
int pclmulqdq : 1;
int smx : 1;
int sgx : 1;
int cx16 : 1; // aka. CMPXCHG16B
int sha : 1;
int popcnt : 1;
int movbe : 1;
int rdrnd : 1;
int dca : 1;
int ss : 1;
// Make sure to update X86FeaturesEnum below if you add a field here.
} X86Features;
typedef struct {
X86Features features;
int family;
int model;
int stepping;
char vendor[13]; // 0 terminated string
} X86Info;
// Calls cpuid and returns an initialized X86info.
// This function is guaranteed to be malloc, memset and memcpy free.
X86Info GetX86Info(void);
// Returns cache hierarchy informations.
// Can call cpuid multiple times.
// Only works on Intel CPU at the moment.
// This function is guaranteed to be malloc, memset and memcpy free.
CacheInfo GetX86CacheInfo(void);
typedef enum {
X86_UNKNOWN,
INTEL_CORE, // CORE
INTEL_PNR, // PENRYN
INTEL_NHM, // NEHALEM
INTEL_ATOM_BNL, // BONNELL
INTEL_WSM, // WESTMERE
INTEL_SNB, // SANDYBRIDGE
INTEL_IVB, // IVYBRIDGE
INTEL_ATOM_SMT, // SILVERMONT
INTEL_HSW, // HASWELL
INTEL_BDW, // BROADWELL
INTEL_SKL, // SKYLAKE
INTEL_ATOM_GMT, // GOLDMONT
INTEL_KBL, // KABY LAKE
INTEL_CFL, // COFFEE LAKE
INTEL_WHL, // WHISKEY LAKE
INTEL_CNL, // CANNON LAKE
INTEL_ICL, // ICE LAKE
AMD_HAMMER, // K8
AMD_K10, // K10
AMD_BOBCAT, // K14
AMD_BULLDOZER, // K15
AMD_JAGUAR, // K16
AMD_ZEN, // K17
} X86Microarchitecture;
// Returns the underlying microarchitecture by looking at X86Info's vendor,
// family and model.
X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
// Calls cpuid and fills the brand_string.
// - brand_string *must* be of size 49 (beware of array decaying).
// - brand_string will be zero terminated.
// - This function calls memcpy.
void FillX86BrandString(char brand_string[49]);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
X86_FPU,
X86_TSC,
X86_CX8,
X86_CLFSH,
X86_MMX,
X86_AES,
X86_ERMS,
X86_F16C,
X86_FMA4,
X86_FMA3,
X86_VAES,
X86_VPCLMULQDQ,
X86_BMI1,
X86_HLE,
X86_BMI2,
X86_RTM,
X86_RDSEED,
X86_CLFLUSHOPT,
X86_CLWB,
X86_SSE,
X86_SSE2,
X86_SSE3,
X86_SSSE3,
X86_SSE4_1,
X86_SSE4_2,
X86_SSE4A,
X86_AVX,
X86_AVX2,
X86_AVX512F,
X86_AVX512CD,
X86_AVX512ER,
X86_AVX512PF,
X86_AVX512BW,
X86_AVX512DQ,
X86_AVX512VL,
X86_AVX512IFMA,
X86_AVX512VBMI,
X86_AVX512VBMI2,
X86_AVX512VNNI,
X86_AVX512BITALG,
X86_AVX512VPOPCNTDQ,
X86_AVX512_4VNNIW,
X86_AVX512_4VBMI2,
X86_PCLMULQDQ,
X86_SMX,
X86_SGX,
X86_CX16,
X86_SHA,
X86_POPCNT,
X86_MOVBE,
X86_RDRND,
X86_DCA,
X86_SS,
X86_LAST_,
} X86FeaturesEnum;
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
const char* GetX86MicroarchitectureName(X86Microarchitecture);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_X86)
#error "Including cpuinfo_x86.h from a non-x86 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_

View File

@@ -0,0 +1,39 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
inline static bool IsBitSet(uint32_t reg, uint32_t bit) {
return (reg >> bit) & 0x1;
}
inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb,
uint32_t lsb) {
const uint64_t bits = msb - lsb + 1ULL;
const uint64_t mask = (1ULL << bits) - 1ULL;
assert(msb >= lsb);
return (reg >> lsb) & mask;
}
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_

View File

@@ -0,0 +1,36 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// A struct to hold the result of a call to cpuid.
typedef struct {
uint32_t eax, ebx, ecx, edx;
} Leaf;
Leaf CpuIdEx(uint32_t leaf_id, int ecx);
// Returns the eax value of the XCR0 register.
uint32_t GetXCR0Eax(void);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_

View File

@@ -0,0 +1,38 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// An interface for the filesystem that allows mocking the filesystem in
// unittests.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
#include <stddef.h>
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR.
int CpuFeatures_OpenFile(const char* filename);
// Same as linux "read(file_descriptor, buffer, buffer_size)", retries
// automatically on EINTR.
int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size);
// Same as linux "close(file_descriptor)".
void CpuFeatures_CloseFile(int file_descriptor);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_

View File

@@ -0,0 +1,163 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Interface to retrieve hardware capabilities. It relies on Linux's getauxval
// or `/proc/self/auxval` under the hood.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// To avoid depending on the linux kernel we reproduce the architecture specific
// constants here.
// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
#define AARCH64_HWCAP_FP (1UL << 0)
#define AARCH64_HWCAP_ASIMD (1UL << 1)
#define AARCH64_HWCAP_EVTSTRM (1UL << 2)
#define AARCH64_HWCAP_AES (1UL << 3)
#define AARCH64_HWCAP_PMULL (1UL << 4)
#define AARCH64_HWCAP_SHA1 (1UL << 5)
#define AARCH64_HWCAP_SHA2 (1UL << 6)
#define AARCH64_HWCAP_CRC32 (1UL << 7)
#define AARCH64_HWCAP_ATOMICS (1UL << 8)
#define AARCH64_HWCAP_FPHP (1UL << 9)
#define AARCH64_HWCAP_ASIMDHP (1UL << 10)
#define AARCH64_HWCAP_CPUID (1UL << 11)
#define AARCH64_HWCAP_ASIMDRDM (1UL << 12)
#define AARCH64_HWCAP_JSCVT (1UL << 13)
#define AARCH64_HWCAP_FCMA (1UL << 14)
#define AARCH64_HWCAP_LRCPC (1UL << 15)
#define AARCH64_HWCAP_DCPOP (1UL << 16)
#define AARCH64_HWCAP_SHA3 (1UL << 17)
#define AARCH64_HWCAP_SM3 (1UL << 18)
#define AARCH64_HWCAP_SM4 (1UL << 19)
#define AARCH64_HWCAP_ASIMDDP (1UL << 20)
#define AARCH64_HWCAP_SHA512 (1UL << 21)
#define AARCH64_HWCAP_SVE (1UL << 22)
#define AARCH64_HWCAP_ASIMDFHM (1UL << 23)
#define AARCH64_HWCAP_DIT (1UL << 24)
#define AARCH64_HWCAP_USCAT (1UL << 25)
#define AARCH64_HWCAP_ILRCPC (1UL << 26)
#define AARCH64_HWCAP_FLAGM (1UL << 27)
#define AARCH64_HWCAP_SSBS (1UL << 28)
#define AARCH64_HWCAP_SB (1UL << 29)
#define AARCH64_HWCAP_PACA (1UL << 30)
#define AARCH64_HWCAP_PACG (1UL << 31)
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
#define ARM_HWCAP_SWP (1UL << 0)
#define ARM_HWCAP_HALF (1UL << 1)
#define ARM_HWCAP_THUMB (1UL << 2)
#define ARM_HWCAP_26BIT (1UL << 3)
#define ARM_HWCAP_FAST_MULT (1UL << 4)
#define ARM_HWCAP_FPA (1UL << 5)
#define ARM_HWCAP_VFP (1UL << 6)
#define ARM_HWCAP_EDSP (1UL << 7)
#define ARM_HWCAP_JAVA (1UL << 8)
#define ARM_HWCAP_IWMMXT (1UL << 9)
#define ARM_HWCAP_CRUNCH (1UL << 10)
#define ARM_HWCAP_THUMBEE (1UL << 11)
#define ARM_HWCAP_NEON (1UL << 12)
#define ARM_HWCAP_VFPV3 (1UL << 13)
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
#define ARM_HWCAP_TLS (1UL << 15)
#define ARM_HWCAP_VFPV4 (1UL << 16)
#define ARM_HWCAP_IDIVA (1UL << 17)
#define ARM_HWCAP_IDIVT (1UL << 18)
#define ARM_HWCAP_VFPD32 (1UL << 19)
#define ARM_HWCAP_LPAE (1UL << 20)
#define ARM_HWCAP_EVTSTRM (1UL << 21)
#define ARM_HWCAP2_AES (1UL << 0)
#define ARM_HWCAP2_PMULL (1UL << 1)
#define ARM_HWCAP2_SHA1 (1UL << 2)
#define ARM_HWCAP2_SHA2 (1UL << 3)
#define ARM_HWCAP2_CRC32 (1UL << 4)
// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h
#define MIPS_HWCAP_R6 (1UL << 0)
#define MIPS_HWCAP_MSA (1UL << 1)
#define MIPS_HWCAP_CRC32 (1UL << 2)
// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
/* in AT_HWCAP */
#define PPC_FEATURE_32 0x80000000
#define PPC_FEATURE_64 0x40000000
#define PPC_FEATURE_601_INSTR 0x20000000
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#define PPC_FEATURE_HAS_FPU 0x08000000
#define PPC_FEATURE_HAS_MMU 0x04000000
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
#define PPC_FEATURE_HAS_SPE 0x00800000
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
#define PPC_FEATURE_NO_TB 0x00100000
#define PPC_FEATURE_POWER4 0x00080000
#define PPC_FEATURE_POWER5 0x00040000
#define PPC_FEATURE_POWER5_PLUS 0x00020000
#define PPC_FEATURE_CELL 0x00010000
#define PPC_FEATURE_BOOKE 0x00008000
#define PPC_FEATURE_SMT 0x00004000
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
#define PPC_FEATURE_ARCH_2_05 0x00001000
#define PPC_FEATURE_PA6T 0x00000800
#define PPC_FEATURE_HAS_DFP 0x00000400
#define PPC_FEATURE_POWER6_EXT 0x00000200
#define PPC_FEATURE_ARCH_2_06 0x00000100
#define PPC_FEATURE_HAS_VSX 0x00000080
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040
/* Reserved - do not use 0x00000004 */
#define PPC_FEATURE_TRUE_LE 0x00000002
#define PPC_FEATURE_PPC_LE 0x00000001
/* in AT_HWCAP2 */
#define PPC_FEATURE2_ARCH_2_07 0x80000000
#define PPC_FEATURE2_HTM 0x40000000
#define PPC_FEATURE2_DSCR 0x20000000
#define PPC_FEATURE2_EBB 0x10000000
#define PPC_FEATURE2_ISEL 0x08000000
#define PPC_FEATURE2_TAR 0x04000000
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
#define PPC_FEATURE2_HTM_NOSC 0x01000000
#define PPC_FEATURE2_ARCH_3_00 0x00800000
#define PPC_FEATURE2_HAS_IEEE128 0x00400000
#define PPC_FEATURE2_DARN 0x00200000
#define PPC_FEATURE2_SCV 0x00100000
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
#endif
typedef struct {
unsigned long hwcaps;
unsigned long hwcaps2;
} HardwareCapabilities;
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
typedef struct {
char platform[64]; // 0 terminated string
char base_platform[64]; // 0 terminated string
} PlatformType;
PlatformType CpuFeatures_GetPlatformType(void);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_

View File

@@ -0,0 +1,49 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Reads a file line by line and stores the data on the stack. This allows
// parsing files in one go without allocating.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
#include <stdbool.h>
#include "cpu_features_macros.h"
#include "internal/string_view.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
char buffer[STACK_LINE_READER_BUFFER_SIZE];
StringView view;
int fd;
bool skip_mode;
} StackLineReader;
// Initializes a StackLineReader.
void StackLineReader_Initialize(StackLineReader* reader, int fd);
typedef struct {
StringView line; // A view of the line.
bool eof; // Nothing more to read, we reached EOF.
bool full_line; // If false the line was truncated to
// STACK_LINE_READER_BUFFER_SIZE.
} LineResult;
// Reads the file pointed to by fd and tries to read a full line.
LineResult StackLineReader_NextLine(StackLineReader* reader);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_

View File

@@ -0,0 +1,108 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// A view over a piece of string. The view is not 0 terminated.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
const char* ptr;
size_t size;
} StringView;
#ifdef __cplusplus
static const StringView kEmptyStringView = {NULL, 0};
#else
static const StringView kEmptyStringView;
#endif
// Returns a StringView from the provided string.
// Passing NULL is valid only if size is 0.
static inline StringView view(const char* str, const size_t size) {
StringView view;
view.ptr = str;
view.size = size;
return view;
}
static inline StringView str(const char* str) { return view(str, strlen(str)); }
// Returns the index of the first occurrence of c in view or -1 if not found.
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c);
// Returns the index of the first occurrence of sub_view in view or -1 if not
// found.
int CpuFeatures_StringView_IndexOf(const StringView view,
const StringView sub_view);
// Returns whether a is equal to b (same content).
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b);
// Returns whether a starts with b.
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b);
// Removes count characters from the beginning of view or kEmptyStringView if
// count if greater than view.size.
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
size_t count);
// Removes count characters from the end of view or kEmptyStringView if count if
// greater than view.size.
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
size_t count);
// Keeps the count first characters of view or view if count if greater than
// view.size.
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
size_t count);
// Retrieves the first character of view. If view is empty the behavior is
// undefined.
char CpuFeatures_StringView_Front(const StringView view);
// Retrieves the last character of view. If view is empty the behavior is
// undefined.
char CpuFeatures_StringView_Back(const StringView view);
// Removes leading and tailing space characters.
StringView CpuFeatures_StringView_TrimWhitespace(StringView view);
// Convert StringView to positive integer. e.g. "42", "0x2a".
// Returns -1 on error.
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view);
// Copies src StringView to dst buffer.
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
size_t dst_size);
// Checks if line contains the specified whitespace separated word.
bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word);
// Get key/value from line. key and value are separated by ": ".
// key and value are cleaned up from leading and trailing whitespaces.
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
StringView* key,
StringView* value);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_

View File

@@ -0,0 +1,72 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// CapabilityConfig provides a way to map cpu features to hardware caps and
// /proc/cpuinfo flags. We then provide functions to update capabilities from
// either source.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_
#include <ctype.h>
#include <stdint.h>
#include "cpu_features_macros.h"
#include "internal/hwcaps.h"
#include "internal/string_view.h"
CPU_FEATURES_START_CPP_NAMESPACE
// Use the following macro to declare setter functions to be used in
// CapabilityConfig.
#define DECLARE_SETTER(FeatureType, FeatureName) \
static void set_##FeatureName(void* const features, bool value) { \
((FeatureType*)features)->FeatureName = value; \
}
// Use the following macro to declare getter functions to be used in
// CapabilityConfig.
#define DECLARE_GETTER(FeatureType, FeatureName) \
static int get_##FeatureName(void* const features) { \
return ((FeatureType*)features)->FeatureName; \
}
#define DECLARE_SETTER_AND_GETTER(FeatureType, FeatureName) \
DECLARE_SETTER(FeatureType, FeatureName) \
DECLARE_GETTER(FeatureType, FeatureName)
// Describes the relationship between hardware caps and /proc/cpuinfo flags.
typedef struct {
const HardwareCapabilities hwcaps_mask;
const char* const proc_cpuinfo_flag;
void (*set_bit)(void* const, bool); // setter for the corresponding bit.
int (*get_bit)(void* const); // getter for the corresponding bit.
} CapabilityConfig;
// For every config, looks into flags_line for the presence of the
// corresponding proc_cpuinfo_flag, calls `set_bit` accordingly.
// Note: features is a pointer to the underlying Feature struct.
void CpuFeatures_SetFromFlags(const size_t configs_size,
const CapabilityConfig* configs,
const StringView flags_line,
void* const features);
// For every config, looks into hwcaps for the presence of the feature. Calls
// `set_bit` with true if the hardware capability is found.
// Note: features is a pointer to the underlying Feature struct.
void CpuFeatures_OverrideFromHwCaps(const size_t configs_size,
const CapabilityConfig* configs,
const HardwareCapabilities hwcaps,
void* const features);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_

View File

@@ -0,0 +1,162 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_aarch64.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#include "internal/unix_features_aggregator.h"
#include <assert.h>
#include <ctype.h>
DECLARE_SETTER_AND_GETTER(Aarch64Features, fp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimd)
DECLARE_SETTER_AND_GETTER(Aarch64Features, evtstrm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, aes)
DECLARE_SETTER_AND_GETTER(Aarch64Features, pmull)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha1)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha2)
DECLARE_SETTER_AND_GETTER(Aarch64Features, crc32)
DECLARE_SETTER_AND_GETTER(Aarch64Features, atomics)
DECLARE_SETTER_AND_GETTER(Aarch64Features, fphp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimdhp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, cpuid)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimdrdm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, jscvt)
DECLARE_SETTER_AND_GETTER(Aarch64Features, fcma)
DECLARE_SETTER_AND_GETTER(Aarch64Features, lrcpc)
DECLARE_SETTER_AND_GETTER(Aarch64Features, dcpop)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha3)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sm3)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sm4)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimddp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha512)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sve)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimdfhm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, dit)
DECLARE_SETTER_AND_GETTER(Aarch64Features, uscat)
DECLARE_SETTER_AND_GETTER(Aarch64Features, ilrcpc)
DECLARE_SETTER_AND_GETTER(Aarch64Features, flagm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, ssbs)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sb)
DECLARE_SETTER_AND_GETTER(Aarch64Features, paca)
DECLARE_SETTER_AND_GETTER(Aarch64Features, pacg)
static const CapabilityConfig kConfigs[] = {
[AARCH64_FP] = {{AARCH64_HWCAP_FP, 0}, "fp", &set_fp, &get_fp},
[AARCH64_ASIMD] = {{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd, &get_asimd},
[AARCH64_EVTSTRM] = {{AARCH64_HWCAP_EVTSTRM, 0}, "evtstrm", &set_evtstrm, &get_evtstrm},
[AARCH64_AES] = {{AARCH64_HWCAP_AES, 0}, "aes", &set_aes, &get_aes},
[AARCH64_PMULL] = {{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull, &get_pmull},
[AARCH64_SHA1] = {{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1, &get_sha1},
[AARCH64_SHA2] = {{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2, &get_sha2},
[AARCH64_CRC32] = {{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32, &get_crc32},
[AARCH64_ATOMICS] = {{AARCH64_HWCAP_ATOMICS, 0}, "atomics", &set_atomics, &get_atomics},
[AARCH64_FPHP] = {{AARCH64_HWCAP_FPHP, 0}, "fphp", &set_fphp, &get_fphp},
[AARCH64_ASIMDHP] = {{AARCH64_HWCAP_ASIMDHP, 0}, "asimdhp", &set_asimdhp, &get_asimdhp},
[AARCH64_CPUID] = {{AARCH64_HWCAP_CPUID, 0}, "cpuid", &set_cpuid, &get_cpuid},
[AARCH64_ASIMDRDM] = {{AARCH64_HWCAP_ASIMDRDM, 0}, "asimdrdm", &set_asimdrdm, &get_asimdrdm},
[AARCH64_JSCVT] = {{AARCH64_HWCAP_JSCVT, 0}, "jscvt", &set_jscvt, &get_jscvt},
[AARCH64_FCMA] = {{AARCH64_HWCAP_FCMA, 0}, "fcma", &set_fcma, &get_fcma},
[AARCH64_LRCPC] = {{AARCH64_HWCAP_LRCPC, 0}, "lrcpc", &set_lrcpc, &get_lrcpc},
[AARCH64_DCPOP] = {{AARCH64_HWCAP_DCPOP, 0}, "dcpop", &set_dcpop, &get_dcpop},
[AARCH64_SHA3] = {{AARCH64_HWCAP_SHA3, 0}, "sha3", &set_sha3, &get_sha3},
[AARCH64_SM3] = {{AARCH64_HWCAP_SM3, 0}, "sm3", &set_sm3, &get_sm3},
[AARCH64_SM4] = {{AARCH64_HWCAP_SM4, 0}, "sm4", &set_sm4, &get_sm4},
[AARCH64_ASIMDDP] = {{AARCH64_HWCAP_ASIMDDP, 0}, "asimddp", &set_asimddp, &get_asimddp},
[AARCH64_SHA512] = {{AARCH64_HWCAP_SHA512, 0}, "sha512", &set_sha512, &get_sha512},
[AARCH64_SVE] = {{AARCH64_HWCAP_SVE, 0}, "sve", &set_sve, &get_sve},
[AARCH64_ASIMDFHM] = {{AARCH64_HWCAP_ASIMDFHM, 0}, "asimdfhm", &set_asimdfhm, &get_asimdfhm},
[AARCH64_DIT] = {{AARCH64_HWCAP_DIT, 0}, "dit", &set_dit, &get_dit},
[AARCH64_USCAT] = {{AARCH64_HWCAP_USCAT, 0}, "uscat", &set_uscat, &get_uscat},
[AARCH64_ILRCPC] = {{AARCH64_HWCAP_ILRCPC, 0}, "ilrcpc", &set_ilrcpc, &get_ilrcpc},
[AARCH64_FLAGM] = {{AARCH64_HWCAP_FLAGM, 0}, "flagm", &set_flagm, &get_flagm},
[AARCH64_SSBS] = {{AARCH64_HWCAP_SSBS, 0}, "ssbs", &set_ssbs, &get_ssbs},
[AARCH64_SB] = {{AARCH64_HWCAP_SB, 0}, "sb", &set_sb, &get_sb},
[AARCH64_PACA] = {{AARCH64_HWCAP_PACA, 0}, "paca", &set_paca, &get_paca},
[AARCH64_PACG] = {{AARCH64_HWCAP_PACG, 0}, "pacg", &set_pacg, &get_pacg},
};
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
static bool HandleAarch64Line(const LineResult result,
Aarch64Info* const info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
}
}
return !result.eof;
}
static void FillProcCpuInfoData(Aarch64Info* const info) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const Aarch64Info kEmptyAarch64Info;
Aarch64Info GetAarch64Info(void) {
assert(kConfigsSize == AARCH64_LAST_);
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
Aarch64Info info = kEmptyAarch64Info;
FillProcCpuInfoData(&info);
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
CpuFeatures_GetHardwareCapabilities(),
&info.features);
return info;
}
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
Aarch64FeaturesEnum value) {
if(value >= kConfigsSize)
return false;
return kConfigs[value].get_bit((Aarch64Features*)features);
}
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
if(value >= kConfigsSize)
return "unknown feature";
return kConfigs[value].proc_cpuinfo_flag;
}

View File

@@ -0,0 +1,236 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_arm.h"
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#include "internal/unix_features_aggregator.h"
#include <assert.h>
#include <ctype.h>
DECLARE_SETTER_AND_GETTER(ArmFeatures, swp)
DECLARE_SETTER_AND_GETTER(ArmFeatures, half)
DECLARE_SETTER_AND_GETTER(ArmFeatures, thumb)
DECLARE_SETTER_AND_GETTER(ArmFeatures, _26bit)
DECLARE_SETTER_AND_GETTER(ArmFeatures, fastmult)
DECLARE_SETTER_AND_GETTER(ArmFeatures, fpa)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfp)
DECLARE_SETTER_AND_GETTER(ArmFeatures, edsp)
DECLARE_SETTER_AND_GETTER(ArmFeatures, java)
DECLARE_SETTER_AND_GETTER(ArmFeatures, iwmmxt)
DECLARE_SETTER_AND_GETTER(ArmFeatures, crunch)
DECLARE_SETTER_AND_GETTER(ArmFeatures, thumbee)
DECLARE_SETTER_AND_GETTER(ArmFeatures, neon)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpv3)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpv3d16)
DECLARE_SETTER_AND_GETTER(ArmFeatures, tls)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpv4)
DECLARE_SETTER_AND_GETTER(ArmFeatures, idiva)
DECLARE_SETTER_AND_GETTER(ArmFeatures, idivt)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpd32)
DECLARE_SETTER_AND_GETTER(ArmFeatures, lpae)
DECLARE_SETTER_AND_GETTER(ArmFeatures, evtstrm)
DECLARE_SETTER_AND_GETTER(ArmFeatures, aes)
DECLARE_SETTER_AND_GETTER(ArmFeatures, pmull)
DECLARE_SETTER_AND_GETTER(ArmFeatures, sha1)
DECLARE_SETTER_AND_GETTER(ArmFeatures, sha2)
DECLARE_SETTER_AND_GETTER(ArmFeatures, crc32)
static const CapabilityConfig kConfigs[] = {
[ARM_SWP] = {{ARM_HWCAP_SWP, 0}, "swp", &set_swp, &get_swp}, //
[ARM_HALF] = {{ARM_HWCAP_HALF, 0}, "half", &set_half, &get_half}, //
[ARM_THUMB] = {{ARM_HWCAP_THUMB, 0}, "thumb", &set_thumb, &get_thumb}, //
[ARM_26BIT] = {{ARM_HWCAP_26BIT, 0}, "26bit", &set__26bit, &get__26bit}, //
[ARM_FASTMULT] = {{ARM_HWCAP_FAST_MULT, 0}, "fastmult", &set_fastmult, &get_fastmult}, //
[ARM_FPA] = {{ARM_HWCAP_FPA, 0}, "fpa", &set_fpa, &get_fpa}, //
[ARM_VFP] = {{ARM_HWCAP_VFP, 0}, "vfp", &set_vfp, &get_vfp}, //
[ARM_EDSP] = {{ARM_HWCAP_EDSP, 0}, "edsp", &set_edsp, &get_edsp}, //
[ARM_JAVA] = {{ARM_HWCAP_JAVA, 0}, "java", &set_java, &get_java}, //
[ARM_IWMMXT] = {{ARM_HWCAP_IWMMXT, 0}, "iwmmxt", &set_iwmmxt, &get_iwmmxt}, //
[ARM_CRUNCH] = {{ARM_HWCAP_CRUNCH, 0}, "crunch", &set_crunch, &get_crunch}, //
[ARM_THUMBEE] = {{ARM_HWCAP_THUMBEE, 0}, "thumbee", &set_thumbee, &get_thumbee}, //
[ARM_NEON] = {{ARM_HWCAP_NEON, 0}, "neon", &set_neon, &get_neon}, //
[ARM_VFPV3] = {{ARM_HWCAP_VFPV3, 0}, "vfpv3", &set_vfpv3, &get_vfpv3}, //
[ARM_VFPV3D16] = {{ARM_HWCAP_VFPV3D16, 0}, "vfpv3d16", &set_vfpv3d16, &get_vfpv3d16}, //
[ARM_TLS] = {{ARM_HWCAP_TLS, 0}, "tls", &set_tls, &get_tls}, //
[ARM_VFPV4] = {{ARM_HWCAP_VFPV4, 0}, "vfpv4", &set_vfpv4, &get_vfpv4}, //
[ARM_IDIVA] = {{ARM_HWCAP_IDIVA, 0}, "idiva", &set_idiva, &get_idiva}, //
[ARM_IDIVT] = {{ARM_HWCAP_IDIVT, 0}, "idivt", &set_idivt, &get_idivt}, //
[ARM_VFPD32] = {{ARM_HWCAP_VFPD32, 0}, "vfpd32", &set_vfpd32, &get_vfpd32}, //
[ARM_LPAE] = {{ARM_HWCAP_LPAE, 0}, "lpae", &set_lpae, &get_lpae}, //
[ARM_EVTSTRM] = {{ARM_HWCAP_EVTSTRM, 0}, "evtstrm", &set_evtstrm, &get_evtstrm}, //
[ARM_AES] = {{0, ARM_HWCAP2_AES}, "aes", &set_aes, &get_aes}, //
[ARM_PMULL] = {{0, ARM_HWCAP2_PMULL}, "pmull", &set_pmull, &get_pmull}, //
[ARM_SHA1] = {{0, ARM_HWCAP2_SHA1}, "sha1", &set_sha1, &get_sha1}, //
[ARM_SHA2] = {{0, ARM_HWCAP2_SHA2}, "sha2", &set_sha2, &get_sha2}, //
[ARM_CRC32] = {{0, ARM_HWCAP2_CRC32}, "crc32", &set_crc32, &get_crc32}, //
};
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
typedef struct {
bool processor_reports_armv6;
bool hardware_reports_goldfish;
} ProcCpuInfoData;
static int IndexOfNonDigit(StringView str) {
size_t index = 0;
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
str = CpuFeatures_StringView_PopFront(str, 1);
++index;
}
return index;
}
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
ProcCpuInfoData* const proc_info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
// CPU architecture is a number that may be followed by letters. e.g.
// "6TEJ", "7".
const StringView digits =
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor"))
|| CpuFeatures_StringView_IsEquals(key, str("model name")) ) {
// Android reports this in a non-Linux standard "Processor" but sometimes
// also in "model name", Linux reports it only in "model name"
// see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
proc_info->processor_reports_armv6 =
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
proc_info->hardware_reports_goldfish =
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
}
}
return !result.eof;
}
uint32_t GetArmCpuId(const ArmInfo* const info) {
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
(ExtractBitRange(info->variant, 3, 0) << 20) |
(ExtractBitRange(info->part, 11, 0) << 4) |
(ExtractBitRange(info->revision, 3, 0) << 0);
}
static void FixErrors(ArmInfo* const info,
ProcCpuInfoData* const proc_cpu_info_data) {
// Fixing Samsung kernel reporting invalid cpu architecture.
// http://code.google.com/p/android/issues/detail?id=10812
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
info->architecture = 6;
}
// Handle kernel configuration bugs that prevent the correct reporting of CPU
// features.
switch (GetArmCpuId(info)) {
case 0x4100C080:
// Special case: The emulator-specific Android 4.2 kernel fails to report
// support for the 32-bit ARM IDIV instruction. Technically, this is a
// feature of the virtual CPU implemented by the emulator. Note that it
// could also support Thumb IDIV in the future, and this will have to be
// slightly updated.
if (info->architecture >= 7 &&
proc_cpu_info_data->hardware_reports_goldfish) {
info->features.idiva = true;
}
break;
case 0x511004D0:
// https://crbug.com/341598.
info->features.neon = false;
break;
case 0x510006F2:
case 0x510006F3:
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
// IDIV support.
info->features.idiva = true;
info->features.idivt = true;
break;
}
// Propagate cpu features.
if (info->features.vfpv4) info->features.vfpv3 = true;
if (info->features.neon) info->features.vfpv3 = true;
if (info->features.vfpv3) info->features.vfp = true;
}
static void FillProcCpuInfoData(ArmInfo* const info,
ProcCpuInfoData* proc_cpu_info_data) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
proc_cpu_info_data)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const ArmInfo kEmptyArmInfo;
static const ProcCpuInfoData kEmptyProcCpuInfoData;
ArmInfo GetArmInfo(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
ArmInfo info = kEmptyArmInfo;
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
FillProcCpuInfoData(&info, &proc_cpu_info_data);
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
CpuFeatures_GetHardwareCapabilities(),
&info.features);
FixErrors(&info, &proc_cpu_info_data);
return info;
}
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
int GetArmFeaturesEnumValue(const ArmFeatures* features,
ArmFeaturesEnum value) {
if(value >= kConfigsSize)
return false;
return kConfigs[value].get_bit((ArmFeatures*)features);
}
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
if(value >= kConfigsSize)
return "unknown feature";
return kConfigs[value].proc_cpuinfo_flag;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/filesystem.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(CPU_FEATURES_MOCK_FILESYSTEM)
// Implementation will be provided by test/filesystem_for_testing.cc.
#elif defined(_MSC_VER)
#include <io.h>
int CpuFeatures_OpenFile(const char* filename) {
int fd = -1;
_sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD);
return fd;
}
void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
size_t buffer_size) {
return _read(file_descriptor, buffer, (unsigned int)buffer_size);
}
#else
#include <unistd.h>
int CpuFeatures_OpenFile(const char* filename) {
int result;
do {
result = open(filename, O_RDONLY);
} while (result == -1L && errno == EINTR);
return result;
}
void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); }
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
size_t buffer_size) {
int result;
do {
result = read(file_descriptor, buffer, buffer_size);
} while (result == -1L && errno == EINTR);
return result;
}
#endif

View File

@@ -0,0 +1,162 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/string_view.h"
#if defined(NDEBUG)
#define D(...)
#else
#include <stdio.h>
#define D(...) \
do { \
printf(__VA_ARGS__); \
fflush(stdout); \
} while (0)
#endif
////////////////////////////////////////////////////////////////////////////////
// Implementation of GetElfHwcapFromGetauxval
////////////////////////////////////////////////////////////////////////////////
#if defined(CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL)
// Implementation will be provided by test/hwcaps_for_testing.cc.
#elif defined(HAVE_STRONG_GETAUXVAL)
#include <sys/auxv.h>
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
return getauxval(hwcap_type);
}
#elif defined(HAVE_DLFCN_H)
// On Android we probe the system's C library for a 'getauxval' function and
// call it if it exits, or return 0 for failure. This function is available
// since API level 20.
//
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
// case where some NDK developers use headers for a platform that is newer than
// the one really targetted by their application. This is typically done to use
// newer native APIs only when running on more recent Android versions, and
// requires careful symbol management.
//
// Note that getauxval() can't really be re-implemented here, because its
// implementation does not parse /proc/self/auxv. Instead it depends on values
// that are passed by the kernel at process-init time to the C runtime
// initialization layer.
#include <dlfcn.h>
#define AT_HWCAP 16
#define AT_HWCAP2 26
#define AT_PLATFORM 15
#define AT_BASE_PLATFORM 24
typedef unsigned long getauxval_func_t(unsigned long);
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
uint32_t ret = 0;
void* libc_handle = NULL;
getauxval_func_t* func = NULL;
dlerror(); // Cleaning error state before calling dlopen.
libc_handle = dlopen("libc.so", RTLD_NOW);
if (!libc_handle) {
D("Could not dlopen() C library: %s\n", dlerror());
return 0;
}
func = (getauxval_func_t*)dlsym(libc_handle, "getauxval");
if (!func) {
D("Could not find getauxval() in C library\n");
} else {
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
ret = (uint32_t)(*func)(hwcap_type);
}
dlclose(libc_handle);
return ret;
}
#else
#error "This platform does not provide hardware capabilities."
#endif
// Implementation of GetHardwareCapabilities for OS that provide
// GetElfHwcapFromGetauxval().
// Fallback when getauxval is not available, retrieves hwcaps from
// "/proc/self/auxv".
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
struct {
uint32_t tag;
uint32_t value;
} entry;
uint32_t result = 0;
const char filepath[] = "/proc/self/auxv";
const int fd = CpuFeatures_OpenFile(filepath);
if (fd < 0) {
D("Could not open %s\n", filepath);
return 0;
}
for (;;) {
const int ret = CpuFeatures_ReadFile(fd, (char*)&entry, sizeof entry);
if (ret < 0) {
D("Error while reading %s\n", filepath);
break;
}
// Detect end of list.
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
break;
}
if (entry.tag == hwcap_type) {
result = entry.value;
break;
}
}
CpuFeatures_CloseFile(fd);
return result;
}
// Retrieves hardware capabilities by first trying to call getauxval, if not
// available falls back to reading "/proc/self/auxv".
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
if (!hwcaps) {
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
}
return hwcaps;
}
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
HardwareCapabilities capabilities;
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
return capabilities;
}
PlatformType kEmptyPlatformType;
PlatformType CpuFeatures_GetPlatformType(void) {
PlatformType type = kEmptyPlatformType;
char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
if (platform != NULL)
CpuFeatures_StringView_CopyString(str(platform), type.platform,
sizeof(type.platform));
if (base_platform != NULL)
CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
sizeof(type.base_platform));
return type;
}

View File

@@ -0,0 +1,131 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/stack_line_reader.h"
#include "internal/filesystem.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
reader->view.ptr = reader->buffer;
reader->view.size = 0;
reader->skip_mode = false;
reader->fd = fd;
}
// Replaces the content of buffer with bytes from the file.
static int LoadFullBuffer(StackLineReader* reader) {
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
STACK_LINE_READER_BUFFER_SIZE);
assert(read >= 0);
reader->view.ptr = reader->buffer;
reader->view.size = read;
return read;
}
// Appends with bytes from the file to buffer, filling the remaining space.
static int LoadMore(StackLineReader* reader) {
char* const ptr = reader->buffer + reader->view.size;
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
assert(read >= 0);
assert(read <= (int)size_to_read);
reader->view.size += read;
return read;
}
static int IndexOfEol(StackLineReader* reader) {
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
}
// Relocate buffer's pending bytes at the beginning of the array and fills the
// remaining space with bytes from the file.
static int BringToFrontAndLoadMore(StackLineReader* reader) {
if (reader->view.size && reader->view.ptr != reader->buffer) {
memmove(reader->buffer, reader->view.ptr, reader->view.size);
}
reader->view.ptr = reader->buffer;
return LoadMore(reader);
}
// Loads chunks of buffer size from disks until it contains a newline character
// or end of file.
static void SkipToNextLine(StackLineReader* reader) {
for (;;) {
const int read = LoadFullBuffer(reader);
if (read == 0) {
break;
} else {
const int eol_index = IndexOfEol(reader);
if (eol_index >= 0) {
reader->view =
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
break;
}
}
}
}
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
LineResult result;
result.eof = eof;
result.full_line = full_line;
result.line = view;
return result;
}
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
static LineResult CreateEOFLineResult(StringView view) {
return CreateLineResult(true, true, view);
}
static LineResult CreateTruncatedLineResult(StringView view) {
return CreateLineResult(false, false, view);
}
static LineResult CreateValidLineResult(StringView view) {
return CreateLineResult(false, true, view);
}
LineResult StackLineReader_NextLine(StackLineReader* reader) {
if (reader->skip_mode) {
SkipToNextLine(reader);
reader->skip_mode = false;
}
{
const bool can_load_more =
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
int eol_index = IndexOfEol(reader);
if (eol_index < 0 && can_load_more) {
const int read = BringToFrontAndLoadMore(reader);
if (read == 0) {
return CreateEOFLineResult(reader->view);
}
eol_index = IndexOfEol(reader);
}
if (eol_index < 0) {
reader->skip_mode = true;
return CreateTruncatedLineResult(reader->view);
}
{
StringView line =
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
reader->view =
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
return CreateValidLineResult(line);
}
}
}

View File

@@ -0,0 +1,182 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/string_view.h"
#include <assert.h>
#include <ctype.h>
#include <string.h>
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
if (view.ptr && view.size) {
const char* const found = (const char*)memchr(view.ptr, c, view.size);
if (found) {
return (int)(found - view.ptr);
}
}
return -1;
}
int CpuFeatures_StringView_IndexOf(const StringView view,
const StringView sub_view) {
if (sub_view.size) {
StringView remainder = view;
while (remainder.size >= sub_view.size) {
const int found_index =
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
if (found_index < 0) break;
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
return (int)(remainder.ptr - view.ptr);
}
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
}
}
return -1;
}
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
if (a.size == b.size) {
return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0;
}
return false;
}
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
return a.ptr && b.ptr && b.size && a.size >= b.size
? memcmp(a.ptr, b.ptr, b.size) == 0
: false;
}
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
size_t count) {
if (count > str_view.size) {
return kEmptyStringView;
}
return view(str_view.ptr + count, str_view.size - count);
}
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
size_t count) {
if (count > str_view.size) {
return kEmptyStringView;
}
return view(str_view.ptr, str_view.size - count);
}
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
size_t count) {
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
}
char CpuFeatures_StringView_Front(const StringView view) {
assert(view.size);
assert(view.ptr);
return view.ptr[0];
}
char CpuFeatures_StringView_Back(const StringView view) {
assert(view.size);
return view.ptr[view.size - 1];
}
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
view = CpuFeatures_StringView_PopFront(view, 1);
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
view = CpuFeatures_StringView_PopBack(view, 1);
return view;
}
static int HexValue(const char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
// Returns -1 if view contains non digits.
static int ParsePositiveNumberWithBase(const StringView view, int base) {
int result = 0;
StringView remainder = view;
for (; remainder.size;
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
if (value < 0 || value >= base) return -1;
result = (result * base) + value;
}
return result;
}
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
if (view.size) {
const StringView hex_prefix = str("0x");
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
const StringView span_no_prefix =
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
return ParsePositiveNumberWithBase(span_no_prefix, 16);
}
return ParsePositiveNumberWithBase(view, 10);
}
return -1;
}
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
size_t dst_size) {
if (dst_size > 0) {
const size_t max_copy_size = dst_size - 1;
const size_t copy_size =
src.size > max_copy_size ? max_copy_size : src.size;
memcpy(dst, src.ptr, copy_size);
dst[copy_size] = '\0';
}
}
bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word_str) {
const StringView word = str(word_str);
StringView remainder = line;
for (;;) {
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
if (index_of_word < 0) {
return false;
} else {
const StringView before =
CpuFeatures_StringView_KeepFront(line, index_of_word);
const StringView after =
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
const bool valid_before =
before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
const bool valid_after =
after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
if (valid_before && valid_after) return true;
remainder =
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
}
}
return false;
}
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
StringView* key,
StringView* value) {
const StringView sep = str(": ");
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
if (index_of_separator < 0) return false;
*value = CpuFeatures_StringView_TrimWhitespace(
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
*key = CpuFeatures_StringView_TrimWhitespace(
CpuFeatures_StringView_KeepFront(line, index_of_separator));
return true;
}

View File

@@ -0,0 +1,52 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/unix_features_aggregator.h"
#include "internal/string_view.h"
void CpuFeatures_SetFromFlags(const size_t configs_size,
const CapabilityConfig* configs,
const StringView flags_line,
void* const features) {
size_t i = 0;
for (; i < configs_size; ++i) {
const CapabilityConfig config = configs[i];
config.set_bit(features, CpuFeatures_StringView_HasWord(
flags_line, config.proc_cpuinfo_flag));
}
}
static bool IsSet(const uint32_t mask, const uint32_t value) {
if (mask == 0) return false;
return (value & mask) == mask;
}
static bool IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps) {
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
}
void CpuFeatures_OverrideFromHwCaps(const size_t configs_size,
const CapabilityConfig* configs,
const HardwareCapabilities hwcaps,
void* const features) {
size_t i = 0;
for (; i < configs_size; ++i) {
const CapabilityConfig* config = &configs[i];
if (IsHwCapsSet(config->hwcaps_mask, hwcaps)) {
config->set_bit(features, true);
}
}
}

View File

@@ -23,6 +23,12 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/resource.h> #include <sys/resource.h>
#if defined(__arm__)
#include "cpuinfo_arm.h"
#elif defined(__i386__)
#include "cpuinfo_x86.h"
#endif
/* /*
* Class: org_petero_droidfish_engine_EngineUtil * Class: org_petero_droidfish_engine_EngineUtil
* Method: chmod * Method: chmod
@@ -48,3 +54,21 @@ extern "C" JNIEXPORT void JNICALL Java_org_petero_droidfish_engine_EngineUtil_re
setpriority(PRIO_PROCESS, pid, prio); setpriority(PRIO_PROCESS, pid, prio);
} }
/*
* Class: org_petero_droidfish_engine_EngineUtil
* Method: isSimdSupported
* Signature: ()Z
*/
extern "C" JNIEXPORT jboolean JNICALL Java_org_petero_droidfish_engine_EngineUtil_isSimdSupported
(JNIEnv *env, jclass) {
#if defined(__arm__)
using namespace cpu_features;
ArmFeatures features = GetArmInfo().features;
return features.neon ? JNI_TRUE : JNI_FALSE;
#elif defined(__i386__)
using namespace cpu_features;
X86Features features = GetX86Info().features;
return features.sse4_1 ? JNI_TRUE : JNI_FALSE;
#endif
return true;
}

View File

@@ -41,7 +41,7 @@ public class EngineUtil {
!"arm64-v8a".equals(abi)) { !"arm64-v8a".equals(abi)) {
abi = "armeabi-v7a"; // Unknown ABI, assume 32-bit arm abi = "armeabi-v7a"; // Unknown ABI, assume 32-bit arm
} }
return abi + "/stockfish"; return abi + "/stockfish" + (isSimdSupported() ? "" : "_nosimd");
} }
/** Return true if file "engine" is a network engine. */ /** Return true if file "engine" is a network engine. */
@@ -100,6 +100,9 @@ public class EngineUtil {
/** Change the priority of a process. */ /** Change the priority of a process. */
static native void reNice(int pid, int prio); static native void reNice(int pid, int prio);
/** Return true if the required SIMD instructions are supported by the CPU. */
static native boolean isSimdSupported();
/** For synchronizing non thread safe native calls. */ /** For synchronizing non thread safe native calls. */
public static final Object nativeLock = new Object(); public static final Object nativeLock = new Object();
} }