mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-01-24 12:46:25 -06:00
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:
parent
c5e8da8159
commit
56f421daed
@ -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 }
|
||||||
]
|
]
|
||||||
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
@ -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} });
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user