refactor(cli): simplify feature flags and make stats mandatory for clients
Remove the optional "stats" feature by merging it into the "client" and "tui" features to reduce conditional compilation complexity. Replace the "client-runtime" internal feature with direct dependency sets.
This commit is contained in:
6 files changed
+29
-82
No files matched your search
@@ -37,13 +37,10 @@ required-features = ["server"]
|
||||
doc = false
|
||||
|
||||
[features]
|
||||
default = ["client", "server", "stats"]
|
||||
client-runtime = ["dep:irtt-client", "irtt-client/ancillary", "irtt-client/tokio", "dep:irtt-proto"]
|
||||
client = ["client-runtime"]
|
||||
default = ["client", "server", "tui"]
|
||||
client = ["dep:irtt-client", "irtt-client/ancillary", "irtt-client/tokio", "dep:irtt-proto", "dep:irtt-stats"]
|
||||
server = ["dep:irtt-server", "dep:tokio"]
|
||||
stats = ["client-runtime", "dep:irtt-stats"]
|
||||
tui = ["client-runtime", "stats", "dep:ratatui", "dep:crossterm"]
|
||||
full = ["client", "server", "stats", "tui"]
|
||||
tui =["dep:irtt-client", "irtt-client/ancillary", "irtt-client/tokio", "dep:irtt-proto", "dep:irtt-stats", "dep:ratatui", "dep:crossterm"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.6.6", features = ["derive"] }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
pub mod args;
|
||||
pub mod output;
|
||||
pub mod run;
|
||||
#[cfg(feature = "stats")]
|
||||
pub mod summary;
|
||||
|
||||
pub use args::{ClientArgs, HeaderMode, OutputFormat};
|
||||
|
||||
@@ -164,7 +164,6 @@ pub struct IpdvPair {
|
||||
pub receive_ipdv: Option<Duration>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
impl From<irtt_stats::EventStatsUpdate> for EventRenderStats {
|
||||
fn from(value: irtt_stats::EventStatsUpdate) -> Self {
|
||||
Self {
|
||||
@@ -174,7 +173,6 @@ impl From<irtt_stats::EventStatsUpdate> for EventRenderStats {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
impl From<irtt_stats::IpdvPairUpdate> for IpdvPair {
|
||||
fn from(value: irtt_stats::IpdvPairUpdate) -> Self {
|
||||
Self {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#[cfg(feature = "stats")]
|
||||
use std::collections::BTreeMap;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
@@ -21,7 +20,7 @@ use super::{
|
||||
args::ClientArgs,
|
||||
output::{EventRenderStats, OutputConfig},
|
||||
};
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
use crate::shared::client::expected_probe_count;
|
||||
use crate::shared::client::{
|
||||
is_shutdown_requested,
|
||||
@@ -30,20 +29,19 @@ use crate::shared::client::{
|
||||
request_managed_stop_once, should_print_final_summary, ManagedDrainState,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
use irtt_stats::{StatsCollector, StatsConfig};
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
const FINITE_STATS_BYTES_PER_PROBE: u64 = 500;
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
const MIB: u64 = 1024 * 1024;
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
const GIB: u64 = 1024 * MIB;
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
const FINITE_STATS_MEMORY_WARNING_BYTES: u64 = 128 * MIB;
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
const FINITE_STATS_MEMORY_STRONG_WARNING_BYTES: u64 = 512 * MIB;
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
const FINITE_STATS_MEMORY_VERY_STRONG_WARNING_BYTES: u64 = GIB;
|
||||
const MANAGED_EVENT_WAIT_SLICE: Duration = Duration::from_millis(20);
|
||||
const MANAGED_EVENT_CAPACITY: usize = 16_384;
|
||||
@@ -70,7 +68,7 @@ pub fn run_stream(
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||
let continuous = args.is_continuous();
|
||||
let target_count = targets.len();
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
if let Some(warning) = finite_stats_memory_warning(&args, target_count) {
|
||||
eprintln!("{warning}");
|
||||
}
|
||||
@@ -102,7 +100,7 @@ pub fn run_stream(
|
||||
show_running_only_summary_note: false,
|
||||
out: &mut stdout,
|
||||
};
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
let mut stats = targets
|
||||
.iter()
|
||||
.map(|target| {
|
||||
@@ -135,7 +133,6 @@ pub fn run_stream(
|
||||
let drain_state = drain_events(
|
||||
&mut events,
|
||||
&mut stream_output,
|
||||
#[cfg(feature = "stats")]
|
||||
&mut stats,
|
||||
&mut terminal_targets,
|
||||
&mut dropped_events,
|
||||
@@ -156,7 +153,6 @@ pub fn run_stream(
|
||||
drain_final_events(
|
||||
&mut events,
|
||||
&mut stream_output,
|
||||
#[cfg(feature = "stats")]
|
||||
&mut stats,
|
||||
&mut terminal_targets,
|
||||
&mut dropped_events,
|
||||
@@ -196,7 +192,6 @@ pub fn run_stream(
|
||||
stream_output.print_final_summary = should_print_final_summary(continuous, interrupted);
|
||||
stream_output.show_running_only_summary_note =
|
||||
continuous && interrupted && stream_output.print_final_summary;
|
||||
#[cfg(feature = "stats")]
|
||||
for (label, stats) in &stats {
|
||||
if multi_target
|
||||
&& stream_output.print_final_summary
|
||||
@@ -207,8 +202,6 @@ pub fn run_stream(
|
||||
}
|
||||
stream_output.print_summary(stats)?;
|
||||
}
|
||||
#[cfg(not(feature = "stats"))]
|
||||
stream_output.print_summary()?;
|
||||
stream_output.out.flush()?;
|
||||
if let Some(error) = terminal_error {
|
||||
return Err(error.into());
|
||||
@@ -219,28 +212,19 @@ pub fn run_stream(
|
||||
fn process_event<W: Write>(
|
||||
event: ManagedEvent,
|
||||
stream_output: &mut StreamOutput<'_, W>,
|
||||
#[cfg(feature = "stats")] stats: &mut BTreeMap<String, StatsCollector>,
|
||||
stats: &mut BTreeMap<String, StatsCollector>,
|
||||
terminal_targets: &mut HashSet<TargetInstance>,
|
||||
) -> io::Result<()> {
|
||||
match event {
|
||||
ManagedEvent::Client { target, event } => {
|
||||
#[cfg(feature = "stats")]
|
||||
{
|
||||
let collector = stats
|
||||
.entry(target.id.as_str().to_owned())
|
||||
.or_insert_with(|| StatsCollector::new(stats_config(false)));
|
||||
print_events_with_stats(
|
||||
stream_output,
|
||||
std::slice::from_ref(&event),
|
||||
Some(target.id.as_str()),
|
||||
collector,
|
||||
)?;
|
||||
}
|
||||
#[cfg(not(feature = "stats"))]
|
||||
let collector = stats
|
||||
.entry(target.id.as_str().to_owned())
|
||||
.or_insert_with(|| StatsCollector::new(stats_config(false)));
|
||||
print_events_with_stats(
|
||||
stream_output,
|
||||
std::slice::from_ref(&event),
|
||||
Some(target.id.as_str()),
|
||||
collector,
|
||||
)?;
|
||||
}
|
||||
ManagedEvent::TargetFinished { outcome } => {
|
||||
@@ -255,37 +239,25 @@ fn process_event<W: Write>(
|
||||
fn drain_events<W: Write>(
|
||||
events: &mut ManagedEventSubscription,
|
||||
stream_output: &mut StreamOutput<'_, W>,
|
||||
#[cfg(feature = "stats")] stats: &mut BTreeMap<String, StatsCollector>,
|
||||
stats: &mut BTreeMap<String, StatsCollector>,
|
||||
terminal_targets: &mut HashSet<TargetInstance>,
|
||||
dropped_events: &mut u64,
|
||||
) -> io::Result<ManagedDrainState> {
|
||||
drain_managed_events(events, dropped_events, |event| {
|
||||
process_event(
|
||||
event,
|
||||
stream_output,
|
||||
#[cfg(feature = "stats")]
|
||||
stats,
|
||||
terminal_targets,
|
||||
)
|
||||
process_event(event, stream_output, stats, terminal_targets)
|
||||
})
|
||||
}
|
||||
|
||||
fn drain_final_events<W: Write>(
|
||||
events: &mut ManagedEventSubscription,
|
||||
stream_output: &mut StreamOutput<'_, W>,
|
||||
#[cfg(feature = "stats")] stats: &mut BTreeMap<String, StatsCollector>,
|
||||
stats: &mut BTreeMap<String, StatsCollector>,
|
||||
terminal_targets: &mut HashSet<TargetInstance>,
|
||||
dropped_events: &mut u64,
|
||||
) -> io::Result<()> {
|
||||
loop {
|
||||
match events.try_recv() {
|
||||
Ok(event) => process_event(
|
||||
event,
|
||||
stream_output,
|
||||
#[cfg(feature = "stats")]
|
||||
stats,
|
||||
terminal_targets,
|
||||
)?,
|
||||
Ok(event) => process_event(event, stream_output, stats, terminal_targets)?,
|
||||
Err(ManagedEventTryRecvError::Empty | ManagedEventTryRecvError::Closed) => break,
|
||||
Err(ManagedEventTryRecvError::Lagged(count)) => {
|
||||
*dropped_events = dropped_events.saturating_add(count);
|
||||
@@ -353,7 +325,7 @@ impl<W: Write> StreamOutput<'_, W> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
fn print_summary(&mut self, stats: &StatsCollector) -> io::Result<()> {
|
||||
if self.print_final_summary && self.config.prints_summary() {
|
||||
write!(
|
||||
@@ -370,12 +342,8 @@ impl<W: Write> StreamOutput<'_, W> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(not(feature = "stats"))]
|
||||
fn print_summary(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
fn print_events_with_stats<W: Write>(
|
||||
stream_output: &mut StreamOutput<'_, W>,
|
||||
events: &[ClientEvent],
|
||||
@@ -388,19 +356,7 @@ fn print_events_with_stats<W: Write>(
|
||||
.collect::<Vec<_>>();
|
||||
stream_output.print_events(events, target, &updates)
|
||||
}
|
||||
#[cfg(not(feature = "stats"))]
|
||||
fn print_events_with_stats<W: Write>(
|
||||
stream_output: &mut StreamOutput<'_, W>,
|
||||
events: &[ClientEvent],
|
||||
target: Option<&str>,
|
||||
) -> io::Result<()> {
|
||||
stream_output.print_events(
|
||||
events,
|
||||
target,
|
||||
&vec![EventRenderStats::default(); events.len()],
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "stats")]
|
||||
|
||||
fn stats_config(continuous: bool) -> StatsConfig {
|
||||
if continuous {
|
||||
StatsConfig::continuous()
|
||||
@@ -408,7 +364,6 @@ fn stats_config(continuous: bool) -> StatsConfig {
|
||||
StatsConfig::finite()
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "stats")]
|
||||
fn finite_stats_memory_warning(args: &ClientArgs, target_count: usize) -> Option<String> {
|
||||
if args.is_continuous() || args.duration.is_zero() {
|
||||
return None;
|
||||
@@ -443,7 +398,6 @@ mod tests {
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
#[test]
|
||||
fn finite_stats_memory_warning_accounts_for_target_count() {
|
||||
use clap::Parser;
|
||||
@@ -468,7 +422,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
#[test]
|
||||
fn finite_stats_memory_warning_saturates_target_count_multiplication() {
|
||||
use clap::Parser;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[cfg(feature = "client-runtime")]
|
||||
#[cfg(any(feature = "client", feature = "tui"))]
|
||||
use irtt_client::managed::{ManagedEvent, ManagedEventSubscription, ManagedEventTryRecvError};
|
||||
|
||||
#[cfg(feature = "client-runtime")]
|
||||
#[cfg(any(feature = "client", feature = "tui"))]
|
||||
pub(crate) const MANAGED_EVENT_WORK_BUDGET: usize = 128;
|
||||
|
||||
#[cfg(feature = "client-runtime")]
|
||||
#[cfg(any(feature = "client", feature = "tui"))]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum ManagedDrainState {
|
||||
Empty,
|
||||
@@ -16,7 +16,7 @@ pub(crate) enum ManagedDrainState {
|
||||
|
||||
/// Drain a bounded amount of lossy presentation work before returning to the
|
||||
/// frontend control loop.
|
||||
#[cfg(feature = "client-runtime")]
|
||||
#[cfg(any(feature = "client", feature = "tui"))]
|
||||
pub(crate) fn drain_managed_events<E>(
|
||||
events: &mut ManagedEventSubscription,
|
||||
dropped_events: &mut u64,
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#[cfg(feature = "client-runtime")]
|
||||
#[cfg(any(feature = "client", feature = "tui"))]
|
||||
pub mod client;
|
||||
Reference in new issue
Block a user