use chrono::{DateTime, Local, TimeDelta};
use routee_compass_core::model::unit::TimeUnit;
use serde::{Deserialize, Serialize};
use uom::si::f64::Time;
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Runtimes {
input: f64,
input_wall: f64,
search: f64,
output: f64,
#[serde(skip_serializing_if = "Vec::is_empty")]
input_plugins: Vec<InputPluginRuntime>,
#[serde(skip_serializing_if = "Vec::is_empty")]
output_plugins: Vec<OutputPluginRuntime>,
total: f64,
wall: f64,
time_unit: TimeUnit,
}
#[derive(Default, Clone, Debug)]
pub struct InputPluginRuntimes {
pub runtimes: Vec<InputPluginRecordedRuntime>,
}
#[derive(Debug, Clone)]
pub struct InputPluginRecordedRuntime {
name: String,
time: TimeDelta,
wall: TimeDelta,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputPluginRuntime {
name: String,
time: f64,
wall: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutputPluginRuntime {
name: String,
time: f64,
}
impl Runtimes {
pub fn new(time_unit: TimeUnit) -> Self {
Self {
input: 0.0,
input_wall: 0.0,
search: 0.0,
output: 0.0,
input_plugins: vec![],
output_plugins: vec![],
total: 0.0,
wall: 0.0,
time_unit,
}
}
pub fn add_search_runtime(&mut self, td: TimeDelta) {
let time = to_serializable(&td, &self.time_unit);
self.total += time;
self.wall += time;
self.search = time;
}
pub fn add_input_plugin_runtimes(&mut self, ipr: &InputPluginRuntimes) {
for record in ipr.runtimes.iter() {
let time = to_serializable(&record.time, &self.time_unit);
let wall = to_serializable(&record.wall, &self.time_unit);
self.wall += wall;
self.input_wall += wall;
self.total += time;
self.input += time;
self.input_plugins.push(InputPluginRuntime {
name: record.name.clone(),
time,
wall,
});
}
}
pub fn add_output_plugin_runtime(&mut self, name: &str, start_time: DateTime<Local>) {
let duration = chrono::Local::now() - start_time;
let time = to_serializable(&duration, &self.time_unit);
self.total += time;
self.wall += time;
self.output += time;
self.output_plugins.push(OutputPluginRuntime {
name: name.to_string(),
time,
});
}
}
impl InputPluginRuntimes {
pub fn record(&mut self, name: &str, start_time: DateTime<Local>, n_results: usize) {
let duration = chrono::Local::now() - start_time;
let denom = if n_results == 0 {
1
} else if (i32::MAX as usize) < n_results {
i32::MAX
} else {
n_results as i32
};
let dur_prop = duration.checked_div(denom).unwrap_or_default();
let recorded = InputPluginRecordedRuntime {
name: name.to_string(),
time: dur_prop,
wall: duration,
};
self.runtimes.push(recorded);
}
}
const NANOS_PER_SEC: f64 = 1_000_000_000.0;
fn to_fractional_seconds(td: &TimeDelta) -> f64 {
let nanos_f64 = td.num_nanoseconds().unwrap_or(0) as f64;
nanos_f64 / NANOS_PER_SEC
}
fn to_serializable(value: &TimeDelta, time_unit: &TimeUnit) -> f64 {
let secs_uom: Time = TimeUnit::Seconds.to_uom(to_fractional_seconds(value));
time_unit.from_uom(secs_uom)
}