### Quick start: load system topology and get CPU binding Source: https://pyhwloc.readthedocs.io/en/latest/_sources/intro.rst.txt Creates a system topology using from_this_system() and prints the number of CPU cores, NUMA nodes, and the current CPU binding. Uses a context manager to ensure proper cleanup. ```python from pyhwloc import from_this_system # Create and load system topology with from_this_system() as topo: # Get basic system information n_cores = topo.n_cores() n_numa = topo.n_numa_nodes() print(f"System has {n_cores} CPU cores") print(f"System has {n_numa} NUMA nodes") # Get the current CPU binding cpuset = topo.get_cpubind() print(f"Current CPU binding: {cpuset}") ``` -------------------------------- ### Low-level API topology traversal example Source: https://pyhwloc.readthedocs.io/en/latest/_sources/examples/intro_low_level.rst.txt This example initializes a topology, loads it, and prints all objects using both array-style and tree-style walks. It uses ctypes and pyhwloc low-level functions. The code is a direct translation of the original C example. ```Python import ctypes import platform from typing import cast from pyhwloc.hwloc.bitmap import ( bitmap_asprintf, bitmap_dup, bitmap_free, bitmap_singlify, ) from pyhwloc.hwloc.core import ( HWLOC_UNKNOWN_INDEX, GetTypeDepth, MemBindFlags, MemBindPolicy, ObjPtr, ObjType, alloc_membind, free, get_nbobjs_by_depth, get_nbobjs_by_type, get_obj_by_depth, get_obj_by_type, get_root_obj, get_type_depth, get_type_or_below_depth, obj_attr_snprintf, obj_type_is_cache, obj_type_snprintf, set_area_membind, set_cpubind, topology_destroy, topology_get_depth, topology_init, topology_load, topology_t, ) def print_children(topology: topology_t, obj: ObjPtr, depth: int) -> None: type_buf = ctypes.create_string_buffer(32) attr_buf = ctypes.create_string_buffer(1024) obj_type_snprintf(cast(ctypes.c_char_p, type_buf), 32, obj, 0) print(" " * depth + type_buf.value.decode(), end="") if obj.contents.os_index != HWLOC_UNKNOWN_INDEX: print(f"#{obj.contents.os_index}", end="") obj_attr_snprintf(attr_buf, 1024, obj, " ", 0) if attr_buf.value: print(f"({attr_buf.value.decode()})", end="") print() for i in range(obj.contents.arity): child = obj.contents.children[i] print_children(topology, child, depth + 1) def main() -> int: # Variable definitions from C code depth: int i: int n: int size: int levels: int string_buf = ctypes.create_string_buffer(128) topodepth: int m: ctypes.c_void_p topology = topology_t() cpuset = None obj: ObjPtr | None # Allocate and initialize topology object. topology_init(topology) # ... Optionally, put detection configuration here to ignore # some objects types, define a synthetic topology, etc.... # # The default is to detect all the objects of the machine that # the caller is allowed to access. See Configure Topology # Detection. # Perform the topology detection. topology_load(topology) # Optionally, get some additional topology information # in case we need the topology depth later. topodepth = topology_get_depth(topology) ######################################################################### # First example: # Walk the topology with an array style, from level 0 (always # the system level) to the lowest level (always the proc level). ######################################################################### for depth in range(topodepth): print(f"*** Objects at level {depth}") for i in range(get_nbobjs_by_depth(topology, depth)): obj = get_obj_by_depth(topology, depth, i) if obj: obj_type_snprintf(cast(ctypes.c_char_p, string_buf), 128, obj, 0) print(f"Index {i}: {string_buf.value.decode()}") ######################################################################### # Second example: # Walk the topology with a tree style. ######################################################################### print("*** Printing overall tree") print_children(topology, get_root_obj(topology), 0) ``` -------------------------------- ### main Source: https://pyhwloc.readthedocs.io/en/latest/_downloads/7bf4ab1bde23c267fb85b0047b5dd961/intro_low_level.ipynb Initializes a topology, loads it, and traverses the objects to print them. This is the main entry point of the example. ```APIDOC ## Function: main ### Description Initializes a topology, loads it, and traverses the objects to print them. This is the main entry point of the example. ### Method Not applicable (Python function) ### Endpoint Not applicable ### Parameters #### Parameters - **None** - No parameters. ### Request Example Not applicable ### Response #### Success Response - **int** - Returns 0 on success. #### Response Example Not applicable ### Error Handling No explicit error handling is shown. ``` -------------------------------- ### High-level pyhwloc API example Source: https://pyhwloc.readthedocs.io/en/latest/_sources/examples/intro.rst.txt Use this snippet to explore the high-level Object interface of pyhwloc. It creates a topology with a context manager, prints system overview counts, iterates objects by depth and type, navigates parent/child/sibling relationships, and shows object attributes. Requires a system with hwloc installed and accessible. ```Python import pyhwloc def main() -> int: # Create and load topology using context manager for automatic cleanup with pyhwloc.from_this_system() as topo: print(f"Topology depth: {topo.depth}") # Print basic system information print(f""" === System Overview === CPUs: {topo.n_cpus()} Cores: {topo.n_cores()} NUMA nodes: {topo.n_numa_nodes()} Packages: {topo.n_packages()} """) # Iterate through all objects by depth print("=== Objects by Depth ===") for depth in range(topo.depth): print(f"Depth {depth}:") for obj in topo.iter_objs_by_depth(depth): print(f" {obj}") print() # Work with specific object types print("=== CPU Information ===") for cpu in topo.iter_cpus(): print(f"CPU {cpu.logical_index}: {cpu}") print("=== Core Information ===") for core in topo.iter_cores(): print(f"Core {core.logical_index}: {core}") # Print children (PUs) print(" PUs:") for pu in core.iter_children(): print(f" {pu}") print("=== NUMA Node Information ===") for node in topo.iter_numa_nodes(): print(f"NUMA Node {node.logical_index}: {node}") print(f" Memory: {node.total_memory // (1024 * 1024)} MB") # Local memory is specific to the NumaNode object type. print(f" Local memory: {node.local_memory // (1024 * 1024)} MB") # Demonstrate object navigation print() print("=== Object Navigation ===") # Get first CPU and navigate the topology first_cpu = next(topo.iter_cpus(), None) if first_cpu: print(f"First CPU: {first_cpu}") # Walk up the hierarchy current = first_cpu while current.parent: current = current.parent print(f"Parent: {current}") print() # Explore first core's children first_core = next(topo.iter_cores(), None) if first_core: print(f"First core: {first_core}") print("Children:") for child in first_core.iter_children(): print(f" {child}") print("Siblings:") for sibling in first_core.iter_siblings(): print(f" {sibling}") # Object comparison and attributes print() print("=== Object Attributes ===") root = topo.get_obj_by_depth(0, 0) # Root object assert root is not None print(f"Root object: {root}") print(f"Type: {root.type}") print(f"Name: {root.name}") print(f"Subtype: {root.subtype}") print(f"OS Index: {root.os_index}") print(f"Depth: {root.depth}") print(f"Logical Index: {root.logical_index}") print(f"Arity: {root.arity}") print(f"Symmetric Subtree: {root.symmetric_subtree}") return 0 if __name__ == "__main__": main() ``` -------------------------------- ### Low-level hwloc API example: topology walk and cache computation Source: https://pyhwloc.readthedocs.io/en/latest/examples/intro_low_level.html Direct translation of the original C hwloc example. It initializes a topology, loads it, and walks the topology in four ways: array-style by depth, tree-style via recursion, counting packages, and summing cache sizes above the first logical processor. Requires pyhwloc and ctypes; the default detection covers all objects the caller is allowed to access. ```python import ctypes import platform from typing import cast from pyhwloc.hwloc.bitmap import ( bitmap_asprintf, bitmap_dup, bitmap_free, bitmap_singlify, ) from pyhwloc.hwloc.core import ( HWLOC_UNKNOWN_INDEX, GetTypeDepth, MemBindFlags, MemBindPolicy, ObjPtr, ObjType, alloc_membind, free, get_nbobjs_by_depth, get_nbobjs_by_type, get_obj_by_depth, get_obj_by_type, get_root_obj, get_type_depth, get_type_or_below_depth, obj_attr_snprintf, obj_type_is_cache, obj_type_snprintf, set_area_membind, set_cpubind, topology_destroy, topology_get_depth, topology_init, topology_load, topology_t, ) def print_children(topology: topology_t, obj: ObjPtr, depth: int) -> None: type_buf = ctypes.create_string_buffer(32) attr_buf = ctypes.create_string_buffer(1024) obj_type_snprintf(cast(ctypes.c_char_p, type_buf), 32, obj, 0) print(" " * depth + type_buf.value.decode(), end="") if obj.contents.os_index != HWLOC_UNKNOWN_INDEX: print(f"#{obj.contents.os_index}", end="") obj_attr_snprintf(attr_buf, 1024, obj, " ", 0) if attr_buf.value: print(f"({attr_buf.value.decode()})", end="") print() for i in range(obj.contents.arity): child = obj.contents.children[i] print_children(topology, child, depth + 1) def main() -> int: # Variable definitions from C code depth: int i: int n: int size: int levels: int string_buf = ctypes.create_string_buffer(128) topodepth: int m: ctypes.c_void_p topology = topology_t() cpuset = None obj: ObjPtr | None # Allocate and initialize topology object. topology_init(topology) # ... Optionally, put detection configuration here to ignore # some objects types, define a synthetic topology, etc.... # # The default is to detect all the objects of the machine that # the caller is allowed to access. See Configure Topology # Detection. # Perform the topology detection. topology_load(topology) # Optionally, get some additional topology information # in case we need the topology depth later. topodepth = topology_get_depth(topology) ######################################################################### # First example: # Walk the topology with an array style, from level 0 (always # the system level) to the lowest level (always the proc level). ######################################################################### for depth in range(topodepth): print(f"*** Objects at level {depth}") for i in range(get_nbobjs_by_depth(topology, depth)): obj = get_obj_by_depth(topology, depth, i) if obj: obj_type_snprintf(cast(ctypes.c_char_p, string_buf), 128, obj, 0) print(f"Index {i}: {string_buf.value.decode()}") ######################################################################### # Second example: # Walk the topology with a tree style. ######################################################################### print("*** Printing overall tree") print_children(topology, get_root_obj(topology), 0) ######################################################################### # Third example: # Print the number of packages. ######################################################################### depth = get_type_depth(topology, ObjType.PACKAGE) if depth == GetTypeDepth.UNKNOWN: print("*** The number of packages is unknown") else: print(f"*** {get_nbobjs_by_depth(topology, depth)} package(s)") ######################################################################### # Fourth example: # Compute the amount of cache that the first logical processor # has above it. ######################################################################### levels = 0 size = 0 obj = get_obj_by_type(topology, ObjType.PU, 0) while obj: if obj_type_is_cache(obj.contents.type): levels += 1 size += obj.contents.attr.contents.cache.size obj = obj.contents.parent print(f"*** Logical processor 0 has {levels} caches totaling {size // 1024}KB") ``` -------------------------------- ### Example of wrapping membind setter as property Source: https://pyhwloc.readthedocs.io/en/latest/_sources/dev.rst.txt Shows a hypothetical property-style API for membind, illustrating an alternative design that was considered but not adopted. ```python topology.membind[proc_id] = Membind(policy, flags) ``` -------------------------------- ### Install pyhwloc editable on Windows Source: https://pyhwloc.readthedocs.io/en/latest/_sources/build.rst.txt Performs an editable installation of pyhwloc on Windows, using the specified hwloc root. Useful for development without building a wheel. ```powershell pip install -e . --no-deps --no-build-isolation --config-settings=hwloc-root-dir="$Env:CONDA_PREFIX" ``` -------------------------------- ### Build pyhwloc binary wheel on Windows Source: https://pyhwloc.readthedocs.io/en/latest/_sources/build.rst.txt Creates a binary wheel for pyhwloc on Windows, specifying the hwloc root directory via --config-settings. Requires the hwloc installation from the previous step. ```powershell pip wheel -v . --no-build-isolation --no-deps --wheel-dir dist --config-settings=hwloc-root-dir="$Env:CONDA_PREFIX" ``` -------------------------------- ### Editable install of pyhwloc on Linux Source: https://pyhwloc.readthedocs.io/en/latest/build.html Installs pyhwloc in editable mode on Linux using a pre-built hwloc. ```bash pip install -e . --no-build-isolation ``` -------------------------------- ### Build pyhwloc binary wheel on Windows Source: https://pyhwloc.readthedocs.io/en/latest/build.html Creates a binary wheel for pyhwloc on Windows. Requires specifying the hwloc root directory because CMake cannot find the installation automatically. ```bash pip wheel -v . --no-build-isolation --no-deps --wheel-dir dist --config-settings=hwloc-root-dir="$Env:CONDA_PREFIX" ``` -------------------------------- ### Python low-level hwloc topology traversal example Source: https://pyhwloc.readthedocs.io/en/latest/_downloads/7bf4ab1bde23c267fb85b0047b5dd961/intro_low_level.ipynb This snippet is a direct translation of the original C example from the hwloc documentation. It uses the pyhwloc low-level API to initialize a topology, traverse its objects, and print their attributes. The code defines a recursive function `print_children` that prints object types, OS indices, and attributes, and then sets up the main function to allocate and initialize the topology object. ```python import ctypes import platform from typing import cast from pyhwloc.hwloc.bitmap import ( bitmap_asprintf, bitmap_dup, bitmap_free, bitmap_singlify, ) from pyhwloc.hwloc.core import ( HWLOC_UNKNOWN_INDEX, GetTypeDepth, MemBindFlags, MemBindPolicy, ObjPtr, ObjType, alloc_membind, free, get_nbobjs_by_depth, get_nbobjs_by_type, get_obj_by_depth, get_obj_by_type, get_root_obj, get_type_depth, get_type_or_below_depth, obj_attr_snprintf, obj_type_is_cache, obj_type_snprintf, set_area_membind, set_cpubind, topology_destroy, topology_get_depth, topology_init, topology_load, topology_t, ) def print_children(topology: topology_t, obj: ObjPtr, depth: int) -> None: type_buf = ctypes.create_string_buffer(32) attr_buf = ctypes.create_string_buffer(1024) obj_type_snprintf(cast(ctypes.c_char_p, type_buf), 32, obj, 0) print(" " * depth + type_buf.value.decode(), end="") if obj.contents.os_index != HWLOC_UNKNOWN_INDEX: print(f"#{obj.contents.os_index}", end="") obj_attr_snprintf(attr_buf, 1024, obj, " ", 0) if attr_buf.value: print(f"({attr_buf.value.decode()})", end="") print() for i in range(obj.contents.arity): child = obj.contents.children[i] print_children(topology, child, depth + 1) def main() -> int: # Variable definitions from C code depth: int i: int n: int size: int levels: int string_buf = ctypes.create_string_buffer(128) topodepth: int m: ctypes.c_void_p topology = topology_t() cpuset = None obj: ObjPtr | None # Allocate and initialize topology object. topology_init(topology) # ... Optionally, put detection configuration here to ignore # some objects types, define a synthetic topology, etc.... # # The default is to detect all the objects of the machine that # the caller is allowed to access. ``` -------------------------------- ### Editable install of pyhwloc on Windows Source: https://pyhwloc.readthedocs.io/en/latest/build.html Installs pyhwloc in editable mode on Windows. Requires specifying the hwloc root directory. ```bash pip install -e . --no-deps --no-build-isolation --config-settings=hwloc-root-dir="$Env:CONDA_PREFIX" ``` -------------------------------- ### Install PyHwloc with pip Source: https://pyhwloc.readthedocs.io/en/latest/_sources/intro.rst.txt Install the pyhwloc package using pip. Supported on Linux (tested with latest Ubuntu LTS) and latest Windows. Optional CUDA 13 plugin support is available in the binaries on PyPI. ```sh pip install pyhwloc ``` -------------------------------- ### Build pyhwloc binary wheel on Linux Source: https://pyhwloc.readthedocs.io/en/latest/build.html Creates a binary wheel for pyhwloc on Linux using a pre-built hwloc in the system or conda environment. Assumes hwloc is built and installed into the conda environment. ```bash pip wheel -v . -w dist/ --no-build-isolation ``` -------------------------------- ### Bind to last core and allocate memory on last NUMA node Source: https://pyhwloc.readthedocs.io/en/latest/examples/intro_low_level.html Shows how to bind the calling thread to a single logical processor of the last core using set_cpubind, and how to allocate memory on the last NUMA node with alloc_membind and bind existing memory with set_area_membind (Linux only). The example ends by destroying the topology object and returning 0. ```python ######################################################################### # Fifth example: # Bind to only one thread of the last core of the machine. # # First find out where cores are, or else smaller sets of CPUs if # the OS doesn't have the notion of a "core". ######################################################################### depth = get_type_or_below_depth(topology, ObjType.CORE) # Get last core. obj = get_obj_by_depth(topology, depth, get_nbobjs_by_depth(topology, depth) - 1) if obj: # Get a copy of its cpuset that we may modify. cpuset = bitmap_dup(obj.contents.cpuset) # Get only one logical processor (in case the core is # SMT/hyper-threaded). bitmap_singlify(cpuset) # And try to bind ourself there. try: set_cpubind(topology, cpuset, 0) except Exception as e: cpu_str = bitmap_asprintf(obj.contents.cpuset) print(f"Couldn't bind to cpuset {cpu_str}: {e}") # Free our cpuset copy bitmap_free(cpuset) ######################################################################### # Sixth example: # Allocate some memory on the last NUMA node, bind some existing # memory to the last NUMA node. ######################################################################### # Get last node. There's always at least one. n = get_nbobjs_by_type(topology, ObjType.NUMANODE) obj = get_obj_by_type(topology, ObjType.NUMANODE, n - 1) assert obj is not None size = 1024 * 1024 m = alloc_membind( topology, size, obj.contents.nodeset, MemBindPolicy.BIND, MemBindFlags.BYNODESET, ) free(topology, m, size) # Allocate using malloc equivalent and bind if platform.system() == "Linux": m = ctypes.cast(ctypes.c_char_p(b"\x00" * size), ctypes.c_void_p) set_area_membind( topology, m, size, obj.contents.nodeset, MemBindPolicy.BIND, MemBindFlags.BYNODESET, ) # Destroy topology object. topology_destroy(topology) return 0 if __name__ == "__main__": main() ``` -------------------------------- ### Build hwloc from source on Windows with CMake Source: https://pyhwloc.readthedocs.io/en/latest/_sources/build.rst.txt Builds hwloc from source on Windows using CMake with Ninja, enabling plugins and installing to the conda prefix. Requires the hwloc source directory and a conda environment. ```powershell cd hwloc\contrib\windows-cmake\ cmake -GNinja -DHWLOC_ENABLE_PLUGINS=ON -DCMAKE_INSTALL_PREFIX="$Env:CONDA_PREFIX" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_SHARED_LIBS=ON .. ninja ninja install ``` -------------------------------- ### Build hwloc from source on Windows using CMake Source: https://pyhwloc.readthedocs.io/en/latest/build.html Commands to build hwloc from source on Windows using CMake with Ninja. Requires the mingw environment is not supported. The install prefix is set to the conda environment. ```bash cd hwloc\contrib\windows-cmake\ cmake -GNinja -DHWLOC_ENABLE_PLUGINS=ON -DCMAKE_INSTALL_PREFIX="$Env:CONDA_PREFIX" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_SHARED_LIBS=ON .. ninja ninja install ``` -------------------------------- ### Build pyhwloc docs with PYHWLOC_XML_PATH Source: https://pyhwloc.readthedocs.io/en/latest/build.html Build the pyhwloc sphinx documentation, informing it of the XML path via the PYHWLOC_XML_PATH environment variable. Run from the pyhwloc/docs directory. ```bash cd pyhwloc/docs PYHWLOC_XML_PATH=/path/hwloc/doc/doxygen-doc/xml make html ``` -------------------------------- ### Generate hwloc doxygen XML Source: https://pyhwloc.readthedocs.io/en/latest/build.html Run doxygen with the HWLOC_DOXYGEN_GENERATE_XML=YES environment variable to generate XML documentation for hwloc. Must be executed from the hwloc/doc directory. ```bash cd hwloc/doc HWLOC_DOXYGEN_GENERATE_XML=YES doxygen ./doxygen.cfg ``` -------------------------------- ### pyhwloc.hwobject.GetTypeDepth Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Constants for getting type depth. ```APIDOC ## pyhwloc.hwobject.GetTypeDepth ### Description Constants for getting type depth. ``` -------------------------------- ### Build fat wheel for pyhwloc Source: https://pyhwloc.readthedocs.io/en/latest/build.html Builds a fat wheel that fetches and bundles hwloc from source. This is mainly for the PyPI package and is not recommended for complex use cases due to potential symbol conflicts. ```bash pip wheel -v . --config-settings=fetch-hwloc=True --wheel-dir dist/ ``` -------------------------------- ### List GPU devices with hwloc using NVML, CUDA runtime, CUDA driver, and OS devices Source: https://pyhwloc.readthedocs.io/en/latest/_downloads/fb3daa40127906abae94b1c5396a1a9f/list_gpus.ipynb Complete script that lists GPU devices using four different hwloc backends: OS devices, CUDA runtime, CUDA driver, and NVML. The main block runs the OS device and CUDA runtime listings on all platforms, and only runs the CUDA driver and NVML listings on non-Windows systems. Requires the cuda.bindings, pynvml, and pyhwloc packages. ```python import sys import cuda.bindings.driver as cuda import cuda.bindings.runtime as cudart from pyhwloc import from_this_system from pyhwloc.hwobject import GetTypeDepth, ObjType, OsDevice from pyhwloc.topology import TypeFilter def list_with_nvml() -> None: import pynvml from pyhwloc.nvml import get_cpu_affinity, get_device try: pynvml.nvmlInit() with from_this_system().set_io_types_filter(TypeFilter.KEEP_ALL) as topo: status, cnt = cudart.cudaGetDeviceCount() assert status == cudart.cudaError_t.cudaSuccess for i in range(cnt): # Create a NVML device dev = get_device(topo, i) # Get the hwloc native device type osdev = dev.get_osdev() assert osdev is not None print(osdev, ":", osdev.format_attr()) print("cpuset:", dev.get_affinity().to_sched_set()) print("cpuset from nvml:", get_cpu_affinity(i).to_sched_set()) finally: pynvml.nvmlShutdown() def list_with_cudart() -> None: from pyhwloc.cuda_runtime import get_device with from_this_system().set_io_types_filter(TypeFilter.KEEP_ALL) as topo: status, cnt = cudart.cudaGetDeviceCount() assert status == cudart.cudaError_t.cudaSuccess for i in range(cnt): # Create a CUDA runtime device dev = get_device(topo, i) # Get the hwloc native device type osdev = dev.get_osdev() assert osdev is not None print(osdev, ":", osdev.format_attr()) print("cpuset:", dev.get_affinity().to_sched_set()) def list_with_cuda() -> None: from pyhwloc.cuda_driver import get_device with from_this_system().set_io_types_filter(TypeFilter.KEEP_ALL) as topo: status, cnt = cuda.cuDeviceGetCount() assert status == cuda.CUresult.CUDA_SUCCESS for i in range(cnt): # Create a CUDA driver device dev = get_device(topo, i) # Get the hwloc native device type osdev = dev.get_osdev() assert osdev is not None print(osdev, ":", osdev.format_attr()) print("cpuset:", dev.get_affinity().to_sched_set()) def list_with_osdev() -> None: # GPU is categorized as IO device. # Hwloc lists devices from both NVML and CUDA. with from_this_system().set_io_types_filter(TypeFilter.KEEP_ALL) as topo: # Look for OS devices (which include GPUs) for obj in topo.iter_objs_by_type(ObjType.OS_DEVICE): # Check if it's a GPU device if isinstance(obj, OsDevice) and obj.is_gpu(): assert obj.depth == GetTypeDepth.OS_DEVICE print(obj, ":", obj.format_attr()) if __name__ == "__main__": print("List by hwloc OS device\n") list_with_osdev() print("\nList by CUDA runtime\n") list_with_cudart() is_windows = sys.platform == "win32" if not is_windows: print("\nList by CUDA driver\n") list_with_cuda() print("\nList by NVML\n") list_with_nvml() ``` -------------------------------- ### Convert bitmap to and from sched_set Source: https://pyhwloc.readthedocs.io/en/latest/_sources/intro.rst.txt Shows how to convert a bitmap to a Python set using to_sched_set and construct a bitmap from an integer set using from_sched_set. Useful for interoperability with os.sched_ module. ```python import os from pyhwloc.bitmap import Bitmap affinity = os.sched_getaffinity(0) cpuset = Bitmap.from_sched_set(affinity) print(cpuset) ``` -------------------------------- ### Use simple enum values with MemBindPolicy Source: https://pyhwloc.readthedocs.io/en/latest/_sources/intro.rst.txt Shows how to use a simple enum value directly and get its human-readable name. The enum value BIND corresponds to integer 2. ```python from pyhwloc.topology import MemBindPolicy # Use enum values directly (integer 2) policy = MemBindPolicy.BIND # Get human-readable name policy_name = MemBindPolicy(policy).name print(f"Policy: {policy_name}") ``` -------------------------------- ### Build pyhwloc Docker image Source: https://pyhwloc.readthedocs.io/en/latest/build.html Build the container image used for GitHub actions from the dev/Dockerfile.cpu file, tagging it as pyhwloc:latest. ```bash docker build --progress=plain -f ./Dockerfile.cpu . -t pyhwloc:latest ``` -------------------------------- ### Build and print hops and cross-CPU matrices Source: https://pyhwloc.readthedocs.io/en/latest/_sources/examples/gds_hops.rst.txt Constructs two matrices: one for hop counts and one for cross-CPU distances, between each GPU and NVMe device. Uses cnt_hops() to compute values and pprint to display the results. ```python hops_rows: list[list[str | int]] = [] cross_rows: list[list[str | bool]] = [] hops_rows.append([cast(str, dev.name) for dev in nvmes]) cross_rows.append([cast(str, dev.name) for dev in nvmes]) for i, gpu in enumerate(gpus): assert gpu.name is not None hops_row: list[str | int] = [gpu.name] cross_row: list[str | bool] = [gpu.name] for j, nvme in enumerate(nvmes): hops, cross = cnt_hops(gpu, nvme) cross_row.append(cross) hops_row.append(hops) hops_rows.append(hops_row) cross_rows.append(cross_row) print("Hops:") pprint(hops_rows) print("Cross CPU:") pprint(cross_rows) ``` -------------------------------- ### Build test image for hwloc V3 Source: https://pyhwloc.readthedocs.io/en/latest/_sources/dev.rst.txt Docker command to build the test image for hwloc V3, tagging it as ghcr.io/open-mpi/pyhwloc:latest. ```sh docker build --progress=plain ./dev -f ./dev/Dockerfile.cpu --build-arg HWLOC_MAJOR=3 -t ghcr.io/open-mpi/pyhwloc:latest ``` -------------------------------- ### Bind numpy array to first NUMA node with pyhwloc membind Source: https://pyhwloc.readthedocs.io/en/latest/_downloads/6b2f6409dfc68e0871adb0d757e44978/membind.ipynb This Python snippet shows how to bind a numpy array to the first NUMA node using pyhwloc's Topology and membind functions. It first checks if numpy is available, then uses get_area_membind to inspect the current binding, sets it to the first node with set_area_membind, and verifies the result. Requires pyhwloc and numpy installed. ```python from pyhwloc import Topology from pyhwloc.topology import MemBindFlags, MemBindPolicy def bind_np_array() -> None: """Show how to bind a numpy array.""" try: import numpy as np except ImportError: print("Numpy is not available.") return array = np.arange(0, 8196) with Topology.from_this_system() as topo: if not topo.get_support().membind.set_area_membind: return nodeset, policy = topo.get_area_membind(array.data, MemBindFlags.BYNODESET) print(policy.name, nodeset) # >>> FIRSTTOUCH 0 # Use to the first node. nodeset.only(0) topo.set_area_membind(array.data, nodeset, MemBindPolicy.BIND, 0) nodeset, policy = topo.get_area_membind(array.data, MemBindFlags.BYNODESET) print(policy.name, nodeset) # >>> BIND 0 assert policy == MemBindPolicy.BIND def main() -> None: bind_np_array() if __name__ == "__main__": main() ``` -------------------------------- ### Convert bitmap to/from sched_set (Bitmap) Source: https://pyhwloc.readthedocs.io/en/latest/intro.html Shows how to create a Bitmap from a Python sched_set (affinity) using from_sched_set(). The bitmap can be printed or used for interpolation. ```python import os from pyhwloc.bitmap import Bitmap affinity = os.sched_getaffinity(0) cpuset = Bitmap.from_sched_set(affinity) print(cpuset) ``` -------------------------------- ### pyhwloc.hwobject.Object Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Base class for all hardware objects. ```APIDOC ## pyhwloc.hwobject.Object ### Description Base class for all hardware objects. ### Members - All public members as documented by automodule ``` -------------------------------- ### Build source distribution for pyhwloc Source: https://pyhwloc.readthedocs.io/en/latest/build.html Creates a source distribution (sdist) for pyhwloc using the build module. ```bash python -m build --sdist ``` -------------------------------- ### Build test image for hwloc V2 Source: https://pyhwloc.readthedocs.io/en/latest/_sources/dev.rst.txt Docker command to build the test image for hwloc V2, tagging it as ghcr.io/open-mpi/pyhwloc:v2.13.0. ```sh docker build --progress=plain ./dev -f ./dev/Dockerfile.cpu --build-arg HWLOC_MAJOR=2 -t ghcr.io/open-mpi/pyhwloc:v2.13.0 ``` -------------------------------- ### pyhwloc.hwobject.ObjOsdevType Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Enumeration of OS device types. ```APIDOC ## pyhwloc.hwobject.ObjOsdevType ### Description Enumeration of OS device types. ``` -------------------------------- ### Walk topology with NUMA nodes Source: https://pyhwloc.readthedocs.io/en/latest/_sources/intro.rst.txt Iterates over NUMA nodes in the topology and prints each node's logical index and total memory in MB. Uses the Topology class directly. ```python import pyhwloc with pyhwloc.Topology() as topo: for node in topo.iter_numa_nodes(): print(f"NUMA Node {node.logical_index}: {node}") print(f" Memory: {node.total_memory // (1024 * 1024)} MB") ``` -------------------------------- ### pyhwloc.hwobject.PciDevice Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Class representing a PCI device. ```APIDOC ## pyhwloc.hwobject.PciDevice ### Description Class representing a PCI device. ### Members - All public members including inherited members as documented by automodule ``` -------------------------------- ### pyhwloc.topology module Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Provides the Topology class and related functions for loading and manipulating hardware topologies. ```APIDOC ## pyhwloc.topology module ### Description Provides the Topology class and related functions for loading and manipulating hardware topologies. ### Members - All public members of the module as documented by automodule ``` -------------------------------- ### Build manylinux image Source: https://pyhwloc.readthedocs.io/en/latest/_sources/dev.rst.txt Docker command to build the manylinux image for portable PyPI wheels, tagging it as ghcr.io/open-mpi/pyhwloc-manylinux_2_34:latest. ```sh docker build --progress=plain ./dev -f ./Dockerfile.manylinux_2_34 -t ghcr.io/open-mpi/pyhwloc-manylinux_2_34:latest ``` -------------------------------- ### pyhwloc.utils module Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Provides utility functions. ```APIDOC ## pyhwloc.utils module ### Description Provides utility functions. ### Members - All public members as documented by automodule ``` -------------------------------- ### pyhwloc.hwobject.OsDevice Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Class representing an OS device. ```APIDOC ## pyhwloc.hwobject.OsDevice ### Description Class representing an OS device. ### Members - All public members including inherited members as documented by automodule ``` -------------------------------- ### pyhwloc.hwobject.ObjType Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Enumeration of hardware object types. ```APIDOC ## pyhwloc.hwobject.ObjType ### Description Enumeration of hardware object types. ``` -------------------------------- ### Bind to one thread of last core using set_cpubind Source: https://pyhwloc.readthedocs.io/en/latest/_sources/examples/intro_low_level.rst.txt This snippet finds the last core (or smaller CPU set if cores are not available), duplicates its cpuset, singlifies it to one logical processor, and attempts to bind the current thread to that CPU. It handles binding errors and frees the cpuset copy. Use this to restrict execution to a single hardware thread. ```python ######################################################################### # Fifth example: # Bind to only one thread of the last core of the machine. # # First find out where cores are, or else smaller sets of CPUs if # the OS doesn't have the notion of a "core". ######################################################################### depth = get_type_or_below_depth(topology, ObjType.CORE) # Get last core. obj = get_obj_by_depth(topology, depth, get_nbobjs_by_depth(topology, depth) - 1) if obj: # Get a copy of its cpuset that we may modify. cpuset = bitmap_dup(obj.contents.cpuset) # Get only one logical processor (in case the core is # SMT/hyper-threaded). bitmap_singlify(cpuset) # And try to bind ourself there. try: set_cpubind(topology, cpuset, 0) except Exception as e: cpu_str = bitmap_asprintf(obj.contents.cpuset) print(f"Couldn't bind to cpuset {cpu_str}: {e}") # Free our cpuset copy bitmap_free(cpuset) ``` -------------------------------- ### hwloc Python low-level API: topology detection and traversal Source: https://pyhwloc.readthedocs.io/en/latest/_downloads/7bf4ab1bde23c267fb85b0047b5dd961/intro_low_level.ipynb This snippet demonstrates the core hwloc low-level API usage in Python: initializing and loading the topology, walking it by depth and as a tree, counting packages, computing cache levels, binding to a core, and allocating memory on a NUMA node. It includes error handling for binding failures and uses ctypes for memory management. ```python import ctypes import platform from hwloc.ctypes import * from hwloc.ctypes import ObjType, MemBindPolicy, MemBindFlags, GetTypeDepth def main(): # Initialize topology object. topology = topology_restrict( topology_alloc(), None, RestrictFlags.RESTRICT_FLAG_NONE, ) # See Configure Topology # Detection. # Perform the topology detection. topology_load(topology) # Optionally, get some additional topology information # in case we need the topology depth later. topodepth = topology_get_depth(topology) ######################################################################### # First example: # Walk the topology with an array style, from level 0 (always # the system level) to the lowest level (always the proc level). ######################################################################### for depth in range(topodepth): print(f"*** Objects at level {depth}") for i in range(get_nbobjs_by_depth(topology, depth)): obj = get_obj_by_depth(topology, depth, i) if obj: obj_type_snprintf(cast(ctypes.c_char_p, string_buf), 128, obj, 0) print(f"Index {i}: {string_buf.value.decode()}") ######################################################################### # Second example: # Walk the topology with a tree style. ######################################################################### print("*** Printing overall tree") print_children(topology, get_root_obj(topology), 0) ######################################################################### # Third example: # Print the number of packages. ######################################################################### depth = get_type_depth(topology, ObjType.PACKAGE) if depth == GetTypeDepth.UNKNOWN: print("*** The number of packages is unknown") else: print(f"*** {get_nbobjs_by_depth(topology, depth)} package(s)") ######################################################################### # Fourth example: # Compute the amount of cache that the first logical processor # has above it. ######################################################################### levels = 0 size = 0 obj = get_obj_by_type(topology, ObjType.PU, 0) while obj: if obj_type_is_cache(obj.contents.type): levels += 1 size += obj.contents.attr.contents.cache.size obj = obj.contents.parent print(f"*** Logical processor 0 has {levels} caches totaling {size // 1024}KB") ######################################################################### # Fifth example: # Bind to only one thread of the last core of the machine. # # First find out where cores are, or else smaller sets of CPUs if # the OS doesn't have the notion of a \"core\". ######################################################################### depth = get_type_or_below_depth(topology, ObjType.CORE) # Get last core. obj = get_obj_by_depth(topology, depth, get_nbobjs_by_depth(topology, depth) - 1) if obj: # Get a copy of its cpuset that we may modify. cpuset = bitmap_dup(obj.contents.cpuset) # Get only one logical processor (in case the core is # SMT/hyper-threaded). bitmap_singlify(cpuset) # And try to bind ourself there. try: set_cpubind(topology, cpuset, 0) except Exception as e: cpu_str = bitmap_asprintf(obj.contents.cpuset) print(f"Couldn't bind to cpuset {cpu_str}: {e}") # Free our cpuset copy bitmap_free(cpuset) ######################################################################### # Sixth example: # Allocate some memory on the last NUMA node, bind some existing # memory to the last NUMA node. ######################################################################### # Get last node. There's always at least one. n = get_nbobjs_by_type(topology, ObjType.NUMANODE) obj = get_obj_by_type(topology, ObjType.NUMANODE, n - 1) assert obj is not None size = 1024 * 1024 m = alloc_membind( topology, size, obj.contents.nodeset, MemBindPolicy.BIND, MemBindFlags.BYNODESET, ) free(topology, m, size) # Allocate using malloc equivalent and bind if platform.system() == "Linux": m = ctypes.cast(ctypes.c_char_p(b"\x00" * size), ctypes.c_void_p) set_area_membind( topology, m, size, obj.contents.nodeset, MemBindPolicy.BIND, MemBindFlags.BYNODESET, ) # Destroy topology object. topology_destroy(topology) return 0 if __name__ == "__main__": main() ``` -------------------------------- ### pyhwloc.cpukinds module Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Provides functions for querying CPU kinds. ```APIDOC ## pyhwloc.cpukinds module ### Description Provides functions for querying CPU kinds. ### Members - All public members as documented by automodule ``` -------------------------------- ### Walk topology with iter_numa_nodes() Source: https://pyhwloc.readthedocs.io/en/latest/intro.html Iterates over NUMA nodes in the topology and prints their logical index and total memory. Use this to explore the topology structure. ```python import pyhwloc with pyhwloc.Topology() as topo: for node in topo.iter_numa_nodes(): print(f"NUMA Node {node.logical_index}: {node}") print(f" Memory: {node.total_memory // (1024 * 1024)} MB") ``` -------------------------------- ### Print number of packages using get_type_depth and get_nbobjs_by_depth Source: https://pyhwloc.readthedocs.io/en/latest/_sources/examples/intro_low_level.rst.txt This snippet checks the depth of the PACKAGE object type and prints the number of packages. If the depth is unknown, it prints a message indicating that. Use this to query the number of packages in the topology. ```python ######################################################################### # Third example: # Print the number of packages. ######################################################################### depth = get_type_depth(topology, ObjType.PACKAGE) if depth == GetTypeDepth.UNKNOWN: print("*** The number of packages is unknown") else: print(f"*** {get_nbobjs_by_depth(topology, depth)} package(s)") ``` -------------------------------- ### Use runtime-defined object type Source: https://pyhwloc.readthedocs.io/en/latest/_sources/intro.rst.txt Iterates NUMA nodes and uses isinstance to check the runtime type against NumaNode and Object. Shows how to handle objects whose type is only known at runtime. ```python import pyhwloc from pyhwloc.hwobject import NumaNode, Object ``` -------------------------------- ### Compute cache amount above first logical processor Source: https://pyhwloc.readthedocs.io/en/latest/_sources/examples/intro_low_level.rst.txt This snippet walks up the parent chain of the first logical processor (PU) and sums the sizes of all cache objects. It prints the total cache size in KB. Use this to determine the cache hierarchy above a given processing unit. ```python ######################################################################### # Fourth example: # Compute the amount of cache that the first logical processor # has above it. ######################################################################### levels = 0 size = 0 obj = get_obj_by_type(topology, ObjType.PU, 0) while obj: if obj_type_is_cache(obj.contents.type): levels += 1 size += obj.contents.attr.contents.cache.size obj = obj.contents.parent print(f"*** Logical processor 0 has {levels} caches totaling {size // 1024}KB") ``` -------------------------------- ### pyhwloc.nvml module Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Provides functions for NVML integration. ```APIDOC ## pyhwloc.nvml module ### Description Provides functions for NVML integration. ### Members - All public members as documented by automodule ``` -------------------------------- ### Run pyhwloc tests with coverage Source: https://pyhwloc.readthedocs.io/en/latest/build.html Run the pyhwloc test suite with pytest and pytest-cov, generating an HTML coverage report. Used to track coverage of hwloc features during early development. ```bash pytest ./pyhwloc/tests/ --cov=pyhwloc --cov-report=html ``` -------------------------------- ### pyhwloc.hwobject.ObjTypeCmp Source: https://pyhwloc.readthedocs.io/en/latest/_sources/pyhwloc_api.rst.txt Comparison functions for object types. ```APIDOC ## pyhwloc.hwobject.ObjTypeCmp ### Description Comparison functions for object types. ```