mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2026-10-25 22:30:05 -05:00
Set CPU governor to performance by default (FIXES #1039)
This commit is contained in:
1 parent
06a268f663
commit
2656aa9e65
14 files changed
+191
-32
No files matched your search
@@ -14,10 +14,14 @@ systemctl show -p WantedBy network-online.target
|
||||
systemctl disable cloud-config iscsid cloud-final
|
||||
```
|
||||
|
||||
### Set proper governor for CPU (baremetal/hypervisior host)
|
||||
### CPU governor on bare metal / hypervisor hosts
|
||||
|
||||
LibreQoS now attempts to set the CPU governor to `performance` automatically during startup tuning.
|
||||
|
||||
Disable it only if needed with `[tuning].set_cpu_governor_performance = false`, or verify the active governor with:
|
||||
|
||||
```shell
|
||||
cpupower frequency-set --governor performance
|
||||
cpupower frequency-info | grep 'current policy'
|
||||
```
|
||||
|
||||
### OSPF
|
||||
|
||||
@@ -10,10 +10,14 @@
|
||||
|
||||
## Base de CPU e IRQ
|
||||
|
||||
Configure el governor de CPU en modo rendimiento para bare metal/hipervisor:
|
||||
LibreQoS ahora intenta configurar automáticamente el governor de CPU en modo `performance` durante el ajuste de arranque en hosts bare metal e hipervisor.
|
||||
|
||||
Este comportamiento está habilitado por defecto mediante `[tuning].set_cpu_governor_performance = true`. Desactívelo solo si su plataforma requiere otra política de governor.
|
||||
|
||||
Si necesita verificar manualmente el governor actual:
|
||||
|
||||
```bash
|
||||
sudo cpupower frequency-set --governor performance
|
||||
cpupower frequency-info | grep 'current policy'
|
||||
```
|
||||
|
||||
Confirme que el conteo de colas NIC y la distribución por CPU sean razonables:
|
||||
|
||||
@@ -10,10 +10,14 @@
|
||||
|
||||
## CPU and IRQ Baseline
|
||||
|
||||
Set CPU frequency governor to performance on bare metal/hypervisor hosts:
|
||||
LibreQoS now attempts to set the CPU frequency governor to `performance` automatically during startup tuning on bare metal and hypervisor hosts.
|
||||
|
||||
This behavior is enabled by default through `[tuning].set_cpu_governor_performance = true`. Disable it only if your platform requires a different governor policy.
|
||||
|
||||
If you need to verify the current governor manually:
|
||||
|
||||
```bash
|
||||
sudo cpupower frequency-set --governor performance
|
||||
cpupower frequency-info | grep 'current policy'
|
||||
```
|
||||
|
||||
Confirm NIC queue count and CPU distribution are sensible for your hardware:
|
||||
|
||||
@@ -10,6 +10,7 @@ enable_site_heatmaps = true
|
||||
enable_asn_heatmaps = true
|
||||
|
||||
[tuning]
|
||||
set_cpu_governor_performance = true
|
||||
stop_irq_balance = true
|
||||
netdev_budget_usecs = 8000
|
||||
netdev_budget_packets = 300
|
||||
|
||||
@@ -6,6 +6,10 @@ use thiserror::Error;
|
||||
use toml_edit::{DocumentMut, value};
|
||||
use tracing::{error, info};
|
||||
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Represents the top-level of the `/etc/lqos.conf` file. Serialization
|
||||
/// structure.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
@@ -55,6 +59,10 @@ pub struct EtcLqos {
|
||||
/// applied (in place of the previous version's offload service)
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Tunables {
|
||||
/// Should LibreQoS set the CPU governor to `performance` during tuning?
|
||||
#[serde(default = "default_true")]
|
||||
pub set_cpu_governor_performance: bool,
|
||||
|
||||
/// Should the `irq_balance` system service be stopped?
|
||||
pub stop_irq_balance: bool,
|
||||
|
||||
@@ -270,6 +278,8 @@ pub enum EtcLqosError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::etc::test_data::OLD_CONFIG;
|
||||
|
||||
const EXAMPLE_LQOS_CONF: &str = include_str!("../../../../lqos.example");
|
||||
|
||||
#[test]
|
||||
@@ -290,4 +300,21 @@ mod test {
|
||||
let reserialized = doc.to_string();
|
||||
assert!(reserialized.contains("node_id = \"test\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_tuning_defaults_cpu_governor_to_true_when_missing() {
|
||||
let raw = OLD_CONFIG
|
||||
.lines()
|
||||
.filter(|line| !line.trim().starts_with("set_cpu_governor_performance"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let config = super::EtcLqos::load_from_string(&raw)
|
||||
.expect("Unable to read legacy config fixture");
|
||||
assert!(
|
||||
config
|
||||
.tuning
|
||||
.expect("Legacy config fixture should contain tuning")
|
||||
.set_cpu_governor_performance
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -156,6 +156,7 @@ fn migrate_top_level(old_config: &EtcLqos, new_config: &mut Config) -> Result<()
|
||||
|
||||
fn migrate_tunables(old_config: &EtcLqos, new_config: &mut Config) -> Result<(), MigrationError> {
|
||||
if let Some(tunables) = &old_config.tuning {
|
||||
new_config.tuning.set_cpu_governor_performance = tunables.set_cpu_governor_performance;
|
||||
new_config.tuning.stop_irq_balance = tunables.stop_irq_balance;
|
||||
new_config.tuning.netdev_budget_packets = tunables.netdev_budget_packets;
|
||||
new_config.tuning.netdev_budget_usecs = tunables.netdev_budget_usecs;
|
||||
@@ -335,3 +336,34 @@ fn migrate_influx(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::etc::test_data::OLD_CONFIG;
|
||||
|
||||
#[test]
|
||||
fn legacy_migration_defaults_cpu_governor_to_true_when_missing() {
|
||||
let old_raw = OLD_CONFIG
|
||||
.lines()
|
||||
.filter(|line| !line.trim().starts_with("set_cpu_governor_performance"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let old_config = EtcLqos::load_from_string(&old_raw).expect("Legacy config should parse");
|
||||
let python_config = PythonMigration {
|
||||
sqm: "cake diffserv4".to_string(),
|
||||
upstream_bandwidth_capacity_download_mbps: 1000,
|
||||
upstream_bandwidth_capacity_upload_mbps: 1000,
|
||||
generated_pndownload_mbps: 1000,
|
||||
generated_pnupload_mbps: 1000,
|
||||
interface_a: "veth_tointernal".to_string(),
|
||||
interface_b: "veth_toexternal".to_string(),
|
||||
enable_actual_shell_commands: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let migrated =
|
||||
do_migration_14_to_15(&old_config, &python_config).expect("Migration should succeed");
|
||||
assert!(migrated.tuning.set_cpu_governor_performance);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ send_anonymous = true
|
||||
anonymous_server = \"127.0.0.1:9125\"
|
||||
|
||||
[tuning]
|
||||
set_cpu_governor_performance = true
|
||||
# IRQ balance breaks XDP_Redirect, which we use. Recommended to leave as true.
|
||||
stop_irq_balance = false
|
||||
netdev_budget_usecs = 8000
|
||||
|
||||
@@ -10,6 +10,7 @@ enable_site_heatmaps = true
|
||||
enable_asn_heatmaps = true
|
||||
|
||||
[tuning]
|
||||
set_cpu_governor_performance = true
|
||||
stop_irq_balance = true
|
||||
netdev_budget_usecs = 8000
|
||||
netdev_budget_packets = 300
|
||||
|
||||
@@ -718,6 +718,29 @@ mod test {
|
||||
assert!(!serialized.contains("enable_spylnx"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuning_cpu_governor_defaults_to_true_when_missing() {
|
||||
let raw = include_str!("example.toml")
|
||||
.lines()
|
||||
.filter(|line| !line.trim().starts_with("set_cpu_governor_performance"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let config = Config::load_from_string(&raw)
|
||||
.expect("Config without tuning governor flag should load");
|
||||
assert!(config.tuning.set_cpu_governor_performance);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuning_cpu_governor_explicit_false_deserializes() {
|
||||
let raw = include_str!("example.toml").replace(
|
||||
"set_cpu_governor_performance = true",
|
||||
"set_cpu_governor_performance = false",
|
||||
);
|
||||
let config =
|
||||
Config::load_from_string(&raw).expect("Config with tuning governor flag should load");
|
||||
assert!(!config.tuning.set_cpu_governor_performance);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rtt_thresholds_default_matches_executive_ramp() {
|
||||
let d = RttThresholds::default();
|
||||
|
||||
@@ -3,10 +3,18 @@
|
||||
use allocative::Allocative;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Represents a set of `sysctl` and `ethtool` tweaks that may be
|
||||
/// applied (in place of the previous version's offload service)
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Allocative)]
|
||||
pub struct Tunables {
|
||||
/// Should LibreQoS set the CPU governor to `performance` during tuning?
|
||||
#[serde(default = "default_true")]
|
||||
pub set_cpu_governor_performance: bool,
|
||||
|
||||
/// Should the `irq_balance` system service be stopped?
|
||||
pub stop_irq_balance: bool,
|
||||
|
||||
@@ -36,6 +44,7 @@ pub struct Tunables {
|
||||
impl Default for Tunables {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
set_cpu_governor_performance: true,
|
||||
stop_irq_balance: true,
|
||||
netdev_budget_usecs: 8000,
|
||||
netdev_budget_packets: 300,
|
||||
|
||||
@@ -32,6 +32,7 @@ function validateConfig() {
|
||||
function updateConfig() {
|
||||
// Update only the tuning section
|
||||
window.config.tuning = {
|
||||
set_cpu_governor_performance: document.getElementById("setCpuGovernorPerformance").checked,
|
||||
stop_irq_balance: document.getElementById("stopIrqBalance").checked,
|
||||
netdev_budget_usecs: parseInt(document.getElementById("netdevBudgetUsecs").value),
|
||||
netdev_budget_packets: parseInt(document.getElementById("netdevBudgetPackets").value),
|
||||
@@ -52,10 +53,12 @@ renderConfigMenu('tuning');
|
||||
loadConfig(() => {
|
||||
// window.config now contains the configuration.
|
||||
// Populate form fields with config values
|
||||
if (window.config && window.config.tuning) {
|
||||
const tunables = window.config.tuning;
|
||||
|
||||
if (window.config) {
|
||||
const tunables = window.config.tuning ?? {};
|
||||
window.config.tuning = tunables;
|
||||
|
||||
// Boolean fields
|
||||
document.getElementById("setCpuGovernorPerformance").checked = tunables.set_cpu_governor_performance ?? true;
|
||||
document.getElementById("stopIrqBalance").checked = tunables.stop_irq_balance ?? false;
|
||||
document.getElementById("disableRxVlan").checked = tunables.disable_rxvlan ?? false;
|
||||
document.getElementById("disableTxVlan").checked = tunables.disable_txvlan ?? false;
|
||||
@@ -80,6 +83,6 @@ loadConfig(() => {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error("Tuning configuration not found in window.config");
|
||||
console.error("Configuration not found in window.config");
|
||||
}
|
||||
});
|
||||
@@ -20,6 +20,12 @@
|
||||
<h6 class="lqos-config-section-title">Interrupts and Budgets</h6>
|
||||
<div class="lqos-config-section-subtitle">Control how aggressively the host services NIC interrupts and packet processing.</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="setCpuGovernorPerformance" aria-describedby="setCpuGovernorPerformanceHelp">
|
||||
<label class="form-check-label" for="setCpuGovernorPerformance">Set CPU Governor to Performance</label>
|
||||
<div id="setCpuGovernorPerformanceHelp" class="form-text">Runs <code>cpupower frequency-set --governor performance</code> during LibreQoS tuning. Enabled by default.</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="stopIrqBalance">
|
||||
<label class="form-check-label" for="stopIrqBalance">Stop IRQ Balance Service</label>
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
mod offloads;
|
||||
use anyhow::Result;
|
||||
use lqos_bus::{BusRequest, BusResponse};
|
||||
use lqos_config::{Config, Tunables};
|
||||
use lqos_queue_tracker::set_queue_refresh_interval;
|
||||
|
||||
fn apply_non_interface_tuning(tuning: &Tunables) {
|
||||
offloads::bpf_sysctls();
|
||||
if tuning.set_cpu_governor_performance {
|
||||
offloads::set_cpu_governor_performance();
|
||||
}
|
||||
if tuning.stop_irq_balance {
|
||||
offloads::stop_irq_balance();
|
||||
}
|
||||
offloads::netdev_budget(tuning.netdev_budget_usecs, tuning.netdev_budget_packets);
|
||||
}
|
||||
|
||||
fn apply_interface_tuning(config: &Config, tuning: &Tunables) {
|
||||
offloads::ethtool_tweaks(&config.internet_interface(), tuning);
|
||||
offloads::ethtool_tweaks(&config.isp_interface(), tuning);
|
||||
}
|
||||
|
||||
pub fn tune_lqosd_from_config_file() -> Result<()> {
|
||||
let config = lqos_config::load_config()?;
|
||||
|
||||
// Disable offloading
|
||||
offloads::bpf_sysctls();
|
||||
if config.tuning.stop_irq_balance {
|
||||
offloads::stop_irq_balance();
|
||||
}
|
||||
offloads::netdev_budget(
|
||||
config.tuning.netdev_budget_usecs,
|
||||
config.tuning.netdev_budget_packets,
|
||||
);
|
||||
offloads::ethtool_tweaks(&config.internet_interface(), &config.tuning);
|
||||
offloads::ethtool_tweaks(&config.isp_interface(), &config.tuning);
|
||||
let interval = config.queue_check_period_ms;
|
||||
set_queue_refresh_interval(interval);
|
||||
apply_non_interface_tuning(&config.tuning);
|
||||
apply_interface_tuning(config.as_ref(), &config.tuning);
|
||||
set_queue_refresh_interval(config.queue_check_period_ms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tune_lqosd_from_bus(request: &BusRequest) -> BusResponse {
|
||||
match request {
|
||||
BusRequest::UpdateLqosDTuning(interval, tuning) => {
|
||||
// Real-time tuning changes. Probably dangerous.
|
||||
apply_non_interface_tuning(tuning);
|
||||
if let Ok(config) = lqos_config::load_config() {
|
||||
if tuning.stop_irq_balance {
|
||||
offloads::stop_irq_balance();
|
||||
}
|
||||
offloads::netdev_budget(tuning.netdev_budget_usecs, tuning.netdev_budget_packets);
|
||||
offloads::ethtool_tweaks(&config.internet_interface(), &config.tuning);
|
||||
offloads::ethtool_tweaks(&config.isp_interface(), &config.tuning);
|
||||
apply_interface_tuning(config.as_ref(), tuning);
|
||||
}
|
||||
set_queue_refresh_interval(*interval);
|
||||
lqos_bus::BusResponse::Ack
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
//! Host tuning commands for sysctls, NIC offloads, and CPU governor policy.
|
||||
|
||||
use lqos_config::Tunables;
|
||||
use std::process::Command;
|
||||
use std::{io::ErrorKind, process::Command};
|
||||
use tracing::warn;
|
||||
|
||||
pub fn bpf_sysctls() {
|
||||
let _ = Command::new("/sbin/sysctl")
|
||||
@@ -7,6 +10,46 @@ pub fn bpf_sysctls() {
|
||||
.output();
|
||||
}
|
||||
|
||||
pub fn set_cpu_governor_performance() {
|
||||
for cpupower in ["/usr/bin/cpupower", "/usr/sbin/cpupower", "cpupower"] {
|
||||
match Command::new(cpupower)
|
||||
.args(["frequency-set", "--governor", "performance"])
|
||||
.output()
|
||||
{
|
||||
Ok(output) if output.status.success() => return,
|
||||
Ok(output) => {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
||||
if stderr.is_empty() {
|
||||
warn!(
|
||||
command = cpupower,
|
||||
status = %output.status,
|
||||
"Failed to set CPU governor to performance"
|
||||
);
|
||||
} else {
|
||||
warn!(
|
||||
command = cpupower,
|
||||
status = %output.status,
|
||||
stderr = %stderr,
|
||||
"Failed to set CPU governor to performance"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Err(error) if error.kind() == ErrorKind::NotFound => continue,
|
||||
Err(error) => {
|
||||
warn!(
|
||||
command = cpupower,
|
||||
error = %error,
|
||||
"Failed to run cpupower to set CPU governor to performance"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warn!("Unable to set CPU governor to performance because cpupower was not found");
|
||||
}
|
||||
|
||||
pub fn stop_irq_balance() {
|
||||
let _ = Command::new("/bin/systemctl")
|
||||
.args(["stop", "irqbalance"])
|
||||
|
||||
Reference in new issue
Block a user