ratecontroller: use durations instead of manually handling time

This commit is contained in:
Nils Andreas Svee committed 2022-11-10 13:54:26 +01:00
1 parent bb9d1ed4af
commit 5c0a6c304f
7 files changed
+84 -67

No files matched your search

+45 -46
View File
@@ -1,11 +1,9 @@
use crate::netlink::{Netlink, NetlinkError, Qdisc};
use crate::time::Time;
use crate::{Config, ReflectorStats};
use log::{debug, error, info, warn};
use rand::seq::SliceRandom;
use rand::thread_rng;
use rand::RngCore;
use rustix::thread::ClockId;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
@@ -13,8 +11,12 @@ use std::net::IpAddr;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex, RwLock};
use std::thread::sleep;
use std::time::Duration;
use std::time::{Duration, Instant, SystemTime};
use thiserror::Error;
use time::format_description::FormatItem;
use time::formatting::Formattable;
use time::macros::format_description;
use time::OffsetDateTime;
#[derive(Copy, Clone, Debug, PartialEq)]
enum Direction {
@@ -34,6 +36,18 @@ pub enum StatsDirection {
TX,
}
const DUMP_DATETIME_FORMAT: &[FormatItem] = format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
sign:mandatory]:[offset_minute]:[offset_second]"
);
fn time_format<T>(dt: T, format: &(impl Formattable + ?Sized)) -> String
where
T: Into<OffsetDateTime>,
{
dt.into().format(format).unwrap()
}
fn generate_initial_speeds(base_speed: f64, size: u32) -> Vec<f64> {
let mut rates = Vec::new();
@@ -76,10 +90,9 @@ struct State {
qdisc: Qdisc,
load: f64,
next_rate: f64,
now_t: f64,
nrate: usize,
previous_bytes: i128,
previous_bytes_t: f64,
prev_t: Instant,
safe_rates: Vec<f64>,
utilisation: f64,
}
@@ -114,6 +127,9 @@ impl Ratecontroller {
)
};
let now_t = Instant::now();
let dur = now_t.duration_since(state.prev_t);
if !state.deltas.is_empty() {
state.next_rate = state.current_rate;
@@ -134,7 +150,7 @@ impl Ratecontroller {
*/
state.utilisation = (8.0 / 1000.0)
* (state.current_bytes as f64 - state.previous_bytes as f64)
/ (state.now_t - state.previous_bytes_t);
/ dur.as_secs_f64();
state.load = state.utilisation / state.current_rate;
if state.delta_stat > 0.0
@@ -170,21 +186,21 @@ impl Ratecontroller {
}
}
state.previous_bytes_t = state.now_t;
state.previous_bytes = state.current_bytes;
state.next_rate = state.next_rate.max(min_rate).round();
state.previous_bytes = state.current_bytes;
state.prev_t = now_t;
Ok(())
}
fn update_deltas(&mut self, now_abstime: f64) {
fn update_deltas(&mut self) {
let state_dl = &mut self.state_dl;
let state_ul = &mut self.state_ul;
state_dl.deltas.clear();
state_ul.deltas.clear();
let now_t = Instant::now();
let owd_baseline = self.owd_baseline.lock().unwrap();
let owd_recent = self.owd_recent.lock().unwrap();
let reflectors = self.reflectors_lock.read().unwrap();
@@ -193,8 +209,10 @@ impl Ratecontroller {
// only consider this data if it's less than 2 * tick_duration seconds old
if owd_baseline.contains_key(reflector)
&& owd_recent.contains_key(reflector)
&& owd_recent[reflector].last_receive_time_s
> now_abstime - 2.0 * self.config.tick_interval
&& now_t
.duration_since(owd_recent[reflector].last_receive_time_s)
.as_secs_f64()
< self.config.tick_interval * 2.0
{
state_dl
.deltas
@@ -255,7 +273,6 @@ impl Ratecontroller {
deltas: Vec::new(),
load: 0.0,
next_rate: 0.0,
now_t: 0.0,
nrate: 0,
qdisc: dl_qdisc,
previous_bytes: cur_rx,
@@ -270,7 +287,6 @@ impl Ratecontroller {
deltas: Vec::new(),
load: 0.0,
next_rate: 0.0,
now_t: 0.0,
nrate: 0,
qdisc: ul_qdisc,
previous_bytes: cur_tx,
@@ -285,12 +301,8 @@ impl Ratecontroller {
pub fn run(&mut self) -> anyhow::Result<()> {
let sleep_time = Duration::from_secs_f64(self.config.min_change_interval);
let time = Time::new(ClockId::Monotonic);
let start_s = time.get_seconds() as f64;
let (mut lastchg_s, mut lastchg_ns) =
(time.get_seconds() as f64, time.get_nanoseconds() as f64);
let mut lastchg_t = lastchg_s - start_s + lastchg_ns / 1e9;
let mut lastdump_t = lastchg_t - 310.0;
let mut lastchg_t = Instant::now();
let mut lastdump_t = Instant::now();
// set qdisc rates to 60% of base rate to make sure we start with sane baselines
self.state_dl.current_rate = self.config.download_base_kbits * 0.6;
@@ -336,14 +348,9 @@ impl Ratecontroller {
loop {
sleep(sleep_time);
let now_t = Instant::now();
let now = Time::new(ClockId::Monotonic);
let (mut now_s, now_ns) = (now.get_seconds() as f64, now.get_nanoseconds() as f64);
let now_abstime = now_s + now_ns / 1e9;
now_s -= start_s;
let now_t = now_s + now_ns / 1e9;
if now_t - lastchg_t > self.config.min_change_interval {
if now_t.duration_since(lastchg_t).as_secs_f64() > self.config.min_change_interval {
// if it's been long enough, and the stats indicate needing to change speeds
// change speeds here
@@ -355,9 +362,7 @@ impl Ratecontroller {
continue;
}
self.state_dl.now_t = now_t;
self.state_ul.now_t = now_t;
self.update_deltas(now_abstime);
self.update_deltas();
self.calculate_rate(Direction::Down)?;
self.calculate_rate(Direction::Up)?;
@@ -381,16 +386,9 @@ impl Ratecontroller {
self.state_dl.current_rate = self.state_dl.next_rate;
self.state_ul.current_rate = self.state_ul.next_rate;
let lastchg = Clock::new(ClockId::Monotonic);
(lastchg_s, lastchg_ns) = (
lastchg.get_seconds() as f64,
lastchg.get_nanoseconds() as f64,
);
debug!(
"{},{},{},{},{},{},{},{}",
lastchg_s,
lastchg_ns,
"{},{},{},{},{},{},{}",
time_format(SystemTime::now(), DUMP_DATETIME_FORMAT),
self.state_dl.load,
self.state_ul.load,
self.state_dl.delta_stat,
@@ -402,9 +400,8 @@ impl Ratecontroller {
if let Some(ref mut fd) = stats_fd {
if let Err(e) = fd.write(
format!(
"{},{},{},{},{},{},{},{}\n",
lastchg_s,
lastchg_ns,
"{},{},{},{},{},{},{}",
time_format(SystemTime::now(), DUMP_DATETIME_FORMAT),
self.state_dl.load,
self.state_ul.load,
self.state_dl.delta_stat,
@@ -418,17 +415,19 @@ impl Ratecontroller {
}
}
lastchg_s -= start_s;
lastchg_t = lastchg_s + lastchg_ns / 1e9;
lastchg_t = now_t;
}
if let Some(ref mut fd) = speed_hist_fd {
if now_t - lastdump_t > 300.0 {
if now_t.duration_since(lastdump_t).as_secs_f64() > 300.0 {
for i in 0..self.config.speed_hist_size as usize {
if let Err(e) = fd.write_all(
format!(
"{},{},{},{}\n",
now_t, i, self.state_ul.safe_rates[i], self.state_dl.safe_rates[i]
time_format(SystemTime::now(), DUMP_DATETIME_FORMAT),
i,
self.state_ul.safe_rates[i],
self.state_dl.safe_rates[i]
)
.as_bytes(),
) {