TC Queue Check Frequency and Display

* The frequency with which TC queues are polled for statistics is
  now controled by `queue_check_period_ms` in `/etc/lqos`.
* Example file updated.
* Configuration display updated.

This is designed to act as a compromise: for detailed analysis, it
can be updated to a low number. For regular running, it can be updated
to 1000 or more.

Signed-off-by: Herbert Wolverson <herberticus@gmail.com>
This commit is contained in:
Herbert Wolverson 2023-01-06 14:38:40 +00:00
parent c5e8da8159
commit 56f421daed
6 changed files with 41 additions and 26 deletions

View File

@ -3,6 +3,7 @@
# Where is LibreQoS installed? # Where is LibreQoS installed?
lqos_directory = '/opt/libreqos/src' lqos_directory = '/opt/libreqos/src'
queue_check_period_ms = 1000
[tuning] [tuning]
stop_irq_balance = true stop_irq_balance = true
@ -30,4 +31,4 @@ interface_mapping = [
vlan_mapping = [ vlan_mapping = [
{ parent = "enp1s0f1", tag = 3, redirect_to = 4 }, { parent = "enp1s0f1", tag = 3, redirect_to = 4 },
{ parent = "enp1s0f1", tag = 4, redirect_to = 3 } { parent = "enp1s0f1", tag = 4, redirect_to = 3 }
] ]

View File

@ -5,6 +5,7 @@ use anyhow::{Result, Error};
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct EtcLqos { pub struct EtcLqos {
pub lqos_directory: String, pub lqos_directory: String,
pub queue_check_period_ms: u64,
pub bridge: Option<BridgeConfig>, pub bridge: Option<BridgeConfig>,
pub tuning: Option<Tunables>, pub tuning: Option<Tunables>,
} }

View File

@ -197,17 +197,17 @@
} }
let graph = document.getElementById("tinTp_" + tin); let graph = document.getElementById("tinTp_" + tin);
let graph_data = [ let graph_data = [
{x: entries.x[0], y:entries.y[0], name: 'Download', type: 'scatter', fill: 'tozeroy'}, {x: entries.x[0], y:entries.y[0], name: 'Download', type: 'scatter'},
{x: entries.x[1], y:entries.y[1], name: 'Upload', type: 'scatter', fill: 'tozeroy'}, {x: entries.x[1], y:entries.y[1], name: 'Upload', type: 'scatter'},
]; ];
Plotly.newPlot(graph, graph_data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true }, xaxis: {automargin: true} }); Plotly.newPlot(graph, graph_data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true }, xaxis: {automargin: true} });
graph = document.getElementById("tinMd_" + tin); graph = document.getElementById("tinMd_" + tin);
graph_data = [ graph_data = [
{x: entries.x[2], y:entries.y[2], name: 'Down Drops', type: 'scatter', fill: 'tozeroy'}, {x: entries.x[2], y:entries.y[2], name: 'Down Drops', type: 'scatter'},
{x: entries.x[3], y:entries.y[3], name: 'Down Marks', type: 'scatter', fill: 'tozeroy'}, {x: entries.x[3], y:entries.y[3], name: 'Down Marks', type: 'scatter'},
{x: entries.x[4], y:entries.y[4], name: 'Up Drops', type: 'scatter', fill: 'tozeroy'}, {x: entries.x[4], y:entries.y[4], name: 'Up Drops', type: 'scatter'},
{x: entries.x[5], y:entries.y[5], name: 'Up Marks', type: 'scatter', fill: 'tozeroy'}, {x: entries.x[5], y:entries.y[5], name: 'Up Marks', type: 'scatter'},
]; ];
Plotly.newPlot(graph, graph_data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true }, xaxis: {automargin: true} }); Plotly.newPlot(graph, graph_data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true }, xaxis: {automargin: true} });
} }

View File

@ -229,6 +229,20 @@
<div class="tab-pane fade" id="v-pills-server" role="tabpanel" aria-labelledby="v-pills-server-tab"> <div class="tab-pane fade" id="v-pills-server" role="tabpanel" aria-labelledby="v-pills-server-tab">
<h2><i class="fa fa-server"></i> Server Settings</h2> <h2><i class="fa fa-server"></i> Server Settings</h2>
<table class="table"> <table class="table">
<tr>
<td colspan="2" class="alert-info" role="alert">
How frequently should the TC queues be polled? 30-50 is good for detailed analysis,
1000 is good for normal running.
</td>
</tr>
<tr>
<td>
Queue Check Frequency (ms)
</td>
<td>
<input type="number" min="10" max="1000" id="queuecheckms" />
</td>
</tr>
<tr> <tr>
<td colspan="2" class="alert-danger"> <td colspan="2" class="alert-danger">
<i class="fa fa-warning"></i> Disabling actual shell commands stops LibreQoS from actually doing anything. Simulated <i class="fa fa-warning"></i> Disabling actual shell commands stops LibreQoS from actually doing anything. Simulated
@ -417,6 +431,7 @@
$("#generatedDownload").val(python_config.generated_download_mbps); $("#generatedDownload").val(python_config.generated_download_mbps);
$("#generatedUpload").val(python_config.generated_upload_mbps); $("#generatedUpload").val(python_config.generated_upload_mbps);
$("#binpacking").prop('checked', python_config.use_binpacking); $("#binpacking").prop('checked', python_config.use_binpacking);
$("#queuecheckms").val(lqosd_config.queue_check_period_ms);
$("#actualShellCommands").prop('checked', python_config.enable_shell_commands); $("#actualShellCommands").prop('checked', python_config.enable_shell_commands);
$("#useSudo").prop('checked', python_config.run_as_sudo); $("#useSudo").prop('checked', python_config.run_as_sudo);
$("#overrideQueues").val(python_config.override_queue_count); $("#overrideQueues").val(python_config.override_queue_count);

