Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(streamer): ♻️ Clarify distinction between bitrate and throughput #2423

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 141 additions & 78 deletions alvr/dashboard/src/dashboard/components/statistics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,16 @@ impl StatisticsTab {
draw_lines(painter, client_fps_points, graph_colors::CLIENT_FPS);
},
|ui, stats| {
ui.colored_label(
graph_colors::SERVER_FPS,
format!("Streamer FPS: {:.2}", stats.server_fps),
);
ui.colored_label(
graph_colors::CLIENT_FPS,
format!("Client FPS: {:.2}", stats.client_fps),
);
Grid::new("fps_tooltip").num_columns(2).show(ui, |ui| {
fn label(ui: &mut Ui, text: &str, value: f32, color: Color32) {
ui.colored_label(color, text);
ui.colored_label(color, format!("{:.2}Hz", value));
ui.end_row();
}

label(ui, "Server FPS", stats.server_fps, graph_colors::SERVER_FPS);
label(ui, "Client FPS", stats.client_fps, graph_colors::CLIENT_FPS);
});
},
);
}
Expand All @@ -264,107 +266,168 @@ impl StatisticsTab {
let mut data = statistics::Data::new(
self.history
.iter()
.map(|stats| stats.actual_bitrate_bps as f64)
.map(|stats| stats.throughput_bps as f64)
.collect::<Vec<_>>(),
);

self.draw_graph(
ui,
available_width,
"Bitrate",
0.0..=(data.quantile(UPPER_QUANTILE) * 2.0) as f32 / 1e6,
"Bitrate and Throughput",
0.0..=(data.quantile(UPPER_QUANTILE) * 1.2) as f32 / 1e6,
|painter, to_screen_trans| {
let mut scaled_calculated = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut decoder_latency_limiter = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut network_latency_limiter = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut encoder_latency_limiter = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut manual_max = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut manual_min = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut requested = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut actual = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut max_throughput = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut min_throughput = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut requested_bitrate = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut recorded_throughput = Vec::with_capacity(GRAPH_HISTORY_SIZE);
let mut recorded_bitrate = Vec::with_capacity(GRAPH_HISTORY_SIZE);
for i in 0..GRAPH_HISTORY_SIZE {
let nom_br = &self.history[i].nominal_bitrate;
let d = &self.history[i].bitrate_directives;

if let Some(value) = nom_br.scaled_calculated_bps {
if let Some(value) = d.scaled_calculated_throughput_bps {
scaled_calculated.push(to_screen_trans * pos2(i as f32, value / 1e6))
}
if let Some(value) = nom_br.decoder_latency_limiter_bps {
if let Some(value) = d.decoder_latency_limiter_bps {
decoder_latency_limiter.push(to_screen_trans * pos2(i as f32, value / 1e6))
}
if let Some(value) = nom_br.network_latency_limiter_bps {
if let Some(value) = d.network_latency_limiter_bps {
network_latency_limiter.push(to_screen_trans * pos2(i as f32, value / 1e6))
}
if let Some(value) = nom_br.encoder_latency_limiter_bps {
if let Some(value) = d.encoder_latency_limiter_bps {
encoder_latency_limiter.push(to_screen_trans * pos2(i as f32, value / 1e6))
}
if let Some(value) = nom_br.manual_max_bps {
manual_max.push(to_screen_trans * pos2(i as f32, value / 1e6))
if let Some(value) = d.manual_max_throughput_bps {
max_throughput.push(to_screen_trans * pos2(i as f32, value / 1e6))
}
if let Some(value) = nom_br.manual_min_bps {
manual_min.push(to_screen_trans * pos2(i as f32, value / 1e6))
if let Some(value) = d.manual_min_throughput_bps {
min_throughput.push(to_screen_trans * pos2(i as f32, value / 1e6))
}
requested.push(to_screen_trans * pos2(i as f32, nom_br.requested_bps / 1e6));
actual.push(
to_screen_trans * pos2(i as f32, self.history[i].actual_bitrate_bps / 1e6),
requested_bitrate
.push(to_screen_trans * pos2(i as f32, d.requested_bitrate_bps / 1e6));
recorded_throughput.push(
to_screen_trans * pos2(i as f32, self.history[i].throughput_bps / 1e6),
);
recorded_bitrate
.push(to_screen_trans * pos2(i as f32, self.history[i].bitrate_bps / 1e6));
}

draw_lines(painter, scaled_calculated, Color32::GRAY);
draw_lines(painter, encoder_latency_limiter, graph_colors::TRANSCODE);
draw_lines(painter, network_latency_limiter, graph_colors::NETWORK);
draw_lines(painter, decoder_latency_limiter, graph_colors::TRANSCODE);
draw_lines(painter, manual_max, graph_colors::RENDER);
draw_lines(painter, manual_min, graph_colors::RENDER);
draw_lines(painter, requested, theme::OK_GREEN);
draw_lines(painter, actual, theme::FG);
},
|ui, stats| {
fn maybe_label(
ui: &mut Ui,
text: &str,
maybe_value_bps: Option<f32>,
color: Color32,
) {
if let Some(value) = maybe_value_bps {
ui.colored_label(color, format!("{text}: {:.2} Mbps", value / 1e6));
}
}

let n = &stats.nominal_bitrate;

maybe_label(
ui,
"Initial calculated",
n.scaled_calculated_bps,
Color32::GRAY,
draw_lines(
painter,
scaled_calculated,
graph_colors::INITIAL_CALCULATED_THROUGHPUT,
);
draw_lines(
painter,
encoder_latency_limiter,
graph_colors::ENCODER_DECODER_LATENCY_LIMITER,
);
draw_lines(
painter,
network_latency_limiter,
graph_colors::NETWORK_LATENCY_LIMITER,
);
maybe_label(
ui,
"Encoder latency limiter",
n.encoder_latency_limiter_bps,
graph_colors::TRANSCODE,
draw_lines(
painter,
decoder_latency_limiter,
graph_colors::ENCODER_DECODER_LATENCY_LIMITER,
);
maybe_label(
ui,
"Network latency limiter",
n.network_latency_limiter_bps,
graph_colors::NETWORK,
draw_lines(
painter,
max_throughput,
graph_colors::MIN_MAX_LATENCY_THROUGHPUT,
);
maybe_label(
ui,
"Decoder latency limiter",
n.decoder_latency_limiter_bps,
graph_colors::TRANSCODE,
draw_lines(
painter,
min_throughput,
graph_colors::MIN_MAX_LATENCY_THROUGHPUT,
);
maybe_label(ui, "Manual max", n.manual_max_bps, graph_colors::RENDER);
maybe_label(ui, "Manual min", n.manual_min_bps, graph_colors::RENDER);
maybe_label(ui, "Requested", Some(n.requested_bps), theme::OK_GREEN);
maybe_label(
ui,
"Actual recorded",
Some(stats.actual_bitrate_bps),
theme::FG,
draw_lines(painter, requested_bitrate, graph_colors::REQUESTED_BITRATE);
draw_lines(
painter,
recorded_throughput,
graph_colors::RECORDED_THROUGHPUT,
);
draw_lines(painter, recorded_bitrate, theme::FG);
},
|ui, stats| {
Grid::new("bitrate_tooltip").num_columns(2).show(ui, |ui| {
fn maybe_label(
ui: &mut Ui,
text: &str,
maybe_value_bps: Option<f32>,
color: Color32,
) {
if let Some(value) = maybe_value_bps {
ui.colored_label(color, text);
ui.colored_label(color, format!("{:.2} Mbps", value / 1e6));
ui.end_row();
}
}

let td = &stats.bitrate_directives;

maybe_label(
ui,
"Initial calculated throughput",
td.scaled_calculated_throughput_bps,
graph_colors::INITIAL_CALCULATED_THROUGHPUT,
);
maybe_label(
ui,
"Encoder latency limiter",
td.encoder_latency_limiter_bps,
graph_colors::ENCODER_DECODER_LATENCY_LIMITER,
);
maybe_label(
ui,
"Network latency limiter",
td.network_latency_limiter_bps,
graph_colors::NETWORK_LATENCY_LIMITER,
);
maybe_label(
ui,
"Decoder latency limiter",
td.decoder_latency_limiter_bps
.filter(|l| *l < stats.throughput_bps),
graph_colors::ENCODER_DECODER_LATENCY_LIMITER,
);
maybe_label(
ui,
"Manual max throughput",
td.manual_max_throughput_bps,
graph_colors::MIN_MAX_LATENCY_THROUGHPUT,
);
maybe_label(
ui,
"Manual min throughput",
td.manual_min_throughput_bps,
graph_colors::MIN_MAX_LATENCY_THROUGHPUT,
);
maybe_label(
ui,
"Requested bitrate",
Some(td.requested_bitrate_bps),
graph_colors::REQUESTED_BITRATE,
);
maybe_label(
ui,
"Recorded throughput",
Some(stats.throughput_bps),
graph_colors::RECORDED_THROUGHPUT,
);
maybe_label(
ui,
"Recorded bitrate",
Some(stats.bitrate_bps),
graph_colors::RECORDED_BITRATE,
);
});

ui.small("Note: throughput is the peak bitrate, packet_size/network_latency.");
},
)
}
Expand Down
15 changes: 8 additions & 7 deletions alvr/events/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ pub struct StatisticsSummary {

// Bitrate statistics minus the empirical output value
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct NominalBitrateStats {
pub scaled_calculated_bps: Option<f32>,
pub struct BitrateDirectives {
pub scaled_calculated_throughput_bps: Option<f32>,
pub decoder_latency_limiter_bps: Option<f32>,
pub network_latency_limiter_bps: Option<f32>,
pub encoder_latency_limiter_bps: Option<f32>,
pub manual_max_bps: Option<f32>,
pub manual_min_bps: Option<f32>,
pub requested_bps: f32,
pub manual_max_throughput_bps: Option<f32>,
pub manual_min_throughput_bps: Option<f32>,
pub requested_bitrate_bps: f32,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
Expand All @@ -47,8 +47,9 @@ pub struct GraphStatistics {
pub vsync_queue_s: f32,
pub client_fps: f32,
pub server_fps: f32,
pub nominal_bitrate: NominalBitrateStats,
pub actual_bitrate_bps: f32,
pub bitrate_directives: BitrateDirectives,
pub throughput_bps: f32,
pub bitrate_bps: f32,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
Expand Down
8 changes: 8 additions & 0 deletions alvr/gui_common/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ pub mod graph_colors {

pub const SERVER_FPS: Color32 = Color32::LIGHT_BLUE;
pub const CLIENT_FPS: Color32 = Color32::KHAKI;

pub const INITIAL_CALCULATED_THROUGHPUT: Color32 = Color32::GRAY;
pub const ENCODER_DECODER_LATENCY_LIMITER: Color32 = TRANSCODE;
pub const NETWORK_LATENCY_LIMITER: Color32 = NETWORK;
pub const MIN_MAX_LATENCY_THROUGHPUT: Color32 = Color32::RED;
pub const REQUESTED_BITRATE: Color32 = Color32::GREEN;
pub const RECORDED_THROUGHPUT: Color32 = Color32::KHAKI;
pub const RECORDED_BITRATE: Color32 = super::FG;
}

pub fn set_theme(ctx: &Context) {
Expand Down
Loading
Loading