mirror of
				https://github.com/google/cpu_features.git
				synced 2025-10-31 13:10:48 +01:00 
			
		
		
		
	Adding code. Closes #0.
This commit is contained in:
		
							
								
								
									
										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 | ||||
		Reference in New Issue
	
	Block a user
	 Guillaume Chatelet
					Guillaume Chatelet