View File

@ -2,7 +2,7 @@ use std::{time::{Duration, Instant}, collections::HashMap};
use lqos_bus::BusResponse; use lqos_bus::BusResponse;
use lqos_config::LibreQoSConfig; use lqos_config::LibreQoSConfig;
use serde::Serialize; use serde::Serialize;
use tokio::{task, time}; use tokio::{task, time, join};
use crate::libreqos_tracker::QUEUE_STRUCTURE; use crate::libreqos_tracker::QUEUE_STRUCTURE;
use self::queue_reader::{QueueType, QueueDiff, make_queue_diff}; use self::queue_reader::{QueueType, QueueDiff, make_queue_diff};
mod queue_reader; mod queue_reader;
@ -54,16 +54,17 @@ lazy_static! {
pub(crate) static ref CIRCUIT_TO_QUEUE : RwLock<HashMap<String, QueueStore>> = RwLock::new(HashMap::new()); pub(crate) static ref CIRCUIT_TO_QUEUE : RwLock<HashMap<String, QueueStore>> = RwLock::new(HashMap::new());
} }
fn track_queues() { async fn track_queues() {
let config = LibreQoSConfig::load().unwrap(); let config = LibreQoSConfig::load().unwrap();
let queues = if config.on_a_stick_mode { let queues = if config.on_a_stick_mode {
let queues = queue_reader::read_tc_queues(&config.internet_interface).unwrap(); let queues = queue_reader::read_tc_queues(&config.internet_interface).await.unwrap();
vec![queues] vec![queues]
} else { } else {
vec![ let (isp, internet) = join!{
queue_reader::read_tc_queues(&config.isp_interface).unwrap(), queue_reader::read_tc_queues(&config.isp_interface),
queue_reader::read_tc_queues(&config.internet_interface).unwrap(), queue_reader::read_tc_queues(&config.internet_interface),
] };
vec![isp.unwrap(), internet.unwrap()]
}; };
// Time to associate queues with circuits // Time to associate queues with circuits
@ -164,18 +165,15 @@ fn track_queues() {
pub async fn spawn_queue_monitor() { pub async fn spawn_queue_monitor() {
let _ = task::spawn(async { let _ = task::spawn(async {
let mut interval = time::interval(Duration::from_secs(1)); let queue_check_period_ms = lqos_config::EtcLqos::load().unwrap().queue_check_period_ms;
let mut interval = time::interval(Duration::from_millis(queue_check_period_ms));
loop { loop {
let now = Instant::now(); let now = Instant::now();
let _ = task::spawn_blocking(move || { let _ = track_queues().await;
track_queues()
})
.await;
let elapsed = now.elapsed(); let elapsed = now.elapsed();
println!("TC Reader tick with mapping consumed {:.4} seconds.", elapsed.as_secs_f32()); //println!("TC Reader tick with mapping consumed {} ms.", elapsed.as_millis());
if elapsed.as_secs_f32() < 10.0 { if elapsed.as_millis() < queue_check_period_ms as u128 {
let duration = Duration::from_secs(1) - elapsed; let duration = Duration::from_millis(queue_check_period_ms) - elapsed;
//println!("Sleeping for {:.2} seconds", duration.as_secs_f32()); //println!("Sleeping for {:.2} seconds", duration.as_secs_f32());
tokio::time::sleep(duration).await; tokio::time::sleep(duration).await;
} else { } else {

View File

@ -5,10 +5,10 @@ mod tc_cake;
use anyhow::{Result, Error}; use anyhow::{Result, Error};
use serde::Serialize; use serde::Serialize;
use serde_json::Value; use serde_json::Value;
use std::process::Command;
mod queue_diff; mod queue_diff;
pub use queue_diff::QueueDiff; pub use queue_diff::QueueDiff;
pub(crate) use queue_diff::make_queue_diff; pub(crate) use queue_diff::make_queue_diff;
use tokio::process::Command;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub(crate) enum QueueType { pub(crate) enum QueueType {
@ -32,11 +32,11 @@ impl QueueType {
} }
} }
pub(crate) fn read_tc_queues(interface: &str) -> Result<Vec<QueueType>> { pub(crate) async fn read_tc_queues(interface: &str) -> Result<Vec<QueueType>> {
let mut result = Vec::new(); let mut result = Vec::new();
let command_output = Command::new("/sbin/tc") let command_output = Command::new("/sbin/tc")
.args(["-s", "-j", "qdisc", "show", "dev", interface]) .args(["-s", "-j", "qdisc", "show", "dev", interface])
.output()?; .output().await?;
let json = String::from_utf8(command_output.stdout)?; let json = String::from_utf8(command_output.stdout)?;
let json: Value = serde_json::from_str(&json)?; let json: Value = serde_json::from_str(&json)?;
if let Value::Array(array) = &json { if let Value::Array(array) = &json {