在具有两个以上处理器组的双插槽系统上通过 ctypes 在 Python 中使用 GetLogicalProcessorInformationEx()
Using GetLogicalProcessorInformationEx() in Python via ctypes on a two socket system with more than two processor groups
所以我正在尝试通过套接字获取处理器分组。我有一个用 C++ 编写的 POC,输出如下。
[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,],[0,1,2,3,4,5,6,7,8,9,10,11,],]
[[12,13,14,15,16,17,18,19,20,21,22,23,],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,],]
虽然我可以像下面那样做一些事情,但我更愿意保持代码的连续性并保持项目的纯粹性 python。另外,为了体验,这似乎是一个很好的谜题。
socket_groups = eval(run_cmd_popen("get_logical_processor_information.exe", return_output=True).strip("\n"))
我到目前为止的工作,但只在一个套接字系统上,对于两个套接字系统,第二个套接字似乎没有任何数据,并打印以下内容.
[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,][0,1,2,3,4,5,6,7,8,9,10,11,]]
[]
这是我目前的情况:
import os
import math
import platform
from ctypes.wintypes import BYTE, INT, WORD, DWORD, BOOL, PDWORD, UINT
from ctypes import Structure, Union, WinDLL, c_uint64, POINTER, byref, get_last_error, WinError
from wmi import WMI
if platform.machine().endswith('64'):
KAFFINITY = c_uint64
else:
KAFFINITY = UINT
wmi = WMI()
NUM_SOCKETS = 0
for wmi_obj in wmi.query(f'SELECT * FROM Win32_processor '):
if wmi_obj is not None:
NUM_SOCKETS += 1
NUM_CPUS = os.cpu_count()
NUM_CPU_GROUPS = math.ceil(NUM_CPUS / 64)
ANYSIZE_ARRAY = NUM_CPU_GROUPS
ERROR_INSUFFICIENT_BUFFER = 122
RELATION_CACHE = 2
RELATION_NUMA_NODE = 1
RELATION_PROCESSOR_CORE = 0
RELATION_PROCESSOR_PACKAGE = 3
RELATION_GROUP = 4
RELATION_ALL = 0xffff
class _GROUP_AFFINITY(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY, *PGROUP_AFFINITY;
'''
_fields_ = (
('Mask', KAFFINITY),
('Group', WORD),
('Reserved', WORD * 3)
)
class _PROCESSOR_GROUP_INFO(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_group_info
typedef struct _PROCESSOR_GROUP_INFO {
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
'''
_fields_ = (
('MaximumProcessorCount', BYTE),
('ActiveProcessorCount', BYTE),
('Reserved', BYTE * 38),
('ActiveProcessorMask', KAFFINITY),
)
class _GROUP_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_relationship
typedef struct _GROUP_RELATIONSHIP {
WORD MaximumGroupCount;
WORD ActiveGroupCount;
BYTE Reserved[20];
PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
'''
_fields_ = (
('MaximumGroupCount', WORD),
('ActiveGroupCount', WORD),
('Reserved', BYTE * 20),
('GroupInfo', _PROCESSOR_GROUP_INFO * ANYSIZE_ARRAY)
)
class _DUMMYUNIONNAME_CACHE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY) # * number of groups
)
class _CACHE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
typedef struct _CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
'''
_fields_ = (
('Level', BYTE),
('Associativity', BYTE),
('LineSize', WORD),
('CacheSize', DWORD),
('Type', INT), # PROCESSOR_CACHE_TYPE is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME ', _DUMMYUNIONNAME_CACHE_RELATIONSHIP)
)
class _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY) # * number of groups
)
class _NUMA_NODE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
typedef struct _NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
'''
_fields_ = (
('NodeNumber', DWORD),
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP)
)
class _PROCESSOR_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
typedef struct _PROCESSOR_RELATIONSHIP {
BYTE Flags;
BYTE EfficiencyClass;
BYTE Reserved[20];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
'''
_fields_ = (
('Flags', BYTE),
('EfficiencyClass', BYTE),
('Reserved', BYTE * 20),
('GroupCount', WORD),
('GroupMask', _GROUP_AFFINITY * ANYSIZE_ARRAY) # * number of groups
)
class _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
'''
_fields_ = (
('Processor', _PROCESSOR_RELATIONSHIP),
('NumaNode', _NUMA_NODE_RELATIONSHIP),
('Cache', _CACHE_RELATIONSHIP),
('Group', _GROUP_RELATIONSHIP)
)
class _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
'''
_anonymous_ = 'DUMMYUNIONNAME',
_fields_ = (
('Relationship', INT), # _LOGICAL_PROCESSOR_RELATIONSHIP is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Size', DWORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)
)
def GetLogicalProcessorInformationEx(relation_type):
'''https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
BOOL GetLogicalProcessorInformationEx(
[in] LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
[out, optional] PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
[in, out] PDWORD ReturnedLength
);
'''
dll = WinDLL('kernel32', use_last_error=True)
dll.GetLogicalProcessorInformationEx.argtypes = INT, POINTER(_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX), PDWORD
dll.GetLogicalProcessorInformationEx.restype = BOOL
byte_len = DWORD()
# Call with null buffer to get required buffer size
result = dll.GetLogicalProcessorInformationEx(relation_type, None, byref(byte_len))
if (err := get_last_error()) != ERROR_INSUFFICIENT_BUFFER:
raise WinError(err)
# Allocate buffer
allocated_structure = (_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * NUM_SOCKETS)()
global byte_len_for_advance
byte_len_for_advance = byte_len
# Now do the call with the allocated buffer to fill it up
result = dll.GetLogicalProcessorInformationEx(relation_type, allocated_structure, byref(byte_len))
if not result:
raise WinError(get_last_error())
return allocated_structure
def _print_mask(mask):
# print(f"{mask=}")
digits = [int(x) for x in mask]
group_core_list = []
print("[", end='')
core = 0
for i in digits:
if i == 1:
print(f"{core},", end='')
group_core_list.append(core)
core += 1
print("]", end='')
# print(group_core_list)
if __name__ == "__main__":
enum_info = GetLogicalProcessorInformationEx(RELATION_PROCESSOR_PACKAGE)
for p_info in enum_info:
print("[", end='')
for group_index in range(0, p_info.Processor.GroupCount):
_print_mask(f"{p_info.Processor.GroupMask[group_index].Mask:8b}")
print("]\n", end='')
breakpoint
我想我可能需要做一些事情,将指针转移到下一个结构?但我不知道该怎么做。此外,我不确定 _print_mask() 是否会在我获得第二个套接字信息时完全按照我的要求进行操作,但这是以后的问题。
想上网吗?
编辑
感谢 Mark Tolonen 的 answer/help!
这是我的工作解决方案:
from typing import Dict, List
from ctypes.wintypes import BYTE, INT, WORD, DWORD, BOOL, PDWORD, WPARAM
from ctypes import Structure, Union, WinDLL, c_char_p, POINTER, byref, cast, get_last_error, WinError, create_string_buffer
KAFFINITY = WPARAM # WPARAM is 32-bit or 64-bit unsigned depending on platform
ANYSIZE_ARRAY = 1
ERROR_INSUFFICIENT_BUFFER = 122
RELATION_CACHE = 2
RELATION_NUMA_NODE = 1
RELATION_PROCESSOR_CORE = 0
RELATION_PROCESSOR_PACKAGE = 3
RELATION_GROUP = 4
RELATION_ALL = 0xffff
class _GROUP_AFFINITY(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY, *PGROUP_AFFINITY;
'''
_fields_ = (
('Mask', KAFFINITY),
('Group', WORD),
('Reserved', WORD * 3)
)
class _PROCESSOR_GROUP_INFO(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_group_info
typedef struct _PROCESSOR_GROUP_INFO {
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
'''
_fields_ = (
('MaximumProcessorCount', BYTE),
('ActiveProcessorCount', BYTE),
('Reserved', BYTE * 38),
('ActiveProcessorMask', KAFFINITY),
)
class _GROUP_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_relationship
typedef struct _GROUP_RELATIONSHIP {
WORD MaximumGroupCount;
WORD ActiveGroupCount;
BYTE Reserved[20];
PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
'''
_fields_ = (
('MaximumGroupCount', WORD),
('ActiveGroupCount', WORD),
('Reserved', BYTE * 20),
('GroupInfo', _PROCESSOR_GROUP_INFO * ANYSIZE_ARRAY)
)
class _DUMMYUNIONNAME_CACHE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY)
)
class _CACHE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
typedef struct _CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
'''
_fields_ = (
('Level', BYTE),
('Associativity', BYTE),
('LineSize', WORD),
('CacheSize', DWORD),
('Type', INT), # PROCESSOR_CACHE_TYPE is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME ', _DUMMYUNIONNAME_CACHE_RELATIONSHIP)
)
class _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY)
)
class _NUMA_NODE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
typedef struct _NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
'''
_fields_ = (
('NodeNumber', DWORD),
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP)
)
class _PROCESSOR_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
typedef struct _PROCESSOR_RELATIONSHIP {
BYTE Flags;
BYTE EfficiencyClass;
BYTE Reserved[20];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
'''
_fields_ = (
('Flags', BYTE),
('EfficiencyClass', BYTE),
('Reserved', BYTE * 20),
('GroupCount', WORD),
('GroupMask', _GROUP_AFFINITY * ANYSIZE_ARRAY)
)
class _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
'''
_fields_ = (
('Processor', _PROCESSOR_RELATIONSHIP),
('NumaNode', _NUMA_NODE_RELATIONSHIP),
('Cache', _CACHE_RELATIONSHIP),
('Group', _GROUP_RELATIONSHIP)
)
class _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
'''
_anonymous_ = 'DUMMYUNIONNAME',
_fields_ = (
('Relationship', INT), # _LOGICAL_PROCESSOR_RELATIONSHIP is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Size', DWORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)
)
def _GetLogicalProcessorInformationEx(relation_type):
'''https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
BOOL GetLogicalProcessorInformationEx(
[in] LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
[out, optional] PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
[in, out] PDWORD ReturnedLength
);
'''
dll = WinDLL('kernel32', use_last_error=True)
# Manage the allocated buffer as a c_char_p for easier pointer manipulation
dll.GetLogicalProcessorInformationEx.argtypes = INT, c_char_p, PDWORD
dll.GetLogicalProcessorInformationEx.restype = BOOL
byte_len = DWORD()
# Call with null buffer to get required buffer size
result = dll.GetLogicalProcessorInformationEx(relation_type, None, byref(byte_len))
if (err := get_last_error()) != ERROR_INSUFFICIENT_BUFFER:
raise WinError(err)
# Allocate byte buffer
buffer = create_string_buffer(byte_len.value)
# Now do the call with the buffer to fill it up
result = dll.GetLogicalProcessorInformationEx(relation_type, buffer, byref(byte_len))
if not result:
raise WinError(get_last_error())
return buffer, byte_len.value # return buffer and length
def get_socket_to_group_mappings() -> List[Dict[int, List[int]]]:
'''
'''
# The returned structure array can vary in element size, so walk the buffer by the size of its element.
buffer, buffer_len = _GetLogicalProcessorInformationEx(RELATION_PROCESSOR_PACKAGE)
offset = 0
sockets = []
while offset < buffer_len:
# Cast the current offset to the structure and extract contents
processor_info = cast(byref(buffer, offset), POINTER(_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)).contents
# print(f"{processor_info.Size=} {processor_info.Processor.GroupCount=}")
# Cast the group mask array to the correct size
group_infos = cast(byref(processor_info.Processor.GroupMask), POINTER(_GROUP_AFFINITY * processor_info.Processor.GroupCount)).contents
groups = {}
for group_info in group_infos:
# print(f"{group_affinity.Mask=:016X} {group_affinity.Group=}")
core_index = 0
group_cores = []
# Convert the mask to the binary representation of an 8-digit, zero-padded on the left string.
# Then turn that string of 1's and 0's into a list, and reverse it.
for i in [int(x) for x in f"{group_info.Mask:8b}"][::-1]:
if i == 1:
# If the this core is part of this socket in this group (indicated by a 1 in the mask).
# Add the groups core number to the groups core list
group_cores.append(core_index)
core_index += 1
# Add this group to this sockets groups dict
groups[group_info.Group] = group_cores
# Add this sockets group info to the systems socket list
sockets.append(groups)
# Advance by the size consumed
offset += processor_info.Size
return sockets
我只有一个带有 8 个逻辑处理器的单核,所以我无法验证我的一切是否适合您的情况,但试试这个:
from ctypes.wintypes import BYTE, INT, WORD, DWORD, BOOL, PDWORD, UINT, WPARAM
from ctypes import (Structure, Union, WinDLL, c_uint64, POINTER, byref, cast,
get_last_error, WinError, c_char_p, create_string_buffer)
KAFFINITY = WPARAM # WPARAM is 32-bit or 64-bit unsigned depending on platform
ANYSIZE_ARRAY = 1 # actual definition
#
# unchanged portion elided
#
def GetLogicalProcessorInformationEx(relation_type):
'''https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
BOOL GetLogicalProcessorInformationEx(
[in] LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
[out, optional] PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
[in, out] PDWORD ReturnedLength
);
'''
dll = WinDLL('kernel32', use_last_error=True)
# manage the allocated buffer as a c_char_p for easier pointer manipulation
dll.GetLogicalProcessorInformationEx.argtypes = INT, c_char_p, PDWORD
dll.GetLogicalProcessorInformationEx.restype = BOOL
byte_len = DWORD()
# Call with null buffer to get required buffer size
result = dll.GetLogicalProcessorInformationEx(relation_type, None, byref(byte_len))
if (err := get_last_error()) != ERROR_INSUFFICIENT_BUFFER:
raise WinError(err)
# Allocate byte buffer
buffer = create_string_buffer(byte_len.value)
# Now do the call with the buffer to fill it up
result = dll.GetLogicalProcessorInformationEx(relation_type, buffer, byref(byte_len))
if not result:
raise WinError(get_last_error())
return buffer,byte_len.value # return buffer and length
if __name__ == "__main__":
# The returned structure array can vary in element size,
# so walk the buffer by the size of its element.
buffer,len = GetLogicalProcessorInformationEx(RELATION_PROCESSOR_PACKAGE)
offset = 0
while offset < len:
# cast the current offset to the structure and extract contents
info = cast(byref(buffer,offset), POINTER(_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)).contents
print(f'{info.Size=} {info.Processor.GroupCount=}')
# cast the group mask array to the correct size
gaffs = cast(byref(info.Processor.GroupMask),POINTER(_GROUP_AFFINITY * info.Processor.GroupCount)).contents
for gaff in gaffs:
print(f'{gaff.Mask=:016X} {gaff.Group=}')
# advance by the size consumed
offset += info.Size
在我的一个核心、8 个逻辑进程系统上的输出:
info.Size=48 info.Processor.GroupCount=1
gaff.Mask=00000000000000FF gaff.Group=0
如果这对您的复杂系统不起作用,post 我的解决方案返回的 buffer,len
由您的系统返回,我会修复它。
所以我正在尝试通过套接字获取处理器分组。我有一个用 C++ 编写的 POC,输出如下。
[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,],[0,1,2,3,4,5,6,7,8,9,10,11,],]
[[12,13,14,15,16,17,18,19,20,21,22,23,],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,],]
虽然我可以像下面那样做一些事情,但我更愿意保持代码的连续性并保持项目的纯粹性 python。另外,为了体验,这似乎是一个很好的谜题。
socket_groups = eval(run_cmd_popen("get_logical_processor_information.exe", return_output=True).strip("\n"))
我到目前为止的工作,但只在一个套接字系统上,对于两个套接字系统,第二个套接字似乎没有任何数据,并打印以下内容.
[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,][0,1,2,3,4,5,6,7,8,9,10,11,]]
[]
这是我目前的情况:
import os
import math
import platform
from ctypes.wintypes import BYTE, INT, WORD, DWORD, BOOL, PDWORD, UINT
from ctypes import Structure, Union, WinDLL, c_uint64, POINTER, byref, get_last_error, WinError
from wmi import WMI
if platform.machine().endswith('64'):
KAFFINITY = c_uint64
else:
KAFFINITY = UINT
wmi = WMI()
NUM_SOCKETS = 0
for wmi_obj in wmi.query(f'SELECT * FROM Win32_processor '):
if wmi_obj is not None:
NUM_SOCKETS += 1
NUM_CPUS = os.cpu_count()
NUM_CPU_GROUPS = math.ceil(NUM_CPUS / 64)
ANYSIZE_ARRAY = NUM_CPU_GROUPS
ERROR_INSUFFICIENT_BUFFER = 122
RELATION_CACHE = 2
RELATION_NUMA_NODE = 1
RELATION_PROCESSOR_CORE = 0
RELATION_PROCESSOR_PACKAGE = 3
RELATION_GROUP = 4
RELATION_ALL = 0xffff
class _GROUP_AFFINITY(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY, *PGROUP_AFFINITY;
'''
_fields_ = (
('Mask', KAFFINITY),
('Group', WORD),
('Reserved', WORD * 3)
)
class _PROCESSOR_GROUP_INFO(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_group_info
typedef struct _PROCESSOR_GROUP_INFO {
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
'''
_fields_ = (
('MaximumProcessorCount', BYTE),
('ActiveProcessorCount', BYTE),
('Reserved', BYTE * 38),
('ActiveProcessorMask', KAFFINITY),
)
class _GROUP_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_relationship
typedef struct _GROUP_RELATIONSHIP {
WORD MaximumGroupCount;
WORD ActiveGroupCount;
BYTE Reserved[20];
PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
'''
_fields_ = (
('MaximumGroupCount', WORD),
('ActiveGroupCount', WORD),
('Reserved', BYTE * 20),
('GroupInfo', _PROCESSOR_GROUP_INFO * ANYSIZE_ARRAY)
)
class _DUMMYUNIONNAME_CACHE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY) # * number of groups
)
class _CACHE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
typedef struct _CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
'''
_fields_ = (
('Level', BYTE),
('Associativity', BYTE),
('LineSize', WORD),
('CacheSize', DWORD),
('Type', INT), # PROCESSOR_CACHE_TYPE is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME ', _DUMMYUNIONNAME_CACHE_RELATIONSHIP)
)
class _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY) # * number of groups
)
class _NUMA_NODE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
typedef struct _NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
'''
_fields_ = (
('NodeNumber', DWORD),
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP)
)
class _PROCESSOR_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
typedef struct _PROCESSOR_RELATIONSHIP {
BYTE Flags;
BYTE EfficiencyClass;
BYTE Reserved[20];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
'''
_fields_ = (
('Flags', BYTE),
('EfficiencyClass', BYTE),
('Reserved', BYTE * 20),
('GroupCount', WORD),
('GroupMask', _GROUP_AFFINITY * ANYSIZE_ARRAY) # * number of groups
)
class _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
'''
_fields_ = (
('Processor', _PROCESSOR_RELATIONSHIP),
('NumaNode', _NUMA_NODE_RELATIONSHIP),
('Cache', _CACHE_RELATIONSHIP),
('Group', _GROUP_RELATIONSHIP)
)
class _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
'''
_anonymous_ = 'DUMMYUNIONNAME',
_fields_ = (
('Relationship', INT), # _LOGICAL_PROCESSOR_RELATIONSHIP is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Size', DWORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)
)
def GetLogicalProcessorInformationEx(relation_type):
'''https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
BOOL GetLogicalProcessorInformationEx(
[in] LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
[out, optional] PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
[in, out] PDWORD ReturnedLength
);
'''
dll = WinDLL('kernel32', use_last_error=True)
dll.GetLogicalProcessorInformationEx.argtypes = INT, POINTER(_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX), PDWORD
dll.GetLogicalProcessorInformationEx.restype = BOOL
byte_len = DWORD()
# Call with null buffer to get required buffer size
result = dll.GetLogicalProcessorInformationEx(relation_type, None, byref(byte_len))
if (err := get_last_error()) != ERROR_INSUFFICIENT_BUFFER:
raise WinError(err)
# Allocate buffer
allocated_structure = (_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * NUM_SOCKETS)()
global byte_len_for_advance
byte_len_for_advance = byte_len
# Now do the call with the allocated buffer to fill it up
result = dll.GetLogicalProcessorInformationEx(relation_type, allocated_structure, byref(byte_len))
if not result:
raise WinError(get_last_error())
return allocated_structure
def _print_mask(mask):
# print(f"{mask=}")
digits = [int(x) for x in mask]
group_core_list = []
print("[", end='')
core = 0
for i in digits:
if i == 1:
print(f"{core},", end='')
group_core_list.append(core)
core += 1
print("]", end='')
# print(group_core_list)
if __name__ == "__main__":
enum_info = GetLogicalProcessorInformationEx(RELATION_PROCESSOR_PACKAGE)
for p_info in enum_info:
print("[", end='')
for group_index in range(0, p_info.Processor.GroupCount):
_print_mask(f"{p_info.Processor.GroupMask[group_index].Mask:8b}")
print("]\n", end='')
breakpoint
我想我可能需要做一些事情,将指针转移到下一个结构?但我不知道该怎么做。此外,我不确定 _print_mask() 是否会在我获得第二个套接字信息时完全按照我的要求进行操作,但这是以后的问题。
想上网吗?
编辑
感谢 Mark Tolonen 的 answer/help!
这是我的工作解决方案:
from typing import Dict, List
from ctypes.wintypes import BYTE, INT, WORD, DWORD, BOOL, PDWORD, WPARAM
from ctypes import Structure, Union, WinDLL, c_char_p, POINTER, byref, cast, get_last_error, WinError, create_string_buffer
KAFFINITY = WPARAM # WPARAM is 32-bit or 64-bit unsigned depending on platform
ANYSIZE_ARRAY = 1
ERROR_INSUFFICIENT_BUFFER = 122
RELATION_CACHE = 2
RELATION_NUMA_NODE = 1
RELATION_PROCESSOR_CORE = 0
RELATION_PROCESSOR_PACKAGE = 3
RELATION_GROUP = 4
RELATION_ALL = 0xffff
class _GROUP_AFFINITY(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY, *PGROUP_AFFINITY;
'''
_fields_ = (
('Mask', KAFFINITY),
('Group', WORD),
('Reserved', WORD * 3)
)
class _PROCESSOR_GROUP_INFO(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_group_info
typedef struct _PROCESSOR_GROUP_INFO {
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
'''
_fields_ = (
('MaximumProcessorCount', BYTE),
('ActiveProcessorCount', BYTE),
('Reserved', BYTE * 38),
('ActiveProcessorMask', KAFFINITY),
)
class _GROUP_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_relationship
typedef struct _GROUP_RELATIONSHIP {
WORD MaximumGroupCount;
WORD ActiveGroupCount;
BYTE Reserved[20];
PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
'''
_fields_ = (
('MaximumGroupCount', WORD),
('ActiveGroupCount', WORD),
('Reserved', BYTE * 20),
('GroupInfo', _PROCESSOR_GROUP_INFO * ANYSIZE_ARRAY)
)
class _DUMMYUNIONNAME_CACHE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY)
)
class _CACHE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-cache_relationship
typedef struct _CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
'''
_fields_ = (
('Level', BYTE),
('Associativity', BYTE),
('LineSize', WORD),
('CacheSize', DWORD),
('Type', INT), # PROCESSOR_CACHE_TYPE is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME ', _DUMMYUNIONNAME_CACHE_RELATIONSHIP)
)
class _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
'''
_fields_ = (
('GroupMask', _GROUP_AFFINITY),
('GroupMasks', _GROUP_AFFINITY * ANYSIZE_ARRAY)
)
class _NUMA_NODE_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-numa_node_relationship
typedef struct _NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[18];
WORD GroupCount;
union {
GROUP_AFFINITY GroupMask;
GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY];
} DUMMYUNIONNAME;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
'''
_fields_ = (
('NodeNumber', DWORD),
('Reserved', BYTE * 18),
('GroupCount', WORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_NUMA_NODE_RELATIONSHIP)
)
class _PROCESSOR_RELATIONSHIP(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
typedef struct _PROCESSOR_RELATIONSHIP {
BYTE Flags;
BYTE EfficiencyClass;
BYTE Reserved[20];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
'''
_fields_ = (
('Flags', BYTE),
('EfficiencyClass', BYTE),
('Reserved', BYTE * 20),
('GroupCount', WORD),
('GroupMask', _GROUP_AFFINITY * ANYSIZE_ARRAY)
)
class _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Union):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
'''
_fields_ = (
('Processor', _PROCESSOR_RELATIONSHIP),
('NumaNode', _NUMA_NODE_RELATIONSHIP),
('Cache', _CACHE_RELATIONSHIP),
('Group', _GROUP_RELATIONSHIP)
)
class _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Structure):
'''https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
} DUMMYUNIONNAME;
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
'''
_anonymous_ = 'DUMMYUNIONNAME',
_fields_ = (
('Relationship', INT), # _LOGICAL_PROCESSOR_RELATIONSHIP is an Enum type, which, At least for GCC, is just a simple numeric type. (
('Size', DWORD),
('DUMMYUNIONNAME', _DUMMYUNIONNAME_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)
)
def _GetLogicalProcessorInformationEx(relation_type):
'''https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
BOOL GetLogicalProcessorInformationEx(
[in] LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
[out, optional] PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
[in, out] PDWORD ReturnedLength
);
'''
dll = WinDLL('kernel32', use_last_error=True)
# Manage the allocated buffer as a c_char_p for easier pointer manipulation
dll.GetLogicalProcessorInformationEx.argtypes = INT, c_char_p, PDWORD
dll.GetLogicalProcessorInformationEx.restype = BOOL
byte_len = DWORD()
# Call with null buffer to get required buffer size
result = dll.GetLogicalProcessorInformationEx(relation_type, None, byref(byte_len))
if (err := get_last_error()) != ERROR_INSUFFICIENT_BUFFER:
raise WinError(err)
# Allocate byte buffer
buffer = create_string_buffer(byte_len.value)
# Now do the call with the buffer to fill it up
result = dll.GetLogicalProcessorInformationEx(relation_type, buffer, byref(byte_len))
if not result:
raise WinError(get_last_error())
return buffer, byte_len.value # return buffer and length
def get_socket_to_group_mappings() -> List[Dict[int, List[int]]]:
'''
'''
# The returned structure array can vary in element size, so walk the buffer by the size of its element.
buffer, buffer_len = _GetLogicalProcessorInformationEx(RELATION_PROCESSOR_PACKAGE)
offset = 0
sockets = []
while offset < buffer_len:
# Cast the current offset to the structure and extract contents
processor_info = cast(byref(buffer, offset), POINTER(_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)).contents
# print(f"{processor_info.Size=} {processor_info.Processor.GroupCount=}")
# Cast the group mask array to the correct size
group_infos = cast(byref(processor_info.Processor.GroupMask), POINTER(_GROUP_AFFINITY * processor_info.Processor.GroupCount)).contents
groups = {}
for group_info in group_infos:
# print(f"{group_affinity.Mask=:016X} {group_affinity.Group=}")
core_index = 0
group_cores = []
# Convert the mask to the binary representation of an 8-digit, zero-padded on the left string.
# Then turn that string of 1's and 0's into a list, and reverse it.
for i in [int(x) for x in f"{group_info.Mask:8b}"][::-1]:
if i == 1:
# If the this core is part of this socket in this group (indicated by a 1 in the mask).
# Add the groups core number to the groups core list
group_cores.append(core_index)
core_index += 1
# Add this group to this sockets groups dict
groups[group_info.Group] = group_cores
# Add this sockets group info to the systems socket list
sockets.append(groups)
# Advance by the size consumed
offset += processor_info.Size
return sockets
我只有一个带有 8 个逻辑处理器的单核,所以我无法验证我的一切是否适合您的情况,但试试这个:
from ctypes.wintypes import BYTE, INT, WORD, DWORD, BOOL, PDWORD, UINT, WPARAM
from ctypes import (Structure, Union, WinDLL, c_uint64, POINTER, byref, cast,
get_last_error, WinError, c_char_p, create_string_buffer)
KAFFINITY = WPARAM # WPARAM is 32-bit or 64-bit unsigned depending on platform
ANYSIZE_ARRAY = 1 # actual definition
#
# unchanged portion elided
#
def GetLogicalProcessorInformationEx(relation_type):
'''https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
BOOL GetLogicalProcessorInformationEx(
[in] LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
[out, optional] PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
[in, out] PDWORD ReturnedLength
);
'''
dll = WinDLL('kernel32', use_last_error=True)
# manage the allocated buffer as a c_char_p for easier pointer manipulation
dll.GetLogicalProcessorInformationEx.argtypes = INT, c_char_p, PDWORD
dll.GetLogicalProcessorInformationEx.restype = BOOL
byte_len = DWORD()
# Call with null buffer to get required buffer size
result = dll.GetLogicalProcessorInformationEx(relation_type, None, byref(byte_len))
if (err := get_last_error()) != ERROR_INSUFFICIENT_BUFFER:
raise WinError(err)
# Allocate byte buffer
buffer = create_string_buffer(byte_len.value)
# Now do the call with the buffer to fill it up
result = dll.GetLogicalProcessorInformationEx(relation_type, buffer, byref(byte_len))
if not result:
raise WinError(get_last_error())
return buffer,byte_len.value # return buffer and length
if __name__ == "__main__":
# The returned structure array can vary in element size,
# so walk the buffer by the size of its element.
buffer,len = GetLogicalProcessorInformationEx(RELATION_PROCESSOR_PACKAGE)
offset = 0
while offset < len:
# cast the current offset to the structure and extract contents
info = cast(byref(buffer,offset), POINTER(_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)).contents
print(f'{info.Size=} {info.Processor.GroupCount=}')
# cast the group mask array to the correct size
gaffs = cast(byref(info.Processor.GroupMask),POINTER(_GROUP_AFFINITY * info.Processor.GroupCount)).contents
for gaff in gaffs:
print(f'{gaff.Mask=:016X} {gaff.Group=}')
# advance by the size consumed
offset += info.Size
在我的一个核心、8 个逻辑进程系统上的输出:
info.Size=48 info.Processor.GroupCount=1
gaff.Mask=00000000000000FF gaff.Group=0
如果这对您的复杂系统不起作用,post 我的解决方案返回的 buffer,len
由您的系统返回,我会修复它。