xref: /aosp_15_r20/external/crosvm/devices/src/virtcpufreq_v2.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicU32;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
11*bb4ee6a4SAndroid Build Coastguard Worker 
12*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::sched_attr;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::sched_setattr;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::set_cpu_affinity;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::Error;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::Timer;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::TimerTrait;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
25*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
26*bb4ee6a4SAndroid Build Coastguard Worker 
27*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::CrosvmDeviceId;
28*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusAccessInfo;
29*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusDevice;
30*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceId;
31*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
32*bb4ee6a4SAndroid Build Coastguard Worker 
33*bb4ee6a4SAndroid Build Coastguard Worker const CPUFREQ_GOV_SCALE_FACTOR_DEFAULT: u32 = 100;
34*bb4ee6a4SAndroid Build Coastguard Worker const CPUFREQ_GOV_SCALE_FACTOR_SCHEDUTIL: u32 = 80;
35*bb4ee6a4SAndroid Build Coastguard Worker 
36*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_FLAG_RESET_ON_FORK: u64 = 0x1;
37*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_FLAG_KEEP_POLICY: u64 = 0x08;
38*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_FLAG_KEEP_PARAMS: u64 = 0x10;
39*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_FLAG_UTIL_CLAMP_MIN: u64 = 0x20;
40*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_FLAG_UTIL_CLAMP_MAX: u64 = 0x40;
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker const VCPUFREQ_CUR_PERF: u32 = 0x0;
43*bb4ee6a4SAndroid Build Coastguard Worker const VCPUFREQ_SET_PERF: u32 = 0x4;
44*bb4ee6a4SAndroid Build Coastguard Worker const VCPUFREQ_FREQTBL_LEN: u32 = 0x8;
45*bb4ee6a4SAndroid Build Coastguard Worker const VCPUFREQ_FREQTBL_SEL: u32 = 0xc;
46*bb4ee6a4SAndroid Build Coastguard Worker const VCPUFREQ_FREQTBL_RD: u32 = 0x10;
47*bb4ee6a4SAndroid Build Coastguard Worker const VCPUFREQ_PERF_DOMAIN: u32 = 0x14;
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_FLAG_KEEP_ALL: u64 = SCHED_FLAG_KEEP_POLICY | SCHED_FLAG_KEEP_PARAMS;
50*bb4ee6a4SAndroid Build Coastguard Worker const SCHED_CAPACITY_SCALE: u32 = 1024;
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker // Timer values in microseconds
53*bb4ee6a4SAndroid Build Coastguard Worker const MIN_TIMER_US: u32 = 75;
54*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_OVERHEAD_US: u32 = 15;
55*bb4ee6a4SAndroid Build Coastguard Worker 
56*bb4ee6a4SAndroid Build Coastguard Worker /// Upstream linux compatible version of the virtual cpufreq interface
57*bb4ee6a4SAndroid Build Coastguard Worker pub struct VirtCpufreqV2 {
58*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_freq_table: Vec<u32>,
59*bb4ee6a4SAndroid Build Coastguard Worker     pcpu_fmax: u32,
60*bb4ee6a4SAndroid Build Coastguard Worker     pcpu_capacity: u32,
61*bb4ee6a4SAndroid Build Coastguard Worker     pcpu: u32,
62*bb4ee6a4SAndroid Build Coastguard Worker     util_factor: u32,
63*bb4ee6a4SAndroid Build Coastguard Worker     freqtbl_sel: u32,
64*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_domain: u32,
65*bb4ee6a4SAndroid Build Coastguard Worker     domain_uclamp_min: Option<File>,
66*bb4ee6a4SAndroid Build Coastguard Worker     domain_uclamp_max: Option<File>,
67*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_fmax: u32,
68*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_capacity: u32,
69*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_relative_capacity: u32,
70*bb4ee6a4SAndroid Build Coastguard Worker     worker: Option<WorkerThread<()>>,
71*bb4ee6a4SAndroid Build Coastguard Worker     timer: Arc<Mutex<Timer>>,
72*bb4ee6a4SAndroid Build Coastguard Worker     vm_ctrl: Arc<Mutex<Tube>>,
73*bb4ee6a4SAndroid Build Coastguard Worker     pcpu_min_cap: u32,
74*bb4ee6a4SAndroid Build Coastguard Worker     /// The largest(or the last) pCPU index to be used by all the vCPUs. This index is used to
75*bb4ee6a4SAndroid Build Coastguard Worker     /// figure out the proper placement of the throttle workers which are placed on pCPUs right
76*bb4ee6a4SAndroid Build Coastguard Worker     /// after the last pCPU being used the vCPUs. Throttle workers require their own exclusive
77*bb4ee6a4SAndroid Build Coastguard Worker     /// pCPU allocation and this ensure that the workers are placed contiguously and makes it
78*bb4ee6a4SAndroid Build Coastguard Worker     /// easier for user to manage pCPU allocations when running multiple instances on a large
79*bb4ee6a4SAndroid Build Coastguard Worker     /// server.
80*bb4ee6a4SAndroid Build Coastguard Worker     largest_pcpu_idx: usize,
81*bb4ee6a4SAndroid Build Coastguard Worker     //TODO: Put the shared_domain_members in a struct
82*bb4ee6a4SAndroid Build Coastguard Worker     shared_domain_vcpus: Vec<usize>,
83*bb4ee6a4SAndroid Build Coastguard Worker     shared_domain_perf: Arc<AtomicU32>,
84*bb4ee6a4SAndroid Build Coastguard Worker }
85*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_info(cpu_id: u32, property: &str) -> Result<u32, Error>86*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_info(cpu_id: u32, property: &str) -> Result<u32, Error> {
87*bb4ee6a4SAndroid Build Coastguard Worker     let path = format!("/sys/devices/system/cpu/cpu{cpu_id}/{property}");
88*bb4ee6a4SAndroid Build Coastguard Worker     std::fs::read_to_string(path)?
89*bb4ee6a4SAndroid Build Coastguard Worker         .trim()
90*bb4ee6a4SAndroid Build Coastguard Worker         .parse()
91*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::new(libc::EINVAL))
92*bb4ee6a4SAndroid Build Coastguard Worker }
93*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_info_str(cpu_id: u32, property: &str) -> Result<String, Error>94*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_info_str(cpu_id: u32, property: &str) -> Result<String, Error> {
95*bb4ee6a4SAndroid Build Coastguard Worker     let path = format!("/sys/devices/system/cpu/cpu{cpu_id}/{property}");
96*bb4ee6a4SAndroid Build Coastguard Worker     std::fs::read_to_string(path).map_err(|_| Error::new(libc::EINVAL))
97*bb4ee6a4SAndroid Build Coastguard Worker }
98*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_capacity(cpu_id: u32) -> Result<u32, Error>99*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_capacity(cpu_id: u32) -> Result<u32, Error> {
100*bb4ee6a4SAndroid Build Coastguard Worker     get_cpu_info(cpu_id, "cpu_capacity")
101*bb4ee6a4SAndroid Build Coastguard Worker }
102*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_maxfreq_khz(cpu_id: u32) -> Result<u32, Error>103*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_maxfreq_khz(cpu_id: u32) -> Result<u32, Error> {
104*bb4ee6a4SAndroid Build Coastguard Worker     get_cpu_info(cpu_id, "cpufreq/cpuinfo_max_freq")
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_minfreq_khz(cpu_id: u32) -> Result<u32, Error>107*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_minfreq_khz(cpu_id: u32) -> Result<u32, Error> {
108*bb4ee6a4SAndroid Build Coastguard Worker     get_cpu_info(cpu_id, "cpufreq/cpuinfo_min_freq")
109*bb4ee6a4SAndroid Build Coastguard Worker }
110*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_curfreq_khz(cpu_id: u32) -> Result<u32, Error>111*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_curfreq_khz(cpu_id: u32) -> Result<u32, Error> {
112*bb4ee6a4SAndroid Build Coastguard Worker     get_cpu_info(cpu_id, "cpufreq/scaling_cur_freq")
113*bb4ee6a4SAndroid Build Coastguard Worker }
114*bb4ee6a4SAndroid Build Coastguard Worker 
get_cpu_util_factor(cpu_id: u32) -> Result<u32, Error>115*bb4ee6a4SAndroid Build Coastguard Worker fn get_cpu_util_factor(cpu_id: u32) -> Result<u32, Error> {
116*bb4ee6a4SAndroid Build Coastguard Worker     let gov = get_cpu_info_str(cpu_id, "cpufreq/scaling_governor")?;
117*bb4ee6a4SAndroid Build Coastguard Worker     match gov.trim() {
118*bb4ee6a4SAndroid Build Coastguard Worker         "schedutil" => Ok(CPUFREQ_GOV_SCALE_FACTOR_SCHEDUTIL),
119*bb4ee6a4SAndroid Build Coastguard Worker         _ => Ok(CPUFREQ_GOV_SCALE_FACTOR_DEFAULT),
120*bb4ee6a4SAndroid Build Coastguard Worker     }
121*bb4ee6a4SAndroid Build Coastguard Worker }
122*bb4ee6a4SAndroid Build Coastguard Worker 
123*bb4ee6a4SAndroid Build Coastguard Worker impl VirtCpufreqV2 {
new( pcpu: u32, vcpu_freq_table: Vec<u32>, vcpu_domain_path: Option<PathBuf>, vcpu_domain: u32, vcpu_capacity: u32, largest_pcpu_idx: usize, vm_ctrl: Arc<Mutex<Tube>>, shared_domain_vcpus: Vec<usize>, shared_domain_perf: Arc<AtomicU32>, ) -> Self124*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
125*bb4ee6a4SAndroid Build Coastguard Worker         pcpu: u32,
126*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_freq_table: Vec<u32>,
127*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_domain_path: Option<PathBuf>,
128*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_domain: u32,
129*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_capacity: u32,
130*bb4ee6a4SAndroid Build Coastguard Worker         largest_pcpu_idx: usize,
131*bb4ee6a4SAndroid Build Coastguard Worker         vm_ctrl: Arc<Mutex<Tube>>,
132*bb4ee6a4SAndroid Build Coastguard Worker         shared_domain_vcpus: Vec<usize>,
133*bb4ee6a4SAndroid Build Coastguard Worker         shared_domain_perf: Arc<AtomicU32>,
134*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Self {
135*bb4ee6a4SAndroid Build Coastguard Worker         let pcpu_capacity = get_cpu_capacity(pcpu).expect("Error reading capacity");
136*bb4ee6a4SAndroid Build Coastguard Worker         let pcpu_fmax = get_cpu_maxfreq_khz(pcpu).expect("Error reading max freq");
137*bb4ee6a4SAndroid Build Coastguard Worker         let util_factor = get_cpu_util_factor(pcpu).expect("Error getting util factor");
138*bb4ee6a4SAndroid Build Coastguard Worker         let freqtbl_sel = 0;
139*bb4ee6a4SAndroid Build Coastguard Worker         let mut domain_uclamp_min = None;
140*bb4ee6a4SAndroid Build Coastguard Worker         let mut domain_uclamp_max = None;
141*bb4ee6a4SAndroid Build Coastguard Worker         // The vcpu_capacity passed in is normalized for frequency, reverse the normalization to
142*bb4ee6a4SAndroid Build Coastguard Worker         // get the performance per clock ratio between the vCPU and the pCPU its running on. This
143*bb4ee6a4SAndroid Build Coastguard Worker         // "relative capacity" is an approximation of the delta in IPC (Instructions per Cycle)
144*bb4ee6a4SAndroid Build Coastguard Worker         // between the pCPU vs vCPU running a usecase containing a mix of instruction types.
145*bb4ee6a4SAndroid Build Coastguard Worker         let vcpu_fmax = vcpu_freq_table.clone().into_iter().max().unwrap();
146*bb4ee6a4SAndroid Build Coastguard Worker         let vcpu_relative_capacity =
147*bb4ee6a4SAndroid Build Coastguard Worker             u32::try_from(u64::from(vcpu_capacity) * u64::from(pcpu_fmax) / u64::from(vcpu_fmax))
148*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
149*bb4ee6a4SAndroid Build Coastguard Worker         let pcpu_min_cap =
150*bb4ee6a4SAndroid Build Coastguard Worker             get_cpu_minfreq_khz(pcpu).expect("Error reading min freq") * pcpu_capacity / pcpu_fmax;
151*bb4ee6a4SAndroid Build Coastguard Worker 
152*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(cgroup_path) = &vcpu_domain_path {
153*bb4ee6a4SAndroid Build Coastguard Worker             domain_uclamp_min = Some(
154*bb4ee6a4SAndroid Build Coastguard Worker                 File::create(cgroup_path.join("cpu.uclamp.min")).unwrap_or_else(|err| {
155*bb4ee6a4SAndroid Build Coastguard Worker                     panic!(
156*bb4ee6a4SAndroid Build Coastguard Worker                         "Err: {}, Unable to open: {}",
157*bb4ee6a4SAndroid Build Coastguard Worker                         err,
158*bb4ee6a4SAndroid Build Coastguard Worker                         cgroup_path.join("cpu.uclamp.min").display()
159*bb4ee6a4SAndroid Build Coastguard Worker                     )
160*bb4ee6a4SAndroid Build Coastguard Worker                 }),
161*bb4ee6a4SAndroid Build Coastguard Worker             );
162*bb4ee6a4SAndroid Build Coastguard Worker             domain_uclamp_max = Some(
163*bb4ee6a4SAndroid Build Coastguard Worker                 File::create(cgroup_path.join("cpu.uclamp.max")).unwrap_or_else(|err| {
164*bb4ee6a4SAndroid Build Coastguard Worker                     panic!(
165*bb4ee6a4SAndroid Build Coastguard Worker                         "Err: {}, Unable to open: {}",
166*bb4ee6a4SAndroid Build Coastguard Worker                         err,
167*bb4ee6a4SAndroid Build Coastguard Worker                         cgroup_path.join("cpu.uclamp.max").display()
168*bb4ee6a4SAndroid Build Coastguard Worker                     )
169*bb4ee6a4SAndroid Build Coastguard Worker                 }),
170*bb4ee6a4SAndroid Build Coastguard Worker             );
171*bb4ee6a4SAndroid Build Coastguard Worker         }
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker         VirtCpufreqV2 {
174*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_freq_table,
175*bb4ee6a4SAndroid Build Coastguard Worker             pcpu_fmax,
176*bb4ee6a4SAndroid Build Coastguard Worker             pcpu_capacity,
177*bb4ee6a4SAndroid Build Coastguard Worker             pcpu,
178*bb4ee6a4SAndroid Build Coastguard Worker             util_factor,
179*bb4ee6a4SAndroid Build Coastguard Worker             freqtbl_sel,
180*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_domain,
181*bb4ee6a4SAndroid Build Coastguard Worker             domain_uclamp_min,
182*bb4ee6a4SAndroid Build Coastguard Worker             domain_uclamp_max,
183*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_fmax,
184*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_capacity,
185*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_relative_capacity,
186*bb4ee6a4SAndroid Build Coastguard Worker             worker: None,
187*bb4ee6a4SAndroid Build Coastguard Worker             timer: Arc::new(Mutex::new(Timer::new().expect("failed to create Timer"))),
188*bb4ee6a4SAndroid Build Coastguard Worker             vm_ctrl,
189*bb4ee6a4SAndroid Build Coastguard Worker             pcpu_min_cap,
190*bb4ee6a4SAndroid Build Coastguard Worker             largest_pcpu_idx,
191*bb4ee6a4SAndroid Build Coastguard Worker             shared_domain_vcpus,
192*bb4ee6a4SAndroid Build Coastguard Worker             shared_domain_perf,
193*bb4ee6a4SAndroid Build Coastguard Worker         }
194*bb4ee6a4SAndroid Build Coastguard Worker     }
195*bb4ee6a4SAndroid Build Coastguard Worker }
196*bb4ee6a4SAndroid Build Coastguard Worker 
197*bb4ee6a4SAndroid Build Coastguard Worker impl BusDevice for VirtCpufreqV2 {
device_id(&self) -> DeviceId198*bb4ee6a4SAndroid Build Coastguard Worker     fn device_id(&self) -> DeviceId {
199*bb4ee6a4SAndroid Build Coastguard Worker         CrosvmDeviceId::VirtCpufreq.into()
200*bb4ee6a4SAndroid Build Coastguard Worker     }
201*bb4ee6a4SAndroid Build Coastguard Worker 
debug_label(&self) -> String202*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> String {
203*bb4ee6a4SAndroid Build Coastguard Worker         "VirtCpufreq Device".to_owned()
204*bb4ee6a4SAndroid Build Coastguard Worker     }
205*bb4ee6a4SAndroid Build Coastguard Worker 
read(&mut self, info: BusAccessInfo, data: &mut [u8])206*bb4ee6a4SAndroid Build Coastguard Worker     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
207*bb4ee6a4SAndroid Build Coastguard Worker         if data.len() != std::mem::size_of::<u32>() {
208*bb4ee6a4SAndroid Build Coastguard Worker             warn!(
209*bb4ee6a4SAndroid Build Coastguard Worker                 "{}: unsupported read length {}, only support 4bytes read",
210*bb4ee6a4SAndroid Build Coastguard Worker                 self.debug_label(),
211*bb4ee6a4SAndroid Build Coastguard Worker                 data.len()
212*bb4ee6a4SAndroid Build Coastguard Worker             );
213*bb4ee6a4SAndroid Build Coastguard Worker             return;
214*bb4ee6a4SAndroid Build Coastguard Worker         }
215*bb4ee6a4SAndroid Build Coastguard Worker 
216*bb4ee6a4SAndroid Build Coastguard Worker         let val = match info.offset as u32 {
217*bb4ee6a4SAndroid Build Coastguard Worker             VCPUFREQ_CUR_PERF => {
218*bb4ee6a4SAndroid Build Coastguard Worker                 let shared_util = self.shared_domain_perf.load(Ordering::SeqCst);
219*bb4ee6a4SAndroid Build Coastguard Worker                 if shared_util != 0 && shared_util < self.pcpu_min_cap {
220*bb4ee6a4SAndroid Build Coastguard Worker                     shared_util * self.vcpu_fmax / self.vcpu_capacity
221*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
222*bb4ee6a4SAndroid Build Coastguard Worker                     match get_cpu_curfreq_khz(self.pcpu) {
223*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(freq) => u32::try_from(
224*bb4ee6a4SAndroid Build Coastguard Worker                             u64::from(freq) * u64::from(self.pcpu_capacity)
225*bb4ee6a4SAndroid Build Coastguard Worker                                 / u64::from(self.vcpu_relative_capacity),
226*bb4ee6a4SAndroid Build Coastguard Worker                         )
227*bb4ee6a4SAndroid Build Coastguard Worker                         .unwrap(),
228*bb4ee6a4SAndroid Build Coastguard Worker                         Err(_) => 0,
229*bb4ee6a4SAndroid Build Coastguard Worker                     }
230*bb4ee6a4SAndroid Build Coastguard Worker                 }
231*bb4ee6a4SAndroid Build Coastguard Worker             }
232*bb4ee6a4SAndroid Build Coastguard Worker             VCPUFREQ_FREQTBL_LEN => self.vcpu_freq_table.len() as u32,
233*bb4ee6a4SAndroid Build Coastguard Worker             VCPUFREQ_PERF_DOMAIN => self.vcpu_domain,
234*bb4ee6a4SAndroid Build Coastguard Worker             VCPUFREQ_FREQTBL_RD => *self
235*bb4ee6a4SAndroid Build Coastguard Worker                 .vcpu_freq_table
236*bb4ee6a4SAndroid Build Coastguard Worker                 .get(self.freqtbl_sel as usize)
237*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap_or(&0),
238*bb4ee6a4SAndroid Build Coastguard Worker             _ => {
239*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("{}: unsupported read address {}", self.debug_label(), info);
240*bb4ee6a4SAndroid Build Coastguard Worker                 return;
241*bb4ee6a4SAndroid Build Coastguard Worker             }
242*bb4ee6a4SAndroid Build Coastguard Worker         };
243*bb4ee6a4SAndroid Build Coastguard Worker 
244*bb4ee6a4SAndroid Build Coastguard Worker         let val_arr = val.to_ne_bytes();
245*bb4ee6a4SAndroid Build Coastguard Worker         data.copy_from_slice(&val_arr);
246*bb4ee6a4SAndroid Build Coastguard Worker     }
247*bb4ee6a4SAndroid Build Coastguard Worker 
write(&mut self, info: BusAccessInfo, data: &[u8])248*bb4ee6a4SAndroid Build Coastguard Worker     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
249*bb4ee6a4SAndroid Build Coastguard Worker         let val: u32 = match data.try_into().map(u32::from_ne_bytes) {
250*bb4ee6a4SAndroid Build Coastguard Worker             Ok(v) => v,
251*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
252*bb4ee6a4SAndroid Build Coastguard Worker                 warn!(
253*bb4ee6a4SAndroid Build Coastguard Worker                     "{}: unsupported write length {:#}, only support 4bytes write",
254*bb4ee6a4SAndroid Build Coastguard Worker                     self.debug_label(),
255*bb4ee6a4SAndroid Build Coastguard Worker                     e
256*bb4ee6a4SAndroid Build Coastguard Worker                 );
257*bb4ee6a4SAndroid Build Coastguard Worker                 return;
258*bb4ee6a4SAndroid Build Coastguard Worker             }
259*bb4ee6a4SAndroid Build Coastguard Worker         };
260*bb4ee6a4SAndroid Build Coastguard Worker 
261*bb4ee6a4SAndroid Build Coastguard Worker         match info.offset as u32 {
262*bb4ee6a4SAndroid Build Coastguard Worker             VCPUFREQ_SET_PERF => {
263*bb4ee6a4SAndroid Build Coastguard Worker                 // Util margin depends on the cpufreq governor on the host
264*bb4ee6a4SAndroid Build Coastguard Worker                 let util_raw = match u32::try_from(
265*bb4ee6a4SAndroid Build Coastguard Worker                     u64::from(self.vcpu_capacity) * u64::from(val) / u64::from(self.vcpu_fmax),
266*bb4ee6a4SAndroid Build Coastguard Worker                 ) {
267*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(util) => util,
268*bb4ee6a4SAndroid Build Coastguard Worker                     Err(e) => {
269*bb4ee6a4SAndroid Build Coastguard Worker                         warn!("Potential overflow {:#}", e);
270*bb4ee6a4SAndroid Build Coastguard Worker                         SCHED_CAPACITY_SCALE
271*bb4ee6a4SAndroid Build Coastguard Worker                     }
272*bb4ee6a4SAndroid Build Coastguard Worker                 };
273*bb4ee6a4SAndroid Build Coastguard Worker 
274*bb4ee6a4SAndroid Build Coastguard Worker                 let util = util_raw * self.util_factor / CPUFREQ_GOV_SCALE_FACTOR_DEFAULT;
275*bb4ee6a4SAndroid Build Coastguard Worker 
276*bb4ee6a4SAndroid Build Coastguard Worker                 if let (Some(domain_uclamp_min), Some(domain_uclamp_max)) =
277*bb4ee6a4SAndroid Build Coastguard Worker                     (&mut self.domain_uclamp_min, &mut self.domain_uclamp_max)
278*bb4ee6a4SAndroid Build Coastguard Worker                 {
279*bb4ee6a4SAndroid Build Coastguard Worker                     use std::io::Write;
280*bb4ee6a4SAndroid Build Coastguard Worker                     let val = util as f32 * 100.0 / SCHED_CAPACITY_SCALE as f32;
281*bb4ee6a4SAndroid Build Coastguard Worker                     let val_formatted = format!("{:4}", val).into_bytes();
282*bb4ee6a4SAndroid Build Coastguard Worker 
283*bb4ee6a4SAndroid Build Coastguard Worker                     if self.vcpu_fmax != self.pcpu_fmax {
284*bb4ee6a4SAndroid Build Coastguard Worker                         if let Err(e) = domain_uclamp_max.write(&val_formatted) {
285*bb4ee6a4SAndroid Build Coastguard Worker                             warn!("Error setting uclamp_max: {:#}", e);
286*bb4ee6a4SAndroid Build Coastguard Worker                         }
287*bb4ee6a4SAndroid Build Coastguard Worker                     }
288*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = domain_uclamp_min.write(&val_formatted) {
289*bb4ee6a4SAndroid Build Coastguard Worker                         warn!("Error setting uclamp_min: {:#}", e);
290*bb4ee6a4SAndroid Build Coastguard Worker                     }
291*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
292*bb4ee6a4SAndroid Build Coastguard Worker                     let mut sched_attr = sched_attr::default();
293*bb4ee6a4SAndroid Build Coastguard Worker                     sched_attr.sched_flags = SCHED_FLAG_KEEP_ALL
294*bb4ee6a4SAndroid Build Coastguard Worker                         | SCHED_FLAG_UTIL_CLAMP_MIN
295*bb4ee6a4SAndroid Build Coastguard Worker                         | SCHED_FLAG_UTIL_CLAMP_MAX
296*bb4ee6a4SAndroid Build Coastguard Worker                         | SCHED_FLAG_RESET_ON_FORK;
297*bb4ee6a4SAndroid Build Coastguard Worker                     sched_attr.sched_util_min = util;
298*bb4ee6a4SAndroid Build Coastguard Worker 
299*bb4ee6a4SAndroid Build Coastguard Worker                     if self.vcpu_fmax != self.pcpu_fmax {
300*bb4ee6a4SAndroid Build Coastguard Worker                         sched_attr.sched_util_max = util;
301*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
302*bb4ee6a4SAndroid Build Coastguard Worker                         sched_attr.sched_util_max = SCHED_CAPACITY_SCALE;
303*bb4ee6a4SAndroid Build Coastguard Worker                     }
304*bb4ee6a4SAndroid Build Coastguard Worker 
305*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = sched_setattr(0, &mut sched_attr, 0) {
306*bb4ee6a4SAndroid Build Coastguard Worker                         panic!("{}: Error setting util value: {:#}", self.debug_label(), e);
307*bb4ee6a4SAndroid Build Coastguard Worker                     }
308*bb4ee6a4SAndroid Build Coastguard Worker                 }
309*bb4ee6a4SAndroid Build Coastguard Worker 
310*bb4ee6a4SAndroid Build Coastguard Worker                 self.shared_domain_perf.store(util_raw, Ordering::SeqCst);
311*bb4ee6a4SAndroid Build Coastguard Worker                 let timer = self.timer.clone();
312*bb4ee6a4SAndroid Build Coastguard Worker                 if self.worker.is_none() {
313*bb4ee6a4SAndroid Build Coastguard Worker                     let vcpu_id = info.id;
314*bb4ee6a4SAndroid Build Coastguard Worker                     let vm_ctrl = self.vm_ctrl.clone();
315*bb4ee6a4SAndroid Build Coastguard Worker                     let worker_cpu_affinity = self.largest_pcpu_idx + self.vcpu_domain as usize + 1;
316*bb4ee6a4SAndroid Build Coastguard Worker                     let shared_domain_vcpus = self.shared_domain_vcpus.clone();
317*bb4ee6a4SAndroid Build Coastguard Worker 
318*bb4ee6a4SAndroid Build Coastguard Worker                     self.worker = Some(WorkerThread::start(
319*bb4ee6a4SAndroid Build Coastguard Worker                         format!("vcpu_throttle{vcpu_id}"),
320*bb4ee6a4SAndroid Build Coastguard Worker                         move |kill_evt| {
321*bb4ee6a4SAndroid Build Coastguard Worker                             vcpufreq_worker_thread(
322*bb4ee6a4SAndroid Build Coastguard Worker                                 shared_domain_vcpus,
323*bb4ee6a4SAndroid Build Coastguard Worker                                 kill_evt,
324*bb4ee6a4SAndroid Build Coastguard Worker                                 timer,
325*bb4ee6a4SAndroid Build Coastguard Worker                                 vm_ctrl,
326*bb4ee6a4SAndroid Build Coastguard Worker                                 worker_cpu_affinity,
327*bb4ee6a4SAndroid Build Coastguard Worker                             )
328*bb4ee6a4SAndroid Build Coastguard Worker                             .expect("error running vpucfreq_worker")
329*bb4ee6a4SAndroid Build Coastguard Worker                         },
330*bb4ee6a4SAndroid Build Coastguard Worker                     ));
331*bb4ee6a4SAndroid Build Coastguard Worker                 } else if util_raw < self.pcpu_min_cap {
332*bb4ee6a4SAndroid Build Coastguard Worker                     // The period is porportional to the performance requested by the vCPU, we
333*bb4ee6a4SAndroid Build Coastguard Worker                     // reduce the timeout period to increase the amount of throttling applied to
334*bb4ee6a4SAndroid Build Coastguard Worker                     // the vCPU as the performance decreases. Ex. If vCPU requests half of the
335*bb4ee6a4SAndroid Build Coastguard Worker                     // performance relatively to its pCPU@FMin, the vCPU will spend 50% of its
336*bb4ee6a4SAndroid Build Coastguard Worker                     // cycles being throttled to increase time for the same workload that otherwise
337*bb4ee6a4SAndroid Build Coastguard Worker                     // would've taken 1/2 of the time if ran at pCPU@FMin. We could've
338*bb4ee6a4SAndroid Build Coastguard Worker                     // alternatively adjusted the workload and used some fixed period (such as
339*bb4ee6a4SAndroid Build Coastguard Worker                     // 250us), but there's a floor for the minimum delay we add (cost of handling
340*bb4ee6a4SAndroid Build Coastguard Worker                     // the userspace exit) and limits the range of performance we can emulate.
341*bb4ee6a4SAndroid Build Coastguard Worker                     let timeout_period = (MIN_TIMER_US + TIMER_OVERHEAD_US) as f32
342*bb4ee6a4SAndroid Build Coastguard Worker                         / (1.0 - (util_raw as f32 / self.pcpu_min_cap as f32));
343*bb4ee6a4SAndroid Build Coastguard Worker                     let _ = timer
344*bb4ee6a4SAndroid Build Coastguard Worker                         .lock()
345*bb4ee6a4SAndroid Build Coastguard Worker                         .reset_repeating(Duration::from_micros(timeout_period as u64));
346*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
347*bb4ee6a4SAndroid Build Coastguard Worker                     let _ = timer.lock().clear();
348*bb4ee6a4SAndroid Build Coastguard Worker                 }
349*bb4ee6a4SAndroid Build Coastguard Worker             }
350*bb4ee6a4SAndroid Build Coastguard Worker             VCPUFREQ_FREQTBL_SEL => self.freqtbl_sel = val,
351*bb4ee6a4SAndroid Build Coastguard Worker             _ => {
352*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("{}: unsupported read address {}", self.debug_label(), info);
353*bb4ee6a4SAndroid Build Coastguard Worker             }
354*bb4ee6a4SAndroid Build Coastguard Worker         }
355*bb4ee6a4SAndroid Build Coastguard Worker     }
356*bb4ee6a4SAndroid Build Coastguard Worker }
357*bb4ee6a4SAndroid Build Coastguard Worker 
vcpufreq_worker_thread( shared_domain_vcpus: Vec<usize>, kill_evt: Event, timer: Arc<Mutex<Timer>>, vm_ctrl: Arc<Mutex<Tube>>, cpu_affinity: usize, ) -> anyhow::Result<()>358*bb4ee6a4SAndroid Build Coastguard Worker pub fn vcpufreq_worker_thread(
359*bb4ee6a4SAndroid Build Coastguard Worker     shared_domain_vcpus: Vec<usize>,
360*bb4ee6a4SAndroid Build Coastguard Worker     kill_evt: Event,
361*bb4ee6a4SAndroid Build Coastguard Worker     timer: Arc<Mutex<Timer>>,
362*bb4ee6a4SAndroid Build Coastguard Worker     vm_ctrl: Arc<Mutex<Tube>>,
363*bb4ee6a4SAndroid Build Coastguard Worker     cpu_affinity: usize,
364*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
365*bb4ee6a4SAndroid Build Coastguard Worker     #[derive(EventToken)]
366*bb4ee6a4SAndroid Build Coastguard Worker     enum Token {
367*bb4ee6a4SAndroid Build Coastguard Worker         // The timer expired.
368*bb4ee6a4SAndroid Build Coastguard Worker         TimerExpire,
369*bb4ee6a4SAndroid Build Coastguard Worker         // The parent thread requested an exit.
370*bb4ee6a4SAndroid Build Coastguard Worker         Kill,
371*bb4ee6a4SAndroid Build Coastguard Worker     }
372*bb4ee6a4SAndroid Build Coastguard Worker 
373*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx = WaitContext::build_with(&[
374*bb4ee6a4SAndroid Build Coastguard Worker         (&*timer.lock(), Token::TimerExpire),
375*bb4ee6a4SAndroid Build Coastguard Worker         (&kill_evt, Token::Kill),
376*bb4ee6a4SAndroid Build Coastguard Worker     ])
377*bb4ee6a4SAndroid Build Coastguard Worker     .context("Failed to create wait_ctx")?;
378*bb4ee6a4SAndroid Build Coastguard Worker 
379*bb4ee6a4SAndroid Build Coastguard Worker     // The vcpufreq thread has strict scheduling requirements, let's affine it away from the vCPU
380*bb4ee6a4SAndroid Build Coastguard Worker     // threads and clamp its util to high value.
381*bb4ee6a4SAndroid Build Coastguard Worker     let cpu_set: Vec<usize> = vec![cpu_affinity];
382*bb4ee6a4SAndroid Build Coastguard Worker     set_cpu_affinity(cpu_set)?;
383*bb4ee6a4SAndroid Build Coastguard Worker 
384*bb4ee6a4SAndroid Build Coastguard Worker     let mut sched_attr = sched_attr::default();
385*bb4ee6a4SAndroid Build Coastguard Worker     sched_attr.sched_flags = SCHED_FLAG_KEEP_ALL
386*bb4ee6a4SAndroid Build Coastguard Worker         | SCHED_FLAG_UTIL_CLAMP_MIN
387*bb4ee6a4SAndroid Build Coastguard Worker         | SCHED_FLAG_UTIL_CLAMP_MAX
388*bb4ee6a4SAndroid Build Coastguard Worker         | SCHED_FLAG_RESET_ON_FORK;
389*bb4ee6a4SAndroid Build Coastguard Worker     sched_attr.sched_util_min = SCHED_CAPACITY_SCALE;
390*bb4ee6a4SAndroid Build Coastguard Worker     sched_attr.sched_util_max = SCHED_CAPACITY_SCALE;
391*bb4ee6a4SAndroid Build Coastguard Worker     if let Err(e) = sched_setattr(0, &mut sched_attr, 0) {
392*bb4ee6a4SAndroid Build Coastguard Worker         warn!("Error setting util value: {}", e);
393*bb4ee6a4SAndroid Build Coastguard Worker     }
394*bb4ee6a4SAndroid Build Coastguard Worker 
395*bb4ee6a4SAndroid Build Coastguard Worker     loop {
396*bb4ee6a4SAndroid Build Coastguard Worker         let events = wait_ctx.wait().context("Failed to wait for events")?;
397*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
398*bb4ee6a4SAndroid Build Coastguard Worker             match event.token {
399*bb4ee6a4SAndroid Build Coastguard Worker                 Token::TimerExpire => {
400*bb4ee6a4SAndroid Build Coastguard Worker                     timer
401*bb4ee6a4SAndroid Build Coastguard Worker                         .lock()
402*bb4ee6a4SAndroid Build Coastguard Worker                         .mark_waited()
403*bb4ee6a4SAndroid Build Coastguard Worker                         .context("failed to reset timer")?;
404*bb4ee6a4SAndroid Build Coastguard Worker                     let vm_ctrl_unlocked = vm_ctrl.lock();
405*bb4ee6a4SAndroid Build Coastguard Worker                     for vcpu_id in &shared_domain_vcpus {
406*bb4ee6a4SAndroid Build Coastguard Worker                         let msg = vm_control::VmRequest::Throttle(*vcpu_id, MIN_TIMER_US);
407*bb4ee6a4SAndroid Build Coastguard Worker                         vm_ctrl_unlocked
408*bb4ee6a4SAndroid Build Coastguard Worker                             .send(&msg)
409*bb4ee6a4SAndroid Build Coastguard Worker                             .context("failed to stall vCPUs")?;
410*bb4ee6a4SAndroid Build Coastguard Worker                     }
411*bb4ee6a4SAndroid Build Coastguard Worker                 }
412*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Kill => {
413*bb4ee6a4SAndroid Build Coastguard Worker                     return Ok(());
414*bb4ee6a4SAndroid Build Coastguard Worker                 }
415*bb4ee6a4SAndroid Build Coastguard Worker             }
416*bb4ee6a4SAndroid Build Coastguard Worker         }
417*bb4ee6a4SAndroid Build Coastguard Worker     }
418*bb4ee6a4SAndroid Build Coastguard Worker }
419*bb4ee6a4SAndroid Build Coastguard Worker 
420*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for VirtCpufreqV2 {}
421