From 3da8126f2537e806fc971c6d88cdc87fdd3cafc0 Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Tue, 25 Nov 2014 03:16:45 +0100 Subject: [PATCH] Moved the CPU detection code into the MUtils library. --- MUtilities_VS2013.vcxproj | 2 + MUtilities_VS2013.vcxproj.filters | 6 ++ include/MUtils/CPUFeatures.h | 60 +++++++++++++++++ include/MUtils/Version.h | 4 +- src/CPUFeatures_Win32.cpp | 135 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 include/MUtils/CPUFeatures.h create mode 100644 src/CPUFeatures_Win32.cpp diff --git a/MUtilities_VS2013.vcxproj b/MUtilities_VS2013.vcxproj index 794fdc5..5109d15 100644 --- a/MUtilities_VS2013.vcxproj +++ b/MUtilities_VS2013.vcxproj @@ -15,6 +15,7 @@ + @@ -23,6 +24,7 @@ + diff --git a/MUtilities_VS2013.vcxproj.filters b/MUtilities_VS2013.vcxproj.filters index e231689..d48f878 100644 --- a/MUtilities_VS2013.vcxproj.filters +++ b/MUtilities_VS2013.vcxproj.filters @@ -39,6 +39,9 @@ Source Files + + Source Files + @@ -62,6 +65,9 @@ Header Files + + Public Headers + diff --git a/include/MUtils/CPUFeatures.h b/include/MUtils/CPUFeatures.h new file mode 100644 index 0000000..ac70201 --- /dev/null +++ b/include/MUtils/CPUFeatures.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////// +// MuldeR's Utilities for Qt +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// http://www.gnu.org/licenses/lgpl-2.1.txt +////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +//MUtils +#include + +//Qt +#include + +namespace MUtils +{ + namespace CPUFetaures + { + //CPU flags + static const quint32 FLAG_MMX = 0x01; + static const quint32 FLAG_SSE = 0x02; + static const quint32 FLAG_SSE2 = 0x04; + static const quint32 FLAG_SSE3 = 0x08; + static const quint32 FLAG_SSSE3 = 0x10; + static const quint32 FLAG_SSE4 = 0x20; + static const quint32 FLAG_SSE42 = 0x40; + + //CPU features + typedef struct _cpu_info_t + { + quint32 family; + quint32 model; + quint32 stepping; + quint32 count; + quint32 features; + bool x64; + bool intel; + char vendor[0x40]; + char brand[0x40]; + } + cpu_info_t; + + MUTILS_API cpu_info_t detect(const QStringList &argv); + } +} diff --git a/include/MUtils/Version.h b/include/MUtils/Version.h index a0d9e7f..8e47a62 100644 --- a/include/MUtils/Version.h +++ b/include/MUtils/Version.h @@ -41,7 +41,7 @@ namespace MUtils MUTILS_API static const QTime build_time(const char *const time_str = build_time_raw()); //Compiler detection - MUTILS_API static const char *const compiler_version(void) + static const char *const compiler_version(void) { #if defined(__INTEL_COMPILER) #if (__INTEL_COMPILER >= 1500) @@ -109,7 +109,7 @@ namespace MUtils } //Architecture detection - MUTILS_API static const char *const compiler_arch(void) + static const char *const compiler_arch(void) { #if defined(_M_X64) static const char *const COMPILER_ARCH = "x64"; diff --git a/src/CPUFeatures_Win32.cpp b/src/CPUFeatures_Win32.cpp new file mode 100644 index 0000000..fe45cdb --- /dev/null +++ b/src/CPUFeatures_Win32.cpp @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////////////////////////////// +// MuldeR's Utilities for Qt +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// http://www.gnu.org/licenses/lgpl-2.1.txt +////////////////////////////////////////////////////////////////////////////////// + +//Win32 API +#define WIN32_LEAN_AND_MEAN 1 +#include + +//MUtils +#include + +//Qt +#include + +MUtils::CPUFetaures::cpu_info_t MUtils::CPUFetaures::detect(const QStringList &argv) +{ + typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process); + + cpu_info_t features; + SYSTEM_INFO systemInfo; + int CPUInfo[4] = {-1}; + char CPUIdentificationString[0x40]; + char CPUBrandString[0x40]; + + memset(&features, 0, sizeof(cpu_info_t)); + memset(&systemInfo, 0, sizeof(SYSTEM_INFO)); + memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString)); + memset(CPUBrandString, 0, sizeof(CPUBrandString)); + + __cpuid(CPUInfo, 0); + memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int)); + memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int)); + memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int)); + features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0); + strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE); + + if(CPUInfo[0] >= 1) + { + __cpuid(CPUInfo, 1); + if(CPUInfo[3] & 0x00800000) features.features |= FLAG_MMX; + if(CPUInfo[3] & 0x02000000) features.features |= FLAG_SSE; + if(CPUInfo[3] & 0x04000000) features.features |= FLAG_SSE2; + if(CPUInfo[2] & 0x00000001) features.features |= FLAG_SSE3; + if(CPUInfo[2] & 0x00000200) features.features |= FLAG_SSSE3; + if(CPUInfo[2] & 0x00080000) features.features |= FLAG_SSE4; + if(CPUInfo[2] & 0x00100000) features.features |= FLAG_SSE42; + features.stepping = CPUInfo[0] & 0xf; + features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4); + features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff); + } + + __cpuid(CPUInfo, 0x80000000); + int nExIds = qMax(qMin(CPUInfo[0], 0x80000004), 0x80000000); + + for(int i = 0x80000002; i <= nExIds; ++i) + { + __cpuid(CPUInfo, i); + switch(i) + { + case 0x80000002: + memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); + break; + case 0x80000003: + memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); + break; + case 0x80000004: + memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); + break; + } + } + + strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE); + + if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE); + if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE); + +#if (!(defined(_M_X64) || defined(_M_IA64))) + QLibrary Kernel32Lib("kernel32.dll"); + if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process")) + { + BOOL x64flag = FALSE; + if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag)) + { + features.x64 = (x64flag == TRUE); + } + } +#else + features.x64 = true; +#endif + + DWORD_PTR procAffinity, sysAffinity; + if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity)) + { + for(DWORD_PTR mask = 1; mask; mask <<= 1) + { + features.count += ((sysAffinity & mask) ? (1) : (0)); + } + } + if(features.count < 1) + { + GetNativeSystemInfo(&systemInfo); + features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL); + } + + if(argv.count() > 0) + { + bool flag = false; + for(int i = 0; i < argv.count(); i++) + { + if(!argv[i].compare("--force-cpu-no-64bit", Qt::CaseInsensitive)) { flag = true; features.x64 = false; } + if(!argv[i].compare("--force-cpu-no-sse", Qt::CaseInsensitive)) { flag = true; features.features &= (~(FLAG_SSE | FLAG_SSE2 | FLAG_SSE3 | FLAG_SSSE3 | FLAG_SSE4 | FLAG_SSE42)); } + if(!argv[i].compare("--force-cpu-no-intel", Qt::CaseInsensitive)) { flag = true; features.intel = false; } + } + if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n"); + } + + return features; +} -- 2.11.0