Skip to content

Commit

Permalink
Merge pull request #11 from psteinb/cmake-detect-feature
Browse files Browse the repository at this point in the history
Cmake detect feature
  • Loading branch information
Peter Steinbach authored Apr 30, 2018
2 parents 43b10f6 + 3be9d77 commit be79a83
Show file tree
Hide file tree
Showing 12 changed files with 1,131 additions and 6 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
*~
build
build/*
debug/*
*sln
*.vcxproj*
x64
x32
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ matrix:
- os: osx
osx_image: xcode9
env:
- MATRIX_EVAL="CC=clang && CXX=clang"
- MATRIX_EVAL="CC=clang && CXX=clang++"

before_install:
- eval "${MATRIX_EVAL}"

script:
- mkdir -p build && cd build
- cmake ..
- cat tests/build_machine.hpp
- make VERBOSE=1
- ctest -V -j
- cd ..
1 change: 1 addition & 0 deletions CTestLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ endif()

add_test(NAME compass_impl COMMAND test_compass_impl)
add_test(NAME bitview COMMAND test_bitview)
add_test(NAME build_machine COMMAND test_build_machine)
1 change: 1 addition & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ install: []

build_script:
- IF "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" ( SET GEN="Visual Studio 14 2015") ELSE (SET GEN="Visual Studio 15 2017")
- wmic.exe cpu get
- cmake . -G%GEN% # -DCMAKE_CXX_FLAGS="%additional_flags%"
- cmake --build . --config Release

Expand Down
337 changes: 337 additions & 0 deletions cmake/FindCPU_FEATURES.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
##extract a single line that contains the given pattern (starting from that patter)
function(extract_line LINESTART_PATTERN MULTILINE_STRING OUTPUT_VARIABLE)

STRING(FIND ${MULTILINE_STRING} "${PATTERN}" MATCH_OFFSET)
STRING(SUBSTRING ${MATCH_OFFSET} 0 ${MATCH_OFFSET} MULTILINE_NO_START)
STRING(FIND ${MULTILINE_NO_START} "\n" MULTILINE_RETURN_OFFSET)
STRING(SUBSTRING ${MULTILINE_NO_START} 0 ${MULTILINE_RETURN_OFFSET} MATCHING_LINE)
set(OUTPUT_VARIABLE ${MATCHING_LINE} PARENT_SCOPE)

endfunction(extract_line)

##extract system information from wmic.exe on Windows
function(wmic_get ATTRIBUTENAME RESULTVALUE)
EXEC_PROGRAM("wmic.exe" ARGS "cpu get ${ATTRIBUTENAME}" OUTPUT_VARIABLE WMIC_OUTPUT)
string(REGEX REPLACE " [ ]+" ";" WMIC_OUTPUT_CLEANED ${WMIC_OUTPUT})
set(WMIC_OUTPUT_LIST "${WMIC_OUTPUT_CLEANED};")
list(GET WMIC_OUTPUT_LIST 1 VALUEOFINTEREST)

string(STRIP "${VALUEOFINTEREST}" VALUEOFINTEREST)
set(${RESULTVALUE} ${VALUEOFINTEREST} PARENT_SCOPE)
#message(STATUS "[wmic_get] RESULT = ${VALUEOFINTEREST}")

endfunction(wmic_get)

IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO)

##FIND VENDOR
STRING(FIND ${CPUINFO} "vendor" VENDOR_TITLE_OFFSET)
STRING(SUBSTRING ${CPUINFO} ${VENDOR_TITLE_OFFSET} 50 GUESSED_VENDOR_LINE)
STRING(REGEX REPLACE "^vendor.*: ([a-zA-Z]+)\n.*" "\\1" VENDOR_TITLE ${GUESSED_VENDOR_LINE})
message(STATUS "vendor found: ${VENDOR_TITLE}")
set(CPU_VENDOR "${VENDOR_TITLE}" CACHE STRING "cpu vendor")

##FIND MODEL NAME
STRING(FIND ${CPUINFO} "model name" MODEL_NAME_OFFSET)
STRING(SUBSTRING ${CPUINFO} ${MODEL_NAME_OFFSET} 100 GUESSED_MODEL_NAME_LINE)
STRING(FIND ${GUESSED_MODEL_NAME_LINE} "\n" MODEL_NAME_RETURN_OFFSET)
STRING(SUBSTRING ${GUESSED_MODEL_NAME_LINE} 0 ${MODEL_NAME_RETURN_OFFSET} GUESSED_MODEL_NAME_LINE)

STRING(REGEX REPLACE "^model name.*: ([a-zA-Z]+.*)$" "\\1" MODEL_NAME ${GUESSED_MODEL_NAME_LINE})
message(STATUS "model name found: ${MODEL_NAME}")
set(CPU_MODEL_NAME "${MODEL_NAME}" CACHE STRING "cpu model name")

##FIND INSTRUCTIONS
STRING(REGEX REPLACE "^.*(sse) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "sse" "${SSE_THERE}" SSE_TRUE)
IF (SSE_TRUE)
set(SSE_FOUND true CACHE BOOL "SSE available on host")
ELSE (SSE_TRUE)
set(SSE_FOUND false CACHE BOOL "SSE available on host")
ENDIF (SSE_TRUE)

STRING(REGEX REPLACE "^.*(sse2) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "sse2" "${SSE_THERE}" SSE2_TRUE)
IF (SSE2_TRUE)
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
ELSE (SSE2_TRUE)
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
ENDIF (SSE2_TRUE)

# /proc/cpuinfo apparently omits sse3 :(
STRING(REGEX REPLACE "^.*[^s](sse3) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "sse3" "${SSE_THERE}" SSE3_TRUE)
IF (NOT SSE3_TRUE)
STRING(REGEX REPLACE "^.*(T2300).*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "T2300" "${SSE_THERE}" SSE3_TRUE)
ENDIF (NOT SSE3_TRUE)

STRING(REGEX REPLACE "^.* (ssse3) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "ssse3" "${SSE_THERE}" SSSE3_TRUE)
IF (SSE3_TRUE OR SSSE3_TRUE)
set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
ELSE (SSE3_TRUE OR SSSE3_TRUE)
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
ENDIF (SSE3_TRUE OR SSSE3_TRUE)
IF (SSSE3_TRUE)
set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
ELSE (SSSE3_TRUE)
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
ENDIF (SSSE3_TRUE)

STRING(REGEX REPLACE "^.* (sse4_1) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "sse4_1" "${SSE_THERE}" SSE41_TRUE)
IF (SSE41_TRUE)
set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
ELSE (SSE41_TRUE)
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
ENDIF (SSE41_TRUE)

STRING(REGEX REPLACE "^.* (sse4_2) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE)
IF (SSE42_TRUE)
set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host")
ELSE (SSE42_TRUE)
set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
ENDIF (SSE42_TRUE)

if("${CPUINFO}" MATCHES ".*avx .*")
set(AVX_FOUND true CACHE BOOL "AVX available on host")
else()
set(AVX_FOUND false CACHE BOOL "AVX available on host")
endif()

if("${CPUINFO}" MATCHES ".*avx2 .*")
set(AVX2_FOUND true CACHE BOOL "AVX2 available on host")
else()
set(AVX2_FOUND false CACHE BOOL "AVX2 available on host")
endif()

#
if(EXISTS "/sys/devices/system/cpu/cpu0/cache/index2/size")
EXEC_PROGRAM(cat ARGS "/sys/devices/system/cpu/cpu0/cache/index2/size" OUTPUT_VARIABLE L2_SIZE_KB_STRING)

if(${L2_SIZE_KB_STRING} MATCHES ".*[K|k]")
string(REGEX REPLACE "[K|k]" "" L2_SIZE_KB ${L2_SIZE_KB_STRING})
set(CPU_L2_SIZE_KB "${L2_SIZE_KB}" CACHE STRING "cpu L2 cache size in kB")
else()
if(${L2_SIZE_KB_STRING} MATCHES ".*[M|m]")
string(REGEX REPLACE "[M|m]" "000" L2_SIZE_KB ${L2_SIZE_KB_STRING})
set(CPU_L2_SIZE_KB "${L2_SIZE_KB}" CACHE STRING "cpu L2 cache size in kB")
else()
message(WARNING "unable to find unit prefix (K|M) in /sys/devices/system/cpu/cpu0/cache/index2/size:${L2_SIZE_KB_STRING} (assuming it's contents as expressed in kB, crossing fingers)")
set(CPU_L2_SIZE_KB "${L2_SIZE_KB_STRING}" CACHE STRING "cpu L2 cache size in kB")
endif()

endif()

else()
message("unable to find /sys/devices/system/cpu/cpu0/cache/index2/size")
set(CPU_L2_SIZE_KB "0" CACHE STRING "cpu L2 cache size in kB")
endif()


ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE
CPUINFO)

EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.leaf7_features" OUTPUT_VARIABLE
LEAF7_CPUINFO)

EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.vendor" OUTPUT_VARIABLE
VENDOR_TITLE)

EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.brand_string" OUTPUT_VARIABLE
MODEL_NAME)

EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.cache.size" OUTPUT_VARIABLE
CPU_L2_SIZE_KB)

set(CPU_VENDOR "${VENDOR_TITLE}" CACHE STRING "cpu vendor")
set(CPU_MODEL_NAME "${MODEL_NAME}" CACHE STRING "cpu model name")

STRING(REGEX REPLACE "^.*[^S](SSE) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSE" "${SSE_THERE}" SSE_TRUE)
IF (SSE_TRUE)
set(SSE_FOUND true CACHE BOOL "SSE2 available on host")
ELSE (SSE_TRUE)
set(SSE_FOUND false CACHE BOOL "SSE2 available on host")
ENDIF (SSE_TRUE)

STRING(REGEX REPLACE "^.*[^S](SSE2) .*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSE2" "${SSE_THERE}" SSE2_TRUE)
IF (SSE2_TRUE)
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
ELSE (SSE2_TRUE)
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
ENDIF (SSE2_TRUE)

STRING(REGEX REPLACE "^.*[^S](SSE2).*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSE2" "${SSE_THERE}" SSE2_TRUE)
IF (SSE2_TRUE)
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
ELSE (SSE2_TRUE)
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
ENDIF (SSE2_TRUE)

STRING(REGEX REPLACE "^.*[^S](SSE3).*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSE3" "${SSE_THERE}" SSE3_TRUE)
IF (SSE3_TRUE)
set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
ELSE (SSE3_TRUE)
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
ENDIF (SSE3_TRUE)

STRING(REGEX REPLACE "^.*(SSSE3).*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSSE3" "${SSE_THERE}" SSSE3_TRUE)
IF (SSSE3_TRUE)
set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
ELSE (SSSE3_TRUE)
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
ENDIF (SSSE3_TRUE)

STRING(REGEX REPLACE "^.*(SSE4.1).*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSE4.1" "${SSE_THERE}" SSE41_TRUE)
IF (SSE41_TRUE)
set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
ELSE (SSE41_TRUE)
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
ENDIF (SSE41_TRUE)

STRING(REGEX REPLACE "^.*(SSE4.2).*$" "\\1" SSE_THERE ${CPUINFO})
STRING(COMPARE EQUAL "SSE4.2" "${SSE_THERE}" SSE42_TRUE)
IF (SSE42_TRUE)
set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host")
ELSE (SSE42_TRUE)
set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
ENDIF (SSE42_TRUE)

if("${CPUINFO}" MATCHES ".*AVX.*")
set(AVX_FOUND true CACHE BOOL "AVX available on host")
else()
set(AVX_FOUND false CACHE BOOL "AVX available on host")
endif()

if("${CPUINFO}" MATCHES ".*AVX2 .*")
set(AVX2_FOUND true CACHE BOOL "AVX2 available on host")
else()
if("${LEAF7_CPUINFO}" MATCHES ".*AVX2 .*")
set(AVX2_FOUND true CACHE BOOL "AVX2 available on host")
else()
set(AVX2_FOUND false CACHE BOOL "AVX2 available on host")
endif()
endif()

ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Windows")

#as an alternative to wmic, use
#get_filename_component(_vendor_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;VendorIdentifier]" NAME CACHE)
#get_filename_component(_cpu_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;Identifier]" NAME CACHE)

wmic_get("Name" MODEL_NAME)
string(STRIP ${MODEL_NAME} MODEL_NAME)
set(CPU_MODEL_NAME "${MODEL_NAME}" CACHE STRING "cpu model name")

wmic_get("Manufacturer" MODEL_VENDOR)
set(CPU_VENDOR "${MODEL_VENDOR}" CACHE STRING "cpu model vendor")

wmic_get("L2CacheSize" L2_CACHE_SIZE)
wmic_get("NumberOfCores" CPU_NPHYS_CORES)

#dirty hack that I need to validate with other machines in Win7
if(NOT "${L2_CACHE_SIZE}" STREQUAL "")
if(${CPU_NPHYS_CORES} GREATER 1)
math(EXPR L2_CACHE_SIZE "${L2_CACHE_SIZE}/${CPU_NPHYS_CORES}")
endif()
set(CPU_L2_SIZE_KB "${L2_CACHE_SIZE}" CACHE STRING "cpu L2 cache size in kB")
else()
message("unable to decipher L2 cache size")
endif()
set(CPU_L2_SIZE_KB "0" CACHE STRING "cpu L2 cache size in kB")
set(CPU_VENDOR "" CACHE STRING "cpu model vendor")
set(CPU_MODEL_NAME "" CACHE STRING "cpu model name")

#thanks to the wonderful VC project (https://github.com/VcDevel/Vc)
include (OptimizeForArchitecture)

OFA_AutodetectHostArchitecture()
OFA_HandleX86Options()


list(FIND _available_vector_units_list "sse" SSE_INDEX)
list(FIND _available_vector_units_list "sse2" SSE2_INDEX)
list(FIND _available_vector_units_list "sse3" SSE3_INDEX)
list(FIND _available_vector_units_list "ssse3" SSSE3_INDEX)
list(FIND _available_vector_units_list "sse4.1" SSE4_1_INDEX)
list(FIND _available_vector_units_list "sse4.2" SSE4_2_INDEX)
list(FIND _available_vector_units_list "avx" AVX_INDEX)
list(FIND _available_vector_units_list "avx2" AVX2_INDEX)

if(${SSE_INDEX} GREATER -1)
set(SSE_FOUND true CACHE BOOL "SSE available on host")
endif()
if(${SSE2_INDEX} GREATER -1)
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
endif()
if(${SSE3_INDEX} GREATER -1)
set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
endif()
if(${SSSE3_INDEX} GREATER -1)
set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
endif()
if(${SSE4_1_INDEX} GREATER -1)
set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
endif()
if(${SSE4_2_INDEX} GREATER -1)
set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host")
endif()
if(${AVX_INDEX} GREATER -1)
set(AVX_FOUND true CACHE BOOL "AVX available on host")
endif()
if(${AVX2_INDEX} GREATER -1)
set(AVX2_FOUND true CACHE BOOL "AVX2 available on host")
endif()

set(SSE_FOUND true CACHE BOOL "SSE available on host")
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
set(AVX_FOUND false CACHE BOOL "AVX available on host")
set(AVX2_FOUND false CACHE BOOL "AVX2 available on host")

ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux")

message(STATUS "found hardware: ${CPU_VENDOR} ${CPU_MODEL_NAME}")
set(FOUND_FEATURES)

if(SSE_FOUND)
list(APPEND FOUND_FEATURES "sse")
endif(SSE_FOUND)
if(SSE2_FOUND)
list(APPEND FOUND_FEATURES "sse2")
endif(SSE2_FOUND)
if( SSE3_FOUND)
list(APPEND FOUND_FEATURES "sse3")
endif( SSE3_FOUND)
if( SSSE3_FOUND)
list(APPEND FOUND_FEATURES "ssse3")
endif( SSSE3_FOUND)
if( SSE4_1_FOUND)
list(APPEND FOUND_FEATURES "sse4.1")
endif( SSE4_1_FOUND)
if( SSE4_2_FOUND)
list(APPEND FOUND_FEATURES "sse4.2")
endif( SSE4_2_FOUND)
if( AVX_FOUND)
list(APPEND FOUND_FEATURES "avx")
endif( AVX_FOUND)
if( AVX2_FOUND)
list(APPEND FOUND_FEATURES "avx2")
endif( AVX2_FOUND)

message(STATUS "found hardware features: ${FOUND_FEATURES}")

mark_as_advanced(SSE_FOUND SSE2_FOUND SSE3_FOUND SSSE3_FOUND SSE4_1_FOUND SSE4_2_FOUND AVX_FOUND AVX2_FOUND CPU_VENDOR CPU_MODEL_NAME CPU_L2_SIZE_KB)
Loading

0 comments on commit be79a83

Please sign in to comment.