Reputation: 3
Here is my code, I find the values of the a never change, then I check the return value, and it is STATUS_BUFFER_TOO_SMALL
#include "stdafx.h"
#include <Windows.h>
extern "C" {
#include <Powrprof.h>
}
#pragma comment(lib, "Powrprof.lib")
typedef struct _PROCESSOR_POWER_INFORMATION {
ULONG Number;
ULONG MaxMhz;
ULONG CurrentMhz;
ULONG MhzLimit;
ULONG MaxIdleState;
ULONG CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
int main(int argc, char* argv[])
{
PROCESSOR_POWER_INFORMATION a;
while (1)
{
CallNtPowerInformation(ProcessorInformation, NULL, 0, &a, sizeof(a));
}
system("pause");
return 0;
}
The OutputBufferSize is sizeof(a), but why it returns STATUS_BUFFER_TOO_SMALL, and how to fix it?
Upvotes: 0
Views: 2052
Reputation: 597941
Per the CallNtPowerInformation()
documentation:
ProcessorInformation
11The
lpInBuffer
parameter must be NULL; otherwise the function returns ERROR_INVALID_PARAMETER.The
lpOutputBuffer
buffer receives onePROCESSOR_POWER_INFORMATION
structure for each processor that is installed on the system. Use theGetSystemInfo
function to retrieve the number of processors.
Your buffer is too small because you are allocating only 1 PROCESSOR_POWER_INFORMATION
total, not 1 for each installed processor. It is very rare nowadays that a PC only has 1 processor installed. Multi-core and hyper-threaded CPUs present multiple processors to the OS.
Try something more like this instead:
#include "stdafx.h"
#include <Windows.h>
extern "C" {
#include <Powrprof.h>
}
#include <vector>
#pragma comment(lib, "Powrprof.lib")
typedef struct _PROCESSOR_POWER_INFORMATION {
ULONG Number;
ULONG MaxMhz;
ULONG CurrentMhz;
ULONG MhzLimit;
ULONG MaxIdleState;
ULONG CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
int main(int argc, char* argv[])
{
SYSTEM_INFO si = {0};
GetSystemInfo(&si);
std::vector<PROCESSOR_POWER_INFORMATION> a(si.dwNumberOfProcessors);
DWORD dwSize = sizeof(PROCESSOR_POWER_INFORMATION) * si.dwNumberOfProcessors;
do
{
CallNtPowerInformation(ProcessorInformation, NULL, 0, &a[0], dwSize);
}
while (true);
a.clear();
system("pause");
return 0;
}
Note the following caveat in the SYSTEM_INFO
documentation:
dwNumberOfProcessors
The number of logical processors in the current group. To retrieve this value, use theGetLogicalProcessorInformation
function.
32-bit systems only support 64 logical processors max. 64bit systems support more processors via Processor Groups.
If your PC has 64 or fewer logical processors installed, the above code will work fine. However, if your PC has more than 64 logical processors installed, use GetActiveProcessorCount()
or GetLogicalProcessorInformation()
to determine the total number of logical processors installed.
The below code is tweaked from the example provided in the GetLogicalProcessorInformation()
documentation:
#include "stdafx.h"
#include <Windows.h>
extern "C" {
#include <Powrprof.h>
}
#include <vector>
#pragma comment(lib, "Powrprof.lib")
typedef struct _PROCESSOR_POWER_INFORMATION {
ULONG Number;
ULONG MaxMhz;
ULONG CurrentMhz;
ULONG MhzLimit;
ULONG MaxIdleState;
ULONG CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
typedef BOOL (WINAPI *LPFN_GLPIEX)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
typedef DWORD (WINAPI *LPFN_GAPC)(WORD);
#define ALL_PROCESSOR_GROUPS 0xffff
// Helper function to count set bits in the processor mask.
DWORD CountSetBits(ULONG_PTR bitMask)
{
DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;
DWORD bitSetCount = 0;
ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;
DWORD i;
for (i = 0; i <= LSHIFT; ++i)
{
bitSetCount += ((bitMask & bitTest)?1:0);
bitTest/=2;
}
return bitSetCount;
}
DWORD GetInstalledProcessorCount()
{
// on Windows 7 and later, use GetActiveProcessorCount() ...
LPFN_GAPC gapc = (LPFN_GAPC) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetActiveProcessorCount");
if (gapc)
return gapc(ALL_PROCESSOR_GROUPS);
// on Vista and later, try GetLogicalProcessorInformationEx() next ...
LPFN_GLPIEX glpiex = (LPFN_GLPIEX) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformationEx");
if (glpiex)
{
std::vector<BYTE> buffer;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = NULL;
DWORD bufsize = 0;
// not using RelationGroup because it does not return accurate info under WOW64...
while (!glpiex(RelationProcessorCore, info, &bufsize))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return 0;
buffer.resize(bufsize);
info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) &buffer[0];
}
DWORD logicalProcessorCount = 0;
while (bufsize >= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX))
{
// for RelationProcessorCore, info->Processor.GroupCount is always 1...
logicalProcessorCount += CountSetBits(info->Processor.GroupMask[0].Mask);
bufsize -= info->Size;
info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((LPBYTE)info) + info->Size);
}
return logicalProcessorCount;
}
// on XP and later, try GetLogicalProcessorInformation() next...
LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
if (glpi)
{
std::vector<BYTE> buffer;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = NULL;
DWORD bufsize = 0;
while (!glpi(info, &bufsize))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return 0;
buffer.resize(bufsize);
info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) &buffer[0];
}
DWORD logicalProcessorCount = 0;
while (bufsize >= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))
{
if (info->Relationship == RelationProcessorCore)
{
// A hyperthreaded core supplies more than one logical processor.
logicalProcessorCount += CountSetBits(info->ProcessorMask);
}
bufsize -= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
++info;
}
return logicalProcessorCount;
}
// fallback to GetSystemInfo() last ...
SYSTEM_INFO si = {0};
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}
int main(int argc, char* argv[])
{
DWORD dwNumProcessors = GetInstalledProcessorCount();
std::vector<PROCESSOR_POWER_INFORMATION> a(dwNumProcessors);
DWORD dwSize = sizeof(PROCESSOR_POWER_INFORMATION) * dwNumProcessors;
while (CallNtPowerInformation(ProcessorInformation, NULL, 0, &a[0], dwSize) == STATUS_SUCCESS)
{
// use data in `a` as needed...
}
a.clear();
system("pause");
return 0;
}
UPDATE
According to @DanielWiddis in comments, CallNtProcessInformation()
returns power info only for the calling thread's current Processor Group. So, if your PC has more than 64 logical processors installed, you can call CallNtProcessInformation()
in a loop, changing the calling thread's current process group via SetThreadGroupAffinity()
as needed on each iteration, per this discussion that I found online. To determine which Processor Groups are present and how many logical processors belong to each group, use GetLogicalProcessorInformationEx()
, or GetActiveProcessorGroupCount()
and GetActiveProcessorCount()
.
Upvotes: 2