1use subms_hdr_histogram::HdrHistogram;
16
17fn main() {
18 base_tick_to_trade();
19
20 #[cfg(feature = "concurrent-writes")]
21 concurrent_feed_handlers();
22
23 #[cfg(feature = "dual-recorder")]
24 dual_recorder_interval_report();
25
26 #[cfg(feature = "merge")]
27 merge_shard_rollup();
28
29 #[cfg(feature = "decay")]
30 decay_recency_weighted();
31
32 #[cfg(feature = "value-tagging")]
33 value_tagging_by_venue();
34
35 #[cfg(feature = "iterators")]
36 iterators_export_bands();
37}
38
39fn base_tick_to_trade() {
47 println!("== base: tick-to-trade latency capture ==");
48 let mut h = HdrHistogram::new(3);
49
50 let mut rng = 0x2545_F491_4F6C_DD1Du64;
54 let mut next = || {
55 rng ^= rng << 13;
56 rng ^= rng >> 7;
57 rng ^= rng << 17;
58 rng
59 };
60 let n = 2_000u64;
61 for i in 0..n {
62 let base = 700 + next() % 300; if i % 50 == 0 {
64 h.record(4_000 + next() % 4_000); } else {
66 h.record(base);
67 }
68 }
69
70 let p50 = h.value_at_percentile(0.50);
71 let p99 = h.value_at_percentile(0.99);
72 let p999 = h.value_at_percentile(0.999);
73 println!(
74 " n={n} p50={p50}ns p99={p99}ns p999={p999}ns max={}ns",
75 h.max()
76 );
77 assert_eq!(h.count(), n, "every sample recorded");
78 assert!(
79 p50 <= 1_100,
80 "median sits in the steady-state band: p50={p50}"
81 );
82 assert!(
83 p99 >= 2_000,
84 "the 2% tail lifts p99 well past the median: p99={p99}"
85 );
86 assert!(p999 >= p99 && h.max() >= p999, "percentiles are monotone");
87
88 let within_slo = h.percentile_at_or_below_value(2_000);
92 println!(
93 " min={}ns mean={:.0}ns within-2us={:.1}% footprint={}KB",
94 h.min(),
95 h.mean(),
96 within_slo * 100.0,
97 h.footprint_bytes() / 1024
98 );
99 assert!(within_slo > 0.9, "most ops sit inside the 2us band");
100
101 let mut naive = HdrHistogram::new(3);
105 let mut corrected = HdrHistogram::new(3);
106 for _ in 0..1_000 {
107 naive.record(10);
108 corrected.record_with_expected_interval(10, 10);
109 }
110 naive.record(1_000);
111 corrected.record_with_expected_interval(1_000, 10);
112 let naive_p99 = naive.value_at_percentile(0.99);
113 let corrected_p99 = corrected.value_at_percentile(0.99);
114 println!(" coordinated omission: naive p99={naive_p99}ns, corrected p99={corrected_p99}ns");
115 assert!(
116 naive_p99 <= 20,
117 "uncorrected tail hides the stall: {naive_p99}"
118 );
119 assert!(
120 corrected_p99 >= 500,
121 "correction lifts the tail: {corrected_p99}"
122 );
123}
124
125#[cfg(feature = "concurrent-writes")]
129fn concurrent_feed_handlers() {
130 use std::sync::Arc;
131 use std::thread;
132 use subms_hdr_histogram::ConcurrentHdrHistogram;
133 println!("\n== concurrent-writes: many feed handlers, one histogram ==");
134 let h = Arc::new(ConcurrentHdrHistogram::new(3));
135 let threads = 4;
136 let per_thread = 50_000u64;
137 let mut handles = vec![];
138 for _ in 0..threads {
139 let h = h.clone();
140 handles.push(thread::spawn(move || {
141 for i in 0..per_thread {
142 h.record((i % 1_000) + 500);
143 }
144 }));
145 }
146 for j in handles {
147 j.join().unwrap();
148 }
149 println!(
150 " {} records lock-free, p99={}ns",
151 h.count(),
152 h.value_at_percentile(0.99)
153 );
154 assert_eq!(
155 h.count(),
156 threads as u64 * per_thread,
157 "no writes lost under contention"
158 );
159}
160
161#[cfg(feature = "dual-recorder")]
165fn dual_recorder_interval_report() {
166 use subms_hdr_histogram::DualRecorder;
167 println!("\n== dual-recorder: lock-free interval percentile report ==");
168 let rec = DualRecorder::new(3);
169 for v in 1..=500u64 {
170 rec.record(v);
171 }
172 let interval = rec.get_interval_histogram();
173 println!(
174 " interval count={}, p99={}",
175 interval.count(),
176 interval.value_at_percentile(0.99)
177 );
178 let next = rec.get_interval_histogram();
179 assert_eq!(
180 interval.count(),
181 500,
182 "first interval captured every record"
183 );
184 assert_eq!(
185 next.count(),
186 0,
187 "the next interval starts empty after the rotate"
188 );
189}
190
191#[cfg(feature = "merge")]
195fn merge_shard_rollup() {
196 use subms_hdr_histogram::merge;
197 println!("\n== merge: roll per-shard histograms into a fleet view ==");
198 let mut shard_a = HdrHistogram::new(3);
199 let mut shard_b = HdrHistogram::new(3);
200 for v in 1..=500u64 {
201 shard_a.record(v);
202 }
203 for v in 501..=1_000u64 {
204 shard_b.record(v);
205 }
206 merge(&mut shard_a, &shard_b).expect("identical shape merges");
207 println!(
208 " fleet count={}, p50={}, p99={}",
209 shard_a.count(),
210 shard_a.value_at_percentile(0.5),
211 shard_a.value_at_percentile(0.99)
212 );
213 assert_eq!(shard_a.count(), 1_000, "both shards folded in");
214 assert!(
215 shard_a.value_at_percentile(0.99) >= 900,
216 "the high tail came from shard b"
217 );
218}
219
220#[cfg(feature = "decay")]
224fn decay_recency_weighted() {
225 use subms_hdr_histogram::{DecayingHdrHistogram, ManualClock};
226 println!("\n== decay: recency-weighted p50 forgets an old spike ==");
227 let clock = ManualClock::new();
228 let halflife = 1_000_000_000u64; let mut h = DecayingHdrHistogram::new(3, halflife, &clock);
230 for _ in 0..1_000 {
231 h.record(5_000); }
233 clock.advance_ns(halflife * 4); for _ in 0..1_000 {
235 h.record(800); }
237 let p50 = h.value_at_percentile(0.5);
238 println!(" decayed count~{:.0}, p50={p50}ns", h.count());
239 assert!(
240 p50 < 2_000,
241 "recent fast ops dominate the decayed distribution: p50={p50}"
242 );
243}
244
245#[cfg(feature = "value-tagging")]
249fn value_tagging_by_venue() {
250 use subms_hdr_histogram::TaggedHdrHistogram;
251 println!("\n== value-tagging: slice latency by venue ==");
252 const COLO: u8 = 0;
253 const REMOTE: u8 = 1;
254 let mut h = TaggedHdrHistogram::new(3);
255 for v in 500..=1_000u64 {
256 h.record(v, COLO); }
258 for v in 5_000..=6_000u64 {
259 h.record(v, REMOTE); }
261 let p99_colo = h.value_at_percentile_for_tag(0.99, COLO);
262 let p99_remote = h.value_at_percentile_for_tag(0.99, REMOTE);
263 println!(" colo p99={p99_colo}ns, remote p99={p99_remote}ns");
264 assert!(p99_colo < p99_remote, "each venue's tail reads on its own");
265}
266
267#[cfg(feature = "iterators")]
271fn iterators_export_bands() {
272 println!("\n== iterators: export the distribution as bands ==");
273 let mut h = HdrHistogram::new(3);
274 for v in 1..=1_000u64 {
275 h.record(v);
276 }
277 let bands = h.iter_logarithmic().count();
278 let quartiles: Vec<u64> = h.iter_percentiles(25.0).map(|e| e.value_lo).collect();
279 println!(" {bands} log2 bands; quartile lower bounds = {quartiles:?}");
280 assert!(bands > 0, "the populated range spans at least one band");
281 assert!(
282 !quartiles.is_empty(),
283 "the percentile walk yields quartile buckets"
284 );
285}