• R/O
  • HTTP
  • SSH
  • HTTPS

MUtilities: 提交

MUtilities development repository


Commit MetaInfo

修订版37e7f72069e8cdc146257ba986d1a79e6d087e4e (tree)
时间2016-12-24 06:14:25
作者LoRd_MuldeR <mulder2@gmx....>
CommiterLoRd_MuldeR

Log Message

Clean up MUtils::CPUFetaures code.

更改概述

差异

--- a/include/MUtils/CPUFeatures.h
+++ b/include/MUtils/CPUFeatures.h
@@ -19,6 +19,13 @@
1919 // http://www.gnu.org/licenses/lgpl-2.1.txt
2020 //////////////////////////////////////////////////////////////////////////////////
2121
22+/**
23+* @file
24+* @brief This file contains function for detecting information about the CPU
25+*
26+* Call the MUtils::CPUFetaures::detect() to detect information about the processor, which will be returned in a `MUtils::CPUFetaures::cpu_info_t` struct.
27+*/
28+
2229 #pragma once
2330
2431 //MUtils
@@ -29,33 +36,52 @@
2936
3037 namespace MUtils
3138 {
39+ /**
40+ * \brief This namespace contains functions and constants for detecting CPU information
41+ *
42+ * Call the detect() to detect information about the processor, which will be returned in a `cpu_info_t` struct.
43+ */
3244 namespace CPUFetaures
3345 {
34- //CPU flags
35- static const quint32 FLAG_MMX = 0x01;
36- static const quint32 FLAG_SSE = 0x02;
37- static const quint32 FLAG_SSE2 = 0x04;
38- static const quint32 FLAG_SSE3 = 0x08;
39- static const quint32 FLAG_SSSE3 = 0x10;
40- static const quint32 FLAG_SSE4 = 0x20;
41- static const quint32 FLAG_SSE42 = 0x40;
42- static const quint32 FLAG_AVX = 0x80;
43-
44- //CPU features
45- typedef struct _cpu_info_t
46+ // CPU vendor flag
47+ static const uint8_t VENDOR_INTEL = 0x01U; ///< \brief CPU vendor flag \details Indicates that the CPU's vendor is *Intel*
48+ static const uint8_t VENDOR_AMD = 0x02U; ///< \brief CPU vendor flag \details Indicates that the CPU's vendor is *AMD*
49+
50+ // CPU feature flag
51+ static const quint32 FLAG_CMOV = 0x001U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *CMOV* instruction
52+ static const quint32 FLAG_MMX = 0x002U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *MMX* instruction set extension
53+ static const quint32 FLAG_SSE = 0x004U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *SSE* instruction set extension
54+ static const quint32 FLAG_SSE2 = 0x008U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *SSE2* instruction set extension
55+ static const quint32 FLAG_SSE3 = 0x010U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *SSE3* instruction set extension
56+ static const quint32 FLAG_SSSE3 = 0x020U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *SSSE3* instruction set extension
57+ static const quint32 FLAG_SSE4 = 0x030U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *SSE4.1* instruction set extension
58+ static const quint32 FLAG_SSE42 = 0x080U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *SSE4.2* instruction set extension
59+ static const quint32 FLAG_AVX = 0x100U; ///< \brief CPU feature flag \details Indicates that the CPU supports the *AVX* instruction set extension
60+
61+ /**
62+ * \brief Struct to hold information about the CPU
63+ */
64+ typedef struct
4665 {
47- quint32 family;
48- quint32 model;
49- quint32 stepping;
50- quint32 count;
51- quint32 features;
52- bool x64;
53- bool intel;
54- char vendor[0x40];
55- char brand[0x40];
66+ quint32 family; ///< CPU *family* indicator, which specifies the processor "generation" to which the CPU belongs
67+ quint32 model; ///< CPU *model* indicator, which is used to distinguish processor "variants" within a generation
68+ quint32 stepping; ///< CPU *stepping* indicator, which is used to distinguish "revisions" of a certain processor model
69+ quint32 count; ///< The number of available (logical) processors
70+ quint32 features; ///< CPU *feature* flags, indicating suppoprt for extended instruction sets; all flags are OR-combined
71+ bool x64; ///< Indicates that the processor and the operating system support 64-Bit (AMD64/EM64T)
72+ uint8_t vendor; ///< CPU *vendor* flag; might be zero, if vendor is unknown
73+ char idstr[13]; ///< CPU *identifier* string, exactly 12 characters (e.g. "GenuineIntel" or "AuthenticAMD")
74+ char brand[48]; ///< CPU *brand* string, up to 48 characters (e.g. "Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz")
5675 }
5776 cpu_info_t;
5877
78+ /**
79+ * \brief Detect processor information
80+ *
81+ * Detects information about the CPU on which the application is running, including CPU vendor, identifier string, feature flags (MMX, SSE, AVX, etc) as well as the CPU core count.
82+ *
83+ * \return The function returns a `cpu_info_t` struct containing the detected information about the CPU.
84+ */
5985 MUTILS_API cpu_info_t detect(void);
6086 }
6187 }
--- a/include/MUtils/Global.h
+++ b/include/MUtils/Global.h
@@ -80,6 +80,9 @@ class QProcess;
8080
8181 ///////////////////////////////////////////////////////////////////////////////
8282
83+/**
84+* \brief Global MUtils namespace
85+*/
8386 namespace MUtils
8487 {
8588 /**
--- a/include/MUtilsInfo.dox
+++ b/include/MUtilsInfo.dox
@@ -10,6 +10,7 @@
1010 *
1111 * The public API of the *MUtilities* library is defined in the following header files (select file for details):
1212 * - **Global.h** &ndash; miscellaneous useful functions
13+ * - **CPUFeatures.h** &ndash; functions for detection information about the CPU
1314 *
1415 *
1516 * # Example
--- a/src/CPUFeatures_Win32.cpp
+++ b/src/CPUFeatures_Win32.cpp
@@ -28,76 +28,73 @@
2828 #include <MUtils/OSSupport.h>
2929 #include "Utils_Win32.h"
3030
31+#define MY_CPUID(X,Y) __cpuid(((int*)(X)), ((int)(Y)))
32+#define CHECK_VENDOR(X,Y,Z) (_stricmp((X), (Y)) ? 0U : (Z));
33+#define CHECK_FLAG(X,Y,Z) (((X) & (Y)) ? (Z) : 0U)
34+
3135 MUtils::CPUFetaures::cpu_info_t MUtils::CPUFetaures::detect(void)
3236 {
3337 const OS::ArgumentMap &args = OS::arguments();
3438 typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
39+ static const quint32 FLAGS_X64 = (FLAG_MMX | FLAG_SSE | FLAG_SSE2);
3540
36- cpu_info_t features;
41+ cpu_info_t features;
3742 SYSTEM_INFO systemInfo;
38- int CPUInfo[4] = {-1};
39- char CPUIdentificationString[0x40];
40- char CPUBrandString[0x40];
43+ uint32_t cpuInfo[4];
4144
42- memset(&features, 0, sizeof(cpu_info_t));
45+ //Initialize variables to zero
46+ memset(&features, 0, sizeof(cpu_info_t));
4347 memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
44- memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
45- memset(CPUBrandString, 0, sizeof(CPUBrandString));
46-
47- __cpuid(CPUInfo, 0);
48- memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
49- memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
50- memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
51- features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
52- strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
53-
54- if(CPUInfo[0] >= 1)
48+ memset(cpuInfo, 0, sizeof(cpuInfo));
49+
50+ //Detect the CPU identifier string
51+ MY_CPUID(&cpuInfo[0], 0);
52+ memcpy(&features.idstr[0U * sizeof(uint32_t)], &cpuInfo[1], sizeof(uint32_t));
53+ memcpy(&features.idstr[1U * sizeof(uint32_t)], &cpuInfo[3], sizeof(uint32_t));
54+ memcpy(&features.idstr[2U * sizeof(uint32_t)], &cpuInfo[2], sizeof(uint32_t));
55+ features.idstr[3U * sizeof(uint32_t)] = '\0';
56+ features.vendor |= CHECK_VENDOR(features.idstr, "GenuineIntel", VENDOR_INTEL);
57+ features.vendor |= CHECK_VENDOR(features.idstr, "AuthenticAMD", VENDOR_AMD);
58+
59+ //Detect the CPU model and feature flags
60+ if(cpuInfo[0] >= 1)
5561 {
56- __cpuid(CPUInfo, 1);
57- if(CPUInfo[3] & 0x00800000) features.features |= FLAG_MMX;
58- if(CPUInfo[3] & 0x02000000) features.features |= FLAG_SSE;
59- if(CPUInfo[3] & 0x04000000) features.features |= FLAG_SSE2;
60- if(CPUInfo[2] & 0x00000001) features.features |= FLAG_SSE3;
61- if(CPUInfo[2] & 0x00000200) features.features |= FLAG_SSSE3;
62- if(CPUInfo[2] & 0x00080000) features.features |= FLAG_SSE4;
63- if(CPUInfo[2] & 0x00100000) features.features |= FLAG_SSE42;
64- if ((CPUInfo[2] & 0x18000000) == 0x18000000)
62+ MY_CPUID(&cpuInfo[0], 1);
63+ features.features |= CHECK_FLAG(cpuInfo[3], 0x00008000, FLAG_CMOV);
64+ features.features |= CHECK_FLAG(cpuInfo[3], 0x00800000, FLAG_MMX);
65+ features.features |= CHECK_FLAG(cpuInfo[3], 0x02000000, FLAG_SSE);
66+ features.features |= CHECK_FLAG(cpuInfo[3], 0x04000000, FLAG_SSE2);
67+ features.features |= CHECK_FLAG(cpuInfo[2], 0x00000001, FLAG_SSE3);
68+ features.features |= CHECK_FLAG(cpuInfo[2], 0x00000200, FLAG_SSSE3);
69+ features.features |= CHECK_FLAG(cpuInfo[2], 0x00080000, FLAG_SSE4);
70+ features.features |= CHECK_FLAG(cpuInfo[2], 0x00100000, FLAG_SSE42);
71+
72+ //Check for AVX
73+ if ((cpuInfo[2] & 0x18000000) == 0x18000000)
6574 {
6675 if((_xgetbv(0) & 0x6ui64) == 0x6ui64) /*AVX requires OS support!*/
6776 {
6877 features.features |= FLAG_AVX;
6978 }
7079 }
71- features.stepping = CPUInfo[0] & 0xf;
72- features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
73- features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
74- }
7580
76- __cpuid(CPUInfo, 0x80000000);
77- int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
81+ //Compute the CPU stepping, model and family
82+ features.stepping = cpuInfo[0] & 0xf;
83+ features.model = ((cpuInfo[0] >> 4) & 0xf) + (((cpuInfo[0] >> 16) & 0xf) << 4);
84+ features.family = ((cpuInfo[0] >> 8) & 0xf) + ((cpuInfo[0] >> 20) & 0xff);
85+ }
7886
79- for(int i = 0x80000002; i <= nExIds; ++i)
87+ //Read the CPU "brand" string
88+ MY_CPUID(&cpuInfo[0], 0x80000000);
89+ const uint32_t nExIds = qBound(0x80000000, cpuInfo[0], 0x80000004);
90+ for(uint32_t i = 0x80000002; i <= nExIds; ++i)
8091 {
81- __cpuid(CPUInfo, i);
82- switch(i)
83- {
84- case 0x80000002:
85- memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
86- break;
87- case 0x80000003:
88- memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
89- break;
90- case 0x80000004:
91- memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
92- break;
93- }
92+ MY_CPUID(&cpuInfo[0], i);
93+ memcpy(&features.brand[(i - 0x80000002) * sizeof(cpuInfo)], &cpuInfo[0], sizeof(cpuInfo));
9494 }
95+ features.brand[sizeof(features.brand) - 1] = '\0';
9596
96- strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
97-
98- if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
99- if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
100-
97+ //Detect 64-Bit processors
10198 #if (!(defined(_M_X64) || defined(_M_IA64)))
10299 const IsWow64ProcessFun isWow64ProcessPtr = MUtils::Win32Utils::resolve<IsWow64ProcessFun>(QLatin1String("kernel32"), QLatin1String("IsWow64Process"));
103100 if(isWow64ProcessPtr)
@@ -105,24 +102,26 @@ MUtils::CPUFetaures::cpu_info_t MUtils::CPUFetaures::detect(void)
105102 BOOL x64flag = FALSE;
106103 if(isWow64ProcessPtr(GetCurrentProcess(), &x64flag))
107104 {
108- if(x64flag) features.x64 = true;
105+ if (x64flag)
106+ {
107+ features.x64 = true;
108+ features.features |= FLAGS_X64; /*x86_64 implies SSE2*/
109+ }
109110 }
110111 }
111112 #else
112113 features.x64 = true;
114+ features.features |= FLAGS_X64;
113115 #endif
114116
115- if (features.x64)
116- {
117- features.features |= (FLAG_MMX | FLAG_SSE | FLAG_SSE2); /*x86_64 implies SSE2*/
118- }
119-
117+ //Make sure that (at least) the MMX flag has been set!
120118 if (!(features.features & FLAG_MMX))
121119 {
122120 qWarning("Warning: CPU does not seem to support MMX. Take care!\n");
123121 features.features = 0;
124122 }
125123
124+ //Count the number of available(!) CPU cores
126125 DWORD_PTR procAffinity, sysAffinity;
127126 if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
128127 {
@@ -137,11 +136,11 @@ MUtils::CPUFetaures::cpu_info_t MUtils::CPUFetaures::detect(void)
137136 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
138137 }
139138
139+ //Apply manual CPU overwrites
140140 bool userFlag = false;
141- if(args.contains("force-cpu-no-64bit")) { userFlag = true; features.x64 = false; }
142- if(args.contains("force-cpu-no-sse" )) { userFlag = true; features.features &= (~(FLAG_SSE | FLAG_SSE2 | FLAG_SSE3 | FLAG_SSSE3 | FLAG_SSE4 | FLAG_SSE42)); }
143- if(args.contains("force-cpu-no-intel")) { userFlag = true; features.intel = false; }
144-
141+ if (args.contains(QLatin1String("cpu-no-simd"))) { userFlag = true; features.features = 0U; }
142+ if (args.contains(QLatin1String("cpu-no-vendor"))) { userFlag = true; features.vendor = 0U; }
143+ if (args.contains(QLatin1String("cpu-no-x64"))) { userFlag = true; features.x64 = 0U; }
145144 if(userFlag)
146145 {
147146 qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
Show on old repository browser