mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Track TCP retransmits up the full node tree, and display them on the tree summary panel.
This commit is contained in:
parent
91d26d315c
commit
699f78d2ac
@ -7,7 +7,7 @@ use std::{
|
||||
path::{Path, PathBuf}, sync::atomic::AtomicU64,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use lqos_utils::units::AtomicDownUp;
|
||||
use lqos_utils::units::{AtomicDownUp, DownUpOrder};
|
||||
|
||||
/// Describes a node in the network map tree.
|
||||
#[derive(Debug)]
|
||||
@ -21,6 +21,9 @@ pub struct NetworkJsonNode {
|
||||
/// Current throughput (in bytes/second) at this node
|
||||
pub current_throughput: AtomicDownUp, // In bytes
|
||||
|
||||
/// Current TCP Retransmits
|
||||
pub current_tcp_retransmits: AtomicDownUp, // In retries
|
||||
|
||||
/// Approximate RTTs reported for this level of the tree.
|
||||
/// It's never going to be as statistically accurate as the actual
|
||||
/// numbers, being based on medians.
|
||||
@ -48,6 +51,10 @@ impl NetworkJsonNode {
|
||||
self.current_throughput.get_down(),
|
||||
self.current_throughput.get_up(),
|
||||
),
|
||||
current_retransmits: (
|
||||
self.current_tcp_retransmits.get_down(),
|
||||
self.current_tcp_retransmits.get_up(),
|
||||
),
|
||||
rtts: self.rtts.iter().map(|n| *n as f32 / 100.0).collect(),
|
||||
parents: self.parents.clone(),
|
||||
immediate_parent: self.immediate_parent,
|
||||
@ -67,6 +74,8 @@ pub struct NetworkJsonTransport {
|
||||
pub max_throughput: (u32, u32),
|
||||
/// Current node throughput
|
||||
pub current_throughput: (u64, u64),
|
||||
/// Current count of TCP retransmits
|
||||
pub current_retransmits: (u64, u64),
|
||||
/// Set of RTT data
|
||||
pub rtts: Vec<f32>,
|
||||
/// Node indices of parents
|
||||
@ -125,6 +134,7 @@ impl NetworkJson {
|
||||
name: "Root".to_string(),
|
||||
max_throughput: (0, 0),
|
||||
current_throughput: AtomicDownUp::zeroed(),
|
||||
current_tcp_retransmits: AtomicDownUp::zeroed(),
|
||||
parents: Vec::new(),
|
||||
immediate_parent: None,
|
||||
rtts: DashSet::new(),
|
||||
@ -201,6 +211,7 @@ impl NetworkJson {
|
||||
pub fn zero_throughput_and_rtt(&self) {
|
||||
self.nodes.iter().for_each(|n| {
|
||||
n.current_throughput.set_to_zero();
|
||||
n.current_tcp_retransmits.set_to_zero();
|
||||
n.rtts.clear();
|
||||
});
|
||||
}
|
||||
@ -235,6 +246,17 @@ impl NetworkJson {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_retransmit_cycle(&self, targets: &[usize], tcp_retransmits: DownUpOrder<u64>) {
|
||||
for idx in targets {
|
||||
// Safety first; use "get" to ensure that the node exists
|
||||
if let Some(node) = self.nodes.get(*idx) {
|
||||
node.current_tcp_retransmits.checked_add(tcp_retransmits);
|
||||
} else {
|
||||
warn!("No network tree entry for index {idx}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn json_to_u32(val: Option<&Value>) -> u32 {
|
||||
@ -271,6 +293,7 @@ fn recurse_node(
|
||||
json_to_u32(json.get("uploadBandwidthMbps")),
|
||||
),
|
||||
current_throughput: AtomicDownUp::zeroed(),
|
||||
current_tcp_retransmits: AtomicDownUp::zeroed(),
|
||||
name: name.to_string(),
|
||||
immediate_parent: Some(immediate_parent),
|
||||
rtts: DashSet::new(),
|
||||
|
@ -33,6 +33,18 @@ impl AtomicDownUp {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add(&self, n: DownUpOrder<u64>) {
|
||||
let n0 = self.down.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if let Some(n) = n0.checked_add(n.down) {
|
||||
self.down.store(n, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
let n1 = self.up.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if let Some(n) = n1.checked_add(n.up) {
|
||||
self.up.store(n, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_down(&self) -> u64 {
|
||||
self.down.load(Relaxed)
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ export class TopTreeSummary extends BaseDashlet {
|
||||
th.appendChild(theading("Branch"));
|
||||
th.appendChild(theading("DL ⬇️"));
|
||||
th.appendChild(theading("UL ⬆️"));
|
||||
th.appendChild(theading("TCP Re-xmit"));
|
||||
t.appendChild(th);
|
||||
|
||||
let tbody = document.createElement("tbody");
|
||||
@ -45,6 +46,7 @@ export class TopTreeSummary extends BaseDashlet {
|
||||
row.appendChild(simpleRow(r[1].name));
|
||||
row.appendChild(simpleRow(scaleNumber(r[1].current_throughput[0] * 8)));
|
||||
row.appendChild(simpleRow(scaleNumber(r[1].current_throughput[1] * 8)));
|
||||
row.appendChild(simpleRow(r[1].current_retransmits[0] + " / " + r[1].current_retransmits[1]))
|
||||
t.appendChild(row);
|
||||
});
|
||||
|
||||
|
@ -83,9 +83,12 @@ pub fn get_top_n_root_queues(n_queues: usize) -> BusResponse {
|
||||
// Summarize everything after n_queues
|
||||
if nodes.len() > n_queues {
|
||||
let mut other_bw = (0, 0);
|
||||
let mut other_xmit = (0, 0);
|
||||
nodes.drain(n_queues..).for_each(|n| {
|
||||
other_bw.0 += n.1.current_throughput.0;
|
||||
other_bw.1 += n.1.current_throughput.1;
|
||||
other_xmit.0 += n.1.current_retransmits.0;
|
||||
other_xmit.1 += n.1.current_retransmits.1;
|
||||
});
|
||||
|
||||
nodes.push((
|
||||
@ -94,6 +97,7 @@ pub fn get_top_n_root_queues(n_queues: usize) -> BusResponse {
|
||||
name: "Others".into(),
|
||||
max_throughput: (0, 0),
|
||||
current_throughput: other_bw,
|
||||
current_retransmits: other_xmit,
|
||||
rtts: Vec::new(),
|
||||
parents: Vec::new(),
|
||||
immediate_parent: None,
|
||||
|
@ -297,6 +297,14 @@ impl ThroughputTracker {
|
||||
tracker.tcp_retransmits.up = retries.up.saturating_sub(tracker.prev_tcp_retransmits.up);
|
||||
tracker.prev_tcp_retransmits.down = retries.down;
|
||||
tracker.prev_tcp_retransmits.up = retries.up;
|
||||
|
||||
// Send it upstream
|
||||
if let Some(parents) = &tracker.network_json_parents {
|
||||
let net_json = NETWORK_JSON.write().unwrap();
|
||||
// Send it upstream
|
||||
println!("{:?}", tracker.tcp_retransmits);
|
||||
net_json.add_retransmit_cycle(parents, tracker.tcp_retransmits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user