Watt is a modern, low-overhead CPU frequency and power management utility for Linux systems. It provides intelligent control of your CPU, governors, frequencies and power-saving features to help optimize performance and battery life overall.
It is greatly inspired by auto-cpufreq and similar tools, but is rewritten from ground up to provide a smoother experience with the fraction of its runtime cost with an emphasis on efficiency, correctness and future-proofing. Some features are omitted, and it is not a drop-in replacement for auto-cpufreq, but most common usecases are already implemented or planned to be implemented. In addition, Watt features a very powerful configuration DSL to allow cooking up intricate power management rules to get the best possible performance out of your system.
Watt is written in Rust, because "languages such as JS and Python should never be used for system level daemons" 1 Overhead is little to none, and performance is as high as it can be, which should be a standard for all system daemons.
Watt is a tiny binary with a small footprint, but it packs a bunch. Namely:
- Daemon Mode: Run in background with adaptive polling to minimize overhead.
- Real-time CPU Management: Monitor and control CPU governors, frequencies, and turbo boost.
- Conflict Detection: Identifies and warns about conflicts with other power management tools.
- Powerful Config DSL: Built on TOML, Watt features a robust configuration
DSL to allow configuring the daemon exactly to your needs.
- Intelligent Power Management: Different profiles for AC and battery operation.
- Dynamic Turbo Boost Control: Automatically enables/disables turbo based on CPU load and temperature.
- Fine-tuned Controls: Adjust energy performance preferences, biases, and frequency limits.
- Per-core Control: Apply settings globally or to specific CPU cores.
- Battery Management: Monitor battery status and power consumption.
- System Load Tracking: Track system load and make intelligent decisions.
Using Watt is quite simple. It comes with a powerful default configuration tested on a variety of systems to provide better performance out of the box. Unless the user wishes to configure Watt from ground up, it's enough to simply start the Watt daemon and leave it at that.
# Run as a daemon in the background with default configuration
sudo watt
# Run with adjusted logging
#
# You can also use the logform options
# --quiet and --verbose, and repeat them.
sudo watt -qqq # Log level: OFF (won't log)
sudo watt -qq # Log level: ERROR (will log only ERROR)
sudo watt -q # Log level: WARN (will log ERROR and up)
sudo watt # Log level: INFO (will log INFO and up)
sudo watt -v # Log level: DEBUG (will log DEBUG and up)
sudo watt -vv # Log level: TRACE (will log everything)
# Run with a custom configuration file
sudo watt --config /path/to/config.tomlWatt operates primarily as a daemon that runs in the background and automatically manages CPU and power settings based on set configuration rules, using the various kernel power management APIs. All CPU settings are specified in the configuration file:
[[rule]]
if = "?discharging"
priority = 10
cpu.governor = "powersave"
cpu.energy-performance-preference = "power"
cpu.turbo = falseYou can apply settings to specific CPU cores using the cpu.for option:
[[rule]]
cpu.for = [0, 1] # Apply to first two cores
cpu.governor = "performance"Power settings are also specified in the configuration file:
[[rule]]
if = "?discharging"
priority = 10
# Set battery charging thresholds (as percentages, 0.0-1.0)
power.charge-threshold-start = 0.4
power.charge-threshold-end = 0.8
# Set ACPI platform profile
power.platform-profile = "low-power"
# Apply to specific power supplies
power.for = ["BAT0"]Battery charging thresholds help extend battery longevity by preventing constant charging to 100%. Different laptop vendors implement this feature differently, but Watt attempts to support multiple vendor implementations including:
- Lenovo ThinkPad/IdeaPad
- ASUS laptops
- Huawei laptops
- Framework laptops
- Other devices using the standard Linux power_supply API
Note
Battery management is sensitive, and your mileage may vary. Please open an issue if your vendor is not supported, but patches would help more than issue reports, as supporting hardware needs hardware.
# High performance for sustained workloads with thermal protection
[[rule]]
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.governor = "performance"
cpu.energy-performance-preference = "performance"
cpu.turbo = true# Critical battery preservation
[[rule]]
if.all = [
"?discharging",
{ is-less-than = 0.3, value = "%power-supply-charge" }
]
priority = 90
cpu.governor = "powersave"
cpu.energy-performance-preference = "power"
cpu.frequency-mhz-maximum = 800
cpu.turbo = false
power.platform-profile = "low-power"
# Moderate battery conservation
[[rule]]
if.all = [
"?discharging",
{ is-less-than = 0.5, value = "%power-supply-charge" }
]
priority = 30
cpu.governor = "powersave"
cpu.frequency-mhz-maximum = 2000
cpu.turbo = false# Adaptive frequency scaling based on temperature
[[rule]]
if = { is-more-than = 10.0, value = { value = "$cpu-temperature", minus = 50.0 } }
priority = 60
cpu.frequency-mhz-maximum = 2400
cpu.governor = "schedutil"Watt uses a rule-based TOML configuration system that allows you to define intelligent power management policies. The daemon evaluates rules by priority and applies the all matching rules. Rule settings with higher priority shadow ones with lower priority.
Configuration locations (in order of precedence):
- Custom path via
--configflag. - Custom path via
WATT_CONFIGenvironment variable (if no flag is specified). - Built-in default configuration (if no custom path is specified).
If no configuration file is found, Watt uses a built-in default configuration.
Rules are the core of Watt's configuration system. Each rule can specify:
- Conditions: When the rule should apply (using the expression DSL). If not
specified, always applies (defaults to
true). - Priority: Higher numbers take precedence (0-65535).
- Actions: CPU and power management settings to apply.
Watt includes a powerful expression language for defining conditions:
true,false- Booleans123.456,42- 64-bit Floats
"%cpu-usage"- Current CPU usage percentage (0.0-1.0)"$cpu-usage-volatility"- CPU usage volatility measurement"$cpu-temperature"- CPU temperature in Celsius"$cpu-temperature-volatility"- CPU temperature volatility"$cpu-idle-seconds"- Seconds since last significant CPU activity"$cpu-frequency-maximum"- CPU hardware maximum frequency in MHz"$cpu-frequency-minimum"- CPU hardware minimum frequency in MHz"%power-supply-charge"- Battery charge percentage (0.0-1.0)"%power-supply-discharge-rate"- Current discharge rate"?discharging"- Boolean indicating if system is on battery power"?frequency-available"- Boolean indicating if CPU frequency control is available"?turbo-available"- Boolean indicating if turbo boost control is available
The expression language only has boolean and 64-bit float values.
Predicates check if a specific value is available on the system:
if.is-governor-available = "powersave"
if.is-energy-performance-preference-available = "balance_performance"
if.is-energy-performance-bias-available = "5"
if.is-platform-profile-available = "low-power"Each will be true only if the named value is available on your system. If the
argument is not a string, Watt will fail with a configuration error.
- Comparison:
is-less-than,is-more-than,is-equal(withleewayparameter) - Logical:
and,or,not,all,any - Arithmetic:
plus,minus,multiply,divide,power - Aggregation:
minimum,maximum- take a list of expressions
You can use operators with TOML attribute sets:
[[rule]]
if = { is-more-than = "%cpu-usage", value = 0.8 }However, all and any do not take a value argument, but instead take a list
of expressions as the parameter:
[[rule]]
if = { all = [ <expression>, <expression2> ] }Settings can be conditionally applied based on availability:
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "balance_performance", then = "balance_performance" }
cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "5", then = "5" }
cpu.frequency-mhz-maximum = { if = "?frequency-available", then = 2000 }
cpu.turbo = { if = "?turbo-available", then = true }If the condition is not met, the setting will not be applied.
# Emergency thermal protection (highest priority)
[[rule]]
if = { is-more-than = 85.0, value = "$cpu-temperature" }
priority = 100
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 = 2000 }
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }
# Critical battery preservation
[[rule]]
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 = 800
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]]
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.governor = { if.is-governor-available = "performance", then = "performance" }
cpu.turbo = { if = "?turbo-available", then = true }
# Performance mode when not discharging
[[rule]]
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.governor = { if.is-governor-available = "performance", then = "performance" }
cpu.turbo = { if = "?turbo-available", then = true }
# Moderate performance for medium load
[[rule]]
if.all = [
{ is-more-than = 0.4, value = "%cpu-usage" },
{ is-less-than = 0.8, value = "%cpu-usage" },
]
priority = 60
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" }
# Power saving during low activity
[[rule]]
if.all = [
{ is-less-than = 0.2, value = "%cpu-usage" },
{ is-more-than = 60.0, value = "$cpu-idle-seconds" },
]
priority = 50
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.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }
# Extended idle power optimization
[[rule]]
if = { is-more-than = 300.0, value = "$cpu-idle-seconds" }
priority = 40
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 = 1600 }
cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
cpu.turbo = { if = "?turbo-available", then = false }
# Battery conservation when discharging
[[rule]]
if.all = [ "?discharging", { is-less-than = 0.5, value = "%power-supply-charge" } ]
priority = 30
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 = 2000 }
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" }
# General battery mode
[[rule]]
if = "?discharging"
priority = 20
cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "balance_power", then = "balance_power" }
cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "power", then = "power" }
cpu.frequency-mhz-maximum = { if = "?frequency-available", then = 1800 }
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]]
priority = 0
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" }Available CPU configuration options:
-
governor- CPU frequency governor (performance,powersave,schedutil, etc.). You can conditionally set a governor only if it is available using:cpu.governor = { if.is-governor-available = "powersave", then = "powersave" }
If the governor name is not a string, Watt will fail with a configuration error.
-
energy-performance-preference- EPP setting (performance,balance_performance,balance_power,power, etc.). You can conditionally set an EPP only if it is available using:cpu.energy-performance-preference = { if.is-energy-performance-preference-available = "balance_performance", then = "balance_performance" }
-
energy-performance-bias- EPB setting (performance,balance_performance,balance_power,power, etc.). You can conditionally set an EPB only if it is available using:cpu.energy-performance-bias = { if.is-energy-performance-bias-available = "5", then = "5" }
-
frequency-mhz-minimum- Minimum CPU frequency in MHz. Can use conditional expression:cpu.frequency-mhz-minimum = { if = "?frequency-available", then = 200 }
-
frequency-mhz-maximum- Maximum CPU frequency in MHz. Can use conditional expression:cpu.frequency-mhz-maximum = { if = "?frequency-available", then = 3000 }
-
turbo- Enable/disable turbo boost (boolean). Can use conditional expression:cpu.turbo = { if = "?turbo-available", then = true }
-
for- Apply settings to specific CPU cores (list of core IDs):cpu.for = [0, 1, 2]
Available power management options:
-
platform-profile- ACPI platform profile (performance,balanced,low-power). Can use conditional expression:power.platform-profile = { if.is-platform-profile-available = "low-power", then = "low-power" }
-
charge-threshold-start- Battery charge level to start charging (0.0-1.0) -
charge-threshold-end- Battery charge level to stop charging (0.0-1.0) -
for- Apply settings to specific power supplies (list of supply names):power.for = ["BAT0"]
Most CPU management commands require root privileges. If you see permission
errors, try running with sudo.
Not all features are available on all hardware:
- Turbo boost control requires CPU support for Intel/AMD boost features
- EPP/EPB settings require CPU driver support
- Platform profiles require ACPI platform profile support in your hardware
- Settings not applying: Check for conflicts with other power management tools
- CPU frequencies fluctuating: May be due to thermal throttling
- Missing CPU information: Verify kernel module support for your CPU
While reporting issues, please include your system information and any relevant logs.
Contributions to Watt are always welcome! Whether it's bug reports, feature requests, or code contributions, please feel free to contribute.
Note
If you are looking to reimplement features from auto-cpufreq, please consider opening an issue first and let us know what you have in mind. Certain features (such as the system tray) are deliberately ignored, and might not be desired in the codebase as they stand. Please discuss those features with us first :)
You will need Cargo and Rust installed on your system. Rust 1.85 or later is required.
A .envrc is provided, and it's usage is encouraged for Nix users.
Alternatively, you may use Nix for a reproducible developer environment
nix developNon-Nix users may get the appropriate Cargo and Rust versions from their package manager, or using something like Rustup.
Please make sure to run at least cargo fmt (and taplo format if you have
modified any TOML) inside the repository to make sure all of your code is
properly formatted. For Nix code, please use Alejandra.
Clippy lints are not required as of now, but a good rule of thumb to run them before committing to catch possible code smell early.
Watt is available under Mozilla Public License v2.0 for your convenience, and at our expense. Please see the license file for more details.
Footnotes
-
Wise words from the author of asusctl ↩