1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use base::sched_attr;
6 use base::sched_setattr;
7 use base::warn;
8 use base::Error;
9 use std::os::unix::net::UnixStream;
10 use std::sync::Arc;
11
12 use anyhow::Context;
13 use serde::Deserialize;
14 use serde::Serialize;
15 use sync::Mutex;
16
17 use crate::pci::CrosvmDeviceId;
18 use crate::BusAccessInfo;
19 use crate::BusDevice;
20 use crate::DeviceId;
21 use crate::Suspendable;
22
23 const CPUFREQ_GOV_SCALE_FACTOR_DEFAULT: u32 = 100;
24 const CPUFREQ_GOV_SCALE_FACTOR_SCHEDUTIL: u32 = 80;
25 const SCHED_SCALE_CAPACITY: u32 = 1024;
26
27 const SCHED_FLAG_RESET_ON_FORK: u64 = 0x1;
28 const SCHED_FLAG_KEEP_POLICY: u64 = 0x08;
29 const SCHED_FLAG_KEEP_PARAMS: u64 = 0x10;
30 const SCHED_FLAG_UTIL_CLAMP_MIN: u64 = 0x20;
31 const SCHED_FLAG_UTIL_CLAMP_MAX: u64 = 0x40;
32
33 const SCHED_FLAG_KEEP_ALL: u64 = SCHED_FLAG_KEEP_POLICY | SCHED_FLAG_KEEP_PARAMS;
34
35 #[derive(Serialize, Deserialize)]
36 pub struct VirtCpufreq {
37 pcpu_fmax: u32,
38 pcpu_capacity: u32,
39 vcpu_fmax: u32,
40 vcpu_capacity: u32,
41 vcpu_relative_capacity: u32,
42 pcpu: u32,
43 util_factor: u32,
44 }
45
get_cpu_info(cpu_id: u32, property: &str) -> Result<u32, Error>46 fn get_cpu_info(cpu_id: u32, property: &str) -> Result<u32, Error> {
47 let path = format!("/sys/devices/system/cpu/cpu{cpu_id}/{property}");
48 std::fs::read_to_string(path)?
49 .trim()
50 .parse()
51 .map_err(|_| Error::new(libc::EINVAL))
52 }
53
get_cpu_info_str(cpu_id: u32, property: &str) -> Result<String, Error>54 fn get_cpu_info_str(cpu_id: u32, property: &str) -> Result<String, Error> {
55 let path = format!("/sys/devices/system/cpu/cpu{cpu_id}/{property}");
56 std::fs::read_to_string(path).map_err(|_| Error::new(libc::EINVAL))
57 }
58
get_cpu_capacity(cpu_id: u32) -> Result<u32, Error>59 fn get_cpu_capacity(cpu_id: u32) -> Result<u32, Error> {
60 get_cpu_info(cpu_id, "cpu_capacity")
61 }
62
get_cpu_maxfreq_khz(cpu_id: u32) -> Result<u32, Error>63 fn get_cpu_maxfreq_khz(cpu_id: u32) -> Result<u32, Error> {
64 get_cpu_info(cpu_id, "cpufreq/cpuinfo_max_freq")
65 }
66
get_cpu_curfreq_khz(cpu_id: u32) -> Result<u32, Error>67 fn get_cpu_curfreq_khz(cpu_id: u32) -> Result<u32, Error> {
68 get_cpu_info(cpu_id, "cpufreq/scaling_cur_freq")
69 }
70
handle_read_err(err: Error) -> String71 fn handle_read_err(err: Error) -> String {
72 warn!("Unable to get cpufreq governor, using 100% default util factor. Err: {:?}", err);
73 "unknown_governor".to_string()
74 }
75
get_cpu_util_factor(cpu_id: u32) -> Result<u32, Error>76 fn get_cpu_util_factor(cpu_id: u32) -> Result<u32, Error> {
77 let gov = get_cpu_info_str(cpu_id, "cpufreq/scaling_governor").unwrap_or_else(handle_read_err);
78 match gov.trim() {
79 "schedutil" => Ok(CPUFREQ_GOV_SCALE_FACTOR_SCHEDUTIL),
80 _ => Ok(CPUFREQ_GOV_SCALE_FACTOR_DEFAULT),
81 }
82 }
83
84 impl VirtCpufreq {
new(pcpu: u32, cpu_capacity: u32, cpu_fmax: u32) -> Self85 pub fn new(pcpu: u32, cpu_capacity: u32, cpu_fmax: u32) -> Self {
86 let util_factor = get_cpu_util_factor(pcpu).expect("Error getting util factor");
87 let pcpu_capacity = get_cpu_capacity(pcpu).expect("Error reading capacity");
88 let pcpu_fmax = get_cpu_maxfreq_khz(pcpu).expect("Error reading max freq");
89 let vcpu_relative_capacity = u32::try_from((u64::from(cpu_capacity) * u64::from(pcpu_fmax) / u64::from(cpu_fmax))).unwrap();
90
91 VirtCpufreq {
92 pcpu_fmax,
93 pcpu_capacity,
94 vcpu_fmax: cpu_fmax,
95 vcpu_capacity: cpu_capacity,
96 vcpu_relative_capacity,
97 pcpu,
98 util_factor,
99 }
100 }
101 }
102
103 impl BusDevice for VirtCpufreq {
device_id(&self) -> DeviceId104 fn device_id(&self) -> DeviceId {
105 CrosvmDeviceId::VirtCpufreq.into()
106 }
107
debug_label(&self) -> String108 fn debug_label(&self) -> String {
109 "VirtCpufreq Device".to_owned()
110 }
111
read(&mut self, _info: BusAccessInfo, data: &mut [u8])112 fn read(&mut self, _info: BusAccessInfo, data: &mut [u8]) {
113 if data.len() != std::mem::size_of::<u32>() {
114 warn!(
115 "{}: unsupported read length {}, only support 4bytes read",
116 self.debug_label(),
117 data.len()
118 );
119 return;
120 }
121 // TODO(davidai): Evaluate opening file and re-reading the same fd.
122 let freq = match get_cpu_curfreq_khz(self.pcpu) {
123 Ok(freq) => {
124 u32::try_from((u64::from(freq) * u64::from(self.pcpu_capacity) / u64::from(self.vcpu_relative_capacity))).unwrap()
125 },
126 Err(e) => panic!("{}: Error reading freq: {}", self.debug_label(), e),
127 };
128
129 let freq_arr = freq.to_ne_bytes();
130 data.copy_from_slice(&freq_arr);
131 }
132
write(&mut self, _info: BusAccessInfo, data: &[u8])133 fn write(&mut self, _info: BusAccessInfo, data: &[u8]) {
134 let freq: u32 = match data.try_into().map(u32::from_ne_bytes) {
135 Ok(v) => v,
136 Err(e) => {
137 warn!(
138 "{}: unsupported write length {}, only support 4bytes write",
139 self.debug_label(),
140 e
141 );
142 return;
143 }
144 };
145
146 // Util margin depends on the cpufreq governor on the host
147 let cpu_cap_scaled = self.vcpu_capacity * self.util_factor / CPUFREQ_GOV_SCALE_FACTOR_DEFAULT;
148 let util = u32::try_from(u64::from(cpu_cap_scaled) * u64::from(freq) / u64::from(self.vcpu_fmax)).unwrap();
149
150 let mut sched_attr = sched_attr::default();
151 sched_attr.sched_flags =
152 SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN | SCHED_FLAG_UTIL_CLAMP_MAX | SCHED_FLAG_RESET_ON_FORK;
153 sched_attr.sched_util_min = util;
154
155 if self.vcpu_fmax != self.pcpu_fmax {
156 sched_attr.sched_util_max = util;
157 } else {
158 sched_attr.sched_util_max = 1024;
159 }
160
161 if let Err(e) = sched_setattr(0, &mut sched_attr, 0) {
162 panic!("{}: Error setting util value: {}", self.debug_label(), e);
163 }
164 }
165 }
166
167 impl Suspendable for VirtCpufreq {
168 // Device only active through MMIO writes. Vcpus are frozen before the device tries to sleep,
169 // so the device will not be active at time of calling function.
sleep(&mut self) -> anyhow::Result<()>170 fn sleep(&mut self) -> anyhow::Result<()> {
171 Ok(())
172 }
173
wake(&mut self) -> anyhow::Result<()>174 fn wake(&mut self) -> anyhow::Result<()> {
175 Ok(())
176 }
177
snapshot(&mut self) -> anyhow::Result<serde_json::Value>178 fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
179 serde_json::to_value(&self).with_context(|| format!("failed to serialize"))
180 }
181
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>182 fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
183 let deser: Self = serde_json::from_value(data).with_context(|| format!("failed to deserialize"))?;
184 *self = deser;
185 Ok(())
186 }
187 }
188