Skip to content

Commit 010066f

Browse files
committed
Improve CPU frequency detection
1 parent 6511874 commit 010066f

File tree

5 files changed

+167
-8
lines changed

5 files changed

+167
-8
lines changed

gnwinfo/gnwinfo.ini

0 Bytes
Binary file not shown.

libnw/cpuid.c

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,109 @@ NWL_GetCpuUsage(VOID)
5353
return ret;
5454
}
5555

56+
static PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION
57+
GetProcessorPerfDist(size_t* pCount)
58+
{
59+
ULONG len = 0;
60+
NTSTATUS rc = NWL_NtQuerySystemInformation(SystemProcessorPerformanceDistribution, NULL, 0, &len);
61+
if (len == 0)
62+
return NULL;
63+
PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION ppd = (PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION)malloc(len);
64+
if (!ppd)
65+
return NULL;
66+
rc = NWL_NtQuerySystemInformation(SystemProcessorPerformanceDistribution, ppd, len, &len);
67+
if (!NT_SUCCESS(rc))
68+
{
69+
free(ppd);
70+
return NULL;
71+
}
72+
if (pCount)
73+
*pCount = ppd->ProcessorCount;
74+
return ppd;
75+
}
76+
5677
DWORD
5778
NWL_GetCpuFreq(VOID)
5879
{
59-
DWORD ret = 0;
60-
DWORD freq = 0;
6180
PDH_FMT_COUNTERVALUE value = { 0 };
62-
NWL_GetRegDwordValue(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"~MHz", &ret);
6381
if (NWLC->PdhCpuBaseFreq &&
6482
NWLC->PdhGetFormattedCounterValue(NWLC->PdhCpuBaseFreq, PDH_FMT_LONG, NULL, &value) == ERROR_SUCCESS)
65-
freq = (DWORD)value.longValue;
66-
if (NWLC->PdhCpuFreq &&
67-
NWLC->PdhGetFormattedCounterValue(NWLC->PdhCpuFreq, PDH_FMT_DOUBLE, NULL, &value) == ERROR_SUCCESS)
68-
ret = (DWORD)(value.doubleValue * 0.01 * freq);
69-
return ret;
83+
{
84+
DWORD freq = (DWORD)value.longValue;
85+
if (NWLC->PdhCpuFreq &&
86+
NWLC->PdhGetFormattedCounterValue(NWLC->PdhCpuFreq, PDH_FMT_DOUBLE, NULL, &value) == ERROR_SUCCESS)
87+
return (DWORD)(value.doubleValue * 0.01 * freq);
88+
}
89+
90+
static PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION saved_ppd = NULL;
91+
PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION cur_ppd = NULL;
92+
93+
size_t cpu_count = 0;
94+
PPROCESSOR_POWER_INFORMATION ppi = NWL_NtPowerInformation(&cpu_count);
95+
if (cpu_count == 0 || ppi == NULL)
96+
goto fail;
97+
98+
if (NWLC->NwOsInfo.dwMajorVersion < 10)
99+
{
100+
ULONG sum = 0;
101+
for (size_t i = 0; i < cpu_count; i++)
102+
sum += ppi[i].CurrentMhz;
103+
free(ppi);
104+
return (DWORD) (sum / cpu_count);
105+
}
106+
107+
if (!saved_ppd)
108+
saved_ppd = GetProcessorPerfDist(NULL);
109+
if (!saved_ppd)
110+
goto fail;
111+
cur_ppd = GetProcessorPerfDist(NULL);
112+
if (!cur_ppd)
113+
goto fail;
114+
if (cur_ppd->ProcessorCount != saved_ppd->ProcessorCount ||
115+
cur_ppd->ProcessorCount < cpu_count)
116+
goto fail;
117+
118+
ULONGLONG total_hits_delta = 0;
119+
ULONGLONG total_freq_contrib = 0;
120+
for (size_t i = 0; i < cur_ppd->ProcessorCount; i++)
121+
{
122+
PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION cur_state =
123+
(PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((BYTE*)cur_ppd + cur_ppd->Offsets[i]);
124+
PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION saved_state =
125+
(PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((BYTE*)saved_ppd + saved_ppd->Offsets[i]);
126+
if (cur_state->StateCount != saved_state->StateCount)
127+
continue;
128+
ULONG max_mhz = ppi[i].MaxMhz;
129+
if (max_mhz == 0)
130+
max_mhz = ppi[0].MaxMhz;
131+
for (ULONG j = 0; j < cur_state->StateCount; j++)
132+
{
133+
ULONGLONG hits_delta = cur_state->States[j].Hits - saved_state->States[j].Hits;
134+
total_hits_delta += hits_delta;
135+
total_freq_contrib += hits_delta * cur_state->States[j].PercentFrequency * max_mhz;
136+
}
137+
}
138+
139+
free(ppi);
140+
free(saved_ppd);
141+
saved_ppd = cur_ppd;
142+
143+
if (total_hits_delta == 0)
144+
return 0;
145+
return (DWORD)(total_freq_contrib / total_hits_delta / 100);
146+
147+
fail:
148+
if (saved_ppd)
149+
{
150+
free(saved_ppd);
151+
saved_ppd = NULL;
152+
}
153+
if (cur_ppd)
154+
free(cur_ppd);
155+
156+
DWORD reg_freq = 0;
157+
NWL_GetRegDwordValue(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"~MHz", &reg_freq);
158+
return reg_freq;
70159
}
71160

72161
static LPCSTR

libnw/nt.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,43 @@ VOID NWL_NtGetVersion(LPOSVERSIONINFOEXW osInfo)
192192
RtlGetVersion(osInfo);
193193
}
194194
}
195+
196+
PPROCESSOR_POWER_INFORMATION NWL_NtPowerInformation(size_t* szCount)
197+
{
198+
SYSTEM_INFO sysInfo;
199+
GetSystemInfo(&sysInfo);
200+
*szCount = sysInfo.dwNumberOfProcessors;
201+
PPROCESSOR_POWER_INFORMATION ppInfo = (PPROCESSOR_POWER_INFORMATION)calloc(*szCount, sizeof(PROCESSOR_POWER_INFORMATION));
202+
if (!ppInfo)
203+
return NULL;
204+
NTSTATUS(WINAPI * OsNtPowerInformation)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG) = NULL;
205+
HMODULE hModule = GetModuleHandleW(L"ntdll");
206+
if (!hModule)
207+
goto try_powerprof;
208+
*(FARPROC*)&OsNtPowerInformation = GetProcAddress(hModule, "NtPowerInformation");
209+
if (!OsNtPowerInformation)
210+
goto try_powerprof;
211+
// ProcessorInformation = 11
212+
if (NT_SUCCESS(OsNtPowerInformation(11, NULL, 0, ppInfo, (ULONG)(sizeof(PROCESSOR_POWER_INFORMATION) * (*szCount)))))
213+
return ppInfo;
214+
215+
try_powerprof:
216+
hModule = LoadLibraryW(L"powrprof.dll");
217+
if (!hModule)
218+
goto fail;
219+
*(FARPROC*)&OsNtPowerInformation = GetProcAddress(hModule, "CallNtPowerInformation");
220+
if (!OsNtPowerInformation)
221+
{
222+
FreeLibrary(hModule);
223+
goto fail;
224+
}
225+
if (NT_SUCCESS(OsNtPowerInformation(11, NULL, 0, ppInfo, (ULONG)(sizeof(PROCESSOR_POWER_INFORMATION) * (*szCount)))))
226+
{
227+
FreeLibrary(hModule);
228+
return ppInfo;
229+
}
230+
FreeLibrary(hModule);
231+
fail:
232+
free(ppInfo);
233+
return NULL;
234+
}

