Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion watt/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ mod expression {
named!(power_supply_discharge_rate => "%power-supply-discharge-rate");

named!(discharging => "?discharging");
named!(intel_pstate => "?intel-pstate");
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -454,6 +455,9 @@ pub enum Expression {
#[serde(with = "expression::discharging")]
Discharging,

#[serde(with = "expression::intel_pstate")]
IntelPstate,

Boolean(bool),

Number(f64),
Expand Down Expand Up @@ -615,7 +619,8 @@ pub struct EvalState<'peripherals, 'context> {
pub power_supply_charge: Option<f64>,
pub power_supply_discharge_rate: Option<f64>,

pub discharging: bool,
pub discharging: bool,
pub intel_pstate: bool,

pub context: EvalContext<'context>,

Expand Down Expand Up @@ -748,6 +753,7 @@ impl Expression {
},

Discharging => Boolean(state.discharging),
IntelPstate => Boolean(state.intel_pstate),

literal @ (Boolean(_) | Number(_) | String(_)) => literal.clone(),

Expand Down Expand Up @@ -896,6 +902,7 @@ fn literal_is_true(expression: &Expression) -> bool {
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub struct Rule {
pub name: String,
pub priority: u16,

#[serde(
Expand All @@ -914,6 +921,7 @@ pub struct Rule {
impl Default for Rule {
fn default() -> Self {
Self {
name: String::default(),
priority: u16::default(),
condition: literal_true(),
cpu: CpusDelta::default(),
Expand Down Expand Up @@ -1039,6 +1047,7 @@ mod tests {
power_supply_charge: Some(0.8),
power_supply_discharge_rate: Some(10.0),
discharging: false,
intel_pstate: false,
context: EvalContext::Cpu(&cpu),
cpus: &cpus,
power_supplies: &power_supplies,
Expand Down Expand Up @@ -1123,6 +1132,7 @@ mod tests {
power_supply_charge: Some(0.8),
power_supply_discharge_rate: Some(10.0),
discharging: false,
intel_pstate: false,
context: EvalContext::Cpu(&cpu),
cpus: &cpus,
power_supplies: &power_supplies,
Expand Down
29 changes: 14 additions & 15 deletions watt/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Rules are evaluated by priority (higher number => higher priority).
# Each rule can specify conditions and actions for CPU and power management.

# Emergency thermal protection (highest priority).
[[rule]]
name = "emergency-thermal-protection"
if = { is-more-than = 85.0, value = "$cpu-temperature" }
priority = 100

Expand All @@ -14,48 +14,47 @@ cpu.frequency-mhz-maximum = { if = "?frequency-available", then = 2000 }
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }

# Critical battery preservation.
[[rule]]
name = "critical-battery-preservation"
if.all = [ "?discharging", { is-less-than = 0.3, value = "%power-supply-charge" } ]
priority = 90

cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "power", then = "power" }
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "power", then = "power" }
cpu.frequency-mhz-maximum = { if = "?frequency-available", then = 800 } # More aggressive below critical threshold.
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }
power.platform-profile = { if.is-platform-profile-available = "low-power", then = "low-power" }

# High performance mode for sustained high load.
[[rule]]
name = "high-load-performance-sustainance"
if.all = [
{ is-more-than = 0.8, value = "%cpu-usage" },
{ is-less-than = 30.0, value = "$cpu-idle-seconds" },
{ is-less-than = 75.0, value = "$cpu-temperature" },
]
priority = 80

cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "performance", then = "performance" }
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "performance", then = "performance" }
cpu.energy-performance-bias = { if.all = [{ not = "?intel-pstate" }, { is-energy-performance-bias-available = "performance" }], then = "performance" }
cpu.energy-performance-preference = { if.all = [{ not = "?intel-pstate" }, { is-energy-performance-preference-available = "performance" }], then = "performance" }
cpu.governor = { if.is-governor-available = "performance", then = "performance" }
cpu.turbo = { if = "?turbo-available", then = true }

# Performance mode when not discharging.
[[rule]]
name = "plugged-in-performance"
if.all = [
{ not = "?discharging" },
{ is-more-than = 0.1, value = "%cpu-usage" },
{ is-less-than = 80.0, value = "$cpu-temperature" },
]
priority = 70

cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "balance_performance", then = "balance_performance" }
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "performance", then = "performance" }
cpu.energy-performance-bias = { if.all = [{ not = "?intel-pstate" }, { is-energy-performance-bias-available = "balance_performance" }], then = "balance_performance" }
cpu.energy-performance-preference = { if.all = [{ not = "?intel-pstate" }, { is-energy-performance-preference-available = "performance" }], then = "performance" }
cpu.governor = { if.is-governor-available = "performance", then = "performance" }
cpu.turbo = { if = "?turbo-available", then = true }

# Moderate performance for medium load.
[[rule]]
name = "moderate-load-balanced-performance"
if.all = [
{ is-more-than = 0.4, value = "%cpu-usage" },
{ is-less-than = 0.8, value = "%cpu-usage" },
Expand All @@ -66,8 +65,8 @@ cpu.energy-performance-bias = { if.is-energy-performance-bias-available =
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "balance_performance", then = "balance_performance" }
cpu.governor = { if.is-governor-available = "schedutil", then = "schedutil" }

# Power saving during low activity.
[[rule]]
name = "low-activity-power-saving"
if.all = [
{ is-less-than = 0.2, value = "%cpu-usage" },
{ is-more-than = 60.0, value = "$cpu-idle-seconds" },
Expand All @@ -79,8 +78,8 @@ cpu.energy-performance-preference = { if.is-energy-performance-preference-availa
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }

# Extended idle power optimization.
[[rule]]
name = "extended-idle-power-saving"
if = { is-more-than = 300.0, value = "$cpu-idle-seconds" }
priority = 40

Expand All @@ -90,8 +89,8 @@ cpu.frequency-mhz-maximum = { if = "?frequency-available", then = 1600 }
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }

# Battery conservation when discharging.
[[rule]]
name = "discharging-battery-conservation"
if.all = [ "?discharging", { is-less-than = 0.5, value = "%power-supply-charge" } ]
priority = 30

Expand All @@ -102,8 +101,8 @@ cpu.governor = { if.is-governor-available = "powersave", th
cpu.turbo = { if = "?turbo-available", then = false }
power.platform-profile = { if.is-platform-profile-available = "low-power", then = "low-power" }

# General battery mode.
[[rule]]
name = "battery-balanced"
if = "?discharging"
priority = 20

Expand All @@ -114,8 +113,8 @@ cpu.frequency-mhz-minimum = { if = "?frequency-available", then = 200 }
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }

# Balanced performance for general use. Default fallback rule.
[[rule]]
name = "default-balanced"
cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "balance_performance", then = "balance_performance" }
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "balance_performance", then = "balance_performance" }
cpu.governor = { if.is-governor-available = "schedutil", then = "schedutil" }
Expand Down
4 changes: 4 additions & 0 deletions watt/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,10 @@ impl Cpu {
.map(|x| x.map(|freq| freq / 1000))
}

pub fn is_intel_pstate() -> bool {
fs::exists("/sys/devices/system/cpu/intel_pstate")
}

pub fn turbo() -> anyhow::Result<Option<bool>> {
log::trace!("reading turbo boost status");

Expand Down
3 changes: 2 additions & 1 deletion watt/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,8 @@ pub fn run_daemon(config: config::DaemonConfig) -> anyhow::Result<()> {
.map(|log| log.charge),
power_supply_discharge_rate: system.power_supply_discharge_rate(),

discharging: system.is_discharging(),
discharging: system.is_discharging(),
intel_pstate: cpu::Cpu::is_intel_pstate(),

context: config::EvalContext::WidestPossible,

Expand Down