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();
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 __i = 0; \
61 (__dom = global.domains[__i]), (__i < global.domain_count); __i++)
62
63#define domain_for_each_domain_id(__id) \
64 for (domain_id_t __i = 0; \
65 (__id = global.domains[__i]->id), (__i < global.domain_count); __i++)
66
67#define domain_for_each_core(__pos, __dom) \
68 for (domain_id_t __i = 0; \
69 (__pos = __dom->cores[__i]), (__i < __dom->num_cores); __i++)
70
71#define domain_for_each_core_id(__pos, __dom) \
72 for (domain_id_t __i = 0; \
73 (__pos = __dom->cores[__i]->id), (__i < __dom->num_cores); __i++)
74
75#define domain_for_each_core_local(__clr, __pos) \
76 domain_for_each_core(__pos, smp_core(__clr)->domain)
77