//! Benchmarks for a variety of I/O operations. use async_io::Async; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use futures_lite::{future, prelude::*}; use std::net::{Ipv4Addr, SocketAddr, TcpListener, TcpStream, UdpSocket}; /// Block on a future, either using the I/O driver or simple parking. fn block_on(fut: impl Future, drive: bool) -> R { if drive { async_io::block_on(fut) } else { future::block_on(fut) } } fn read_and_write(b: &mut Criterion) { const TCP_AMOUNT: usize = 1024 * 1024; let mut group = b.benchmark_group("read_and_write"); for (driver_name, exec) in [("Undriven", false), ("Driven", true)] { // Benchmark the TCP streams. let init_reader_writer = || { let listener = TcpListener::bind("localhost:12345").unwrap(); let read_stream = TcpStream::connect("localhost:12345").unwrap(); let (write_stream, _) = listener.accept().unwrap(); let reader = Async::new(read_stream).unwrap(); let writer = Async::new(write_stream).unwrap(); (listener, reader, writer) }; group.bench_function(format!("TcpStream.{}", driver_name), move |b| { let (_listener, mut reader, mut writer) = init_reader_writer(); let mut buf = vec![0x42; TCP_AMOUNT]; b.iter(|| { let buf = &mut buf; block_on( async { black_box(writer.write_all(&*buf).await.ok()); black_box(reader.read_exact(buf).await.ok()); }, exec, ); }); }); #[cfg(unix)] { // Benchmark the Unix sockets. use std::os::unix::net::UnixStream; const UNIX_AMOUNT: usize = 1024; group.bench_function(format!("UnixStream.{}", driver_name), |b| { let (mut reader, mut writer) = Async::::pair().unwrap(); let mut buf = vec![0x42; UNIX_AMOUNT]; b.iter(|| { let buf = &mut buf; block_on( async { black_box(writer.write_all(&*buf).await.ok()); black_box(reader.read_exact(buf).await.ok()); }, exec, ); }); }); } } } fn connect_and_accept(c: &mut Criterion) { let mut group = c.benchmark_group("connect_and_accept"); for (driver_name, exec) in [("Undriven", false), ("Driven", true)] { // Benchmark the TCP streams. group.bench_function(format!("TcpStream.{}", driver_name), move |b| { let socket_addr = SocketAddr::new("127.0.0.1".parse::().unwrap().into(), 12345); let listener = Async::::bind(socket_addr).unwrap(); b.iter(|| { block_on( async { let _reader = Async::::connect(socket_addr).await.ok(); black_box(listener.accept().await.ok()); drop(black_box(_reader)); }, exec, ); }); }); #[cfg(unix)] { // Benchmark the Unix sockets. use std::os::unix::net::{UnixListener, UnixStream}; let mut id = [0u8; 8]; getrandom::getrandom(&mut id).unwrap(); let id = u64::from_ne_bytes(id); let socket_addr = format!("/tmp/async-io-bench-{}.sock", id); let listener = Async::::bind(&socket_addr).unwrap(); group.bench_function(format!("UnixStream.{}", driver_name), |b| { b.iter(|| { block_on( async { let _reader = Async::::connect(&socket_addr).await.ok(); black_box(listener.accept().await.ok()); drop(black_box(_reader)); }, exec, ); }); }); drop(listener); } } } fn udp_send_recv(c: &mut Criterion) { const UDP_AMOUNT: usize = 1024; let mut group = c.benchmark_group("udp_send_recv"); // Create a pair of UDP sockets. let socket_addr = |port| SocketAddr::new("127.0.0.1".parse::().unwrap().into(), port); let socket_addr1 = socket_addr(12345); let socket_addr2 = socket_addr(12346); let reader = Async::::bind(socket_addr1).unwrap(); let writer = Async::::bind(socket_addr2).unwrap(); let mut buf = vec![0x42; UDP_AMOUNT]; for (driver_name, exec) in [("Undriven", false), ("Driven", true)] { group.bench_function(format!("UdpSocket.{}", driver_name), |b| { b.iter(|| { let buf = &mut buf; block_on( async { black_box(writer.send_to(&*buf, socket_addr1).await.ok()); black_box(reader.recv_from(buf).await.ok()); }, exec, ); }); }); } } criterion_group! { io_benchmarks, read_and_write, connect_and_accept, udp_send_recv } criterion_main!(io_benchmarks);