1use full_palette::PURPLE_500;
28use plotters::coord::types::RangedCoordf64;
29use plotters::coord::types::RangedCoordu64;
30use plotters::coord::Shift;
31
32use crate::plots::colors::*;
33use crate::plots::*;
34
35use crate::datastore::Datastore;
36use crate::seriesstore::SeriesStore;
37
38use super::minmax::XYMinMax;
39
40pub fn draw_congestion_plot<'a, DB: DrawingBackend + 'a>(
41 params: &PlotParameters, axis: &XYMinMax<u64>, ss: &SeriesStore,
42 ds: &Datastore, plot: &plotters::drawing::DrawingArea<DB, Shift>,
43) -> ChartContext<'a, DB, Cartesian2d<RangedCoordf64, RangedCoordu64>> {
44 let mut builder = ChartBuilder::on(plot);
45
46 builder
47 .x_label_area_size(params.area_margin.x)
48 .y_label_area_size(params.area_margin.y);
49
50 if params.display_chart_title {
51 builder
52 .caption("Congestion", chart_subtitle_style(¶ms.colors.caption));
53 }
54
55 let extended_y =
56 axis.y_range.start..axis.y_range.end + (axis.y_range.end / 10) * 5;
57
58 let mut plot = builder
59 .build_cartesian_2d(axis.x.range(), extended_y.clone())
60 .unwrap();
61
62 draw_mesh(
63 ¶ms.colors,
64 "Relative time (ms)",
65 "Data (bytes)",
66 false,
67 &mut plot,
68 );
69
70 draw_cc_updates(
71 &ds.congestion_state_updates,
72 axis.y_range.clone(),
73 extended_y,
74 &mut plot,
75 );
76 draw_bytes_in_flight(&ss.local_bytes_in_flight, &mut plot);
77 draw_cwnd(&ss.local_cwnd, &mut plot);
78 draw_ssthresh(&ss.local_ssthresh, &mut plot);
79
80 if params.display_legend {
81 plot.configure_series_labels()
82 .label_font(chart_label_style(¶ms.colors.caption))
83 .background_style(params.colors.fill.mix(0.8))
84 .border_style(params.colors.axis)
85 .position(SeriesLabelPosition::UpperLeft)
86 .draw()
87 .unwrap();
88 }
89
90 plot
91}
92
93#[cfg(target_arch = "wasm32")]
94pub fn plot_cc_plot<'a>(
95 params: &PlotParameters, ss: &SeriesStore, ds: &Datastore, canvas_id: &str,
96) -> ChartContext<'a, CanvasBackend, Cartesian2d<RangedCoordf64, RangedCoordu64>>
97{
98 let root =
99 make_chart_canvas_area(&canvas_id, params.colors, params.chart_margin);
100
101 let cwnd_y_max = if let Some(y_max) = params.cwnd_y_max {
102 y_max
103 } else {
104 ss.y_max_congestion_plot + ss.y_max_congestion_plot / 10
106 };
107
108 let axis = super::minmax::XYMinMax::init(
110 ss.sent_x_min..ss.sent_x_max,
111 params.clamp.start,
112 params.clamp.end,
113 0..cwnd_y_max,
114 );
115
116 draw_congestion_plot(params, &axis, ss, ds, &root)
117}
118
119fn draw_cc_updates<DB: DrawingBackend>(
120 data: &[(f64, u64, String)], y_range: std::ops::Range<u64>,
121 y_range_extended: std::ops::Range<u64>,
122 congestion_chart: &mut ChartContext<
123 DB,
124 Cartesian2d<RangedCoordf64, RangedCoordu64>,
125 >,
126) {
127 let my_label = |x: f64, y: u64, name: &str| {
128 let color = cc_state_to_color(name);
129 let text_width = name.len() as i32 * 6; let text_height = 12;
131
132 return EmptyElement::at((x, y))
133 + Rectangle::new([(1, -2), (1 + text_width, text_height)],
135 WHITE.mix(0.7).filled()) + Text::new(
137 name.to_owned(),
138 (1, 0),
139 ("sans-serif", 12.0).into_font().color(&color),
140 );
141 };
142
143 let mut woggle = vec![0];
144
145 for i in 1..5 {
146 woggle.push((y_range.end / 10) * i);
147 }
148
149 let iter = data.iter().rev();
152 for cc_state in iter {
153 let color = cc_state_to_color(&cc_state.2);
154 let x = cc_state.0;
155
156 let line_coords =
157 [(x, y_range_extended.start), (x, y_range_extended.end)];
158
159 congestion_chart
160 .draw_series(LineSeries::new(line_coords, color))
161 .unwrap();
162
163 let area = congestion_chart.plotting_area();
164
165 let y = y_range.end + woggle[0];
167 area.draw(&my_label(x, y, &cc_state.2)).unwrap();
168
169 woggle.rotate_left(1);
170 }
171}
172
173fn draw_bytes_in_flight<DB: DrawingBackend>(
174 data: &[(f64, u64)],
175 congestion_chart: &mut ChartContext<
176 DB,
177 Cartesian2d<RangedCoordf64, RangedCoordu64>,
178 >,
179) {
180 draw_line(data, Some("bytes in flight"), TAUPE, congestion_chart);
181}
182
183fn draw_cwnd<DB: DrawingBackend>(
184 data: &[(f64, u64)],
185 congestion_chart: &mut ChartContext<
186 DB,
187 Cartesian2d<RangedCoordf64, RangedCoordu64>,
188 >,
189) {
190 draw_line(data, Some("cwnd"), PURPLE_500, congestion_chart);
191}
192
193fn draw_ssthresh<DB: DrawingBackend>(
194 data: &[(f64, u64)],
195 congestion_chart: &mut ChartContext<
196 DB,
197 Cartesian2d<RangedCoordf64, RangedCoordu64>,
198 >,
199) {
200 draw_line(data, Some("ssthresh"), ORANGE, congestion_chart);
201}
202
203fn cc_state_to_color(cc_state: &str) -> RGBColor {
205 match cc_state {
206 "slow_start" => RGBColor(204, 81, 81),
208 "recovery" => RGBColor(127, 51, 51),
209 "congestion_avoidance" => RGBColor(81, 204, 204),
210
211 "bbr_startup" => RGBColor(204, 81, 81),
213 "bbr_drain" => RGBColor(127, 51, 51),
214 "bbr_probe_bw" => RGBColor(81, 204, 204),
215 "bbr_probe_rtt" => RGBColor(51, 127, 127),
216
217 _ => BLACK,
218 }
219}