mirror of
https://github.com/google/cpu_features.git
synced 2025-04-26 22:52:30 +02:00
Adding code. Closes #0.
This commit is contained in:
parent
44d56a0a28
commit
439d371594
4
.clang-format
Normal file
4
.clang-format
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
...
|
393
BUILD
Normal file
393
BUILD
Normal file
@ -0,0 +1,393 @@
|
||||
# cpu_features, a cross platform C89 library to get cpu features at runtime.
|
||||
package(
|
||||
default_copts = [
|
||||
"-DDISABLE_GOOGLE_GLOBAL_USING_DECLARATIONS",
|
||||
"-Wno-implicit-fallthrough",
|
||||
"-Ithird_party/cpu_features/include",
|
||||
],
|
||||
default_visibility = ["//visibility:public"],
|
||||
features = [
|
||||
"-parse_headers", # disabled because tests (C++) depends on C target compiled with -std=gnu89.
|
||||
"-layering_check", # disabled because it depends on parse_headers.
|
||||
],
|
||||
)
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
# MOE:begin_strip
|
||||
filegroup(
|
||||
name = "opensource_filegroup",
|
||||
srcs = [
|
||||
".clang-format",
|
||||
"BUILD",
|
||||
"CMakeLists.txt",
|
||||
"CMakeLists.txt.in",
|
||||
"CONTRIBUTING.md",
|
||||
"LICENSE",
|
||||
"OWNERS",
|
||||
"README.md",
|
||||
"WORKSPACE",
|
||||
"include/cpu_features_macros.h",
|
||||
"include/cpuinfo_aarch64.h",
|
||||
"include/cpuinfo_arm.h",
|
||||
"include/cpuinfo_mips.h",
|
||||
"include/cpuinfo_x86.h",
|
||||
"include/internal/bit_utils.h",
|
||||
"include/internal/cpuid_x86.h",
|
||||
"include/internal/filesystem.h",
|
||||
"include/internal/hwcaps.h",
|
||||
"include/internal/linux_features_aggregator.h",
|
||||
"include/internal/stack_line_reader.h",
|
||||
"include/internal/string_view.h",
|
||||
"src/cpuid_x86_clang.c",
|
||||
"src/cpuid_x86_gcc.c",
|
||||
"src/cpuid_x86_msvc.c",
|
||||
"src/cpuinfo_aarch64.c",
|
||||
"src/cpuinfo_arm.c",
|
||||
"src/cpuinfo_mips.c",
|
||||
"src/cpuinfo_x86.c",
|
||||
"src/filesystem.c",
|
||||
"src/hwcaps.c",
|
||||
"src/linux_features_aggregator.c",
|
||||
"src/list_cpu_features.cc",
|
||||
"src/stack_line_reader.c",
|
||||
"src/string_view.c",
|
||||
"test/CMakeLists.txt",
|
||||
"test/bit_utils_test.cc",
|
||||
"test/cpuinfo_aarch64_test.cc",
|
||||
"test/cpuinfo_arm_test.cc",
|
||||
"test/cpuinfo_mips_test.cc",
|
||||
"test/cpuinfo_x86_test.cc",
|
||||
"test/filesystem_for_testing.cc",
|
||||
"test/filesystem_for_testing.h",
|
||||
"test/hwcaps_for_testing.cc",
|
||||
"test/hwcaps_for_testing.h",
|
||||
"test/linux_features_aggregator_test.cc",
|
||||
"test/stack_line_reader_test.cc",
|
||||
"test/string_view_test.cc",
|
||||
],
|
||||
visibility = ["//third_party/cpu_features:__subpackages__"],
|
||||
)
|
||||
|
||||
# MOE:end_strip
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
vardef(
|
||||
"GNU89_FLAGS",
|
||||
"-std=gnu89 " +
|
||||
"-Wall " +
|
||||
"-Wdeclaration-after-statement " +
|
||||
"-Wextra " +
|
||||
"-Wmissing-declarations " +
|
||||
"-Wmissing-prototypes " +
|
||||
"-Wold-style-definition " +
|
||||
"-Wshadow " +
|
||||
"-Wsign-compare " +
|
||||
"-Wstrict-prototypes ",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpu_features_macros",
|
||||
srcs = ["include/cpu_features_macros.h"],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bit_utils",
|
||||
srcs = ["include/internal/bit_utils.h"],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "bit_utils_test",
|
||||
srcs = ["test/bit_utils_test.cc"],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "string_view",
|
||||
srcs = ["src/string_view.c"],
|
||||
hdrs = ["include/internal/string_view.h"],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "string_view_test",
|
||||
srcs = ["test/string_view_test.cc"],
|
||||
deps = [
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "filesystem",
|
||||
srcs = [
|
||||
"include/internal/filesystem.h",
|
||||
"src/filesystem.c",
|
||||
],
|
||||
copts = [
|
||||
varref("GNU89_FLAGS"),
|
||||
],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "filesystem_for_testing",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"include/internal/filesystem.h",
|
||||
"test/filesystem_for_testing.cc",
|
||||
"test/filesystem_for_testing.h",
|
||||
],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
"//base",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "stack_line_reader",
|
||||
srcs = [
|
||||
"include/internal/stack_line_reader.h",
|
||||
"src/stack_line_reader.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "stack_line_reader_for_testing",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"include/internal/stack_line_reader.h",
|
||||
"src/stack_line_reader.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem_for_testing",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "stack_line_reader_test",
|
||||
srcs = [
|
||||
"include/internal/stack_line_reader.h",
|
||||
"src/stack_line_reader.c",
|
||||
"test/stack_line_reader_test.cc",
|
||||
],
|
||||
defines = ["STACK_LINE_READER_BUFFER_SIZE=16"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem_for_testing",
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hwcaps",
|
||||
srcs = [
|
||||
"include/internal/hwcaps.h",
|
||||
"src/hwcaps.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hwcaps_for_testing",
|
||||
testonly = 1,
|
||||
srcs = ["test/hwcaps_for_testing.cc"],
|
||||
hdrs = [
|
||||
"include/internal/hwcaps.h",
|
||||
"test/hwcaps_for_testing.h",
|
||||
],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "linux_features_aggregator",
|
||||
srcs = [
|
||||
"include/internal/linux_features_aggregator.h",
|
||||
"src/linux_features_aggregator.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [
|
||||
":hwcaps",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "linux_features_aggregator_test",
|
||||
srcs = ["test/linux_features_aggregator_test.cc"],
|
||||
deps = [
|
||||
":linux_features_aggregator",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuinfo_mips",
|
||||
srcs = [
|
||||
"include/cpuinfo_mips.h",
|
||||
"src/cpuinfo_mips.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [
|
||||
":linux_features_aggregator",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cpuinfo_mips_test",
|
||||
srcs = [
|
||||
"include/cpuinfo_mips.h",
|
||||
"src/cpuinfo_mips.c",
|
||||
"test/cpuinfo_mips_test.cc",
|
||||
],
|
||||
deps = [
|
||||
":filesystem_for_testing",
|
||||
":hwcaps_for_testing",
|
||||
":linux_features_aggregator",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuinfo_aarch64",
|
||||
srcs = [
|
||||
"include/cpuinfo_aarch64.h",
|
||||
"src/cpuinfo_aarch64.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [
|
||||
":linux_features_aggregator",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cpuinfo_aarch64_test",
|
||||
srcs = [
|
||||
"include/cpuinfo_aarch64.h",
|
||||
"src/cpuinfo_aarch64.c",
|
||||
"test/cpuinfo_aarch64_test.cc",
|
||||
],
|
||||
deps = [
|
||||
":filesystem_for_testing",
|
||||
":hwcaps_for_testing",
|
||||
":linux_features_aggregator",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuinfo_arm",
|
||||
srcs = [
|
||||
"include/cpuinfo_arm.h",
|
||||
"src/cpuinfo_arm.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":linux_features_aggregator",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cpuinfo_arm_test",
|
||||
srcs = [
|
||||
"include/cpuinfo_arm.h",
|
||||
"src/cpuinfo_arm.c",
|
||||
"test/cpuinfo_arm_test.cc",
|
||||
],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":filesystem_for_testing",
|
||||
":hwcaps_for_testing",
|
||||
":linux_features_aggregator",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuid_x86",
|
||||
srcs = [
|
||||
"include/internal/cpuid_x86.h",
|
||||
"src/cpuid_x86_clang.c",
|
||||
"src/cpuid_x86_gcc.c",
|
||||
"src/cpuid_x86_msvc.c",
|
||||
],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuinfo_x86",
|
||||
srcs = ["src/cpuinfo_x86.c"],
|
||||
hdrs = ["include/cpuinfo_x86.h"],
|
||||
copts = [varref("GNU89_FLAGS")],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":cpu_features_macros",
|
||||
":cpuid_x86",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cpuinfo_x86_test",
|
||||
srcs = [
|
||||
"include/cpuinfo_x86.h",
|
||||
"src/cpuinfo_x86.c",
|
||||
"test/cpuinfo_x86_test.cc",
|
||||
],
|
||||
defines = ["CPU_FEATURES_TEST"],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":cpu_features_macros",
|
||||
":cpuid_x86",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "list_cpu_features",
|
||||
srcs = ["src/list_cpu_features.cc"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":cpuinfo_aarch64",
|
||||
":cpuinfo_arm",
|
||||
":cpuinfo_mips",
|
||||
":cpuinfo_x86",
|
||||
],
|
||||
)
|
93
CMakeLists.txt
Normal file
93
CMakeLists.txt
Normal file
@ -0,0 +1,93 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(CpuFeatures)
|
||||
|
||||
#
|
||||
# library : cpu_features
|
||||
#
|
||||
|
||||
add_library(cpu_features
|
||||
include/cpuinfo_aarch64.h
|
||||
include/cpuinfo_arm.h
|
||||
include/cpuinfo_mips.h
|
||||
include/cpuinfo_x86.h
|
||||
include/internal/bit_utils.h
|
||||
include/internal/linux_features_aggregator.h
|
||||
include/internal/cpuid_x86.h
|
||||
include/internal/filesystem.h
|
||||
include/internal/hwcaps.h
|
||||
include/internal/stack_line_reader.h
|
||||
include/internal/string_view.h
|
||||
include/cpu_features_macros.h
|
||||
src/linux_features_aggregator.c
|
||||
src/cpuid_x86_clang.c
|
||||
src/cpuid_x86_gcc.c
|
||||
src/cpuid_x86_msvc.c
|
||||
src/cpuinfo_aarch64.c
|
||||
src/cpuinfo_arm.c
|
||||
src/cpuinfo_mips.c
|
||||
src/cpuinfo_x86.c
|
||||
src/filesystem.c
|
||||
src/hwcaps.c
|
||||
src/stack_line_reader.c
|
||||
src/string_view.c
|
||||
)
|
||||
|
||||
target_include_directories(cpu_features PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
||||
target_include_directories(cpu_features PRIVATE include/internal)
|
||||
target_compile_definitions(cpu_features PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024)
|
||||
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
|
||||
|
||||
#
|
||||
# program : list_cpu_features
|
||||
#
|
||||
|
||||
add_executable(list_cpu_features src/list_cpu_features.cc)
|
||||
target_link_libraries(list_cpu_features PRIVATE cpu_features)
|
||||
target_compile_features(list_cpu_features PRIVATE cxx_range_for)
|
||||
|
||||
#
|
||||
# tests
|
||||
#
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
# Download and unpack googletest at configure time.
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker settings on Windows.
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
# Add googletest directly to our build. This defines the gtest and gtest_main
|
||||
# targets.
|
||||
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
|
||||
${CMAKE_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
# The gtest/gtest_main targets carry header search path dependencies
|
||||
# automatically when using CMake 2.8.11 or later. Otherwise we have to add
|
||||
# them here ourselves.
|
||||
if (CMAKE_VERSION VERSION_LESS 2.8.11)
|
||||
include_directories("${gtest_SOURCE_DIR}/include")
|
||||
endif()
|
||||
|
||||
add_subdirectory(test)
|
||||
endif()
|
15
CMakeLists.txt.in
Normal file
15
CMakeLists.txt.in
Normal file
@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
23
CONTRIBUTING.md
Normal file
23
CONTRIBUTING.md
Normal file
@ -0,0 +1,23 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
202
LICENSE
Normal file
202
LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
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.
|
12
README.md
12
README.md
@ -66,12 +66,12 @@ or not.
|
||||
|
||||
## What does it currently support
|
||||
|
||||
| x86 | ARM | aarch64 | mips | POWER
|
||||
---------------------------- | :-: | :-: | :-----: | :----: | :-----:
|
||||
Features From cpu | yes | no* | no* | no yet | not yet
|
||||
Features From Linux | no | yes | yes | yes | not yet
|
||||
Micro Architecture Detection | yes | no | no | no | not yet
|
||||
Windows support | yes | no | no | no | not yet
|
||||
| | x86 | ARM | aarch64 | mips | POWER |
|
||||
|---------------------------- | :-: | :-: | :-----: | :----: | :-----: |
|
||||
|Features From cpu | yes | no* | no* | no yet | not yet |
|
||||
|Features From Linux | no | yes | yes | yes | not yet |
|
||||
|Micro Architecture Detection | yes | no | no | no | not yet |
|
||||
|Windows support | yes | no | no | no | not yet |
|
||||
|
||||
- **Features From Cpuid**: features are retrieved by using the cpuid
|
||||
instruction. (*) Unfortunately this instruction is privileged for some
|
||||
|
7
WORKSPACE
Normal file
7
WORKSPACE
Normal file
@ -0,0 +1,7 @@
|
||||
# ===== googletest =====
|
||||
|
||||
git_repository(
|
||||
name = "com_google_googletest",
|
||||
remote = "https://github.com/google/googletest.git",
|
||||
commit = "c3f65335b79f47b05629e79a54685d899bc53b93",
|
||||
)
|
121
include/cpu_features_macros.h
Normal file
121
include/cpu_features_macros.h
Normal file
@ -0,0 +1,121 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Architectures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if ((defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
|
||||
defined(__x86_64__)) && \
|
||||
!defined(__pnacl__) && !defined(__CLR_VER))
|
||||
#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(__mips__)
|
||||
#define CPU_FEATURES_ARCH_MIPS
|
||||
#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 START_CPP_NAMESPACE \
|
||||
namespace cpu_features { \
|
||||
extern "C" {
|
||||
#define END_CPP_NAMESPACE \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define START_CPP_NAMESPACE
|
||||
#define 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)
|
||||
#define CPU_FEATURES_COMPILED_X86_AES defined(__AES__)
|
||||
#define CPU_FEATURES_COMPILED_X86_F16C defined(__F16C__)
|
||||
#define CPU_FEATURES_COMPILED_X86_BMI defined(__BMI__)
|
||||
#define CPU_FEATURES_COMPILED_X86_BMI2 defined(__BMI2__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE (defined(__SSE__) || (_M_IX86_FP >= 1))
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE2 (defined(__SSE2__) || (_M_IX86_FP >= 2))
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE3 defined(__SSE3__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSSE3 defined(__SSSE3__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE4_1 defined(__SSE4_1__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE4_2 defined(__SSE4_2__)
|
||||
#define CPU_FEATURES_COMPILED_X86_AVX defined(__AVX__)
|
||||
#define CPU_FEATURES_COMPILED_x86_AVX2 defined(__AVX2__)
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON defined(__ARM_NEON__)
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_MIPS)
|
||||
#define CPU_FEATURES_COMPILED_MIPS_MSA defined(__mips_msa)
|
||||
#endif
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
65
include/cpuinfo_aarch64.h
Normal file
65
include/cpuinfo_aarch64.h
Normal file
@ -0,0 +1,65 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int fp : 1; // Floating-point.
|
||||
int asimd : 1; // Advanced SIMD.
|
||||
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 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_AES,
|
||||
AARCH64_PMULL,
|
||||
AARCH64_SHA1,
|
||||
AARCH64_SHA2,
|
||||
AARCH64_CRC32,
|
||||
AARCH64_LAST_,
|
||||
} Aarch64FeaturesEnum;
|
||||
|
||||
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||
Aarch64FeaturesEnum value);
|
||||
|
||||
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
80
include/cpuinfo_arm.h
Normal file
80
include/cpuinfo_arm.h
Normal file
@ -0,0 +1,80 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int vfp : 1; // Vector Floating Point.
|
||||
int iwmmxt : 1; // Intel Wireless MMX Technology.
|
||||
int neon : 1; // Advanced SIMD.
|
||||
int vfpv3 : 1; // VFP version 3
|
||||
int vfpv3d16 : 1; // VFP version 3 with 16 D-registers
|
||||
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 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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
ARM_VFP,
|
||||
ARM_IWMMXT,
|
||||
ARM_NEON,
|
||||
ARM_VFPV3,
|
||||
ARM_VFPV3D16,
|
||||
ARM_VFPV4,
|
||||
ARM_IDIVA,
|
||||
ARM_IDIVT,
|
||||
ARM_AES,
|
||||
ARM_PMULL,
|
||||
ARM_SHA1,
|
||||
ARM_SHA2,
|
||||
ARM_CRC32,
|
||||
ARM_LAST_,
|
||||
} ArmFeaturesEnum;
|
||||
|
||||
int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value);
|
||||
|
||||
const char* GetArmFeaturesEnumName(ArmFeaturesEnum);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
53
include/cpuinfo_mips.h
Normal file
53
include/cpuinfo_mips.h
Normal file
@ -0,0 +1,53 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int msa : 1; // MIPS SIMD Architecture
|
||||
// https://www.mips.com/products/architectures/ase/simd/
|
||||
int eva : 1; // Enhanced Virtual Addressing
|
||||
// https://www.mips.com/products/architectures/mips64/
|
||||
|
||||
// Make sure to update MipsFeaturesEnum below if you add a field here.
|
||||
} MipsFeatures;
|
||||
|
||||
typedef struct {
|
||||
MipsFeatures features;
|
||||
} MipsInfo;
|
||||
|
||||
MipsInfo GetMipsInfo(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
MIPS_MSA,
|
||||
MIPS_EVA,
|
||||
MIPS_LAST_,
|
||||
} MipsFeaturesEnum;
|
||||
|
||||
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||
MipsFeaturesEnum value);
|
||||
|
||||
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
147
include/cpuinfo_x86.h
Normal file
147
include/cpuinfo_x86.h
Normal file
@ -0,0 +1,147 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
START_CPP_NAMESPACE
|
||||
|
||||
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
|
||||
typedef struct {
|
||||
int aes : 1;
|
||||
int erms : 1;
|
||||
int f16c : 1;
|
||||
int fma3 : 1;
|
||||
int vpclmulqdq : 1;
|
||||
int bmi1 : 1;
|
||||
int bmi2 : 1;
|
||||
|
||||
int ssse3 : 1;
|
||||
int sse4_1 : 1;
|
||||
int sse4_2 : 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;
|
||||
|
||||
// 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);
|
||||
|
||||
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_CNL, // CANON 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_AES,
|
||||
X86_ERMS,
|
||||
X86_F16C,
|
||||
X86_FMA3,
|
||||
X86_VPCLMULQDQ,
|
||||
X86_BMI1,
|
||||
X86_BMI2,
|
||||
X86_SSSE3,
|
||||
X86_SSE4_1,
|
||||
X86_SSE4_2,
|
||||
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_LAST_,
|
||||
} X86FeaturesEnum;
|
||||
|
||||
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
|
||||
|
||||
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
|
||||
|
||||
const char* GetX86MicroarchitectureName(X86Microarchitecture);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
39
include/internal/bit_utils.h
Normal file
39
include/internal/bit_utils.h
Normal 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
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 + 1;
|
||||
const uint64_t mask = (1ULL << bits) - 1ULL;
|
||||
assert(msb >= lsb);
|
||||
return (reg >> lsb) & mask;
|
||||
}
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
37
include/internal/cpuid_x86.h
Normal file
37
include/internal/cpuid_x86.h
Normal file
@ -0,0 +1,37 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
START_CPP_NAMESPACE
|
||||
|
||||
// A struct to hold the result of a call to cpuid.
|
||||
typedef struct {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
} Leaf;
|
||||
|
||||
// Retrieves the leaf for a particular cpuid.
|
||||
Leaf CpuId(uint32_t leaf_id);
|
||||
|
||||
// Returns the eax value of the XCR0 register.
|
||||
uint32_t GetXCR0Eax(void);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
38
include/internal/filesystem.h
Normal file
38
include/internal/filesystem.h
Normal 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
START_CPP_NAMESPACE
|
||||
|
||||
// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR.
|
||||
int OpenFile(const char* filename);
|
||||
|
||||
// Same as linux "read(file_descriptor, buffer, buffer_size)", retries
|
||||
// automatically on EINTR.
|
||||
int ReadFile(int file_descriptor, void* buffer, size_t buffer_size);
|
||||
|
||||
// Same as linux "close(file_descriptor)".
|
||||
void CloseFile(int file_descriptor);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
73
include/internal/hwcaps.h
Normal file
73
include/internal/hwcaps.h
Normal file
@ -0,0 +1,73 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
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_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)
|
||||
|
||||
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
|
||||
#define ARM_HWCAP_VFP (1UL << 6)
|
||||
#define ARM_HWCAP_IWMMXT (1UL << 9)
|
||||
#define ARM_HWCAP_NEON (1UL << 12)
|
||||
#define ARM_HWCAP_VFPV3 (1UL << 13)
|
||||
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
|
||||
#define ARM_HWCAP_VFPV4 (1UL << 16)
|
||||
#define ARM_HWCAP_IDIVA (1UL << 17)
|
||||
#define ARM_HWCAP_IDIVT (1UL << 18)
|
||||
#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_VZ (1UL << 0)
|
||||
#define MIPS_HWCAP_EVA (1UL << 1)
|
||||
#define MIPS_HWCAP_HTW (1UL << 2)
|
||||
#define MIPS_HWCAP_FPU (1UL << 3)
|
||||
#define MIPS_HWCAP_MIPS32R2 (1UL << 4)
|
||||
#define MIPS_HWCAP_MIPS32R5 (1UL << 5)
|
||||
#define MIPS_HWCAP_MIPS64R6 (1UL << 6)
|
||||
#define MIPS_HWCAP_DSPR1 (1UL << 7)
|
||||
#define MIPS_HWCAP_DSPR2 (1UL << 8)
|
||||
#define MIPS_HWCAP_MSA (1UL << 9)
|
||||
|
||||
typedef struct {
|
||||
uint32_t hwcaps;
|
||||
uint32_t hwcaps2;
|
||||
} HardwareCapabilities;
|
||||
|
||||
HardwareCapabilities GetHardwareCapabilities(void);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
58
include/internal/linux_features_aggregator.h
Normal file
58
include/internal/linux_features_aggregator.h
Normal file
@ -0,0 +1,58 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_
|
||||
#define THIRD_PARTY_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"
|
||||
|
||||
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; \
|
||||
}
|
||||
|
||||
// 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.
|
||||
} 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 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 OverrideFromHwCaps(const size_t configs_size,
|
||||
const CapabilityConfig* configs,
|
||||
const HardwareCapabilities hwcaps,
|
||||
void* const features);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_
|
49
include/internal/stack_line_reader.h
Normal file
49
include/internal/stack_line_reader.h
Normal 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
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);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
101
include/internal/string_view.h
Normal file
101
include/internal/string_view.h
Normal file
@ -0,0 +1,101 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
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 IndexOfChar(const StringView view, char c);
|
||||
|
||||
// Returns the index of the first occurrence of sub_view in view or -1 if not
|
||||
// found.
|
||||
int IndexOf(const StringView view, const StringView sub_view);
|
||||
|
||||
// Returns whether a is equal to b (same content).
|
||||
bool IsEquals(const StringView a, const StringView b);
|
||||
|
||||
// Returns whether a starts with b.
|
||||
bool 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 PopFront(const StringView view, size_t count);
|
||||
|
||||
// Removes count characters from the end of view or kEmptyStringView if count if
|
||||
// greater than view.size.
|
||||
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 KeepFront(const StringView view, size_t count);
|
||||
|
||||
// Retrieves the first character of view. If view is empty the behavior is
|
||||
// undefined.
|
||||
char Front(const StringView view);
|
||||
|
||||
// Retrieves the last character of view. If view is empty the behavior is
|
||||
// undefined.
|
||||
char Back(const StringView view);
|
||||
|
||||
// Removes leading and tailing space characters.
|
||||
StringView TrimWhitespace(StringView view);
|
||||
|
||||
// Convert StringView to positive integer. e.g. "42", "0x2a".
|
||||
// Returns -1 on error.
|
||||
int ParsePositiveNumber(const StringView view);
|
||||
|
||||
// Copies src StringView to dst buffer.
|
||||
void CopyString(const StringView src, char* dst, size_t dst_size);
|
||||
|
||||
// Checks if line contains the specified whitespace separated word.
|
||||
bool 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 GetAttributeKeyValue(const StringView line, StringView* key,
|
||||
StringView* value);
|
||||
|
||||
END_CPP_NAMESPACE
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
32
src/cpuid_x86_clang.c
Normal file
32
src/cpuid_x86_clang.c
Normal file
@ -0,0 +1,32 @@
|
||||
// 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/cpuid_x86.h"
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_CLANG)
|
||||
#include <cpuid.h>
|
||||
|
||||
Leaf CpuId(uint32_t leaf_id) {
|
||||
Leaf leaf;
|
||||
__cpuid_count(leaf_id, 0, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
|
||||
return leaf;
|
||||
}
|
||||
|
||||
uint32_t GetXCR0Eax(void) {
|
||||
uint32_t eax, edx;
|
||||
__asm("XGETBV" : "=a"(eax), "=d"(edx) : "c"(0));
|
||||
return eax;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_CLANG)
|
32
src/cpuid_x86_gcc.c
Normal file
32
src/cpuid_x86_gcc.c
Normal file
@ -0,0 +1,32 @@
|
||||
// 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/cpuid_x86.h"
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_GCC)
|
||||
#include <cpuid.h>
|
||||
|
||||
Leaf CpuId(uint32_t leaf_id) {
|
||||
Leaf leaf;
|
||||
__cpuid(leaf_id, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
|
||||
return leaf;
|
||||
}
|
||||
|
||||
uint32_t GetXCR0Eax(void) {
|
||||
uint32_t eax, edx;
|
||||
__asm("XGETBV" : "=a"(eax), "=d"(edx) : "c"(0));
|
||||
return eax;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_GCC)
|
34
src/cpuid_x86_msvc.c
Normal file
34
src/cpuid_x86_msvc.c
Normal file
@ -0,0 +1,34 @@
|
||||
// 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/cpuid_x86.h"
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_MSC)
|
||||
#include <immintrin.h>
|
||||
#include <intrin.h> // For __cpuidex()
|
||||
|
||||
Leaf CpuId(uint32_t leaf_id) {
|
||||
Leaf leaf;
|
||||
int data[4];
|
||||
__cpuid(data, leaf_id);
|
||||
leaf.eax = data[0];
|
||||
leaf.ebx = data[1];
|
||||
leaf.ecx = data[2];
|
||||
leaf.edx = data[3];
|
||||
return leaf;
|
||||
}
|
||||
|
||||
uint32_t GetXCR0Eax(void) { return _xgetbv(0); }
|
||||
|
||||
#endif // defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_MSC)
|
140
src/cpuinfo_aarch64.c
Normal file
140
src/cpuinfo_aarch64.c
Normal file
@ -0,0 +1,140 @@
|
||||
// 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/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
DECLARE_SETTER(Aarch64Features, fp)
|
||||
DECLARE_SETTER(Aarch64Features, asimd)
|
||||
DECLARE_SETTER(Aarch64Features, aes)
|
||||
DECLARE_SETTER(Aarch64Features, pmull)
|
||||
DECLARE_SETTER(Aarch64Features, sha1)
|
||||
DECLARE_SETTER(Aarch64Features, sha2)
|
||||
DECLARE_SETTER(Aarch64Features, crc32)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{AARCH64_HWCAP_FP, 0}, "fp", &set_fp}, //
|
||||
{{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd}, //
|
||||
{{AARCH64_HWCAP_AES, 0}, "aes", &set_aes}, //
|
||||
{{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull}, //
|
||||
{{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1}, //
|
||||
{{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2}, //
|
||||
{{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32}, //
|
||||
};
|
||||
|
||||
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 (GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (IsEquals(key, str("Features"))) {
|
||||
SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
|
||||
} else if (IsEquals(key, str("CPU implementer"))) {
|
||||
info->implementer = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU variant"))) {
|
||||
info->variant = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU part"))) {
|
||||
info->part = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU revision"))) {
|
||||
info->revision = ParsePositiveNumber(value);
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(Aarch64Info* const info) {
|
||||
const int fd = OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const Aarch64Info kEmptyAarch64Info;
|
||||
|
||||
Aarch64Info GetAarch64Info(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).
|
||||
Aarch64Info info = kEmptyAarch64Info;
|
||||
|
||||
FillProcCpuInfoData(&info);
|
||||
OverrideFromHwCaps(kConfigsSize, kConfigs, GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||
Aarch64FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case AARCH64_FP:
|
||||
return features->fp;
|
||||
case AARCH64_ASIMD:
|
||||
return features->asimd;
|
||||
case AARCH64_AES:
|
||||
return features->aes;
|
||||
case AARCH64_PMULL:
|
||||
return features->pmull;
|
||||
case AARCH64_SHA1:
|
||||
return features->sha1;
|
||||
case AARCH64_SHA2:
|
||||
return features->sha2;
|
||||
case AARCH64_CRC32:
|
||||
return features->crc32;
|
||||
case AARCH64_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case AARCH64_FP:
|
||||
return "fp";
|
||||
case AARCH64_ASIMD:
|
||||
return "asimd";
|
||||
case AARCH64_AES:
|
||||
return "aes";
|
||||
case AARCH64_PMULL:
|
||||
return "pmull";
|
||||
case AARCH64_SHA1:
|
||||
return "sha1";
|
||||
case AARCH64_SHA2:
|
||||
return "sha2";
|
||||
case AARCH64_CRC32:
|
||||
return "crc32";
|
||||
case AARCH64_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown feature";
|
||||
}
|
255
src/cpuinfo_arm.c
Normal file
255
src/cpuinfo_arm.c
Normal file
@ -0,0 +1,255 @@
|
||||
// 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/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
DECLARE_SETTER(ArmFeatures, vfp)
|
||||
DECLARE_SETTER(ArmFeatures, iwmmxt)
|
||||
DECLARE_SETTER(ArmFeatures, neon)
|
||||
DECLARE_SETTER(ArmFeatures, vfpv3)
|
||||
DECLARE_SETTER(ArmFeatures, vfpv3d16)
|
||||
DECLARE_SETTER(ArmFeatures, vfpv4)
|
||||
DECLARE_SETTER(ArmFeatures, idiva)
|
||||
DECLARE_SETTER(ArmFeatures, idivt)
|
||||
DECLARE_SETTER(ArmFeatures, aes)
|
||||
DECLARE_SETTER(ArmFeatures, pmull)
|
||||
DECLARE_SETTER(ArmFeatures, sha1)
|
||||
DECLARE_SETTER(ArmFeatures, sha2)
|
||||
DECLARE_SETTER(ArmFeatures, crc32)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{ARM_HWCAP_VFP, 0}, "vfp", &set_vfp}, //
|
||||
{{ARM_HWCAP_IWMMXT, 0}, "iwmmxt", &set_iwmmxt}, //
|
||||
{{ARM_HWCAP_NEON, 0}, "neon", &set_neon}, //
|
||||
{{ARM_HWCAP_VFPV3, 0}, "vfpv3", &set_vfpv3}, //
|
||||
{{ARM_HWCAP_VFPV3D16, 0}, "vfpv3d16", &set_vfpv3d16}, //
|
||||
{{ARM_HWCAP_VFPV4, 0}, "vfpv4", &set_vfpv4}, //
|
||||
{{ARM_HWCAP_IDIVA, 0}, "idiva", &set_idiva}, //
|
||||
{{ARM_HWCAP_IDIVT, 0}, "idivt", &set_idivt}, //
|
||||
{{0, ARM_HWCAP2_AES}, "aes", &set_aes}, //
|
||||
{{0, ARM_HWCAP2_PMULL}, "pmull", &set_pmull}, //
|
||||
{{0, ARM_HWCAP2_SHA1}, "sha1", &set_sha1}, //
|
||||
{{0, ARM_HWCAP2_SHA2}, "sha2", &set_sha2}, //
|
||||
{{0, ARM_HWCAP2_CRC32}, "crc32", &set_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(Front(str))) {
|
||||
str = 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 (GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (IsEquals(key, str("Features"))) {
|
||||
SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
|
||||
} else if (IsEquals(key, str("CPU implementer"))) {
|
||||
info->implementer = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU variant"))) {
|
||||
info->variant = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU part"))) {
|
||||
info->part = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU revision"))) {
|
||||
info->revision = ParsePositiveNumber(value);
|
||||
} else if (IsEquals(key, str("CPU architecture"))) {
|
||||
// CPU architecture is a number that may be followed by letters. e.g.
|
||||
// "6TEJ", "7".
|
||||
const StringView digits = KeepFront(value, IndexOfNonDigit(value));
|
||||
info->architecture = ParsePositiveNumber(digits);
|
||||
} else if (IsEquals(key, str("Processor"))) {
|
||||
proc_info->processor_reports_armv6 = IndexOf(value, str("(v6l)")) >= 0;
|
||||
} else if (IsEquals(key, str("Hardware"))) {
|
||||
proc_info->hardware_reports_goldfish = IsEquals(value, str("Goldfish"));
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static uint32_t GetCpuId(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 (GetCpuId(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 = OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
|
||||
proc_cpu_info_data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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);
|
||||
OverrideFromHwCaps(kConfigsSize, kConfigs, GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
|
||||
FixErrors(&info, &proc_cpu_info_data);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetArmFeaturesEnumValue(const ArmFeatures* features,
|
||||
ArmFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case ARM_VFP:
|
||||
return features->vfp;
|
||||
case ARM_IWMMXT:
|
||||
return features->iwmmxt;
|
||||
case ARM_NEON:
|
||||
return features->neon;
|
||||
case ARM_VFPV3:
|
||||
return features->vfpv3;
|
||||
case ARM_VFPV3D16:
|
||||
return features->vfpv3d16;
|
||||
case ARM_VFPV4:
|
||||
return features->vfpv4;
|
||||
case ARM_IDIVA:
|
||||
return features->idiva;
|
||||
case ARM_IDIVT:
|
||||
return features->idivt;
|
||||
case ARM_AES:
|
||||
return features->aes;
|
||||
case ARM_PMULL:
|
||||
return features->pmull;
|
||||
case ARM_SHA1:
|
||||
return features->sha1;
|
||||
case ARM_SHA2:
|
||||
return features->sha2;
|
||||
case ARM_CRC32:
|
||||
return features->crc32;
|
||||
case ARM_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case ARM_VFP:
|
||||
return "vfp";
|
||||
case ARM_IWMMXT:
|
||||
return "iwmmxt";
|
||||
case ARM_NEON:
|
||||
return "neon";
|
||||
case ARM_VFPV3:
|
||||
return "vfpv3";
|
||||
case ARM_VFPV3D16:
|
||||
return "vfpv3d16";
|
||||
case ARM_VFPV4:
|
||||
return "vfpv4";
|
||||
case ARM_IDIVA:
|
||||
return "idiva";
|
||||
case ARM_IDIVT:
|
||||
return "idivt";
|
||||
case ARM_AES:
|
||||
return "aes";
|
||||
case ARM_PMULL:
|
||||
return "pmull";
|
||||
case ARM_SHA1:
|
||||
return "sha1";
|
||||
case ARM_SHA2:
|
||||
return "sha2";
|
||||
case ARM_CRC32:
|
||||
return "crc32";
|
||||
case ARM_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown feature";
|
||||
}
|
97
src/cpuinfo_mips.c
Normal file
97
src/cpuinfo_mips.c
Normal file
@ -0,0 +1,97 @@
|
||||
// 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_mips.h"
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
DECLARE_SETTER(MipsFeatures, msa)
|
||||
DECLARE_SETTER(MipsFeatures, eva)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{MIPS_HWCAP_MSA, 0}, "msa", &set_msa}, //
|
||||
{{MIPS_HWCAP_EVA, 0}, "eva", &set_eva}, //
|
||||
};
|
||||
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
|
||||
|
||||
static bool HandleMipsLine(const LineResult result,
|
||||
MipsFeatures* const features) {
|
||||
StringView key, value;
|
||||
// See tests for an example.
|
||||
if (GetAttributeKeyValue(result.line, &key, &value)) {
|
||||
if (IsEquals(key, str("ASEs implemented"))) {
|
||||
SetFromFlags(kConfigsSize, kConfigs, value, features);
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(MipsFeatures* const features) {
|
||||
const int fd = OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const MipsInfo kEmptyMipsInfo;
|
||||
|
||||
MipsInfo GetMipsInfo(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).
|
||||
MipsInfo info = kEmptyMipsInfo;
|
||||
|
||||
FillProcCpuInfoData(&info.features);
|
||||
OverrideFromHwCaps(kConfigsSize, kConfigs, GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||
MipsFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case MIPS_MSA:
|
||||
return features->msa;
|
||||
case MIPS_EVA:
|
||||
return features->eva;
|
||||
case MIPS_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case MIPS_MSA:
|
||||
return "msa";
|
||||
case MIPS_EVA:
|
||||
return "eva";
|
||||
case MIPS_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown feature";
|
||||
}
|
432
src/cpuinfo_x86.c
Normal file
432
src/cpuinfo_x86.c
Normal file
@ -0,0 +1,432 @@
|
||||
// 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_x86.h"
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/cpuid_x86.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static const Leaf kEmptyLeaf;
|
||||
|
||||
static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
|
||||
if (leaf_id <= max_cpuid_leaf) {
|
||||
return CpuId(leaf_id);
|
||||
} else {
|
||||
return kEmptyLeaf;
|
||||
}
|
||||
}
|
||||
|
||||
#define MASK_XMM 0x2
|
||||
#define MASK_YMM 0x4
|
||||
#define MASK_MASKREG 0x20
|
||||
#define MASK_ZMM0_15 0x40
|
||||
#define MASK_ZMM16_31 0x80
|
||||
|
||||
static bool HasMask(uint32_t value, uint32_t mask) {
|
||||
return (value & mask) == mask;
|
||||
}
|
||||
|
||||
// Checks that operating system saves and restores xmm registers during context
|
||||
// switches.
|
||||
static bool HasXmmOsXSave(uint32_t xcr0_eax) {
|
||||
return HasMask(xcr0_eax, MASK_XMM);
|
||||
}
|
||||
|
||||
// Checks that operating system saves and restores ymm registers during context
|
||||
// switches.
|
||||
static bool HasYmmOsXSave(uint32_t xcr0_eax) {
|
||||
return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
|
||||
}
|
||||
|
||||
// Checks that operating system saves and restores zmm registers during context
|
||||
// switches.
|
||||
static bool HasZmmOsXSave(uint32_t xcr0_eax) {
|
||||
return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
|
||||
MASK_ZMM16_31);
|
||||
}
|
||||
|
||||
static void SetVendor(const Leaf leaf, char* const vendor) {
|
||||
*(uint32_t*)(vendor) = leaf.ebx;
|
||||
*(uint32_t*)(vendor + 4) = leaf.edx;
|
||||
*(uint32_t*)(vendor + 8) = leaf.ecx;
|
||||
vendor[12] = '\0';
|
||||
}
|
||||
|
||||
static int IsVendor(const Leaf leaf, const char* const name) {
|
||||
const uint32_t ebx = *(const uint32_t*)(name);
|
||||
const uint32_t edx = *(const uint32_t*)(name + 4);
|
||||
const uint32_t ecx = *(const uint32_t*)(name + 8);
|
||||
return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
|
||||
}
|
||||
|
||||
// Reference https://en.wikipedia.org/wiki/CPUID.
|
||||
static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info) {
|
||||
const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
|
||||
const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
|
||||
|
||||
const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
|
||||
const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
|
||||
const uint32_t xcr0_eax = (have_xsave && have_osxsave) ? GetXCR0Eax() : 0;
|
||||
const bool have_sse_os_support = HasXmmOsXSave(xcr0_eax);
|
||||
const bool have_avx_os_support = HasYmmOsXSave(xcr0_eax);
|
||||
const bool have_avx512_os_support = HasZmmOsXSave(xcr0_eax);
|
||||
|
||||
const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
|
||||
const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
|
||||
const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
|
||||
const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
|
||||
|
||||
X86Features* const features = &info->features;
|
||||
|
||||
info->family = extended_family + family;
|
||||
info->model = (extended_model << 4) + model;
|
||||
info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
|
||||
|
||||
features->aes = IsBitSet(leaf_1.ecx, 25);
|
||||
features->erms = IsBitSet(leaf_7.ebx, 9);
|
||||
features->f16c = IsBitSet(leaf_1.ecx, 29);
|
||||
features->bmi1 = IsBitSet(leaf_7.ebx, 3);
|
||||
features->bmi2 = IsBitSet(leaf_7.ebx, 8);
|
||||
features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
|
||||
|
||||
if (have_sse_os_support) {
|
||||
features->ssse3 = IsBitSet(leaf_1.ecx, 9);
|
||||
features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
|
||||
features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
|
||||
}
|
||||
|
||||
if (have_avx_os_support) {
|
||||
features->fma3 = IsBitSet(leaf_1.ecx, 12);
|
||||
features->avx = IsBitSet(leaf_1.ecx, 28);
|
||||
features->avx2 = IsBitSet(leaf_7.ebx, 5);
|
||||
}
|
||||
|
||||
if (have_avx512_os_support) {
|
||||
features->avx512f = IsBitSet(leaf_7.ebx, 16);
|
||||
features->avx512cd = IsBitSet(leaf_7.ebx, 28);
|
||||
features->avx512er = IsBitSet(leaf_7.ebx, 27);
|
||||
features->avx512pf = IsBitSet(leaf_7.ebx, 26);
|
||||
features->avx512bw = IsBitSet(leaf_7.ebx, 30);
|
||||
features->avx512dq = IsBitSet(leaf_7.ebx, 17);
|
||||
features->avx512vl = IsBitSet(leaf_7.ebx, 31);
|
||||
features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
|
||||
features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
|
||||
features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
|
||||
features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
|
||||
features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
|
||||
features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
|
||||
features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
|
||||
features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
|
||||
}
|
||||
}
|
||||
|
||||
static const X86Info kEmptyX86Info;
|
||||
|
||||
X86Info GetX86Info(void) {
|
||||
X86Info info = kEmptyX86Info;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const uint32_t max_cpuid_leaf = leaf_0.eax;
|
||||
SetVendor(leaf_0, info.vendor);
|
||||
if (IsVendor(leaf_0, "GenuineIntel") || IsVendor(leaf_0, "AuthenticAMD")) {
|
||||
ParseCpuId(max_cpuid_leaf, &info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
#define CPUID(FAMILY, MODEL) (((FAMILY & 0xFF) << 8) | (MODEL & 0xFF))
|
||||
|
||||
X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
|
||||
if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
|
||||
switch (CPUID(info->family, info->model)) {
|
||||
case CPUID(0x06, 0x35):
|
||||
case CPUID(0x06, 0x36):
|
||||
// https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
|
||||
return INTEL_ATOM_BNL;
|
||||
case CPUID(0x06, 0x37):
|
||||
case CPUID(0x06, 0x4C):
|
||||
// https://en.wikipedia.org/wiki/Silvermont
|
||||
return INTEL_ATOM_SMT;
|
||||
case CPUID(0x06, 0x5C):
|
||||
// https://en.wikipedia.org/wiki/Goldmont
|
||||
return INTEL_ATOM_GMT;
|
||||
case CPUID(0x06, 0x0F):
|
||||
case CPUID(0x06, 0x16):
|
||||
// https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
|
||||
return INTEL_CORE;
|
||||
case CPUID(0x06, 0x17):
|
||||
case CPUID(0x06, 0x1D):
|
||||
// https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
|
||||
return INTEL_PNR;
|
||||
case CPUID(0x06, 0x1A):
|
||||
case CPUID(0x06, 0x1E):
|
||||
case CPUID(0x06, 0x1F):
|
||||
case CPUID(0x06, 0x2E):
|
||||
// https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
|
||||
return INTEL_NHM;
|
||||
case CPUID(0x06, 0x25):
|
||||
case CPUID(0x06, 0x2C):
|
||||
case CPUID(0x06, 0x2F):
|
||||
// https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
|
||||
return INTEL_WSM;
|
||||
case CPUID(0x06, 0x2A):
|
||||
case CPUID(0x06, 0x2D):
|
||||
// https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
|
||||
return INTEL_SNB;
|
||||
case CPUID(0x06, 0x3A):
|
||||
case CPUID(0x06, 0x3E):
|
||||
// https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
|
||||
return INTEL_IVB;
|
||||
case CPUID(0x06, 0x3C):
|
||||
case CPUID(0x06, 0x3F):
|
||||
case CPUID(0x06, 0x45):
|
||||
case CPUID(0x06, 0x46):
|
||||
// https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
|
||||
return INTEL_HSW;
|
||||
case CPUID(0x06, 0x3D):
|
||||
case CPUID(0x06, 0x47):
|
||||
case CPUID(0x06, 0x4F):
|
||||
case CPUID(0x06, 0x56):
|
||||
// https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
|
||||
return INTEL_BDW;
|
||||
case CPUID(0x06, 0x4E):
|
||||
case CPUID(0x06, 0x55):
|
||||
case CPUID(0x06, 0x5E):
|
||||
// https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
|
||||
return INTEL_SKL;
|
||||
case CPUID(0x06, 0x8E):
|
||||
case CPUID(0x06, 0x9E):
|
||||
// https://en.wikipedia.org/wiki/Kaby_Lake
|
||||
return INTEL_KBL;
|
||||
default:
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
|
||||
switch (info->family) {
|
||||
// https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
|
||||
case 0x0F:
|
||||
return AMD_HAMMER;
|
||||
case 0x10:
|
||||
return AMD_K10;
|
||||
case 0x14:
|
||||
return AMD_BOBCAT;
|
||||
case 0x15:
|
||||
return AMD_BULLDOZER;
|
||||
case 0x16:
|
||||
return AMD_JAGUAR;
|
||||
case 0x17:
|
||||
return AMD_ZEN;
|
||||
default:
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
|
||||
static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
|
||||
char* buffer) {
|
||||
const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
|
||||
// We allow calling memcpy from SetString which is only called when requesting
|
||||
// X86BrandString.
|
||||
memcpy(buffer, &leaf, sizeof(Leaf));
|
||||
}
|
||||
|
||||
void FillX86BrandString(char brand_string[49]) {
|
||||
const Leaf leaf_ext_0 = CpuId(0x80000000);
|
||||
const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
|
||||
SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
|
||||
SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
|
||||
SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
|
||||
brand_string[48] = '\0';
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetX86FeaturesEnumValue(const X86Features* features,
|
||||
X86FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case X86_AES:
|
||||
return features->aes;
|
||||
case X86_ERMS:
|
||||
return features->erms;
|
||||
case X86_F16C:
|
||||
return features->f16c;
|
||||
case X86_FMA3:
|
||||
return features->fma3;
|
||||
case X86_VPCLMULQDQ:
|
||||
return features->vpclmulqdq;
|
||||
case X86_BMI1:
|
||||
return features->bmi1;
|
||||
case X86_BMI2:
|
||||
return features->bmi2;
|
||||
case X86_SSSE3:
|
||||
return features->ssse3;
|
||||
case X86_SSE4_1:
|
||||
return features->sse4_1;
|
||||
case X86_SSE4_2:
|
||||
return features->sse4_2;
|
||||
case X86_AVX:
|
||||
return features->avx;
|
||||
case X86_AVX2:
|
||||
return features->avx2;
|
||||
case X86_AVX512F:
|
||||
return features->avx512f;
|
||||
case X86_AVX512CD:
|
||||
return features->avx512cd;
|
||||
case X86_AVX512ER:
|
||||
return features->avx512er;
|
||||
case X86_AVX512PF:
|
||||
return features->avx512pf;
|
||||
case X86_AVX512BW:
|
||||
return features->avx512bw;
|
||||
case X86_AVX512DQ:
|
||||
return features->avx512dq;
|
||||
case X86_AVX512VL:
|
||||
return features->avx512vl;
|
||||
case X86_AVX512IFMA:
|
||||
return features->avx512ifma;
|
||||
case X86_AVX512VBMI:
|
||||
return features->avx512vbmi;
|
||||
case X86_AVX512VBMI2:
|
||||
return features->avx512vbmi2;
|
||||
case X86_AVX512VNNI:
|
||||
return features->avx512vnni;
|
||||
case X86_AVX512BITALG:
|
||||
return features->avx512bitalg;
|
||||
case X86_AVX512VPOPCNTDQ:
|
||||
return features->avx512vpopcntdq;
|
||||
case X86_AVX512_4VNNIW:
|
||||
return features->avx512_4vnniw;
|
||||
case X86_AVX512_4VBMI2:
|
||||
return features->avx512_4vbmi2;
|
||||
case X86_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case X86_AES:
|
||||
return "aes";
|
||||
case X86_ERMS:
|
||||
return "erms";
|
||||
case X86_F16C:
|
||||
return "f16c";
|
||||
case X86_FMA3:
|
||||
return "fma3";
|
||||
case X86_VPCLMULQDQ:
|
||||
return "vpclmulqdq";
|
||||
case X86_BMI1:
|
||||
return "bmi1";
|
||||
case X86_BMI2:
|
||||
return "bmi2";
|
||||
case X86_SSSE3:
|
||||
return "ssse3";
|
||||
case X86_SSE4_1:
|
||||
return "sse4_1";
|
||||
case X86_SSE4_2:
|
||||
return "sse4_2";
|
||||
case X86_AVX:
|
||||
return "avx";
|
||||
case X86_AVX2:
|
||||
return "avx2";
|
||||
case X86_AVX512F:
|
||||
return "avx512f";
|
||||
case X86_AVX512CD:
|
||||
return "avx512cd";
|
||||
case X86_AVX512ER:
|
||||
return "avx512er";
|
||||
case X86_AVX512PF:
|
||||
return "avx512pf";
|
||||
case X86_AVX512BW:
|
||||
return "avx512bw";
|
||||
case X86_AVX512DQ:
|
||||
return "avx512dq";
|
||||
case X86_AVX512VL:
|
||||
return "avx512vl";
|
||||
case X86_AVX512IFMA:
|
||||
return "avx512ifma";
|
||||
case X86_AVX512VBMI:
|
||||
return "avx512vbmi";
|
||||
case X86_AVX512VBMI2:
|
||||
return "avx512vbmi2";
|
||||
case X86_AVX512VNNI:
|
||||
return "avx512vnni";
|
||||
case X86_AVX512BITALG:
|
||||
return "avx512bitalg";
|
||||
case X86_AVX512VPOPCNTDQ:
|
||||
return "avx512vpopcntdq";
|
||||
case X86_AVX512_4VNNIW:
|
||||
return "avx512_4vnniw";
|
||||
case X86_AVX512_4VBMI2:
|
||||
return "avx512_4vbmi2";
|
||||
case X86_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown_feature";
|
||||
}
|
||||
|
||||
const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
|
||||
switch (uarch) {
|
||||
case X86_UNKNOWN:
|
||||
return "X86_UNKNOWN";
|
||||
case INTEL_CORE:
|
||||
return "INTEL_CORE";
|
||||
case INTEL_PNR:
|
||||
return "INTEL_PNR";
|
||||
case INTEL_NHM:
|
||||
return "INTEL_NHM";
|
||||
case INTEL_ATOM_BNL:
|
||||
return "INTEL_ATOM_BNL";
|
||||
case INTEL_WSM:
|
||||
return "INTEL_WSM";
|
||||
case INTEL_SNB:
|
||||
return "INTEL_SNB";
|
||||
case INTEL_IVB:
|
||||
return "INTEL_IVB";
|
||||
case INTEL_ATOM_SMT:
|
||||
return "INTEL_ATOM_SMT";
|
||||
case INTEL_HSW:
|
||||
return "INTEL_HSW";
|
||||
case INTEL_BDW:
|
||||
return "INTEL_BDW";
|
||||
case INTEL_SKL:
|
||||
return "INTEL_SKL";
|
||||
case INTEL_ATOM_GMT:
|
||||
return "INTEL_ATOM_GMT";
|
||||
case INTEL_KBL:
|
||||
return "INTEL_KBL";
|
||||
case INTEL_CFL:
|
||||
return "INTEL_CFL";
|
||||
case INTEL_CNL:
|
||||
return "INTEL_CNL";
|
||||
case AMD_HAMMER:
|
||||
return "AMD_HAMMER";
|
||||
case AMD_K10:
|
||||
return "AMD_K10";
|
||||
case AMD_BOBCAT:
|
||||
return "AMD_BOBCAT";
|
||||
case AMD_BULLDOZER:
|
||||
return "AMD_BULLDOZER";
|
||||
case AMD_JAGUAR:
|
||||
return "AMD_JAGUAR";
|
||||
case AMD_ZEN:
|
||||
return "AMD_ZEN";
|
||||
}
|
||||
return "unknown microarchitecture";
|
||||
}
|
53
src/filesystem.c
Normal file
53
src/filesystem.c
Normal file
@ -0,0 +1,53 @@
|
||||
// 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 <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
int OpenFile(const char* filename) { return _open(filename, _O_RDONLY); }
|
||||
|
||||
void CloseFile(int file_descriptor) { _close(file_descriptor); }
|
||||
|
||||
int ReadFile(int file_descriptor, void* buffer, size_t buffer_size) {
|
||||
return _read(file_descriptor, buffer, buffer_size);
|
||||
}
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
||||
int OpenFile(const char* filename) {
|
||||
int result;
|
||||
do {
|
||||
result = open(filename, O_RDONLY);
|
||||
} while (result == -1L && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CloseFile(int file_descriptor) { close(file_descriptor); }
|
||||
|
||||
int 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
|
165
src/hwcaps.c
Normal file
165
src/hwcaps.c
Normal file
@ -0,0 +1,165 @@
|
||||
// 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/hwcaps.h"
|
||||
#include "cpu_features_macros.h"
|
||||
#include "internal/filesystem.h"
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define D(...)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define D(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_MIPS) || defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||
#define HWCAPS_ANDROID_MIPS_OR_ARM
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) && \
|
||||
!defined(HWCAPS_ANDROID_MIPS_OR_ARM)
|
||||
#define HWCAPS_REGULAR_LINUX
|
||||
#endif
|
||||
|
||||
#if defined(HWCAPS_ANDROID_MIPS_OR_ARM) || defined(HWCAPS_REGULAR_LINUX)
|
||||
#define HWCAPS_SUPPORTED
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetElfHwcapFromGetauxval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// On Linux we simply use getauxval.
|
||||
#if defined(HWCAPS_REGULAR_LINUX)
|
||||
#include <dlfcn.h>
|
||||
#include <sys/auxv.h>
|
||||
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||
return getauxval(hwcap_type);
|
||||
}
|
||||
#endif // defined(HWCAPS_REGULAR_LINUX)
|
||||
|
||||
// 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.
|
||||
#if defined(HWCAPS_ANDROID_MIPS_OR_ARM)
|
||||
#include <dlfcn.h>
|
||||
#define AT_HWCAP 16
|
||||
#define AT_HWCAP2 26
|
||||
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;
|
||||
}
|
||||
#endif // defined(HWCAPS_ANDROID_MIPS_OR_ARM)
|
||||
|
||||
#if defined(HWCAPS_SUPPORTED)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetHardwareCapabilities for Android and Linux
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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 = OpenFile(filepath);
|
||||
if (fd < 0) {
|
||||
D("Could not open %s\n", filepath);
|
||||
return 0;
|
||||
}
|
||||
for (;;) {
|
||||
const int ret = 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;
|
||||
}
|
||||
}
|
||||
CloseFile(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Retrieves hardware capabilities by first trying to call getauxval, if not
|
||||
// available falls back to reading "/proc/self/auxv".
|
||||
static uint32_t GetHardwareCapabilitiesFor(uint32_t type) {
|
||||
uint32_t hwcaps = GetElfHwcapFromGetauxval(type);
|
||||
if (!hwcaps) {
|
||||
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
|
||||
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
|
||||
}
|
||||
return hwcaps;
|
||||
}
|
||||
|
||||
HardwareCapabilities GetHardwareCapabilities(void) {
|
||||
HardwareCapabilities capabilities;
|
||||
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
|
||||
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
#else // (defined(HWCAPS_SUPPORTED)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetHardwareCapabilities for unsupported platforms.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const HardwareCapabilities kEmptyHardwareCapabilities;
|
||||
HardwareCapabilities GetHardwareCapabilities(void) {
|
||||
return kEmptyHardwareCapabilities;
|
||||
}
|
||||
#endif
|
48
src/linux_features_aggregator.c
Normal file
48
src/linux_features_aggregator.c
Normal file
@ -0,0 +1,48 @@
|
||||
// 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/linux_features_aggregator.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
void 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, HasWord(flags_line, config.proc_cpuinfo_flag));
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSet(const uint32_t mask, const uint32_t value) {
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
111
src/list_cpu_features.cc
Normal file
111
src/list_cpu_features.cc
Normal file
@ -0,0 +1,111 @@
|
||||
// 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 <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "cpuinfo_aarch64.h"
|
||||
#include "cpuinfo_arm.h"
|
||||
#include "cpuinfo_mips.h"
|
||||
#include "cpuinfo_x86.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
// Prints a named numeric value in both decimal and hexadecimal.
|
||||
void PrintN(const char* field, int value) {
|
||||
printf("%-15s : %3d (0x%02X)\n", field, value, value);
|
||||
}
|
||||
|
||||
// Prints a named string.
|
||||
void PrintS(const char* field, const char* value) {
|
||||
printf("%-15s : %s\n", field, value);
|
||||
}
|
||||
|
||||
template <typename HasFeatureFun, typename FeatureNameFun, typename FeatureType,
|
||||
typename EnumType>
|
||||
std::string GetFlags(const HasFeatureFun HasFeature,
|
||||
const FeatureNameFun FeatureName,
|
||||
const FeatureType* features, const EnumType last) {
|
||||
std::vector<std::string> flags;
|
||||
for (int i = 0; i < last; ++i) {
|
||||
const EnumType enum_value = static_cast<EnumType>(i);
|
||||
if (HasFeature(features, enum_value)) {
|
||||
flags.push_back(FeatureName(enum_value));
|
||||
}
|
||||
}
|
||||
std::sort(flags.begin(), flags.end());
|
||||
std::string buffer;
|
||||
for (const auto& flag : flags) {
|
||||
if (!buffer.empty()) buffer += ' ';
|
||||
buffer += flag;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Main() {
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
char brand_string[49];
|
||||
const X86Info info = GetX86Info();
|
||||
const auto flags = GetFlags(&GetX86FeaturesEnumValue, &GetX86FeaturesEnumName,
|
||||
&info.features, X86FeaturesEnum::X86_LAST_);
|
||||
FillX86BrandString(brand_string);
|
||||
PrintS("arch", "x86");
|
||||
PrintS("brand", brand_string);
|
||||
PrintN("family", info.family);
|
||||
PrintN("model", info.model);
|
||||
PrintN("stepping", info.stepping);
|
||||
PrintS("uarch", GetX86MicroarchitectureName(GetX86Microarchitecture(&info)));
|
||||
PrintS("flags", flags.c_str());
|
||||
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||
const ArmInfo info = GetArmInfo();
|
||||
const auto flags = GetFlags(&GetArmFeaturesEnumValue, &GetArmFeaturesEnumName,
|
||||
&info.features, ArmFeaturesEnum::ARM_LAST_);
|
||||
PrintS("arch", "ARM");
|
||||
PrintN("implementer", info.implementer);
|
||||
PrintN("architecture", info.architecture);
|
||||
PrintN("variant", info.variant);
|
||||
PrintN("part", info.part);
|
||||
PrintN("revision", info.revision);
|
||||
PrintS("flags", flags.c_str());
|
||||
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
const Aarch64Info info = GetAarch64Info();
|
||||
const auto flags =
|
||||
GetFlags(&GetAarch64FeaturesEnumValue, &GetAarch64FeaturesEnumName,
|
||||
&info.features, Aarch64FeaturesEnum::AARCH64_LAST_);
|
||||
PrintS("arch", "aarch64");
|
||||
PrintN("implementer", info.implementer);
|
||||
PrintN("variant", info.variant);
|
||||
PrintN("part", info.part);
|
||||
PrintN("revision", info.revision);
|
||||
PrintS("flags", flags.c_str());
|
||||
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||
const MipsInfo info = GetMipsInfo();
|
||||
const auto flags =
|
||||
GetFlags(&GetMipsFeaturesEnumValue, &GetMipsFeaturesEnumName,
|
||||
&info.features, MipsFeaturesEnum::MIPS_LAST_);
|
||||
PrintS("arch", "mips");
|
||||
PrintS("flags", flags.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace cpu_features
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
cpu_features::Main();
|
||||
return 0;
|
||||
}
|
128
src/stack_line_reader.c
Normal file
128
src/stack_line_reader.c
Normal file
@ -0,0 +1,128 @@
|
||||
// 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 =
|
||||
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 = 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 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 = 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 = KeepFront(reader->view, eol_index);
|
||||
reader->view = PopFront(reader->view, eol_index + 1);
|
||||
return CreateValidLineResult(line);
|
||||
}
|
||||
}
|
||||
}
|
163
src/string_view.c
Normal file
163
src/string_view.c
Normal 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.
|
||||
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
int 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 found - view.ptr;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int 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 = IndexOfChar(remainder, sub_view.ptr[0]);
|
||||
if (found_index < 0) break;
|
||||
remainder = PopFront(remainder, found_index);
|
||||
if (StartsWith(remainder, sub_view)) {
|
||||
return remainder.ptr - view.ptr;
|
||||
}
|
||||
remainder = PopFront(remainder, 1);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool 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 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 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 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 KeepFront(const StringView str_view, size_t count) {
|
||||
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
|
||||
}
|
||||
|
||||
char Front(const StringView view) {
|
||||
assert(view.size);
|
||||
assert(view.ptr);
|
||||
return view.ptr[0];
|
||||
}
|
||||
|
||||
char Back(const StringView view) {
|
||||
assert(view.size);
|
||||
return view.ptr[view.size - 1];
|
||||
}
|
||||
|
||||
StringView TrimWhitespace(StringView view) {
|
||||
while (view.size && isspace(Front(view))) view = PopFront(view, 1);
|
||||
while (view.size && isspace(Back(view))) view = 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 = PopFront(remainder, 1)) {
|
||||
const int value = HexValue(Front(remainder));
|
||||
if (value < 0 || value >= base) return -1;
|
||||
result = (result * base) + value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ParsePositiveNumber(const StringView view) {
|
||||
if (view.size) {
|
||||
const StringView hex_prefix = str("0x");
|
||||
if (StartsWith(view, hex_prefix)) {
|
||||
const StringView span_no_prefix = PopFront(view, hex_prefix.size);
|
||||
return ParsePositiveNumberWithBase(span_no_prefix, 16);
|
||||
}
|
||||
return ParsePositiveNumberWithBase(view, 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void 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 HasWord(const StringView line, const char* const word_str) {
|
||||
const StringView word = str(word_str);
|
||||
StringView remainder = line;
|
||||
for (;;) {
|
||||
const int index_of_word = IndexOf(remainder, word);
|
||||
if (index_of_word < 0) {
|
||||
return false;
|
||||
} else {
|
||||
const StringView before = KeepFront(line, index_of_word);
|
||||
const StringView after = PopFront(line, index_of_word + word.size);
|
||||
const bool valid_before = before.size == 0 || Back(before) == ' ';
|
||||
const bool valid_after = after.size == 0 || Front(after) == ' ';
|
||||
if (valid_before && valid_after) return true;
|
||||
remainder = PopFront(remainder, index_of_word + word.size);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetAttributeKeyValue(const StringView line, StringView* key,
|
||||
StringView* value) {
|
||||
const StringView sep = str(": ");
|
||||
const int index_of_separator = IndexOf(line, sep);
|
||||
if (index_of_separator < 0) return false;
|
||||
*value = TrimWhitespace(PopFront(line, index_of_separator + sep.size));
|
||||
*key = TrimWhitespace(KeepFront(line, index_of_separator));
|
||||
return true;
|
||||
}
|
74
test/CMakeLists.txt
Normal file
74
test/CMakeLists.txt
Normal file
@ -0,0 +1,74 @@
|
||||
#
|
||||
# libraries for tests
|
||||
#
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11
|
||||
|
||||
include_directories(../include)
|
||||
add_definitions(-DCPU_FEATURES_TEST)
|
||||
|
||||
##------------------------------------------------------------------------------
|
||||
add_library(string_view ../src/string_view.c)
|
||||
##------------------------------------------------------------------------------
|
||||
add_library(filesystem_for_testing filesystem_for_testing.cc)
|
||||
##------------------------------------------------------------------------------
|
||||
add_library(hwcaps_for_testing hwcaps_for_testing.cc)
|
||||
target_link_libraries(hwcaps_for_testing filesystem_for_testing)
|
||||
##------------------------------------------------------------------------------
|
||||
add_library(stack_line_reader ../src/stack_line_reader.c)
|
||||
target_compile_definitions(stack_line_reader PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024)
|
||||
target_link_libraries(stack_line_reader string_view)
|
||||
##------------------------------------------------------------------------------
|
||||
add_library(stack_line_reader_for_test ../src/stack_line_reader.c)
|
||||
target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16)
|
||||
target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing)
|
||||
##------------------------------------------------------------------------------
|
||||
add_library(all_libraries ../src/stack_line_reader.c ../src/linux_features_aggregator.c)
|
||||
target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view)
|
||||
|
||||
#
|
||||
# tests
|
||||
#
|
||||
link_libraries(gtest gmock_main)
|
||||
|
||||
## bit_utils_test
|
||||
add_executable(bit_utils_test bit_utils_test.cc)
|
||||
target_link_libraries(bit_utils_test)
|
||||
add_test(NAME bit_utils_test COMMAND bit_utils_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## string_view_test
|
||||
add_executable(string_view_test string_view_test.cc ../src/string_view.c)
|
||||
target_link_libraries(string_view_test string_view)
|
||||
add_test(NAME string_view_test COMMAND string_view_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## stack_line_reader_test
|
||||
add_executable(stack_line_reader_test stack_line_reader_test.cc)
|
||||
target_link_libraries(stack_line_reader_test stack_line_reader_for_test)
|
||||
add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## linux_features_aggregator_test
|
||||
add_executable(linux_features_aggregator_test linux_features_aggregator_test.cc)
|
||||
target_link_libraries(linux_features_aggregator_test all_libraries)
|
||||
add_test(NAME linux_features_aggregator_test COMMAND linux_features_aggregator_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## cpuinfo_x86_test
|
||||
add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c)
|
||||
target_link_libraries(cpuinfo_x86_test all_libraries)
|
||||
add_test(NAME cpuinfo_x86_test COMMAND cpuinfo_x86_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## cpuinfo_arm_test
|
||||
add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/cpuinfo_arm.c)
|
||||
target_link_libraries(cpuinfo_arm_test all_libraries)
|
||||
add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## cpuinfo_aarch64_test
|
||||
add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/cpuinfo_aarch64.c)
|
||||
target_link_libraries(cpuinfo_aarch64_test all_libraries)
|
||||
add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test)
|
||||
##------------------------------------------------------------------------------
|
||||
## cpuinfo_mips_test
|
||||
add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/cpuinfo_mips.c)
|
||||
target_link_libraries(cpuinfo_mips_test all_libraries)
|
||||
add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test)
|
53
test/bit_utils_test.cc
Normal file
53
test/bit_utils_test.cc
Normal file
@ -0,0 +1,53 @@
|
||||
// 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/bit_utils.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
namespace {
|
||||
|
||||
TEST(UtilsTest, IsBitSet) {
|
||||
for (size_t bit_set = 0; bit_set < 32; ++bit_set) {
|
||||
const uint32_t value = 1UL << bit_set;
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
EXPECT_EQ(IsBitSet(value, i), i == bit_set);
|
||||
}
|
||||
}
|
||||
|
||||
// testing 0, all bits should be 0.
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
EXPECT_FALSE(IsBitSet(0, i));
|
||||
}
|
||||
|
||||
// testing ~0, all bits should be 1.
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
EXPECT_TRUE(IsBitSet(-1, i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UtilsTest, ExtractBitRange) {
|
||||
// Extracting all bits gives the same number.
|
||||
EXPECT_EQ(ExtractBitRange(123, 31, 0), 123);
|
||||
// Extracting 1 bit gives parity.
|
||||
EXPECT_EQ(ExtractBitRange(123, 0, 0), 1);
|
||||
EXPECT_EQ(ExtractBitRange(122, 0, 0), 0);
|
||||
|
||||
EXPECT_EQ(ExtractBitRange(0xF0, 7, 4), 0xF);
|
||||
EXPECT_EQ(ExtractBitRange(0x42 << 2, 10, 2), 0x42);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
74
test/cpuinfo_aarch64_test.cc
Normal file
74
test/cpuinfo_aarch64_test.cc
Normal file
@ -0,0 +1,74 @@
|
||||
// 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 "filesystem_for_testing.h"
|
||||
#include "hwcaps_for_testing.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
namespace {
|
||||
|
||||
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||
|
||||
TEST(CpuinfoAarch64Test, FromHardwareCap) {
|
||||
SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
|
||||
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||
const auto info = GetAarch64Info();
|
||||
EXPECT_TRUE(info.features.fp);
|
||||
EXPECT_FALSE(info.features.asimd);
|
||||
EXPECT_TRUE(info.features.aes);
|
||||
EXPECT_FALSE(info.features.pmull);
|
||||
EXPECT_FALSE(info.features.sha1);
|
||||
EXPECT_FALSE(info.features.sha2);
|
||||
EXPECT_FALSE(info.features.crc32);
|
||||
}
|
||||
|
||||
TEST(CpuinfoAarch64Test, ARMCortexA53) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(Processor : AArch64 Processor rev 3 (aarch64)
|
||||
processor : 0
|
||||
processor : 1
|
||||
processor : 2
|
||||
processor : 3
|
||||
processor : 4
|
||||
processor : 5
|
||||
processor : 6
|
||||
processor : 7
|
||||
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
|
||||
CPU implementer : 0x41
|
||||
CPU architecture: AArch64
|
||||
CPU variant : 0x0
|
||||
CPU part : 0xd03
|
||||
CPU revision : 3)");
|
||||
const auto info = GetAarch64Info();
|
||||
EXPECT_EQ(info.implementer, 0x41);
|
||||
EXPECT_EQ(info.variant, 0x0);
|
||||
EXPECT_EQ(info.part, 0xd03);
|
||||
EXPECT_EQ(info.revision, 3);
|
||||
|
||||
EXPECT_TRUE(info.features.fp);
|
||||
EXPECT_TRUE(info.features.asimd);
|
||||
EXPECT_TRUE(info.features.aes);
|
||||
EXPECT_TRUE(info.features.pmull);
|
||||
EXPECT_TRUE(info.features.sha1);
|
||||
EXPECT_TRUE(info.features.sha2);
|
||||
EXPECT_TRUE(info.features.crc32);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
182
test/cpuinfo_arm_test.cc
Normal file
182
test/cpuinfo_arm_test.cc
Normal 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 "cpuinfo_arm.h"
|
||||
#include "filesystem_for_testing.h"
|
||||
#include "hwcaps_for_testing.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
namespace {
|
||||
|
||||
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||
|
||||
TEST(CpuinfoArmTest, FromHardwareCap) {
|
||||
SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32);
|
||||
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_TRUE(info.features.vfp); // triggered by vfpv3
|
||||
EXPECT_TRUE(info.features.vfpv3); // triggered by neon
|
||||
EXPECT_TRUE(info.features.neon);
|
||||
EXPECT_TRUE(info.features.aes);
|
||||
EXPECT_TRUE(info.features.crc32);
|
||||
|
||||
EXPECT_FALSE(info.features.vfpv4);
|
||||
EXPECT_FALSE(info.features.iwmmxt);
|
||||
EXPECT_FALSE(info.features.vfpv3d16);
|
||||
EXPECT_FALSE(info.features.idiva);
|
||||
EXPECT_FALSE(info.features.idivt);
|
||||
EXPECT_FALSE(info.features.pmull);
|
||||
EXPECT_FALSE(info.features.sha1);
|
||||
EXPECT_FALSE(info.features.sha2);
|
||||
}
|
||||
|
||||
TEST(CpuinfoArmTest, ODroidFromCpuInfo) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||
model name : ARMv7 Processor rev 3 (v71)
|
||||
BogoMIPS : 120.00
|
||||
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
|
||||
CPU implementer : 0x41
|
||||
CPU architecture: 7
|
||||
CPU variant : 0x2
|
||||
CPU part : 0xc0f
|
||||
CPU revision : 3)");
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_EQ(info.implementer, 0x41);
|
||||
EXPECT_EQ(info.variant, 0x2);
|
||||
EXPECT_EQ(info.part, 0xc0f);
|
||||
EXPECT_EQ(info.revision, 3);
|
||||
EXPECT_EQ(info.architecture, 7);
|
||||
|
||||
EXPECT_TRUE(info.features.vfp);
|
||||
EXPECT_FALSE(info.features.iwmmxt);
|
||||
EXPECT_TRUE(info.features.neon);
|
||||
EXPECT_TRUE(info.features.vfpv3);
|
||||
EXPECT_FALSE(info.features.vfpv3d16);
|
||||
EXPECT_TRUE(info.features.vfpv4);
|
||||
EXPECT_TRUE(info.features.idiva);
|
||||
EXPECT_TRUE(info.features.idivt);
|
||||
EXPECT_FALSE(info.features.aes);
|
||||
EXPECT_FALSE(info.features.pmull);
|
||||
EXPECT_FALSE(info.features.sha1);
|
||||
EXPECT_FALSE(info.features.sha2);
|
||||
EXPECT_FALSE(info.features.crc32);
|
||||
}
|
||||
|
||||
// http://code.google.com/p/android/issues/detail?id=10812
|
||||
TEST(CpuinfoArmTest, InvalidArmv7) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(Processor : ARMv6-compatible processor rev 6 (v6l)
|
||||
BogoMIPS : 199.47
|
||||
Features : swp half thumb fastmult vfp edsp java
|
||||
CPU implementer : 0x41
|
||||
CPU architecture: 7
|
||||
CPU variant : 0x0
|
||||
CPU part : 0xb76
|
||||
CPU revision : 6
|
||||
|
||||
Hardware : SPICA
|
||||
Revision : 0020
|
||||
Serial : 33323613546d00ec )");
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_EQ(info.architecture, 6);
|
||||
}
|
||||
|
||||
// https://crbug.com/341598.
|
||||
TEST(CpuinfoArmTest, InvalidNeon) {
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(Processor: ARMv7 Processory rev 0 (v71)
|
||||
processor: 0
|
||||
BogoMIPS: 13.50
|
||||
|
||||
Processor: 1
|
||||
BogoMIPS: 13.50
|
||||
|
||||
Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
|
||||
CPU implementer : 0x51
|
||||
CPU architecture: 7
|
||||
CPU variant: 0x1
|
||||
CPU part: 0x04d
|
||||
CPU revision: 0
|
||||
|
||||
Hardware: SAMSUNG M2
|
||||
Revision: 0010
|
||||
Serial: 00001e030000354e)");
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_FALSE(info.features.neon);
|
||||
}
|
||||
|
||||
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
|
||||
// support.
|
||||
TEST(CpuinfoArmTest, Nexus4_0x510006f2) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(CPU implementer : 0x51
|
||||
CPU architecture: 7
|
||||
CPU variant : 0x0
|
||||
CPU part : 0x6f
|
||||
CPU revision : 2)");
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_TRUE(info.features.idiva);
|
||||
EXPECT_TRUE(info.features.idivt);
|
||||
}
|
||||
|
||||
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
|
||||
// support.
|
||||
TEST(CpuinfoArmTest, Nexus4_0x510006f3) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(CPU implementer : 0x51
|
||||
CPU architecture: 7
|
||||
CPU variant : 0x0
|
||||
CPU part : 0x6f
|
||||
CPU revision : 3)");
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_TRUE(info.features.idiva);
|
||||
EXPECT_TRUE(info.features.idivt);
|
||||
}
|
||||
|
||||
// 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.
|
||||
TEST(CpuinfoArmTest, EmulatorSpecificIdiv) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(Processor : ARMv7 Processor rev 0 (v7l)
|
||||
BogoMIPS : 629.14
|
||||
Features : swp half thumb fastmult vfp edsp neon vfpv3
|
||||
CPU implementer : 0x41
|
||||
CPU architecture: 7
|
||||
CPU variant : 0x0
|
||||
CPU part : 0xc08
|
||||
CPU revision : 0
|
||||
|
||||
Hardware : Goldfish
|
||||
Revision : 0000
|
||||
Serial : 0000000000000000)");
|
||||
const auto info = GetArmInfo();
|
||||
EXPECT_TRUE(info.features.idiva);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
125
test/cpuinfo_mips_test.cc
Normal file
125
test/cpuinfo_mips_test.cc
Normal file
@ -0,0 +1,125 @@
|
||||
// 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_mips.h"
|
||||
#include "filesystem_for_testing.h"
|
||||
#include "hwcaps_for_testing.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
namespace {
|
||||
|
||||
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||
|
||||
TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
|
||||
SetHardwareCapabilities(MIPS_HWCAP_EVA | MIPS_HWCAP_MSA, 0);
|
||||
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||
const auto info = GetMipsInfo();
|
||||
EXPECT_TRUE(info.features.msa);
|
||||
EXPECT_TRUE(info.features.eva);
|
||||
}
|
||||
|
||||
TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) {
|
||||
SetHardwareCapabilities(MIPS_HWCAP_MSA, 0);
|
||||
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||
const auto info = GetMipsInfo();
|
||||
EXPECT_TRUE(info.features.msa);
|
||||
EXPECT_FALSE(info.features.eva);
|
||||
}
|
||||
|
||||
TEST(CpuinfoMipsTest, Ci40) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0)
|
||||
machine : IMG Marduk – Ci40 with cc2520
|
||||
processor : 0
|
||||
cpu model : MIPS interAptiv (multi) V2.0 FPU V0.0
|
||||
BogoMIPS : 363.72
|
||||
wait instruction : yes
|
||||
microsecond timers : yes
|
||||
tlb_entries : 64
|
||||
extra interrupt vector : yes
|
||||
hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
|
||||
isa : mips1 mips2 mips32r1 mips32r2
|
||||
ASEs implemented : mips16 dsp mt eva
|
||||
shadow register sets : 1
|
||||
kscratch registers : 0
|
||||
package : 0
|
||||
core : 0
|
||||
VCED exceptions : not available
|
||||
VCEI exceptions : not available
|
||||
VPE : 0
|
||||
)");
|
||||
const auto info = GetMipsInfo();
|
||||
EXPECT_FALSE(info.features.msa);
|
||||
EXPECT_TRUE(info.features.eva);
|
||||
}
|
||||
|
||||
TEST(CpuinfoMipsTest, AR7161) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo",
|
||||
R"(system type : Atheros AR7161 rev 2
|
||||
machine : NETGEAR WNDR3700/WNDR3800/WNDRMAC
|
||||
processor : 0
|
||||
cpu model : MIPS 24Kc V7.4
|
||||
BogoMIPS : 452.19
|
||||
wait instruction : yes
|
||||
microsecond timers : yes
|
||||
tlb_entries : 16
|
||||
extra interrupt vector : yes
|
||||
hardware watchpoint : yes, count: 4, address/irw mask: [0x0000, 0x0f98, 0x0f78, 0x0df8]
|
||||
ASEs implemented : mips16
|
||||
shadow register sets : 1
|
||||
kscratch registers : 0
|
||||
core : 0
|
||||
VCED exceptions : not available
|
||||
VCEI exceptions : not available
|
||||
)");
|
||||
const auto info = GetMipsInfo();
|
||||
EXPECT_FALSE(info.features.msa);
|
||||
EXPECT_FALSE(info.features.eva);
|
||||
}
|
||||
|
||||
TEST(CpuinfoMipsTest, Goldfish) {
|
||||
DisableHardwareCapabilities();
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish
|
||||
Hardware : goldfish
|
||||
Revison : 1
|
||||
processor : 0
|
||||
cpu model : MIPS 24Kc V0.0 FPU V0.0
|
||||
BogoMIPS : 1042.02
|
||||
wait instruction : yes
|
||||
microsecond timers : yes
|
||||
tlb_entries : 16
|
||||
extra interrupt vector : yes
|
||||
hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8]
|
||||
ASEs implemented :
|
||||
shadow register sets : 1
|
||||
core : 0
|
||||
VCED exceptions : not available
|
||||
VCEI exceptions : not available
|
||||
)");
|
||||
const auto info = GetMipsInfo();
|
||||
EXPECT_FALSE(info.features.msa);
|
||||
EXPECT_FALSE(info.features.eva);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
172
test/cpuinfo_x86_test.cc
Normal file
172
test/cpuinfo_x86_test.cc
Normal file
@ -0,0 +1,172 @@
|
||||
// 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 <cassert>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "cpuinfo_x86.h"
|
||||
#include "internal/cpuid_x86.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
class FakeCpu {
|
||||
public:
|
||||
Leaf CpuId(uint32_t leaf_id) const {
|
||||
const auto itr = cpuid_leaves_.find(leaf_id);
|
||||
EXPECT_TRUE(itr != cpuid_leaves_.end()) << "Missing leaf " << leaf_id;
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
uint32_t GetXCR0Eax() const { return xcr0_eax_; }
|
||||
|
||||
void SetLeaves(std::map<uint32_t, Leaf> configuration) {
|
||||
cpuid_leaves_ = std::move(configuration);
|
||||
}
|
||||
|
||||
void SetOsBackupsExtendedRegisters(bool os_backups_extended_registers) {
|
||||
xcr0_eax_ = os_backups_extended_registers ? -1 : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<uint32_t, Leaf> cpuid_leaves_;
|
||||
uint32_t xcr0_eax_;
|
||||
};
|
||||
|
||||
auto* g_fake_cpu = new FakeCpu();
|
||||
|
||||
extern "C" Leaf CpuId(uint32_t leaf_id) { return g_fake_cpu->CpuId(leaf_id); }
|
||||
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(CpuidX86Test, SandyBridge) {
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||
g_fake_cpu->SetLeaves({
|
||||
{0x00000000, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{0x00000001, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||
{0x00000007, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
});
|
||||
const auto info = GetX86Info();
|
||||
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||
EXPECT_EQ(info.family, 0x06);
|
||||
EXPECT_EQ(info.model, 0x02A);
|
||||
EXPECT_EQ(info.stepping, 0x06);
|
||||
// Leaf 7 is zeroed out so none of the Leaf 7 flags are set.
|
||||
const auto features = info.features;
|
||||
EXPECT_FALSE(features.erms);
|
||||
EXPECT_FALSE(features.avx2);
|
||||
EXPECT_FALSE(features.avx512f);
|
||||
EXPECT_FALSE(features.avx512cd);
|
||||
EXPECT_FALSE(features.avx512er);
|
||||
EXPECT_FALSE(features.avx512pf);
|
||||
EXPECT_FALSE(features.avx512bw);
|
||||
EXPECT_FALSE(features.avx512dq);
|
||||
EXPECT_FALSE(features.avx512vl);
|
||||
EXPECT_FALSE(features.avx512ifma);
|
||||
EXPECT_FALSE(features.avx512vbmi);
|
||||
EXPECT_FALSE(features.avx512vbmi2);
|
||||
EXPECT_FALSE(features.avx512vnni);
|
||||
EXPECT_FALSE(features.avx512bitalg);
|
||||
EXPECT_FALSE(features.avx512vpopcntdq);
|
||||
EXPECT_FALSE(features.avx512_4vnniw);
|
||||
EXPECT_FALSE(features.avx512_4vbmi2);
|
||||
// All old cpu features should be set.
|
||||
EXPECT_TRUE(features.aes);
|
||||
EXPECT_TRUE(features.ssse3);
|
||||
EXPECT_TRUE(features.sse4_1);
|
||||
EXPECT_TRUE(features.sse4_2);
|
||||
EXPECT_TRUE(features.avx);
|
||||
}
|
||||
|
||||
TEST(CpuidX86Test, SandyBridgeTestOsSupport) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
{0x00000000, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{0x00000001, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||
{0x00000007, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
});
|
||||
// avx is disabled if os does not support backing up ymm registers.
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||
EXPECT_FALSE(GetX86Info().features.avx);
|
||||
// avx is disabled if os does not support backing up ymm registers.
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||
EXPECT_TRUE(GetX86Info().features.avx);
|
||||
}
|
||||
|
||||
TEST(CpuidX86Test, SkyLake) {
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||
g_fake_cpu->SetLeaves({
|
||||
{0x00000000, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{0x00000001, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||
{0x00000007, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||
});
|
||||
const auto info = GetX86Info();
|
||||
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||
EXPECT_EQ(info.family, 0x06);
|
||||
EXPECT_EQ(info.model, 0x04E);
|
||||
EXPECT_EQ(info.stepping, 0x03);
|
||||
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
|
||||
}
|
||||
|
||||
TEST(CpuidX86Test, Branding) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
{0x00000000, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{0x00000001, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||
{0x00000007, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||
{0x80000000, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||
{0x80000001, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||
{0x80000002, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||
{0x80000003, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||
{0x80000004, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
|
||||
});
|
||||
char brand_string[49];
|
||||
FillX86BrandString(brand_string);
|
||||
EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
|
||||
TEST(CpuidX86Test, AMD_K15) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
{0x00000000, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{0x00000001, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
|
||||
{0x00000007, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
{0x80000000, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{0x80000001, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}},
|
||||
{0x80000002, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}},
|
||||
{0x80000003, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}},
|
||||
{0x80000004, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}},
|
||||
{0x80000005, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}},
|
||||
});
|
||||
const auto info = GetX86Info();
|
||||
|
||||
EXPECT_STREQ(info.vendor, "AuthenticAMD");
|
||||
EXPECT_EQ(info.family, 0x15);
|
||||
EXPECT_EQ(info.model, 0x38);
|
||||
EXPECT_EQ(info.stepping, 0x01);
|
||||
EXPECT_EQ(GetX86Microarchitecture(&info),
|
||||
X86Microarchitecture::AMD_BULLDOZER);
|
||||
|
||||
char brand_string[49];
|
||||
FillX86BrandString(brand_string);
|
||||
EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
|
||||
}
|
||||
|
||||
// TODO(user): test what happens when xsave/osxsave are not present.
|
||||
// TODO(user): test what happens when xmm/ymm/zmm os support are not
|
||||
// present.
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
102
test/filesystem_for_testing.cc
Normal file
102
test/filesystem_for_testing.cc
Normal file
@ -0,0 +1,102 @@
|
||||
// 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 "filesystem_for_testing.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
FakeFile::FakeFile(int file_descriptor, const char* content)
|
||||
: file_descriptor_(file_descriptor), content_(content) {}
|
||||
|
||||
FakeFile::~FakeFile() { assert(!opened_); }
|
||||
|
||||
void FakeFile::Open() {
|
||||
assert(!opened_);
|
||||
opened_ = true;
|
||||
}
|
||||
|
||||
void FakeFile::Close() {
|
||||
assert(opened_);
|
||||
opened_ = false;
|
||||
}
|
||||
|
||||
int FakeFile::Read(int fd, void* buf, size_t count) {
|
||||
assert(count < INT_MAX);
|
||||
assert(fd == file_descriptor_);
|
||||
const size_t remainder = content_.size() - head_index_;
|
||||
const size_t read = count > remainder ? remainder : count;
|
||||
memcpy(buf, content_.data() + head_index_, read);
|
||||
head_index_ += read;
|
||||
assert(read < INT_MAX);
|
||||
return read;
|
||||
}
|
||||
|
||||
void FakeFilesystem::Reset() { files_.clear(); }
|
||||
|
||||
FakeFile* FakeFilesystem::CreateFile(const std::string& filename,
|
||||
const char* content) {
|
||||
auto& file = files_[filename];
|
||||
file =
|
||||
std::unique_ptr<FakeFile>(new FakeFile(next_file_descriptor_++, content));
|
||||
return file.get();
|
||||
}
|
||||
|
||||
FakeFile* FakeFilesystem::FindFileOrNull(const std::string& filename) const {
|
||||
const auto itr = files_.find(filename);
|
||||
return itr == files_.end() ? nullptr : itr->second.get();
|
||||
}
|
||||
|
||||
FakeFile* FakeFilesystem::FindFileOrDie(const int file_descriptor) const {
|
||||
for (const auto& filename_file_pair : files_) {
|
||||
FakeFile* const file_ptr = filename_file_pair.second.get();
|
||||
if (file_ptr->GetFileDescriptor() == file_descriptor) {
|
||||
return file_ptr;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static FakeFilesystem* kFilesystem = new FakeFilesystem();
|
||||
|
||||
FakeFilesystem& GetEmptyFilesystem() {
|
||||
kFilesystem->Reset();
|
||||
return *kFilesystem;
|
||||
}
|
||||
|
||||
extern "C" int OpenFile(const char* filename) {
|
||||
auto* const file = kFilesystem->FindFileOrNull(filename);
|
||||
if (file) {
|
||||
file->Open();
|
||||
return file->GetFileDescriptor();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" void CloseFile(int file_descriptor) {
|
||||
kFilesystem->FindFileOrDie(file_descriptor)->Close();
|
||||
}
|
||||
|
||||
extern "C" int ReadFile(int file_descriptor, void* buf, size_t count) {
|
||||
return kFilesystem->FindFileOrDie(file_descriptor)
|
||||
->Read(file_descriptor, buf, count);
|
||||
}
|
||||
|
||||
} // namespace cpu_features
|
61
test/filesystem_for_testing.h
Normal file
61
test/filesystem_for_testing.h
Normal file
@ -0,0 +1,61 @@
|
||||
// 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.
|
||||
|
||||
// Implements a fake filesystem, useful for tests.
|
||||
#ifndef THIRD_PARTY_CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
class FakeFile {
|
||||
public:
|
||||
explicit FakeFile(int file_descriptor, const char* content);
|
||||
~FakeFile();
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
int Read(int fd, void* buf, size_t count);
|
||||
|
||||
int GetFileDescriptor() const { return file_descriptor_; }
|
||||
|
||||
private:
|
||||
const int file_descriptor_;
|
||||
const std::string content_;
|
||||
bool opened_ = false;
|
||||
size_t head_index_ = 0;
|
||||
};
|
||||
|
||||
class FakeFilesystem {
|
||||
public:
|
||||
void Reset();
|
||||
FakeFile* CreateFile(const std::string& filename, const char* content);
|
||||
FakeFile* FindFileOrDie(const int file_descriptor) const;
|
||||
FakeFile* FindFileOrNull(const std::string& filename) const;
|
||||
|
||||
private:
|
||||
size_t next_file_descriptor_ = 0;
|
||||
std::unordered_map<std::string, std::unique_ptr<FakeFile>> files_;
|
||||
};
|
||||
|
||||
FakeFilesystem& GetEmptyFilesystem();
|
||||
|
||||
} // namespace cpu_features
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
32
test/hwcaps_for_testing.cc
Normal file
32
test/hwcaps_for_testing.cc
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 "hwcaps_for_testing.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
namespace {
|
||||
static auto* const g_hardware_capabilities = new HardwareCapabilities();
|
||||
} // namespace
|
||||
|
||||
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) {
|
||||
g_hardware_capabilities->hwcaps = hwcaps;
|
||||
g_hardware_capabilities->hwcaps2 = hwcaps2;
|
||||
}
|
||||
|
||||
HardwareCapabilities GetHardwareCapabilities(void) {
|
||||
return *g_hardware_capabilities;
|
||||
}
|
||||
|
||||
} // namespace cpu_features
|
26
test/hwcaps_for_testing.h
Normal file
26
test/hwcaps_for_testing.h
Normal file
@ -0,0 +1,26 @@
|
||||
// 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 THIRD_PARTY_CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||
#define THIRD_PARTY_CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||
|
||||
#include "internal/hwcaps.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2);
|
||||
|
||||
} // namespace cpu_features
|
||||
|
||||
#endif // THIRD_PARTY_CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
90
test/linux_features_aggregator_test.cc
Normal file
90
test/linux_features_aggregator_test.cc
Normal file
@ -0,0 +1,90 @@
|
||||
// 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 <array>
|
||||
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Features {
|
||||
bool a = false;
|
||||
bool b = false;
|
||||
bool c = false;
|
||||
};
|
||||
|
||||
DECLARE_SETTER(Features, a)
|
||||
DECLARE_SETTER(Features, b)
|
||||
DECLARE_SETTER(Features, c)
|
||||
|
||||
class LinuxFeatureAggregatorTest : public testing::Test {
|
||||
public:
|
||||
const std::array<CapabilityConfig, 3> kConfigs = {
|
||||
{{{0b0001, 0b0000}, "a", &set_a},
|
||||
{{0b0010, 0b0000}, "b", &set_b},
|
||||
{{0b0000, 0b1100}, "c", &set_c}}};
|
||||
};
|
||||
|
||||
TEST_F(LinuxFeatureAggregatorTest, FromFlagsEmpty) {
|
||||
Features features;
|
||||
SetFromFlags(kConfigs.size(), kConfigs.data(), str(""), &features);
|
||||
EXPECT_FALSE(features.a);
|
||||
EXPECT_FALSE(features.b);
|
||||
EXPECT_FALSE(features.c);
|
||||
}
|
||||
|
||||
TEST_F(LinuxFeatureAggregatorTest, FromFlagsAllSet) {
|
||||
Features features;
|
||||
SetFromFlags(kConfigs.size(), kConfigs.data(), str("a c b"), &features);
|
||||
EXPECT_TRUE(features.a);
|
||||
EXPECT_TRUE(features.b);
|
||||
EXPECT_TRUE(features.c);
|
||||
}
|
||||
|
||||
TEST_F(LinuxFeatureAggregatorTest, FromFlagsOnlyA) {
|
||||
Features features;
|
||||
SetFromFlags(kConfigs.size(), kConfigs.data(), str("a"), &features);
|
||||
EXPECT_TRUE(features.a);
|
||||
EXPECT_FALSE(features.b);
|
||||
EXPECT_FALSE(features.c);
|
||||
}
|
||||
|
||||
TEST_F(LinuxFeatureAggregatorTest, FromHwcapsNone) {
|
||||
HardwareCapabilities capability;
|
||||
capability.hwcaps = 0; // matches none
|
||||
capability.hwcaps2 = 0; // matches none
|
||||
Features features;
|
||||
OverrideFromHwCaps(kConfigs.size(), kConfigs.data(), capability, &features);
|
||||
EXPECT_FALSE(features.a);
|
||||
EXPECT_FALSE(features.b);
|
||||
EXPECT_FALSE(features.c);
|
||||
}
|
||||
|
||||
TEST_F(LinuxFeatureAggregatorTest, FromHwcapsSet) {
|
||||
HardwareCapabilities capability;
|
||||
capability.hwcaps = 0b0010; // matches b but not a
|
||||
capability.hwcaps2 = 0b1111; // matches c
|
||||
Features features;
|
||||
OverrideFromHwCaps(kConfigs.size(), kConfigs.data(), capability, &features);
|
||||
EXPECT_FALSE(features.a);
|
||||
EXPECT_TRUE(features.b);
|
||||
EXPECT_TRUE(features.c);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
132
test/stack_line_reader_test.cc
Normal file
132
test/stack_line_reader_test.cc
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 "filesystem_for_testing.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
bool operator==(const StringView& a, const StringView& b) {
|
||||
return IsEquals(a, b);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ToString(StringView view) { return {view.ptr, view.size}; }
|
||||
|
||||
TEST(StackLineReaderTest, Empty) {
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
auto* file = fs.CreateFile("/proc/cpuinfo", "");
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_TRUE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str(""));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StackLineReaderTest, ManySmallLines) {
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
auto* file = fs.CreateFile("/proc/cpuinfo", "a\nb\nc");
|
||||
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("a"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("b"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_TRUE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("c"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StackLineReaderTest, TruncatedLine) {
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
auto* file = fs.CreateFile("/proc/cpuinfo", R"(First
|
||||
Second
|
||||
More than 16 characters, this will be truncated.
|
||||
last)");
|
||||
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("First"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("Second"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_FALSE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("More than 16 cha"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_TRUE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("last"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StackLineReaderTest, TruncatedLines) {
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
auto* file = fs.CreateFile("/proc/cpuinfo", R"(More than 16 characters
|
||||
Another line that is too long)");
|
||||
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_FALSE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("More than 16 cha"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_FALSE(result.eof);
|
||||
EXPECT_FALSE(result.full_line);
|
||||
EXPECT_EQ(result.line, str("Another line tha"));
|
||||
}
|
||||
{
|
||||
const auto result = StackLineReader_NextLine(&reader);
|
||||
EXPECT_TRUE(result.eof);
|
||||
EXPECT_TRUE(result.full_line);
|
||||
EXPECT_EQ(result.line, str(""));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
138
test/string_view_test.cc
Normal file
138
test/string_view_test.cc
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 "gtest/gtest.h"
|
||||
|
||||
namespace cpu_features {
|
||||
|
||||
bool operator==(const StringView& a, const StringView& b) {
|
||||
return IsEquals(a, b);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(StringViewTest, Empty) {
|
||||
EXPECT_EQ(kEmptyStringView.ptr, nullptr);
|
||||
EXPECT_EQ(kEmptyStringView.size, 0);
|
||||
}
|
||||
|
||||
TEST(StringViewTest, Build) {
|
||||
const auto view = str("test");
|
||||
EXPECT_EQ(view.ptr[0], 't');
|
||||
EXPECT_EQ(view.size, 4);
|
||||
}
|
||||
|
||||
TEST(StringViewTest, IndexOfChar) {
|
||||
// Found.
|
||||
EXPECT_EQ(IndexOfChar(str("test"), 'e'), 1);
|
||||
// Not found.
|
||||
EXPECT_EQ(IndexOfChar(str("test"), 'z'), -1);
|
||||
// Empty.
|
||||
EXPECT_EQ(IndexOfChar(kEmptyStringView, 'z'), -1);
|
||||
}
|
||||
|
||||
TEST(StringViewTest, IndexOf) {
|
||||
// Found.
|
||||
EXPECT_EQ(IndexOf(str("test"), str("es")), 1);
|
||||
// Not found.
|
||||
EXPECT_EQ(IndexOf(str("test"), str("aa")), -1);
|
||||
// Empty.
|
||||
EXPECT_EQ(IndexOf(kEmptyStringView, str("aa")), -1);
|
||||
EXPECT_EQ(IndexOf(str("aa"), kEmptyStringView), -1);
|
||||
}
|
||||
|
||||
TEST(StringViewTest, StartsWith) {
|
||||
EXPECT_TRUE(StartsWith(str("test"), str("te")));
|
||||
EXPECT_FALSE(StartsWith(str("test"), str("")));
|
||||
EXPECT_FALSE(StartsWith(str("test"), kEmptyStringView));
|
||||
EXPECT_FALSE(StartsWith(kEmptyStringView, str("test")));
|
||||
}
|
||||
|
||||
TEST(StringViewTest, IsEquals) {
|
||||
EXPECT_TRUE(IsEquals(kEmptyStringView, kEmptyStringView));
|
||||
EXPECT_TRUE(IsEquals(kEmptyStringView, str("")));
|
||||
EXPECT_TRUE(IsEquals(str(""), kEmptyStringView));
|
||||
EXPECT_TRUE(IsEquals(str("a"), str("a")));
|
||||
EXPECT_FALSE(IsEquals(str("a"), str("b")));
|
||||
EXPECT_FALSE(IsEquals(str("a"), kEmptyStringView));
|
||||
EXPECT_FALSE(IsEquals(kEmptyStringView, str("a")));
|
||||
}
|
||||
|
||||
TEST(StringViewTest, PopFront) {
|
||||
EXPECT_EQ(PopFront(str("test"), 2), str("st"));
|
||||
EXPECT_EQ(PopFront(str("test"), 0), str("test"));
|
||||
EXPECT_EQ(PopFront(str("test"), 4), str(""));
|
||||
EXPECT_EQ(PopFront(str("test"), 100), str(""));
|
||||
}
|
||||
|
||||
TEST(StringViewTest, ParsePositiveNumber) {
|
||||
EXPECT_EQ(ParsePositiveNumber(str("42")), 42);
|
||||
EXPECT_EQ(ParsePositiveNumber(str("0x2a")), 42);
|
||||
EXPECT_EQ(ParsePositiveNumber(str("0x2A")), 42);
|
||||
|
||||
EXPECT_EQ(ParsePositiveNumber(str("-0x2A")), -1);
|
||||
EXPECT_EQ(ParsePositiveNumber(str("abc")), -1);
|
||||
EXPECT_EQ(ParsePositiveNumber(str("")), -1);
|
||||
}
|
||||
|
||||
TEST(StringViewTest, CopyString) {
|
||||
char buf[4];
|
||||
buf[0] = 'X';
|
||||
|
||||
// Empty
|
||||
CopyString(str(""), buf, sizeof(buf));
|
||||
EXPECT_STREQ(buf, "");
|
||||
|
||||
// Less
|
||||
CopyString(str("a"), buf, sizeof(buf));
|
||||
EXPECT_STREQ(buf, "a");
|
||||
|
||||
// exact
|
||||
CopyString(str("abc"), buf, sizeof(buf));
|
||||
EXPECT_STREQ(buf, "abc");
|
||||
|
||||
// More
|
||||
CopyString(str("abcd"), buf, sizeof(buf));
|
||||
EXPECT_STREQ(buf, "abc");
|
||||
}
|
||||
|
||||
TEST(StringViewTest, HasWord) {
|
||||
// Find flags at beginning, middle and end.
|
||||
EXPECT_TRUE(HasWord(str("first middle last"), "first"));
|
||||
EXPECT_TRUE(HasWord(str("first middle last"), "middle"));
|
||||
EXPECT_TRUE(HasWord(str("first middle last"), "last"));
|
||||
// Do not match partial flags
|
||||
EXPECT_FALSE(HasWord(str("first middle last"), "irst"));
|
||||
EXPECT_FALSE(HasWord(str("first middle last"), "mid"));
|
||||
EXPECT_FALSE(HasWord(str("first middle last"), "las"));
|
||||
}
|
||||
|
||||
TEST(StringViewTest, GetAttributeKeyValue) {
|
||||
const StringView line = str(" key : first middle last ");
|
||||
StringView key, value;
|
||||
EXPECT_TRUE(GetAttributeKeyValue(line, &key, &value));
|
||||
EXPECT_EQ(key, str("key"));
|
||||
EXPECT_EQ(value, str("first middle last"));
|
||||
}
|
||||
|
||||
TEST(StringViewTest, FailingGetAttributeKeyValue) {
|
||||
const StringView line = str("key first middle last");
|
||||
StringView key, value;
|
||||
EXPECT_FALSE(GetAttributeKeyValue(line, &key, &value));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpu_features
|
Loading…
x
Reference in New Issue
Block a user