rlib
Convenience library for useful things
Loading...
Searching...
No Matches
System and hardware topology

Query CPU and NUMA-node counts, build RBitset masks of the available CPUs / nodes, and walk a discovered hardware topology. More...

Data Structures

struct  RSysCpuCache
 One level of a CPU's cache hierarchy. More...
 

Macros

#define R_SYS_ID_UNKNOWN   RSIZE_MAX
 Returned by the topology id accessors when the platform does not name that part of the topology.
 

Enumerations

enum  RSysCpuCacheType { R_SYS_CPU_CACHE_UNIFIED = 0 , R_SYS_CPU_CACHE_DATA , R_SYS_CPU_CACHE_INSTRUCTION , R_SYS_CPU_CACHE_TRACE }
 What an RSysCpuCache level holds. More...
 

Topology objects

RSysTopology / RSysNode / RSysCpu are refcounted; use the _ref / _unref aliases. The r_sys_topology_node / r_sys_topology_node_cpu accessors return a new reference that the caller must _unref.

typedef struct RSysTopology RSysTopology
 Opaque, refcounted hardware-topology snapshot.
 
typedef struct RSysNode RSysNode
 Opaque, refcounted NUMA node within a topology.
 
typedef struct RSysCpu RSysCpu
 Opaque, refcounted CPU within a topology node.
 
RSysTopology * r_sys_topology_discover (void)
 Discover the current hardware topology.
 
rsize r_sys_topology_node_count (const RSysTopology *topo)
 Number of NUMA nodes in topo.
 
