1//! Benchmark the delay in propagating OS signals to any listeners.
2#![cfg(unix)]
3
4use criterion::{criterion_group, criterion_main, Criterion};
5use std::future::Future;
6use std::pin::Pin;
7use std::task::{Context, Poll};
8use tokio::runtime;
9use tokio::signal::unix::{signal, SignalKind};
10use tokio::sync::mpsc;
11
12struct Spinner {
13 count: usize,
14}
15
16impl Future for Spinner {
17 type Output = ();
18
19 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
20 if self.count > 3 {
21 Poll::Ready(())
22 } else {
23 self.count += 1;
24 cx.waker().wake_by_ref();
25 Poll::Pending
26 }
27 }
28}
29
30impl Spinner {
31 fn new() -> Self {
32 Self { count: 0 }
33 }
34}
35
36pub fn send_signal(signal: libc::c_int) {
37 use libc::{getpid, kill};
38
39 unsafe {
40 assert_eq!(kill(getpid(), signal), 0);
41 }
42}
43
44fn many_signals(c: &mut Criterion) {
45 let num_signals = 10;
46 let (tx, mut rx) = mpsc::channel(num_signals);
47
48 // Intentionally single threaded to measure delays in propagating wakes
49 let rt = runtime::Builder::new_current_thread()
50 .enable_all()
51 .build()
52 .unwrap();
53
54 let spawn_signal = |kind| {
55 let tx = tx.clone();
56 rt.spawn(async move {
57 let mut signal = signal(kind).expect("failed to create signal");
58
59 while signal.recv().await.is_some() {
60 if tx.send(()).await.is_err() {
61 break;
62 }
63 }
64 });
65 };
66
67 for _ in 0..num_signals {
68 // Pick some random signals which don't terminate the test harness
69 spawn_signal(SignalKind::child());
70 spawn_signal(SignalKind::io());
71 }
72 drop(tx);
73
74 // Turn the runtime for a while to ensure that all the spawned
75 // tasks have been polled at least once
76 rt.block_on(Spinner::new());
77
78 c.bench_function("many_signals", |b| {
79 b.iter(|| {
80 rt.block_on(async {
81 send_signal(libc::SIGCHLD);
82 for _ in 0..num_signals {
83 rx.recv().await.expect("channel closed");
84 }
85
86 send_signal(libc::SIGIO);
87 for _ in 0..num_signals {
88 rx.recv().await.expect("channel closed");
89 }
90 });
91 })
92 });
93}
94
95criterion_group!(signal_group, many_signals);
96
97criterion_main!(signal_group);
98