这是我的代码,我发现a的值永远不会改变,然后我检查返回值,它是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;
}
OutputBufferSize是sizeof(a),但为什么它返回STATUS_BUFFER_TOO_SMALL,以及如何修复它?
ProcessorInformation 11
lpInBuffer
参数必须为NULL;否则该函数返回ERROR_INVALID_PARAMETER。
lpOutputBuffer
缓冲区为系统上安装的每个处理器接收一个PROCESSOR_POWER_INFORMATION
结构。使用GetSystemInfo
函数检索处理器的数量。
您的缓冲区太小,因为您只分配了1个PROCESSOR_POWER_INFORMATION
,而不是每个已安装的处理器分配1个。现在非常罕见,PC只安装了1个处理器。多核和超线程CPU为操作系统提供多个处理器。
尝试更像这样的东西:
#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;
}
请注意SYSTEM_INFO
文档中的以下警告:
dwNumberOfProcessors 当前组中的逻辑处理器数。要检索此值,请使用
GetLogicalProcessorInformation
函数。
32位系统最多只支持64个逻辑处理器。 64位系统通过Processor Groups支持更多处理器。
如果您的PC安装了64个或更少的逻辑处理器,上述代码将正常工作。但是,如果您的PC安装了超过64个逻辑处理器,请使用GetActiveProcessorCount()
或GetLogicalProcessorInformation()
确定安装的逻辑处理器总数。
以下代码是根据GetLogicalProcessorInformation()
文档中提供的示例调整的:
#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
根据@DanielWiddis的评论,CallNtProcessInformation()
只返回调用线程当前处理器组的电源信息。因此,如果您的PC安装了超过64个逻辑处理器,您可以循环调用CallNtProcessInformation()
,根据需要在每次迭代时根据需要通过SetThreadGroupAffinity()
更改调用线程的当前进程组,这是我在网上找到的this discussion。要确定存在哪些处理器组以及每组有多少逻辑处理器,请使用GetLogicalProcessorInformationEx()
或GetActiveProcessorGroupCount()
和GetActiveProcessorCount()
。