RSysNode * r_sys_topology_node (RSysTopology *topo, rsize idx)
 Return the idx-th node of topo as a new reference (caller r_sys_node_unref's), or NULL if out of range.
 
rboolean r_sys_topology_node_cpuset (const RSysNode *node, RBitset *cpuset)
 Fill cpuset with the CPUs belonging to node.
 
rsize r_sys_topology_node_cpu_count (const RSysNode *node)
 Number of CPUs in node.
 
RSysCpu * r_sys_topology_node_cpu (RSysNode *node, rsize idx)
 Return the idx-th CPU of node as a new reference (caller r_sys_cpu_unref's), or NULL if out of range.
 
rsize r_sys_topology_node_available_memory (const RSysNode *node)
 Bytes of available (free) memory local to node, or 0 when the platform does not expose it.
 
rsize r_sys_topology_node_total_memory (const RSysNode *node)
 Bytes of memory local to node, or 0 when the platform does not expose it.
 
rsize r_sys_topology_node_id (const RSysNode *node)
 NUMA index of node, or R_SYS_ID_UNKNOWN.
 
rsize r_sys_topology_node_distance (const RSysNode *node, rsize nodeid)
 Relative cost of reaching nodeid's memory from node.
 
#define r_sys_topology_ref   r_ref_ref
 Take a reference on a topology (alias for r_ref_ref).
 
#define r_sys_topology_unref   r_ref_unref
 Drop a reference on a topology (alias for r_ref_unref).
 
#define r_sys_node_ref   r_ref_ref
 Take a reference on a node (alias for r_ref_ref).
 
#define r_sys_node_unref   r_ref_unref
 Drop a reference on a node (alias for r_ref_unref).
 
#define r_sys_cpu_ref   r_ref_ref
 Take a reference on a CPU (alias for r_ref_ref).
 
#define r_sys_cpu_unref   r_ref_unref
 Drop a reference on a CPU (alias for r_ref_unref).
 

CPU counts

ruint r_sys_cpu_packages (void)
 Number of physical CPU packages (sockets).
 
ruint r_sys_cpu_physical_count (void)
 Number of physical cores.
 
ruint r_sys_cpu_logical_count (void)
 Number of logical CPUs (hardware threads).
 
ruint r_sys_cpu_allowed_count (void)
 Number of CPUs this process is allowed to run on.
 
ruint r_sys_cpu_max_count (void)
 Maximum possible CPU count the system can have.
 

CPU sets

ruint r_sys_cpuset_max (void)
 Highest valid CPU index + 1 (sizing hint for a cpuset).
 
RBitset * r_sys_cpuset_new (void)
 Allocate a RBitset sized to hold every possible CPU.
 
rboolean r_sys_cpuset_possible (RBitset *cpuset)
 Fill cpuset with all CPUs the system could ever have.
 
rboolean r_sys_cpuset_present (RBitset *cpuset)
 Fill cpuset with the physically-present CPUs.
 
rboolean r_sys_cpuset_online (RBitset *cpuset)
 Fill cpuset with the currently-online CPUs.
 
rboolean r_sys_cpuset_allowed (RBitset *cpuset)
 Fill cpuset with the CPUs this process may run on.
 
rboolean r_sys_cpuset_for_node (RBitset *cpuset, ruint node)
 Fill cpuset with the CPUs belonging to NUMA node.
 

NUMA-node counts

ruint r_sys_node_count (void)
 Total number of NUMA nodes.
 
ruint r_sys_node_count_with_online_cpus (void)
 Number of nodes that have at least one online CPU.
 
ruint r_sys_node_count_with_allowed_cpus (void)
 Number of nodes that have at least one allowed CPU.
 

NUMA-node sets

ruint r_sys_nodeset_max (void)
 Highest valid node index + 1 (sizing hint for a nodeset).
 
RBitset * r_sys_nodeset_new (void)
 Allocate a RBitset sized to hold every possible node.
 
rboolean r_sys_nodeset_possible (RBitset *nodeset)
 Fill nodeset with all nodes the system could have.
 
rboolean r_sys_nodeset_online (RBitset *nodeset)
 Fill nodeset with the currently-online nodes.
 
rboolean r_sys_nodeset_with_online_cpus (RBitset *nodeset)
 Fill nodeset with nodes that have online CPUs.
 
rboolean r_sys_nodeset_with_allowed_cpus (RBitset *nodeset)
 Fill nodeset with nodes that have allowed CPUs.
 
rboolean r_sys_nodeset_for_cpuset (RBitset *nodeset, const RBitset *cpuset)
 Fill nodeset with the nodes spanned by cpuset.
 

CPU attributes

Per-CPU detail for an RSysCpu handed out by r_sys_topology_node_cpu. Core and package ids only mean anything compared against each other ("same core?"); a platform that does not name them gets enumeration ordinals instead, so neither is safe to use as an array index.

rsize r_sys_topology_cpu_id (const RSysCpu *cpu)
 Logical CPU index, i.e. the bit this CPU occupies in a cpuset.
 
rsize r_sys_topology_cpu_node_id (const RSysCpu *cpu)
 Index of the NUMA node cpu belongs to.
 
rsize r_sys_topology_cpu_core_id (const RSysCpu *cpu)
 Physical core id of cpu, or R_SYS_ID_UNKNOWN.
 
rsize r_sys_topology_cpu_package_id (const RSysCpu *cpu)
 Physical package (socket) id of cpu, or R_SYS_ID_UNKNOWN.
 
rboolean r_sys_topology_cpu_siblings (const RSysCpu *cpu, RBitset *cpuset)
 Fill cpuset with the SMT thread siblings of cpu.
 
ruint64 r_sys_topology_cpu_max_frequency (const RSysCpu *cpu)
 Highest clock frequency cpu can be driven at, in kHz.
 
ruint64 r_sys_topology_cpu_min_frequency (const RSysCpu *cpu)
 Lowest clock frequency cpu can be driven at, in kHz, or 0 when unknown.
 
rsize r_sys_topology_cpu_cache_count (const RSysCpu *cpu)
 Number of cache levels reported for cpu.
 
rboolean r_sys_topology_cpu_cache (const RSysCpu *cpu, rsize idx, RSysCpuCache *cache)
 Copy the idx-th cache level of cpu into cache.
 
rboolean r_sys_topology_cpu_cache_cpuset (const RSysCpu *cpu, rsize idx, RBitset *cpuset)
 Fill cpuset with the CPUs sharing cpu's idx-th cache.
 

Detailed Description

Query CPU and NUMA-node counts, build RBitset masks of the available CPUs / nodes, and walk a discovered hardware topology.

The stateless r_sys_cpu_* / r_sys_node_* / r_sys_*set_* calls answer one-off questions ("how many logical CPUs?", "which CPUs are online?"). For repeated structured access, discover an RSysTopology once and walk its nodes and CPUs.

Macro Definition Documentation

◆ R_SYS_ID_UNKNOWN

#define R_SYS_ID_UNKNOWN   RSIZE_MAX

Returned by the topology id accessors when the platform does not name that part of the topology.

Zero is a valid core, package and node id, so "unknown" needs a sentinel of its own.

Enumeration Type Documentation

◆ RSysCpuCacheType

What an RSysCpuCache level holds.

Enumerator
R_SYS_CPU_CACHE_UNIFIED 

Instructions and data.

R_SYS_CPU_CACHE_DATA 

Data only.

R_SYS_CPU_CACHE_INSTRUCTION 

Instructions only.

R_SYS_CPU_CACHE_TRACE 

Decoded-instruction trace cache.

Function Documentation

◆ r_sys_topology_cpu_cache()

rboolean r_sys_topology_cpu_cache ( const RSysCpu *  cpu,
rsize  idx,
RSysCpuCache *  cache 
)

Copy the idx-th cache level of cpu into cache.

Levels are ordered by increasing level, so index 0 is the closest cache to the core.

Parameters
cpuCPU to query.
idxCache index, below r_sys_topology_cpu_cache_count.
cacheDestination (must be non-NULL).
Returns
TRUE on success, FALSE if idx is out of range.

◆ r_sys_topology_cpu_cache_count()

rsize r_sys_topology_cpu_cache_count ( const RSysCpu *  cpu)

Number of cache levels reported for cpu.

0 on a platform that exposes no cache topology. Split L1s count as two levels, one R_SYS_CPU_CACHE_DATA and one R_SYS_CPU_CACHE_INSTRUCTION.

◆ r_sys_topology_cpu_cache_cpuset()

rboolean r_sys_topology_cpu_cache_cpuset ( const RSysCpu *  cpu,
rsize  idx,
RBitset *  cpuset 
)

Fill cpuset with the CPUs sharing cpu's idx-th cache.

Includes cpu itself. A private cache yields a single bit; an L3 shared across a package yields every CPU in it.

Parameters
cpuCPU to query.
idxCache index, below r_sys_topology_cpu_cache_count.
cpusetDestination, sized by r_sys_cpuset_max.
Returns
TRUE on success, FALSE if idx is out of range.

◆ r_sys_topology_cpu_core_id()

rsize r_sys_topology_cpu_core_id ( const RSysCpu *  cpu)

Physical core id of cpu, or R_SYS_ID_UNKNOWN.

Only unique within a package: two CPUs are on the same physical core iff their core and package ids match.

◆ r_sys_topology_cpu_max_frequency()

ruint64 r_sys_topology_cpu_max_frequency ( const RSysCpu *  cpu)

Highest clock frequency cpu can be driven at, in kHz.

The hardware ceiling, not the current or the governor-capped rate, and 0 when the platform does not report one (which includes Apple Silicon, and any Linux without cpufreq).

◆ r_sys_topology_cpu_min_frequency()

ruint64 r_sys_topology_cpu_min_frequency ( const RSysCpu *  cpu)

Lowest clock frequency cpu can be driven at, in kHz, or 0 when unknown.

Windows reports only the ceiling, so this is 0 there even when r_sys_topology_cpu_max_frequency is not.

◆ r_sys_topology_cpu_siblings()

rboolean r_sys_topology_cpu_siblings ( const RSysCpu *  cpu,
RBitset *  cpuset 
)

Fill cpuset with the SMT thread siblings of cpu.

The set includes cpu itself, so a machine without SMT (or a platform that does not report siblings) yields a single bit.

Parameters
cpuCPU to query.
cpusetDestination, sized by r_sys_cpuset_max.
Returns
TRUE on success.

◆ r_sys_topology_node_distance()

rsize r_sys_topology_node_distance ( const RSysNode *  node,
rsize  nodeid 
)

Relative cost of reaching nodeid's memory from node.

Normalised the way the firmware tables are: 10 means local, 20 means roughly twice as far, and so on. A node's distance to itself is always 10; 0 means the platform does not expose the matrix (win32 and Darwin never do).

Parameters
nodeNode the access starts from.
nodeidIndex of the node being reached, as returned by r_sys_topology_node_id - not an array position.
Returns
Relative distance, or 0 when unknown.

◆ r_sys_topology_node_id()

rsize r_sys_topology_node_id ( const RSysNode *  node)

NUMA index of node, or R_SYS_ID_UNKNOWN.

Node indices are not dense: a machine whose node 1 has been taken offline hands out nodes 0 and 2, so this is what identifies a node, not its position in r_sys_topology_node.

◆ r_sys_topology_node_total_memory()

rsize r_sys_topology_node_total_memory ( const RSysNode *  node)

Bytes of memory local to node, or 0 when the platform does not expose it.

On a single-node machine this is the machine's total physical memory, which win32 and Darwin do report even though neither has a per-node query.