diff --git a/fas-rs-fw/src/scheduler/looper/mod.rs b/fas-rs-fw/src/scheduler/looper/mod.rs index ea10f379..fa3806ca 100755 --- a/fas-rs-fw/src/scheduler/looper/mod.rs +++ b/fas-rs-fw/src/scheduler/looper/mod.rs @@ -73,7 +73,7 @@ impl Looper

{ .values() .filter(|b| b.last_update.elapsed() < Duration::from_secs(1)) .filter_map(|b| b.target_fps) - .max(); + .max(); // 只处理目标fps最大的buffer let Some(message) = self.recv_message(mode, target_fps)? else { continue; @@ -111,7 +111,7 @@ impl Looper

{ self.retain_topapp(mode)?; if self.started { - self.controller.release_max(mode, &self.config)?; + self.controller.release_max(mode, &self.config)?; // 超时10帧时拉满频率以加快游戏加载 } Ok(None) diff --git a/fas-rs-fw/src/scheduler/looper/utils.rs b/fas-rs-fw/src/scheduler/looper/utils.rs index 4b1de34f..a5cecdc4 100755 --- a/fas-rs-fw/src/scheduler/looper/utils.rs +++ b/fas-rs-fw/src/scheduler/looper/utils.rs @@ -61,8 +61,10 @@ impl Looper

{ let frametime = d.frametime; let target_fps = d.target_fps.clone(); - for (_, buffer) in self.buffers.iter_mut().filter(|(k, _)| **k != producer) { - buffer.frame_prepare(); + for (process, buffer) in self.buffers.iter_mut() { + if *process != producer { + buffer.frame_prepare(); // 其它buffer计算额外超时时间 + } } match self.buffers.entry(producer) { @@ -70,7 +72,7 @@ impl Looper

{ o.get_mut().push_frametime(frametime); } Entry::Vacant(v) => { - info!("Loaded fas on game: [{}] pid: [{}]", d.pkg, d.pid); + info!("New fas buffer on game: [{}] pid: [{}]", d.pkg, d.pid); let mut buffer = Buffer::new(target_fps); buffer.push_frametime(frametime); diff --git a/src/cpu_common/policy/force_bound.rs b/src/cpu_common/policy/force_bound.rs new file mode 100644 index 00000000..94404dd8 --- /dev/null +++ b/src/cpu_common/policy/force_bound.rs @@ -0,0 +1,48 @@ +/* Copyright 2023 shadow3aaa@gitbub.com +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. */ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use anyhow::Result; + +use super::Freq; + +const CPUFREQ_DEBUG: &str = "/proc/cpudvfs/cpufreq_debug"; + +#[derive(Debug, PartialEq, Eq)] +pub struct Bounder { + freq_debug: PathBuf, +} + +impl Bounder { + pub fn new() -> Option { + let path = Path::new(CPUFREQ_DEBUG); + + if path.exists() { + Some(Self { + freq_debug: path.to_path_buf(), + }) + } else { + None + } + } + + pub fn force_freq(&self, num: u8, l: Freq, r: Freq) -> Result<()> { + let message = format!("{} {l} {r}", num); + fs::write(&self.freq_debug, message)?; + Ok(()) + } +} diff --git a/src/cpu_common/policy.rs b/src/cpu_common/policy/mod.rs old mode 100755 new mode 100644 similarity index 50% rename from src/cpu_common/policy.rs rename to src/cpu_common/policy/mod.rs index 54e6ff12..616aac94 --- a/src/cpu_common/policy.rs +++ b/src/cpu_common/policy/mod.rs @@ -11,20 +11,23 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ +mod force_bound; +mod utils; + use std::{ cell::RefCell, cmp::Ordering, ffi::OsStr, fs, - os::unix::fs::PermissionsExt, path::{Path, PathBuf}, }; -use anyhow::{Ok, Result}; +use anyhow::Result; use likely_stable::LikelyOption; use super::Freq; use crate::error::Error; +use force_bound::Bounder; #[derive(Debug, PartialEq, Eq)] pub struct Policy { @@ -33,7 +36,7 @@ pub struct Policy { pub path: PathBuf, pub freqs: Vec, gov_snapshot: RefCell>, - force_bound: Option, + force_bound: Option, } impl Ord for Policy { @@ -50,27 +53,25 @@ impl PartialOrd for Policy { impl Policy { pub fn new>(p: P) -> Result { - let p = p.as_ref(); + let path = p.as_ref(); - let mut freqs: Vec = fs::read_to_string(p.join("scaling_available_frequencies"))? + let mut freqs: Vec = fs::read_to_string(path.join("scaling_available_frequencies"))? .split_whitespace() .map(|s| s.parse().unwrap()) .collect(); - freqs.sort_unstable(); + let num = path + .file_name() + .and_then_likely(OsStr::to_str) + .and_then_likely(|p| p.trim().parse().ok()) + .ok_or(Error::Other("Failed to parse cpufreq policy num"))?; - let bound_path = Path::new("/proc/cpudvfs/cpufreq_debug"); - let force_bound = if bound_path.exists() { - Some(bound_path.to_path_buf()) - } else { - None - }; + let force_bound = Bounder::new(); Ok(Self { little: false, - num: Self::parse_policy(p.file_name().and_then_likely(OsStr::to_str).unwrap()) - .ok_or(Error::Other("Failed to parse cpufreq policy num"))?, - path: p.to_path_buf(), + num, + path: path.to_path_buf(), freqs, gov_snapshot: RefCell::new(None), force_bound, @@ -78,16 +79,16 @@ impl Policy { } pub fn init_default(&self) -> Result<()> { - if let Some(ref p) = self.force_bound { - self.force_freq_bound( + if let Some(ref bounder) = self.force_bound { + bounder.force_freq( + self.num, self.freqs.first().copied().unwrap(), self.freqs.last().copied().unwrap(), - p, )?; } - self.set_min_freq(self.freqs[0])?; - self.set_max_freq(self.freqs.last().copied().unwrap())?; + self.unlock_min_freq(self.freqs[0])?; + self.unlock_max_freq(self.freqs.last().copied().unwrap())?; self.reset_gov() } @@ -97,23 +98,19 @@ impl Policy { } pub fn set_fas_freq(&self, f: Freq) -> Result<()> { - self.set_max_freq(f)?; + self.lock_max_freq(f)?; + self.lock_min_freq(self.freqs[0])?; - self.set_min_freq(self.freqs[0])?; - if let Some(ref p) = self.force_bound { - self.force_freq_bound(self.freqs[0], f, p)?; + if let Some(ref bounder) = self.force_bound { + bounder.force_freq(self.num, self.freqs[0], f)?; } Ok(()) } pub fn reset_gov(&self) -> Result<()> { - let path = self.path.join("scaling_governor"); - - if let Some(ref gov) = *self.gov_snapshot.borrow() { - let _ = fs::set_permissions(&path, PermissionsExt::from_mode(0o644)); - fs::write(&path, gov)?; - let _ = fs::set_permissions(&path, PermissionsExt::from_mode(0o444)); + if let Some(ref governor) = *self.gov_snapshot.borrow() { + self.unlock_governor(governor)?; } Ok(()) @@ -128,36 +125,9 @@ impl Policy { self.gov_snapshot.replace(Some(cur_gov)); } - let _ = fs::set_permissions(&path, PermissionsExt::from_mode(0o644)); - fs::write(&path, "performance")?; - let _ = fs::set_permissions(&path, PermissionsExt::from_mode(0o444)); + self.lock_governor("performance")?; } Ok(()) } - - fn set_max_freq(&self, f: Freq) -> Result<()> { - let path = self.path.join("scaling_max_freq"); - let _ = fs::set_permissions(&path, PermissionsExt::from_mode(0o644)); - fs::write(path, f.to_string())?; - Ok(()) - } - - fn set_min_freq(&self, f: Freq) -> Result<()> { - let path = self.path.join("scaling_min_freq"); - let _ = fs::set_permissions(&path, PermissionsExt::from_mode(0o644)); - fs::write(path, f.to_string())?; - Ok(()) - } - - fn force_freq_bound>(&self, l: Freq, r: Freq, p: P) -> Result<()> { - let message = format!("{} {l} {r}", self.num); - fs::write(p, message)?; - Ok(()) - } - - pub fn parse_policy>(p: S) -> Option { - let p = p.as_ref(); - p.replace("policy", "").trim().parse().ok() - } } diff --git a/src/cpu_common/policy/utils.rs b/src/cpu_common/policy/utils.rs new file mode 100644 index 00000000..4fb90673 --- /dev/null +++ b/src/cpu_common/policy/utils.rs @@ -0,0 +1,73 @@ +/* Copyright 2023 shadow3aaa@gitbub.com +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. */ +use std::{fs, os::unix::fs::PermissionsExt, path::Path}; + +use anyhow::Result; + +use super::{Freq, Policy}; + +impl Policy { + pub fn lock_max_freq(&self, f: Freq) -> Result<()> { + let path = self.path.join("scaling_max_freq"); + lock_write(path, f.to_string()) + } + + pub fn lock_min_freq(&self, f: Freq) -> Result<()> { + let path = self.path.join("scaling_min_freq"); + lock_write(path, f.to_string()) + } + + pub fn lock_governor>(&self, g: S) -> Result<()> { + let path = self.path.join("scaling_governor"); + let governor = g.as_ref(); + lock_write(path, governor) + } + + pub fn unlock_max_freq(&self, f: Freq) -> Result<()> { + let path = self.path.join("scaling_max_freq"); + unlock_write(path, f.to_string()) + } + + pub fn unlock_min_freq(&self, f: Freq) -> Result<()> { + let path = self.path.join("scaling_min_freq"); + unlock_write(path, f.to_string()) + } + + pub fn unlock_governor>(&self, g: S) -> Result<()> { + let path = self.path.join("scaling_governor"); + let governor = g.as_ref(); + unlock_write(path, governor) + } +} + +fn lock_write, P: AsRef>(p: P, s: S) -> Result<()> { + let s = s.as_ref(); + let p = p.as_ref(); + + let _ = fs::set_permissions(p, PermissionsExt::from_mode(0o644)); + fs::write(p, s)?; + let _ = fs::set_permissions(p, PermissionsExt::from_mode(0o444)); + + Ok(()) +} + +fn unlock_write, P: AsRef>(p: P, s: S) -> Result<()> { + let s = s.as_ref(); + let p = p.as_ref(); + + let _ = fs::set_permissions(p, PermissionsExt::from_mode(0o644)); + fs::write(p, s)?; + + Ok(()) +}