Использование GetLogicalProcessorInformationEx() в Python через типы ctypes в системе с двумя сокетами с более чем двумя группами процессоров

#python #windows #winapi #ctypes #processor

Вопрос:

Поэтому я пытаюсь получить группировки процессоров по сокетам. У меня есть POC на C , который это делает, вывод выглядит следующим образом.

 [[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. (https://stackoverflow.com/questions/1546355/using-enums-in-ctypes-structure/1546467#1546467)  ('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. (https://stackoverflow.com/questions/1546355/using-enums-in-ctypes-structure/1546467#1546467)  ('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() будет делать именно то, что я хочу, когда я получу информацию о вторых сокетах, но это более поздняя проблема.

Any thought internet?


Edit

Thanks to Mark Tolonen for the answer/help!

Here is my working solution:

 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. (https://stackoverflow.com/questions/1546355/using-enums-in-ctypes-structure/1546467#1546467)  ('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. (https://stackoverflow.com/questions/1546355/using-enums-in-ctypes-structure/1546467#1546467)  ('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() -gt; 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 lt; 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  

Ответ №1:

У меня есть только одно ядро с 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 lt; 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  

Если это не работает для вашей сложной системы, опубликуйте возвращенное buffer,len из моего решения, возвращенное вашей системой, и я исправлю это.

Комментарии:

1. Большое вам спасибо, что сделали это! Я не знал этого о «WPARAM», и я изначально установил «ANNYSIZE_ARRAY» на 1, но получал странные размеры структуры. Но теперь я понимаю, что это было связано с более фундаментальной проблемой.