1/* @title: Topology */
2#pragma once
3#include <stdatomic.h>
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7#include <types/types.h>
8
9enum topology_level {
10 TOPOLOGY_LEVEL_SMT, /* Symmetric multiprocessing threads */
11 TOPOLOGY_LEVEL_CORE, /* SMTs under a core */
12 TOPOLOGY_LEVEL_NUMA, /* NUMA node */
13 TOPOLOGY_LEVEL_LLC, /* Last level cache (some processors
14 * have multiple L3 caches for a given
15 * physical processor) */
16 TOPOLOGY_LEVEL_PACKAGE, /* Physical processor in a socket */
17 TOPOLOGY_LEVEL_MACHINE, /* All processors in a machine */
18 TOPOLOGY_LEVEL_MAX, /* count */
19 TOPOLOGY_LEVEL_COUNT = TOPOLOGY_LEVEL_MAX
20};
21
22struct cpu_mask {
23 bool uses_large;
24 union {
25 _Atomic uint64_t small;
26 _Atomic uint64_t *large;
27 };
28 size_t nbits;
29};
30#define CPU_MASK_WORD_BITS 64
31#define CPU_MASK_WORDS(nbits) \
32 (((nbits) + CPU_MASK_WORD_BITS - 1) / CPU_MASK_WORD_BITS)
33
34struct topology_cache_info {
35 uint8_t level; /* 1, 2, 3 */
36 uint8_t type; /* Data, unified, instruction */
37 uint32_t size_kb;
38 uint32_t line_size;
39 uint32_t cores_sharing; /* Who shares this */
40};
41
42struct topology_package_info {
43 uint32_t package_id;
44 struct cpu_mask cores;
45};
46
47struct topology_node {
48 enum topology_level level;
49 uint64_t id; /* Index in this node */
50 uint64_t parent; /* Parent node index, -1 for root */
51 struct topology_node *parent_node;
52 int32_t first_child; /* For cores this is in the cores array.
53 * For NUMA this is also in the cores array.
54 * For LLC this is in the numa array.
55 * For package this is LLC.
56 * For machine this is package. */
57 int32_t nr_children;
58
59 struct cpu_mask cpus;
60 struct cpu_mask idle;
61 struct cpu_mask rt_shed_rq_active; /* For RT scheduler */
62
63 struct core *core; /* Pointer to this node's `core` struct */
64
65 union {
66 struct numa_node *numa;
67 struct topology_cache_info *cache;
68 struct topology_package_info *package;
69 } data;
70};
71
72struct topology {
73 struct topology_node *level[TOPOLOGY_LEVEL_MAX];
74 uint16_t count[TOPOLOGY_LEVEL_MAX];
75};
76
77/* TODO: move CPUmask into its own header */
78struct cpu_mask *cpu_mask_create(void);
79bool cpu_mask_init(struct cpu_mask *m, size_t nbits);
80void cpu_mask_set(struct cpu_mask *m, size_t cpu);
81void cpu_mask_set_all(struct cpu_mask *m);
82void cpu_mask_clear(struct cpu_mask *m, size_t cpu);
83bool cpu_mask_test(const struct cpu_mask *m, size_t cpu);
84void cpu_mask_or(struct cpu_mask *dst, const struct cpu_mask *b);
85bool cpu_mask_empty(const struct cpu_mask *mask);
86void cpu_mask_clear_all(struct cpu_mask *m);
87size_t cpu_mask_popcount(struct cpu_mask *m);
88void cpu_mask_free(struct cpu_mask *m);
89void cpu_mask_deinit(struct cpu_mask *m);
90#define cpu_mask_for_each(iter, mask) \
91 for (iter = 0; iter < (mask).nbits; ++iter) \
92 if ((mask).uses_large \
93 ? atomic_load(&(mask).large[iter / CPU_MASK_WORD_BITS]) & \
94 (1ULL << (iter % CPU_MASK_WORD_BITS)) \
95 : atomic_load(&(mask).small) & (1ULL << iter))
96
97void topology_mark_core_idle(cpu_id_t cpu_id, bool idle);
98struct core *topology_find_idle_core(struct core *local_core,
99 enum topology_level max_search);
100struct core **topology_get_smts_under_numa(struct topology_node *numa,
101 size_t *count);
102const char *topology_level_name(enum topology_level l);
103