use blunt::websocket::{WebSocketHandler, WebSocketMessage, WebSocketSession};
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use std::time::{Duration, Instant};
use tokio::task::JoinHandle;
#[derive(Debug, Default)]
pub struct EchoServer;
#[blunt::async_trait]
impl WebSocketHandler for EchoServer {
async fn on_open(&mut self, _ws: &WebSocketSession) {}
async fn on_message(&mut self, ws: &WebSocketSession, msg: WebSocketMessage) {
match ws.send(msg) {
Ok(_) => (),
Err(e) => eprintln!("Unable to send: {:?}", e),
};
}
async fn on_close(&mut self, _ws: &WebSocketSession, _msg: WebSocketMessage) {}
}
fn start_echo_server() -> JoinHandle<()> {
tokio::spawn(async {
let handler = EchoServer::default();
let _ = ::blunt::builder()
.for_path("/echo", handler)
.build()
.bind("127.0.0.1:9999".parse().expect("Invalid Socket Addr"))
.await;
})
}
fn single_echo_benchmark(c: &mut Criterion) {
use tungstenite::{connect, Message};
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let _server_handle = start_echo_server();
let (mut socket, _response) = connect("ws://localhost:9999/echo").expect("Can't connect");
let mut group = c.benchmark_group("single echo server");
group.throughput(Throughput::Elements(100));
group.bench_function("100 - Send only", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for _n in 0..iters {
socket.write_message(black_box(ws_message.clone())).unwrap();
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("single echo server");
group.throughput(Throughput::Elements(100));
group.bench_function("100 - Send and receive", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for _n in 0..iters {
socket.write_message(black_box(ws_message.clone())).unwrap();
let _ = socket.read_message().expect("Error reading message");
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("single echo server");
group.throughput(Throughput::Elements(1000));
group.bench_function("1000 - Send only", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for _n in 0..iters {
socket.write_message(black_box(ws_message.clone())).unwrap();
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("single echo server");
group.throughput(Throughput::Elements(1000));
group.bench_function("1000 - Send and receive", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for _n in 0..iters {
socket.write_message(black_box(ws_message.clone())).unwrap();
let _ = socket.read_message().expect("Error reading message");
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("single echo server");
group.throughput(Throughput::Elements(10000));
group.bench_function("10000 - Send only", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for _n in 0..iters {
socket.write_message(black_box(ws_message.clone())).unwrap();
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("single echo server");
group.throughput(Throughput::Elements(10000));
group.bench_function("10000 - Send and receive", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for _n in 0..iters {
socket.write_message(black_box(ws_message.clone())).unwrap();
let _ = socket.read_message().expect("Error reading message");
}
start.elapsed()
})
});
group.finish();
});
}
fn start_multi_echo_server() -> JoinHandle<()> {
tokio::spawn(async {
let handler = EchoServer::default();
let handler2 = EchoServer::default();
let _ = ::blunt::builder()
.for_path("/echo", handler)
.for_path("/echo2", handler2)
.build()
.bind("127.0.0.1:9999".parse().expect("Invalid Socket Addr"))
.await;
})
}
fn multi_echo_benchmark(c: &mut Criterion) {
use tungstenite::{connect, Message};
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let _multi_server_handle = start_multi_echo_server();
let (mut socket, _response) = connect("ws://localhost:9999/echo").expect("Can't connect");
let (mut socket2, _response) = connect("ws://localhost:9999/echo2").expect("Can't connect");
let mut group = c.benchmark_group("multi echo server");
group.throughput(Throughput::Elements(100));
group.bench_function("100 - Send only", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for n in 0..iters {
if n % 2 == 0 {
socket.write_message(black_box(ws_message.clone())).unwrap();
} else {
socket2
.write_message(black_box(ws_message.clone()))
.unwrap();
}
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("multi echo server");
group.throughput(Throughput::Elements(100));
group.bench_function("100 - Send and receive", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for n in 0..iters {
if n % 2 == 0 {
socket.write_message(black_box(ws_message.clone())).unwrap();
let _ = socket.read_message().expect("Error reading message");
} else {
socket2
.write_message(black_box(ws_message.clone()))
.unwrap();
let _ = socket2.read_message().expect("Error reading message");
}
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("multi echo server");
group.measurement_time(Duration::from_secs(15));
group.throughput(Throughput::Elements(1000));
group.bench_function("1000 - Send only", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for n in 0..iters {
if n % 2 == 0 {
socket.write_message(black_box(ws_message.clone())).unwrap();
} else {
socket2
.write_message(black_box(ws_message.clone()))
.unwrap();
}
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("multi echo server");
group.measurement_time(Duration::from_secs(15));
group.throughput(Throughput::Elements(1000));
group.bench_function("1000 - Send and receive", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for n in 0..iters {
if n % 2 == 0 {
socket.write_message(black_box(ws_message.clone())).unwrap();
let _ = socket.read_message().expect("Error reading message");
} else {
socket2
.write_message(black_box(ws_message.clone()))
.unwrap();
let _ = socket2.read_message().expect("Error reading message");
}
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("multi echo server");
group.measurement_time(Duration::from_secs(100));
group.throughput(Throughput::Elements(10000));
group.bench_function("10000 - Send only", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for n in 0..iters {
if n % 2 == 0 {
socket.write_message(black_box(ws_message.clone())).unwrap();
} else {
socket2
.write_message(black_box(ws_message.clone()))
.unwrap();
}
}
start.elapsed()
})
});
group.finish();
let mut group = c.benchmark_group("multi echo server");
group.measurement_time(Duration::from_secs(100));
group.throughput(Throughput::Elements(10000));
group.bench_function("10000 - Send and receive", |b| {
b.iter_custom(|iters| {
let ws_message = Message::Text(String::from("Hello World!"));
let start = Instant::now();
for n in 0..iters {
if n % 2 == 0 {
socket.write_message(black_box(ws_message.clone())).unwrap();
let _ = socket.read_message().expect("Error reading message");
} else {
socket2
.write_message(black_box(ws_message.clone()))
.unwrap();
let _ = socket2.read_message().expect("Error reading message");
}
}
start.elapsed()
})
});
group.finish();
});
}
criterion_group!(benches, single_echo_benchmark, multi_echo_benchmark);
criterion_main!(benches);