scx_wd40/
domain.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2
3// This software may be used and distributed according to the terms of the
4// GNU General Public License version 2.
5use std::collections::BTreeMap;
6
7use crate::bpf_skel::*;
8use anyhow::Result;
9use scx_utils::Cpumask;
10use scx_utils::Topology;
11use std::sync::Arc;
12use std::sync::Mutex;
13
14#[derive(Clone, Debug)]
15pub struct Domain {
16    id: usize,
17    mask: Cpumask,
18    pub ctx: Arc<Mutex<Option<*mut types::dom_ctx>>>,
19}
20
21impl Domain {
22    /// Get the Domain's ID.
23    pub fn id(&self) -> usize {
24        self.id
25    }
26
27    /// Get a copy of the domain's cpumask.
28    pub fn mask(&self) -> Cpumask {
29        self.mask.clone()
30    }
31
32    /// Get a raw slice of the domain's cpumask as a set of one or more u64
33    /// variables whose bits represent CPUs in the mask.
34    pub fn mask_slice(&self) -> &[u64] {
35        self.mask.as_raw_slice()
36    }
37
38    /// The number of CPUs in the domain.
39    pub fn weight(&self) -> usize {
40        self.mask.weight()
41    }
42
43    pub fn ctx(&self) -> Option<&mut types::dom_ctx> {
44        let domc = self.ctx.lock().unwrap();
45
46        // Ideally we would be storing the dom_ctx as a reference in struct Domain,
47        // in the first place. Rust makes embedding references to structs into other
48        // structs very difficult, so this is more pragmatic.
49        match *domc {
50            Some(ptr) => Some(unsafe { &mut *(ptr) }),
51            None => None,
52        }
53    }
54}
55
56#[derive(Debug)]
57pub struct DomainGroup {
58    doms: BTreeMap<usize, Domain>,
59    dom_numa_map: BTreeMap<usize, usize>,
60    num_numa_nodes: usize,
61    span: Cpumask,
62}
63
64impl DomainGroup {
65    pub fn new(top: &Topology) -> Result<Self> {
66        let mut span = Cpumask::new();
67        let mut dom_numa_map = BTreeMap::new();
68        // Track the domain ID separate from the LLC ID, because LLC IDs can
69        // have gaps if there are offlined CPUs, and domain IDs need to be
70        // contiguous (at least for now, until we can update libraries to not
71        // return vectors of domain values).
72        let mut dom_id = 0;
73        let mut doms: BTreeMap<usize, Domain> = BTreeMap::new();
74        for (node_id, node) in &top.nodes {
75            for (_, llc) in node.llcs.iter() {
76                let mask = llc.span.clone();
77                span |= &mask;
78                doms.insert(
79                    dom_id,
80                    Domain {
81                        id: dom_id,
82                        mask,
83                        ctx: Arc::new(Mutex::new(None)),
84                    },
85                );
86                dom_numa_map.insert(dom_id, *node_id);
87                dom_id += 1;
88            }
89        }
90
91        Ok(Self {
92            doms,
93            dom_numa_map,
94            num_numa_nodes: top.nodes.len(),
95            span,
96        })
97    }
98
99    pub fn numa_doms(&self, numa_id: &usize) -> Vec<Domain> {
100        let mut numa_doms = Vec::new();
101        // XXX dom_numa_map never gets updated even if we cross NUMA nodes
102        for (d_id, n_id) in self.dom_numa_map.iter() {
103            if n_id == numa_id {
104                let dom = self.doms.get(d_id).unwrap();
105                numa_doms.push(dom.clone());
106            }
107        }
108
109        numa_doms
110    }
111
112    pub fn doms(&self) -> &BTreeMap<usize, Domain> {
113        &self.doms
114    }
115
116    pub fn nr_doms(&self) -> usize {
117        self.doms.len()
118    }
119
120    pub fn nr_nodes(&self) -> usize {
121        self.num_numa_nodes
122    }
123
124    pub fn dom_numa_id(&self, dom_id: &usize) -> Option<usize> {
125        self.dom_numa_map.get(dom_id).copied()
126    }
127
128    pub fn weight(&self) -> usize {
129        self.span.weight()
130    }
131}