1pub use crate::bpf_skel::types;
10
11use scx_utils::Topology;
12use scx_utils::{Core, Llc};
13
14use std::ffi::CString;
15use std::os::raw::c_ulong;
16use std::sync::Arc;
17
18use anyhow::bail;
19use anyhow::Result;
20
21use libbpf_rs::libbpf_sys;
22use libbpf_rs::AsRawLibbpf;
23use libbpf_rs::Object;
24use libbpf_rs::ProgramInput;
25use libbpf_rs::ProgramMut;
26
27const MAX_CPU_SUPPORTED: usize = 640;
32
33#[derive(Debug)]
35pub struct ArenaLib<'a> {
36 task_size: usize,
37 obj: &'a mut Object,
38}
39
40impl<'a> ArenaLib<'a> {
41 const MAX_CPU_ARRSZ: usize = (MAX_CPU_SUPPORTED + 63) / 64;
43
44 const STATIC_ALLOC_PAGES_GRANULARITY: c_ulong = 8;
46
47 fn run_prog_by_name(&self, name: &str, input: ProgramInput) -> Result<i32> {
48 let c_name = CString::new(name)?;
49 let ptr = unsafe {
50 libbpf_sys::bpf_object__find_program_by_name(
51 self.obj.as_libbpf_object().as_ptr(),
52 c_name.as_ptr(),
53 )
54 };
55 if ptr as u64 == 0 as u64 {
56 bail!("No program with name {} found in object", name);
57 }
58
59 let bpfprog = unsafe { &mut *ptr };
60 let prog = ProgramMut::new_mut(bpfprog);
61
62 let output = prog.test_run(input)?;
63
64 return Ok(output.return_value as i32);
68 }
69
70 fn setup_arena(&self) -> Result<()> {
72 let mut args = types::arena_init_args {
76 static_pages: Self::STATIC_ALLOC_PAGES_GRANULARITY as c_ulong,
77 task_ctx_size: self.task_size as c_ulong,
78 };
79
80 let input = ProgramInput {
81 context_in: Some(unsafe {
82 std::slice::from_raw_parts_mut(
83 &mut args as *mut _ as *mut u8,
84 std::mem::size_of_val(&args),
85 )
86 }),
87 ..Default::default()
88 };
89
90 let ret = self.run_prog_by_name("arena_init", input)?;
91 if ret != 0 {
92 bail!("Could not initialize arenas, setup_arenas returned {}", ret);
93 }
94
95 Ok(())
96 }
97
98 fn setup_topology_node(&self, mask: &[u64]) -> Result<()> {
99 let mut args = types::arena_alloc_mask_args {
100 bitmap: 0 as c_ulong,
101 };
102
103 let input = ProgramInput {
104 context_in: Some(unsafe {
105 std::slice::from_raw_parts_mut(
106 &mut args as *mut _ as *mut u8,
107 std::mem::size_of_val(&args),
108 )
109 }),
110 ..Default::default()
111 };
112
113 let ret = self.run_prog_by_name("arena_alloc_mask", input)?;
114
115 if ret != 0 {
116 bail!(
117 "Could not initialize arenas, setup_topology_node returned {}",
118 ret
119 );
120 }
121
122 let ptr = unsafe { std::mem::transmute::<u64, &mut [u64; MAX_CPU_SUPPORTED]>(args.bitmap) };
123
124 let (valid_mask, _) = ptr.split_at_mut(mask.len());
125 valid_mask.clone_from_slice(mask);
126
127 let mut args = types::arena_topology_node_init_args {
128 bitmap: args.bitmap as c_ulong,
129 data_size: 0 as c_ulong,
130 id: 0 as c_ulong,
131 };
132
133 let input = ProgramInput {
134 context_in: Some(unsafe {
135 std::slice::from_raw_parts_mut(
136 &mut args as *mut _ as *mut u8,
137 std::mem::size_of_val(&args),
138 )
139 }),
140 ..Default::default()
141 };
142
143 let ret = self.run_prog_by_name("arena_topology_node_init", input)?;
144 if ret != 0 {
145 bail!("arena_topology_node_init returned {}", ret);
146 }
147
148 Ok(())
149 }
150
151 fn setup_topology(&self) -> Result<()> {
152 let topo = Topology::new().expect("Failed to build host topology");
153
154 self.setup_topology_node(topo.span.as_raw_slice())?;
155
156 for (_, node) in topo.nodes {
157 self.setup_topology_node(node.span.as_raw_slice())?;
158 }
159
160 for (_, llc) in topo.all_llcs {
161 self.setup_topology_node(
162 Arc::<Llc>::into_inner(llc)
163 .expect("missing llc")
164 .span
165 .as_raw_slice(),
166 )?;
167 }
168
169 for (_, core) in topo.all_cores {
170 self.setup_topology_node(
171 Arc::<Core>::into_inner(core)
172 .expect("missing core")
173 .span
174 .as_raw_slice(),
175 )?;
176 }
177 for (_, cpu) in topo.all_cpus {
178 let mut mask = [0; Self::MAX_CPU_ARRSZ - 1];
179 mask[cpu.id.checked_shr(64).unwrap_or(0)] |= 1 << (cpu.id % 64);
180 self.setup_topology_node(&mask)?;
181 }
182
183 Ok(())
184 }
185
186 pub fn init(obj: &'a mut Object, task_size: usize, nr_cpus: usize) -> Result<Self> {
188 if nr_cpus >= MAX_CPU_SUPPORTED {
189 bail!("Scheduler specifies too many CPUs");
190 }
191
192 Ok(Self { task_size, obj })
193 }
194
195 pub fn setup(&self) -> Result<()> {
197 self.setup_arena()?;
198 self.setup_topology()?;
199
200 Ok(())
201 }
202}