CPUInfo

CPUInfo collects information on CPU-Memory subsystem, and builds
hierarchy which consists of following objects:

CPUInfo is purely hierarchial: Nodes -> Chip -> Core -> Strand. Cache devices
may be bound to Core or to Chip objects.

Each object has corresponding structure which contains its properties and
hi_cpu_objtype_t value, see following table:

Type structure hi_cpu_objtype_t Naming schema
Node hi_cpu_node_t HI_CPU_NODE node:NODEID
Chip hi_cpu_chip_t HI_CPU_CHIP chip:CHIPID
Core (not used) HI_CPU_CORE core:CHIPID:COREID
Strand (not used) HI_CPU_STRAND strand:CHIPID:COREID:STRANDID
Cache hi_cpu_cache_t HI_CPU_CACHE cache:LEVEL:CACHEID where LEVEL is l1, l2, l3 or tlb

Linux

Reads information about cpus (that are considered as NUMA-nodes)
from SYSFS directory /sys/devices/system/node. Frequency and CPU
model is provided by /proc/cpuinfo

CPU frequency is taken from cpufreq driver if from /sys/devices/system/cpu.
If it is not possible, CPUInfo reads frequency /proc/cpuinfo file.

To determine cache relationship with CPU objects it uses shared_cpu_list file
on SYSFS.

NOTE: Node ids are also reliable on Linux, so they may be used in mbind() calls

Solaris

Uses liblgrp to gather NUMA nodes, kstat to collect information about CPUs and
picl daemon to find caches.

picl daemon only operates with processor instances, so there is hard to determine if
cache is assigned to chip or core. So code uses simple assumption: it compares cache_id
from kstat within chip. If it differs, last level cache is individual for cores,
otherwise it is shared between them.

Windows

Uses Windows registry HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\
to get processor frequency and name (alterable by user, but most reliable way
Windows provides).

Whole logic is build upon GetLogicalProcessorInformation() call which also
provides relationships

NOTE: Windows 7 and 2008 R2 (64-bit versions) support processor groups
which allow them to go beyound 64 processor limit. CPUInfo doesn't support
them, so it is limited to 64 bit

NOTE: Windows provides only free amount of memory on per-node basis,
so we currently use this value also for total amount memory (wrong!)

Functions

HI_CPU_CACHEID


Generates ID of the cache

#define HI_CPU_CACHEID(level, type)

HI_CPU_FROM_OBJ, HI_CPU_PARENT_OBJ, HI_CPU_PARENT, HI_CPU_TO_OBJ


Conversion macros

#define HI_CPU_FROM_OBJ(object)
#define HI_CPU_TO_OBJ(object)
#define HI_CPU_PARENT_OBJ(object)
#define HI_CPU_PARENT(object)

hi_cpu_detach, hi_cpu_attach

public


Attaches/detaches CPU objects

REFERENCE
hi_obj_attach
hi_obj_detach

STATIC_INLINE void hi_cpu_attach(hi_cpu_object_t* object, hi_cpu_object_t* parent) 
STATIC_INLINE void hi_cpu_detach(hi_cpu_object_t* object, hi_cpu_object_t* parent) 

hi_cpu_find

public


Find cpu object by it's name

ARGUMENTS

RETURN VALUES
cpu object descriptor or NULL if it wasn't found

REFERENCE
hi_cpu_find_byid

STATIC_INLINE hi_cpu_object_t* hi_cpu_find(const char* name) 

hi_cpu_find_byid


Find CPU object by it's type and id. More confortable than searching by object name.
Walks global list, than walk parents if needed

If parent == NULL, parents aren't checked

void* hi_cpu_find_byid(hi_cpu_object_t* parent, hi_cpu_objtype_t type, int id)

hi_cpu_list

public

STATIC_INLINE list_head_t* hi_cpu_list(boolean_t reprobe) 

hi_cpu_num_cpus, hi_cpu_num_cores, hi_cpu_mem_total

public


Returns total count of Strands, Cores or memory available to system

LIBEXPORT int hi_cpu_num_cpus(void)
LIBEXPORT int hi_cpu_num_cores(void)
LIBEXPORT size_t hi_cpu_mem_total(void)

hi_cpu_mask

public


Create cpumask for cpu object

For caches processes nearest core/chip object (parent)
For other cpu objects - processes all child strands
For null creates mask that includes all strands

LIBEXPORT int hi_cpu_mask(hi_cpu_object_t* object, cpumask_t* mask)

Types

hi_cpu_cache_type_t

typedef enum {
    HI_CPU_CACHE_UNIFIED,
    HI_CPU_CACHE_DATA,
    HI_CPU_CACHE_INSTRUCTION,
} hi_cpu_cache_type_t;

hi_cpu_objtype_t

typedef enum {
    HI_CPU_NODE,
    HI_CPU_CHIP,
    HI_CPU_CORE,
    HI_CPU_STRAND,
    HI_CPU_CACHE
} hi_cpu_objtype_t;

hi_cpu_stat_t

typedef struct {
    uint32_t nodes;

    uint32_t mem_total;
    uint32_t mem_free;
} hi_cpu_stat_t;

hi_cpu_node_t


Descriptor of Node

MEMBERS

typedef struct {
    uint64_t cm_mem_total;
    uint64_t cm_mem_free;
} hi_cpu_node_t;

hi_cpu_chip_t


Descriptor of Chip

MEMBERS

typedef struct {
    AUTOSTRING char* cp_name;
    uint64_t cp_freq;
} hi_cpu_chip_t;

hi_cpu_core_t

typedef struct {
    int unused;
} hi_cpu_core_t;

hi_cpu_strand_t

typedef struct {
    int unused;
} hi_cpu_strand_t;

hi_cpu_cache_t


Descriptor of Cache

MEMBERS

NOTES
TLB units also considered as cache objects, but this information is rarely provided by OS (Solaris is best).

typedef struct {
    int                    c_level;
    hi_cpu_cache_type_t c_type;
    uint32_t               c_size;
    int                 c_associativity;
    union {
        int                line;
        long            page[4];
    } c_unit_size;
} hi_cpu_cache_t;

typedef struct hi_cpu_object


Main CPUInfo descriptor

Each object as id which is unique across all objects of that type (except for caches).

Most of object ids are generated by HostInfo, but for Strand objects they are
taken from operating system, so they may be reused in various API calls like CPU mask
creation.

MEMBERS

typedef struct hi_cpu_object {
    hi_object_header_t        hdr;
#define c_cpu_name          hdr.name
    
    int                     id;
    hi_cpu_objtype_t         type;

    union {
        hi_cpu_node_t node;
        hi_cpu_chip_t chip;
        hi_cpu_core_t core;
        hi_cpu_strand_t strand;
        hi_cpu_cache_t cache;
    };
} hi_cpu_object_t;