From a8b0ef024220de5a9aa01b39dd7284619196ba26 Mon Sep 17 00:00:00 2001 From: Tinyfish Date: Tue, 20 Aug 2024 11:23:06 +0800 Subject: [PATCH 1/5] Upgrade to Visual Studio 2022. --- FeatureDetector/FeatureDetector.vcxproj | 186 ++++++++++++------------ 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/FeatureDetector/FeatureDetector.vcxproj b/FeatureDetector/FeatureDetector.vcxproj index 5837340..c684926 100644 --- a/FeatureDetector/FeatureDetector.vcxproj +++ b/FeatureDetector/FeatureDetector.vcxproj @@ -1,94 +1,94 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - {5AF4062D-386F-48AA-B824-2C10A4B1BA97} - Win32Proj - FeatureDetector - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - true - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + {5AF4062D-386F-48AA-B824-2C10A4B1BA97} + Win32Proj + FeatureDetector + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + \ No newline at end of file From 482461fea2920586dcfee4ab9064609e78f34fcd Mon Sep 17 00:00:00 2001 From: Tinyfish Date: Tue, 20 Aug 2024 15:39:57 +0800 Subject: [PATCH 2/5] Remove unnecessary file. --- FeatureDetector/FeatureDetector.vcxproj.user | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 FeatureDetector/FeatureDetector.vcxproj.user diff --git a/FeatureDetector/FeatureDetector.vcxproj.user b/FeatureDetector/FeatureDetector.vcxproj.user deleted file mode 100644 index ef5ff2a..0000000 --- a/FeatureDetector/FeatureDetector.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From 71d47707fac5cf48d9b9d22384834d37c0fd74d8 Mon Sep 17 00:00:00 2001 From: Tinyfish Date: Tue, 20 Aug 2024 15:41:01 +0800 Subject: [PATCH 3/5] Add command line argument to test feature by script. --- src/Main.cpp | 147 ++++++++++++++++++++++++++++++++++++-------- src/x86/cpu_x86.cpp | 135 ++++++++++++++++++++-------------------- 2 files changed, 189 insertions(+), 93 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index d12d752..aee94bc 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,26 +1,121 @@ -/* Main.cpp - * - * Author : Alexander J. Yee - * Date Created : 04/17/2015 - * Last Modified : 04/17/2015 - * - */ - -#include -using std::cout; -using std::endl; - -#include "x86/cpu_x86.h" -using namespace FeatureDetector; - -int main(){ - - cout << "CPU Vendor String: " << cpu_x86::get_vendor_string() << endl; - cout << endl; - - cpu_x86::print_host(); - -#if _WIN32 - system("pause"); -#endif -} +/* Main.cpp + * + * Author : Alexander J. Yee + * Date Created : 04/17/2015 + * Last Modified : 04/17/2015 + * + */ + +#include +using std::cout; +using std::endl; + +#include "x86/cpu_x86.h" +using namespace FeatureDetector; + +bool case_insensitive_char_compare(char a, char b) { + return std::tolower(a) == std::tolower(b); +} + +bool case_insensitive_compare(const std::string& s1, const std::string& s2) { + return s1.size() == s2.size() && std::equal(s1.begin(), s1.end(), s2.begin(), case_insensitive_char_compare); +} + +int main(int argc, char* argv[]) { + cpu_x86 features; + features.detect_host(); + + if (argc == 1) + { + cout << "CPU Vendor String: " << cpu_x86::get_vendor_string() << endl; + cout << endl; + + features.print(); +#if _WIN32 + system("pause"); +#endif + } + + struct feature { + const char* name; + bool cpu_x86::* feature; + }; + + static feature featureList[] = { + {"AMD", &cpu_x86::Vendor_AMD}, + {"Intel", &cpu_x86::Vendor_Intel}, + + {"OS AVX", &cpu_x86::OS_AVX}, + {"OS AVX512", &cpu_x86::OS_AVX512}, + + {"MMX", &cpu_x86::HW_MMX}, + {"x64", &cpu_x86::HW_x64}, + {"ABM", &cpu_x86::HW_ABM}, + {"RDRAND", &cpu_x86::HW_RDRAND}, + {"RDSEED", &cpu_x86::HW_RDSEED}, + {"BMI1", &cpu_x86::HW_BMI1}, + {"BMI2", &cpu_x86::HW_BMI2}, + {"ADX", &cpu_x86::HW_ADX}, + {"MPX", &cpu_x86::HW_MPX}, + {"PREFETCHW", &cpu_x86::HW_PREFETCHW}, + {"PREFETCHWT1", &cpu_x86::HW_PREFETCHWT1}, + {"RDPID", &cpu_x86::HW_RDPID}, + {"GFNI", &cpu_x86::HW_GFNI}, + {"VAES", &cpu_x86::HW_VAES}, + + {"SSE", &cpu_x86::HW_SSE}, + {"SSE2", &cpu_x86::HW_SSE2}, + {"SSE3", &cpu_x86::HW_SSE3}, + {"SSSE3", &cpu_x86::HW_SSSE3}, + {"SSE4a", &cpu_x86::HW_SSE4a}, + {"SSE4.1", &cpu_x86::HW_SSE41}, + {"SSE4.2", &cpu_x86::HW_SSE42}, + {"AES-NI", &cpu_x86::HW_AES}, + {"SHA", &cpu_x86::HW_SHA}, + + {"AVX", &cpu_x86::HW_AVX}, + {"XOP", &cpu_x86::HW_XOP}, + {"FMA3", &cpu_x86::HW_FMA3}, + {"FMA4", &cpu_x86::HW_FMA4}, + {"AVX2", &cpu_x86::HW_AVX2}, + + {"AVX512-F", &cpu_x86::HW_AVX512_F}, + {"AVX512-CD", &cpu_x86::HW_AVX512_CD}, + {"AVX512-PF", &cpu_x86::HW_AVX512_PF}, + {"AVX512-ER", &cpu_x86::HW_AVX512_ER}, + {"AVX512-VL", &cpu_x86::HW_AVX512_VL}, + {"AVX512-BW", &cpu_x86::HW_AVX512_BW}, + {"AVX512-DQ", &cpu_x86::HW_AVX512_DQ}, + {"AVX512-IFMA", &cpu_x86::HW_AVX512_IFMA}, + {"AVX512-VBMI", &cpu_x86::HW_AVX512_VBMI}, + {"AVX512-VPOPCNTDQ", &cpu_x86::HW_AVX512_VPOPCNTDQ}, + {"AVX512-4VNNIW", &cpu_x86::HW_AVX512_4VNNIW}, + {"AVX512-4FMAPS", &cpu_x86::HW_AVX512_4FMAPS}, + {"AVX512-VBMI2", &cpu_x86::HW_AVX512_VBMI2}, + {"AVX512-VPCLMUL", &cpu_x86::HW_AVX512_VPCLMUL}, + {"AVX512-VNNI", &cpu_x86::HW_AVX512_VNNI}, + {"AVX512-BITALG", &cpu_x86::HW_AVX512_BITALG}, + {"AVX512-BF16", &cpu_x86::HW_AVX512_BF16}, + }; + + auto result = true; + + for (auto argIndex = 1; argIndex < argc; argIndex++) + { + for (const auto& feature : featureList) + { + if (!case_insensitive_compare(argv[argIndex], feature.name)) + continue; + + auto supported = features.*(feature.feature); + if (!supported) + result = false; + + cout << feature.name << " = " << (supported ? "Yes" : "No") << endl; + } + } + + cout << "Final = " << (result ? "Yes" : "No") << endl; + + return result ? 0 : 1; +} diff --git a/src/x86/cpu_x86.cpp b/src/x86/cpu_x86.cpp index 9475f6b..e060ca7 100644 --- a/src/x86/cpu_x86.cpp +++ b/src/x86/cpu_x86.cpp @@ -1,16 +1,16 @@ /* cpu_x86.cpp - * + * * Author : Alexander J. Yee * Date Created : 04/12/2014 * Last Modified : 04/12/2014 - * + * */ -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -// Dependencies + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // Dependencies #include #include #include "cpu_x86.h" @@ -30,16 +30,16 @@ # error "No cpuid intrinsic defined for processor architecture." #endif -namespace FeatureDetector{ - using std::cout; - using std::endl; - using std::memcpy; - using std::memset; +namespace FeatureDetector { +using std::cout; +using std::endl; +using std::memcpy; +using std::memset; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -void cpu_x86::print(const char* label, bool yes){ +void cpu_x86::print(const char* label, bool yes) { cout << label; cout << (yes ? "Yes" : "No") << endl; } @@ -47,10 +47,10 @@ void cpu_x86::print(const char* label, bool yes){ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -cpu_x86::cpu_x86(){ +cpu_x86::cpu_x86() { memset(this, 0, sizeof(*this)); } -bool cpu_x86::detect_OS_AVX(){ +bool cpu_x86::detect_OS_AVX() { // Copied from: http://stackoverflow.com/a/22521619/922184 bool avxSupported = false; @@ -69,14 +69,14 @@ bool cpu_x86::detect_OS_AVX(){ return avxSupported; } -bool cpu_x86::detect_OS_AVX512(){ +bool cpu_x86::detect_OS_AVX512() { if (!detect_OS_AVX()) return false; uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK); return (xcrFeatureMask & 0xe6) == 0xe6; } -std::string cpu_x86::get_vendor_string(){ +std::string cpu_x86::get_vendor_string() { int32_t CPUInfo[4]; char name[13]; @@ -92,7 +92,7 @@ std::string cpu_x86::get_vendor_string(){ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -void cpu_x86::detect_host(){ +void cpu_x86::detect_host() { // OS Features OS_x64 = detect_OS_x64(); OS_AVX = detect_OS_AVX(); @@ -100,9 +100,10 @@ void cpu_x86::detect_host(){ // Vendor std::string vendor(get_vendor_string()); - if (vendor == "GenuineIntel"){ + if (vendor == "GenuineIntel") { Vendor_Intel = true; - }else if (vendor == "AuthenticAMD"){ + } + else if (vendor == "AuthenticAMD") { Vendor_AMD = true; } @@ -114,75 +115,75 @@ void cpu_x86::detect_host(){ uint32_t nExIds = info[0]; // Detect Features - if (nIds >= 0x00000001){ + if (nIds >= 0x00000001) { cpuid(info, 0x00000001, 0); - HW_MMX = (info[3] & ((int)1 << 23)) != 0; - HW_SSE = (info[3] & ((int)1 << 25)) != 0; - HW_SSE2 = (info[3] & ((int)1 << 26)) != 0; - HW_SSE3 = (info[2] & ((int)1 << 0)) != 0; + HW_MMX = (info[3] & ((int)1 << 23)) != 0; + HW_SSE = (info[3] & ((int)1 << 25)) != 0; + HW_SSE2 = (info[3] & ((int)1 << 26)) != 0; + HW_SSE3 = (info[2] & ((int)1 << 0)) != 0; - HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0; - HW_SSE41 = (info[2] & ((int)1 << 19)) != 0; - HW_SSE42 = (info[2] & ((int)1 << 20)) != 0; - HW_AES = (info[2] & ((int)1 << 25)) != 0; + HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0; + HW_SSE41 = (info[2] & ((int)1 << 19)) != 0; + HW_SSE42 = (info[2] & ((int)1 << 20)) != 0; + HW_AES = (info[2] & ((int)1 << 25)) != 0; - HW_AVX = (info[2] & ((int)1 << 28)) != 0; - HW_FMA3 = (info[2] & ((int)1 << 12)) != 0; + HW_AVX = (info[2] & ((int)1 << 28)) != 0; + HW_FMA3 = (info[2] & ((int)1 << 12)) != 0; HW_RDRAND = (info[2] & ((int)1 << 30)) != 0; } - if (nIds >= 0x00000007){ + if (nIds >= 0x00000007) { cpuid(info, 0x00000007, 0); - HW_AVX2 = (info[1] & ((int)1 << 5)) != 0; + HW_AVX2 = (info[1] & ((int)1 << 5)) != 0; - HW_BMI1 = (info[1] & ((int)1 << 3)) != 0; - HW_BMI2 = (info[1] & ((int)1 << 8)) != 0; - HW_ADX = (info[1] & ((int)1 << 19)) != 0; - HW_MPX = (info[1] & ((int)1 << 14)) != 0; - HW_SHA = (info[1] & ((int)1 << 29)) != 0; - HW_RDSEED = (info[1] & ((int)1 << 18)) != 0; - HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0; - HW_RDPID = (info[2] & ((int)1 << 22)) != 0; + HW_BMI1 = (info[1] & ((int)1 << 3)) != 0; + HW_BMI2 = (info[1] & ((int)1 << 8)) != 0; + HW_ADX = (info[1] & ((int)1 << 19)) != 0; + HW_MPX = (info[1] & ((int)1 << 14)) != 0; + HW_SHA = (info[1] & ((int)1 << 29)) != 0; + HW_RDSEED = (info[1] & ((int)1 << 18)) != 0; + HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0; + HW_RDPID = (info[2] & ((int)1 << 22)) != 0; - HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0; - HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0; - HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0; - HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0; + HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0; + HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0; + HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0; + HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0; - HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0; - HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0; - HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0; + HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0; + HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0; + HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0; - HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0; - HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0; + HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0; + HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0; HW_AVX512_VPOPCNTDQ = (info[2] & ((int)1 << 14)) != 0; - HW_AVX512_4VNNIW = (info[3] & ((int)1 << 2)) != 0; - HW_AVX512_4FMAPS = (info[3] & ((int)1 << 3)) != 0; + HW_AVX512_4VNNIW = (info[3] & ((int)1 << 2)) != 0; + HW_AVX512_4FMAPS = (info[3] & ((int)1 << 3)) != 0; - HW_AVX512_VNNI = (info[2] & ((int)1 << 11)) != 0; + HW_AVX512_VNNI = (info[2] & ((int)1 << 11)) != 0; - HW_AVX512_VBMI2 = (info[2] & ((int)1 << 6)) != 0; - HW_GFNI = (info[2] & ((int)1 << 8)) != 0; - HW_VAES = (info[2] & ((int)1 << 9)) != 0; - HW_AVX512_VPCLMUL = (info[2] & ((int)1 << 10)) != 0; - HW_AVX512_BITALG = (info[2] & ((int)1 << 12)) != 0; + HW_AVX512_VBMI2 = (info[2] & ((int)1 << 6)) != 0; + HW_GFNI = (info[2] & ((int)1 << 8)) != 0; + HW_VAES = (info[2] & ((int)1 << 9)) != 0; + HW_AVX512_VPCLMUL = (info[2] & ((int)1 << 10)) != 0; + HW_AVX512_BITALG = (info[2] & ((int)1 << 12)) != 0; cpuid(info, 0x00000007, 1); - HW_AVX512_BF16 = (info[0] & ((int)1 << 5)) != 0; + HW_AVX512_BF16 = (info[0] & ((int)1 << 5)) != 0; } - if (nExIds >= 0x80000001){ + if (nExIds >= 0x80000001) { cpuid(info, 0x80000001, 0); - HW_x64 = (info[3] & ((int)1 << 29)) != 0; - HW_ABM = (info[2] & ((int)1 << 5)) != 0; - HW_SSE4a = (info[2] & ((int)1 << 6)) != 0; - HW_FMA4 = (info[2] & ((int)1 << 16)) != 0; - HW_XOP = (info[2] & ((int)1 << 11)) != 0; + HW_x64 = (info[3] & ((int)1 << 29)) != 0; + HW_ABM = (info[2] & ((int)1 << 5)) != 0; + HW_SSE4a = (info[2] & ((int)1 << 6)) != 0; + HW_FMA4 = (info[2] & ((int)1 << 16)) != 0; + HW_XOP = (info[2] & ((int)1 << 11)) != 0; HW_PREFETCHW = (info[2] & ((int)1 << 8)) != 0; } } -void cpu_x86::print() const{ +void cpu_x86::print() const { cout << "CPU Vendor:" << endl; print(" AMD = ", Vendor_AMD); print(" Intel = ", Vendor_Intel); @@ -258,7 +259,7 @@ void cpu_x86::print() const{ print(" Safe to use AVX512: ", HW_AVX512_F && OS_AVX512); cout << endl; } -void cpu_x86::print_host(){ +void cpu_x86::print_host() { cpu_x86 features; features.detect_host(); features.print(); From 0a74aaf5b0ae88c25d1d3f6e059b0ebb60060163 Mon Sep 17 00:00:00 2001 From: Tinyfish Date: Tue, 20 Aug 2024 15:56:51 +0800 Subject: [PATCH 4/5] When pass no argument, should not output "Final =". --- src/Main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Main.cpp b/src/Main.cpp index aee94bc..48ebcbd 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -34,6 +34,7 @@ int main(int argc, char* argv[]) { #if _WIN32 system("pause"); #endif + return 0; } struct feature { From 12a960c220bda8ece8ca06a9d9d2238b9d9156e0 Mon Sep 17 00:00:00 2001 From: Tinyfish Date: Tue, 20 Aug 2024 16:19:01 +0800 Subject: [PATCH 5/5] Add build scripts for Windows and WSL. --- .gitignore | 4 ++++ BuildLinuxInWsl.cmd | 9 +++++++++ BuildWindows.cmd | 9 +++++++++ CMakeLists.txt | 7 ++++--- src/x86/CMakeLists.txt | 2 +- 5 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 BuildLinuxInWsl.cmd create mode 100644 BuildWindows.cmd diff --git a/.gitignore b/.gitignore index 0699ec9..2e91dc2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ Debug/ Release/ FeatureDetector.VC* .vs/ +/Linux +/Windows +/.vs +/.idea diff --git a/BuildLinuxInWsl.cmd b/BuildLinuxInWsl.cmd new file mode 100644 index 0000000..0213b32 --- /dev/null +++ b/BuildLinuxInWsl.cmd @@ -0,0 +1,9 @@ +@echo off +setlocal +cd /d "%~dp0" + +wsl cmake -B Linux -G "Ninja Multi-Config" %* ^&^& ^ +cmake --build Linux --config Release ||^ +pause + +endlocal diff --git a/BuildWindows.cmd b/BuildWindows.cmd new file mode 100644 index 0000000..c09f2b6 --- /dev/null +++ b/BuildWindows.cmd @@ -0,0 +1,9 @@ +@echo off +setlocal +cd /d "%~dp0" + +cmake.exe -B Windows -G "Visual Studio 17 2022" -A x64 &&^ +cmake.exe --build Windows --config Release ||^ +pause + +endlocal diff --git a/CMakeLists.txt b/CMakeLists.txt index 19aa0b1..40bc975 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,9 @@ cmake_minimum_required(VERSION 3.4) project(FeatureDetector CXX) add_subdirectory(src/x86) -target_include_directories(FeatureDetector PUBLIC src) +target_include_directories(FeatureDetectorLib PUBLIC src) + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - add_executable(FeatureDetector_main src/Main.cpp) - target_link_libraries(FeatureDetector_main PUBLIC FeatureDetector) + add_executable(FeatureDetector src/Main.cpp) + target_link_libraries(FeatureDetector PUBLIC FeatureDetectorLib) endif() diff --git a/src/x86/CMakeLists.txt b/src/x86/CMakeLists.txt index 5851f56..5f2dccb 100644 --- a/src/x86/CMakeLists.txt +++ b/src/x86/CMakeLists.txt @@ -1,2 +1,2 @@ -add_library(FeatureDetector cpu_x86.cpp cpu_x86.h cpu_x86_Linux.ipp cpu_x86_Windows.ipp) +add_library(FeatureDetectorLib cpu_x86.cpp cpu_x86.h cpu_x86_Linux.ipp cpu_x86_Windows.ipp)