X-Git-Url: http://git.osdn.net/view?p=mutilities%2FMUtilities.git;a=blobdiff_plain;f=src%2FCPUFeatures_Win32.cpp;h=a994e7ce7b5952eb8ebdd83a0e563c26ad3eb28e;hp=26d0a088690b2cd03a8468f452c715cdea1f313a;hb=39adf6e7c0330316d7bf0ef96505e460039f996d;hpb=3ec3580ba409f15a1695784a8269e6426d792275 diff --git a/src/CPUFeatures_Win32.cpp b/src/CPUFeatures_Win32.cpp index 26d0a08..a994e7c 100644 --- a/src/CPUFeatures_Win32.cpp +++ b/src/CPUFeatures_Win32.cpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // MuldeR's Utilities for Qt -// Copyright (C) 2004-2015 LoRd_MuldeR +// Copyright (C) 2004-2019 LoRd_MuldeR // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,106 +23,115 @@ #define WIN32_LEAN_AND_MEAN 1 #include +//ASM +#include + //MUtils #include #include #include "Utils_Win32.h" +#define MY_CPUID(X,Y) __cpuid(((int*)(X)), ((int)(Y))) +#define CHECK_VENDOR(X,Y,Z) (_stricmp((X), (Y)) ? 0U : (Z)); +#define CHECK_FLAG(X,Y,Z) (((X) & (Y)) ? (Z) : 0U) + MUtils::CPUFetaures::cpu_info_t MUtils::CPUFetaures::detect(void) { const OS::ArgumentMap &args = OS::arguments(); typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process); + static const quint32 FLAGS_X64 = (FLAG_MMX | FLAG_SSE | FLAG_SSE2); - cpu_info_t features; + cpu_info_t features; SYSTEM_INFO systemInfo; - int CPUInfo[4] = {-1}; - char CPUIdentificationString[0x40]; - char CPUBrandString[0x40]; + uint32_t cpuInfo[4]; - memset(&features, 0, sizeof(cpu_info_t)); + //Initialize variables to zero + 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) + memset(&cpuInfo[0], 0, sizeof(cpuInfo)); + + //Detect the CPU identifier string + MY_CPUID(&cpuInfo[0], 0); + const uint32_t max_basic_cap = cpuInfo[0]; + memcpy(&features.idstr[0U * sizeof(uint32_t)], &cpuInfo[1], sizeof(uint32_t)); + memcpy(&features.idstr[1U * sizeof(uint32_t)], &cpuInfo[3], sizeof(uint32_t)); + memcpy(&features.idstr[2U * sizeof(uint32_t)], &cpuInfo[2], sizeof(uint32_t)); + features.idstr[3U * sizeof(uint32_t)] = '\0'; + features.vendor |= CHECK_VENDOR(features.idstr, "GenuineIntel", VENDOR_INTEL); + features.vendor |= CHECK_VENDOR(features.idstr, "AuthenticAMD", VENDOR_AMD); + + //Detect the CPU model and feature flags + if(max_basic_cap >= 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; - if ((CPUInfo[2] & 0x18000000) == 0x18000000) + MY_CPUID(&cpuInfo[0], 1); + features.features |= CHECK_FLAG(cpuInfo[3], 0x00008000, FLAG_CMOV); + features.features |= CHECK_FLAG(cpuInfo[3], 0x00800000, FLAG_MMX); + features.features |= CHECK_FLAG(cpuInfo[3], 0x02000000, FLAG_SSE); + features.features |= CHECK_FLAG(cpuInfo[3], 0x04000000, FLAG_SSE2); + features.features |= CHECK_FLAG(cpuInfo[2], 0x00000001, FLAG_SSE3); + features.features |= CHECK_FLAG(cpuInfo[2], 0x00000200, FLAG_SSSE3); + features.features |= CHECK_FLAG(cpuInfo[2], 0x00080000, FLAG_SSE41); + features.features |= CHECK_FLAG(cpuInfo[2], 0x00100000, FLAG_SSE42); + + //Check for AVX + if ((cpuInfo[2] & 0x18000000) == 0x18000000) { - if (IsProcessorFeaturePresent(PF_XSAVE_ENABLED)) /*AVX requires OS support!*/ + if((_xgetbv(0) & 0x6ui64) == 0x6ui64) /*AVX requires OS support!*/ { features.features |= FLAG_AVX; + features.features |= CHECK_FLAG(cpuInfo[2], 0x00001000, FLAG_FMA3); } } - 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); + //Compute the CPU stepping, model and family + 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); + } - for(int i = 0x80000002; i <= nExIds; ++i) + //Detect extended feature flags + if (max_basic_cap >= 7) { - __cpuid(CPUInfo, i); - switch(i) + MY_CPUID(&cpuInfo[0], 7); + if (features.features & FLAG_AVX) { - 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; + features.features |= CHECK_FLAG(cpuInfo[1], 0x00000020, FLAG_AVX2); } } - 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))) - const IsWow64ProcessFun isWow64ProcessPtr = MUtils::Win32Utils::resolve(QLatin1String("kernel32"), QLatin1String("IsWow64Process")); - if(isWow64ProcessPtr) + //Read the CPU "brand" string + if (max_basic_cap > 0) { - BOOL x64flag = FALSE; - if(isWow64ProcessPtr(GetCurrentProcess(), &x64flag)) + MY_CPUID(&cpuInfo[0], 0x80000000); + const uint32_t max_extended_cap = qBound(0x80000000, cpuInfo[0], 0x80000004); + if (max_extended_cap >= 0x80000001) { - if(x64flag) features.x64 = true; + MY_CPUID(&cpuInfo[0], 0x80000001); + features.features |= CHECK_FLAG(cpuInfo[2], 0x00000020, FLAG_LZCNT); + for (uint32_t i = 0x80000002; i <= max_extended_cap; ++i) + { + MY_CPUID(&cpuInfo[0], i); + memcpy(&features.brand[(i - 0x80000002) * sizeof(cpuInfo)], &cpuInfo[0], sizeof(cpuInfo)); + } + features.brand[sizeof(features.brand) - 1] = '\0'; } } -#else - features.x64 = true; -#endif - if (features.x64) + //Detect 64-Bit processors + if (OS::os_architecture() == OS::ARCH_X64) { - features.features |= (FLAG_MMX | FLAG_SSE | FLAG_SSE2); /*x86_64 implies SSE2*/ + features.x64 = true; + features.features |= FLAGS_X64; /*x86_64 implies SSE2*/ } + //Make sure that (at least) the MMX flag has been set! if (!(features.features & FLAG_MMX)) { qWarning("Warning: CPU does not seem to support MMX. Take care!\n"); features.features = 0; } + //Count the number of available(!) CPU cores DWORD_PTR procAffinity, sysAffinity; if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity)) { @@ -137,11 +146,11 @@ MUtils::CPUFetaures::cpu_info_t MUtils::CPUFetaures::detect(void) features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL); } + //Apply manual CPU overwrites bool userFlag = false; - if(args.contains("force-cpu-no-64bit")) { userFlag = true; features.x64 = false; } - if(args.contains("force-cpu-no-sse" )) { userFlag = true; features.features &= (~(FLAG_SSE | FLAG_SSE2 | FLAG_SSE3 | FLAG_SSSE3 | FLAG_SSE4 | FLAG_SSE42)); } - if(args.contains("force-cpu-no-intel")) { userFlag = true; features.intel = false; } - + if (args.contains(QLatin1String("cpu-no-simd"))) { userFlag = true; features.features = 0U; } + if (args.contains(QLatin1String("cpu-no-vendor"))) { userFlag = true; features.vendor = 0U; } + if (args.contains(QLatin1String("cpu-no-x64"))) { userFlag = true; features.x64 = 0U; } if(userFlag) { qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");