1/* @title: Domains */
2#pragma once
3#include <smp/core.h>
4#include <stdint.h>
5
6/* NOTE: Definition of a "domain"
7 *
8 * Domains are a first-class topology abstraction used to group CPUs by NUMA
9 * nodes when present or by a fixed number on UMA systems
10 *
11 * The premise: kernels benefit from NUMA awareness, however, the benefits
12 * reaped by NUMA also benefit UMA systems. For instance, memory allocators
13 * that are NUMA aware get better memory locality AND lower lock contention,
14 * however, under UMA, the benefit of lower lock contention, and potentially
15 * better cache performance are helpful.
16 *
17 * Because NUMA logic already exists, we can reuse the logic that handles
18 * NUMA systems with UMA systems, and reap the benefits without NUMA.
19 *
20 */
21
22/* For UMA: TODO: we likely want this to be command line
23 * configurable/adjusted at boot time */
24#define CORES_PER_DOMAIN 4
25
26struct domain {
27 size_t id;
28 size_t num_cores;
29 struct core **cores;
30 struct numa_node *associated_node;
31 struct slab_domain *slab_domain;
32 struct domain_buddy *domain_buddy;
33 struct cpu_mask cpu_mask;
34};
35
36void domain_init(void);
37struct cpu_mask *domain_create_cpu_mask(struct domain *domain);
38void domain_set_cpu_mask(struct cpu_mask *mask, struct domain *domain);
39bool domain_idle(struct domain *domain);
40numa_node_t numa_node_for_cpu(cpu_id_t cpu);
41domain_id_t domain_for_cpu(cpu_id_t cpu);
42void domain_init_after_smp(void);
43void domain_caller_verify(enum topology_caller caller);
44void domain_dump(void);
45
46static inline struct domain *domain_local(enum topology_caller c) {
47 domain_caller_verify(caller: c);
48
49 /* TOPOC_NONE is set here because technically it's not
50 * a big deal if we read the 'wrong CPU' since it's
51 * guaranteed that we're in a domain */
52 return smp_read(TOPC_NONE, domain);
53}
54
55static inline domain_id_t domain_local_id(enum topology_caller c) {
56 return domain_local(c)->id;
57}
58
59#define domain_for_each_domain(dom_) \
60 for (domain_id_t __dom_idx = 0; \
61 __dom_idx < global.domain_count && \
62 (((dom_) = global.domains[__dom_idx]), true); \
63 __dom_idx++)
64
65#define domain_for_each_domain_id(id_) \
66 for (domain_id_t __dom_id_idx = 0; \
67 __dom_id_idx < global.domain_count && \
68 (((id_) = global.domains[__dom_id_idx]->id), true); \
69 __dom_id_idx++)
70
71#define domain_for_each_core(pos_, dom_) \
72 for (size_t __core_idx = 0; __core_idx < (dom_)->num_cores && \
73 (((pos_) = (dom_)->cores[__core_idx]), true); \
74 __core_idx++)
75
76#define domain_for_each_core_id(pos_, dom_) \
77 for (size_t __core_id_idx = 0; \
78 __core_id_idx < (dom_)->num_cores && \
79 (((pos_) = (dom_)->cores[__core_id_idx]->id), true); \
80 __core_id_idx++)
81
82#define domain_for_each_core_local(pos_, clr_) \
83 domain_for_each_core(pos_, smp_core(clr_)->domain)
84