Skip to content

Commit

Permalink
让cpufreq模块更加KFC
Browse files Browse the repository at this point in the history
  • Loading branch information
shadow3aaa committed Jan 5, 2024
1 parent e489cef commit 3bf8eac
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 63 deletions.
4 changes: 2 additions & 2 deletions fas-rs-fw/src/scheduler/looper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<P: PerformanceController> Looper<P> {
.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;
Expand Down Expand Up @@ -111,7 +111,7 @@ impl<P: PerformanceController> Looper<P> {
self.retain_topapp(mode)?;

if self.started {
self.controller.release_max(mode, &self.config)?;
self.controller.release_max(mode, &self.config)?; // 超时10帧时拉满频率以加快游戏加载
}

Ok(None)
Expand Down
8 changes: 5 additions & 3 deletions fas-rs-fw/src/scheduler/looper/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,18 @@ impl<P: PerformanceController> Looper<P> {
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) {
Entry::Occupied(mut o) => {
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);
Expand Down
48 changes: 48 additions & 0 deletions src/cpu_common/policy/force_bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* Copyright 2023 [email protected]
*
* 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<Self> {
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(())
}
}
86 changes: 28 additions & 58 deletions src/cpu_common/policy.rs → src/cpu_common/policy/mod.rs
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -33,7 +36,7 @@ pub struct Policy {
pub path: PathBuf,
pub freqs: Vec<Freq>,
gov_snapshot: RefCell<Option<String>>,
force_bound: Option<PathBuf>,
force_bound: Option<Bounder>,
}

impl Ord for Policy {
Expand All @@ -50,44 +53,42 @@ impl PartialOrd for Policy {

impl Policy {
pub fn new<P: AsRef<Path>>(p: P) -> Result<Self> {
let p = p.as_ref();
let path = p.as_ref();

let mut freqs: Vec<Freq> = fs::read_to_string(p.join("scaling_available_frequencies"))?
let mut freqs: Vec<Freq> = 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,
})
}

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()
}

Expand All @@ -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(())
Expand All @@ -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<P: AsRef<Path>>(&self, l: Freq, r: Freq, p: P) -> Result<()> {
let message = format!("{} {l} {r}", self.num);
fs::write(p, message)?;
Ok(())
}

pub fn parse_policy<S: AsRef<str>>(p: S) -> Option<u8> {
let p = p.as_ref();
p.replace("policy", "").trim().parse().ok()
}
}
73 changes: 73 additions & 0 deletions src/cpu_common/policy/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Copyright 2023 [email protected]
*
* 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<S: AsRef<str>>(&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<S: AsRef<str>>(&self, g: S) -> Result<()> {
let path = self.path.join("scaling_governor");
let governor = g.as_ref();
unlock_write(path, governor)
}
}

fn lock_write<S: AsRef<str>, P: AsRef<Path>>(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<S: AsRef<str>, P: AsRef<Path>>(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(())
}

0 comments on commit 3bf8eac

Please sign in to comment.