pub struct DriverStats {
pub waits: u64,
pub recv_calls: u64,
pub send_calls: u64,
pub accept_calls: u64,
pub other_calls: u64,
pub sqes: u64,
pub os_events: u64,
pub sleeps: u64,
pub spin_polls: u64,
}Expand description
System calls and events counted by a driver (plain counters; read them on the loop thread).
Fields§
§waits: u64Waits: epoll_wait, kevent, io_uring_enter, GetQueuedCompletionStatusEx.
recv_calls: u64Receive calls: recv, recvmmsg, WSARecv/WSARecvMsg (io_uring: none, completions only).
send_calls: u64Send calls: sendmsg/send, WSASend (io_uring: none, submissions only).
accept_calls: u64Accept calls: accept4, AcceptEx.
other_calls: u64Other system calls: registration, epoll_ctl, eventfd reads, io_uring_register, …
sqes: u64io_uring submission queue entries pushed (buffer hand-overs with PROVIDE_BUFFERS not
counted).
os_events: u64Completions or readiness events taken from the OS.
sleeps: u64Waits that blocked (put the thread to sleep, or could have: a non-zero timeout).
spin_polls: u64Non-blocking polls made while busy polling (also counted in waits when they were system
calls; io_uring polls its rings in user space and enters only when work is flagged).
Implementations§
Source§impl DriverStats
impl DriverStats
Sourcepub fn syscalls(&self) -> u64
pub fn syscalls(&self) -> u64
All counted system calls.
Examples found in repository?
107fn main() {
108 let a = args();
109 let addr = format!("127.0.0.1:{}", a.port);
110 if a.mode == "threads" {
111 threads_mode(&addr, a.secs);
112 return;
113 }
114 let cpus = a.cpus.clone();
115 let rt = Runtime::builder()
116 .configure(|c| {
117 c.threads = a.threads;
118 c.driver.backend = a.backend;
119 c.driver.iocp_eager_recv = a.eager;
120 if let Some(cpus) = cpus {
121 c.pin_threads = true;
122 c.cpus = Some(cpus);
123 }
124 })
125 .listen(addr.as_str(), |_: &ConnInfo| Some(Box::new(Raw) as Box<dyn Connection>))
126 .start()
127 .expect("start");
128 eprintln!(
129 "raw_http: {} loops on {:?}, back end {:?}{}",
130 rt.loops().len(),
131 rt.local_addrs(),
132 rt.backend(),
133 rt.fallback_reason().map(|r| format!(" ({r})")).unwrap_or_default()
134 );
135 std::thread::sleep(Duration::from_secs(a.secs));
136 let (tx, rx) = mpsc::channel();
137 for l in rt.loops() {
138 let tx = tx.clone();
139 l.run(move |_| tx.send(SERVED.with(|c| c.get())).unwrap());
140 }
141 drop(tx);
142 let served: u64 = rx.iter().sum();
143 let t = rt.stats().total();
144 let d = t.driver;
145 let per = |x: u64| if served == 0 { 0.0 } else { x as f64 / served as f64 };
146 println!("served {served} requests on {} connections", t.accepted);
147 println!(
148 "per request: {:.3} syscalls (waits {:.3}, recv {:.3}, send {:.3}, other {:.3}); {:.3} io_uring SQEs; {:.3} OS events; {:.3} sleeps; {:.3} spin polls",
149 per(d.syscalls()),
150 per(d.waits),
151 per(d.recv_calls),
152 per(d.send_calls),
153 per(d.accept_calls + d.other_calls),
154 per(d.sqes),
155 per(d.os_events),
156 per(d.sleeps),
157 per(d.spin_polls)
158 );
159 rt.stop(Duration::from_millis(100));
160 rt.join();
161}More examples
76fn main() {
77 let mut addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
78 let (mut conns, mut threads, mut secs, mut pipeline) = (64usize, 4usize, 10u64, 1usize);
79 let mut cpus: Option<Vec<usize>> = None;
80 let v: Vec<String> = std::env::args().skip(1).collect();
81 let mut i = 0;
82 while i < v.len() {
83 let val = v.get(i + 1).cloned().unwrap_or_default();
84 match v[i].as_str() {
85 "--addr" => addr = val.parse().expect("--addr"),
86 "--conns" => conns = val.parse().expect("--conns"),
87 "--threads" => threads = val.parse().expect("--threads"),
88 "--secs" => secs = val.parse().expect("--secs"),
89 "--pipeline" => pipeline = val.parse().expect("--pipeline"),
90 "--cpus" => cpus = Some(val.split(',').map(|s| s.trim().parse().expect("--cpus")).collect()),
91 other => panic!("unknown argument {other}"),
92 }
93 i += 2;
94 }
95 let rt = Runtime::builder()
96 .configure(|c| {
97 c.threads = threads;
98 c.thread_name = "loadgen".into();
99 if let Some(cpus) = cpus {
100 c.pin_threads = true;
101 c.cpus = Some(cpus);
102 }
103 })
104 .start()
105 .expect("start");
106 let (htx, hrx) = mpsc::channel::<ConnHandle>();
107 for k in 0..conns {
108 let sock = Socket::tcp_connect(addr).expect("connect");
109 let htx = htx.clone();
110 rt.loops()[k % threads].run(move |lcx| {
111 let h = lcx.adopt(sock, Box::new(Client { pipeline })).expect("adopt");
112 htx.send(h).unwrap();
113 });
114 }
115 drop(htx);
116 let handles: Vec<ConnHandle> = hrx.iter().take(conns).collect();
117 for h in &handles {
118 h.send(Box::new(()));
119 }
120 let count = |rt: &simoom_rt::RuntimeHandle| -> (u64, u64) {
121 let (tx, rx) = mpsc::channel();
122 for l in rt.loops() {
123 let tx = tx.clone();
124 l.run(move |_| tx.send((DONE.with(|c| c.get()), ERRORS.with(|c| c.get()))).unwrap());
125 }
126 drop(tx);
127 rx.iter().fold((0, 0), |a, b| (a.0 + b.0, a.1 + b.1))
128 };
129 std::thread::sleep(Duration::from_secs(1));
130 let (r0, _) = count(&rt);
131 let s0 = rt.stats().total().driver;
132 let t0 = Instant::now();
133 std::thread::sleep(Duration::from_secs(secs));
134 let (r1, errors) = count(&rt);
135 let el = t0.elapsed().as_secs_f64();
136 let s1 = rt.stats().total().driver;
137 let rps = (r1 - r0) as f64 / el;
138 let lat_us = (conns * pipeline) as f64 / rps * 1e6;
139 println!(
140 "{conns} conns x {pipeline} pipelined, {threads} threads: {rps:.0} req/s, mean latency {lat_us:.1} us (Little), closed connections {errors}, client syscalls/req {:.2}",
141 (s1.syscalls() - s0.syscalls()) as f64 / (r1 - r0).max(1) as f64
142 );
143 rt.stop(Duration::ZERO);
144 rt.join();
145}Trait Implementations§
Source§impl Clone for DriverStats
impl Clone for DriverStats
Source§fn clone(&self) -> DriverStats
fn clone(&self) -> DriverStats
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more