libnw/nt.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,25 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
146146
};
147147
} SYSTEM_BOOT_ENVIRONMENT_INFORMATION, * PSYSTEM_BOOT_ENVIRONMENT_INFORMATION;
148148

149+
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT
150+
{
151+
ULONGLONG Hits;
152+
UCHAR PercentFrequency;
153+
} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT, * PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT;
154+
155+
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION
156+
{
157+
ULONG ProcessorNumber;
158+
ULONG StateCount;
159+
SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT States[1];
160+
} SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION, * PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION;
161+
162+
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION
163+
{
164+
ULONG ProcessorCount;
165+
ULONG Offsets[1];
166+
} SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION, * PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION;
167+
149168
typedef enum _SYSTEM_INFORMATION_CLASS
150169
{
151170
SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION
@@ -396,3 +415,13 @@ typedef enum _SYSTEM_ENVIRONMENT_INFORMATION_CLASS
396415
SystemEnvironmentValueInformation = 2, // q: VARIABLE_NAME_AND_VALUE
397416
MaxSystemEnvironmentInfoClass
398417
} SYSTEM_ENVIRONMENT_INFORMATION_CLASS;
418+
419+
typedef struct _PROCESSOR_POWER_INFORMATION
420+
{
421+
ULONG Number;
422+
ULONG MaxMhz;
423+
ULONG CurrentMhz;
424+
ULONG MhzLimit;
425+
ULONG MaxIdleState;
426+
ULONG CurrentIdleState;
427+
} PROCESSOR_POWER_INFORMATION, * PPROCESSOR_POWER_INFORMATION;

libnw/utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ BOOL NWL_NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClas
5454
BOOL NWL_NtSetSystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
5555
PVOID SystemInformation, ULONG SystemInformationLength);
5656
VOID NWL_NtGetVersion(LPOSVERSIONINFOEXW osInfo);
57+
PPROCESSOR_POWER_INFORMATION NWL_NtPowerInformation(size_t* szCount);
5758

5859
VOID NWL_FindId(PNODE nd, CHAR* Ids, DWORD IdsSize, CONST CHAR* v, CONST CHAR* d, CONST CHAR* s, INT usb);
5960
BOOL NWL_ParseHwid(PNODE nd, CHAR* Ids, DWORD IdsSize, LPCWSTR Hwid, INT usb);

0 commit comments

Comments
 (0)