// 对照真实发送的生成适配层;双方共用运行库,分别记录发送与完整收发,逐字节校验在计时外。 use dever_runtime::{ http::websocket::{self as ws, Message, WebSocket}, task::{Limits, Runtime}, }; use std::{hint::black_box, time::Instant}; async fn send(generated: bool, borrowed: bool, socket: &WebSocket, message: &MESSAGE_TYPE) { if generated && borrowed { WS_SEND_MESSAGE(socket, message).await.unwrap(); return; } match message { MESSAGE_TYPE::Variant0(text) if generated => WS_SEND_TEXT(socket, text).await.unwrap(), MESSAGE_TYPE::Variant1(bytes) if generated => WS_SEND_BINARY(socket, bytes).await.unwrap(), MESSAGE_TYPE::Variant0(text) => socket.send(Message::Text(text.clone())).await.unwrap(), MESSAGE_TYPE::Variant1(bytes) => socket.send(Message::Binary(bytes.clone())).await.unwrap(), _ => unreachable!(), } } fn payload_size(message: &MESSAGE_TYPE) -> usize { match message { MESSAGE_TYPE::Variant0(text) => text.len(), MESSAGE_TYPE::Variant1(bytes) => bytes.len(), _ => unreachable!(), } } fn check(received: Option, expected: &MESSAGE_TYPE) { match (received, expected) { (Some(Message::Text(actual)), MESSAGE_TYPE::Variant0(expected)) => { assert_eq!(&actual, expected) } (Some(Message::Binary(actual)), MESSAGE_TYPE::Variant1(expected)) => { assert_eq!(&actual, expected) } _ => panic!("WebSocket message changed"), } } async fn ready(socket: &WebSocket, input: &MESSAGE_TYPE, count: usize) { socket .send(Message::Text(format!("roundtrip:{count}"))) .await .unwrap(); send(false, false, socket, input).await; assert_eq!( socket.receive().await.unwrap(), Some(Message::Text("ready".to_owned())) ); } fn main() { if std::env::args().any(|argument| argument == "--peer") { peer::run(); return; } let mut peer = peer::Peer::start(1); let runtime = Runtime::new(Limits { threads: 1, workers: 1, tasks: 128, }) .unwrap(); println!("case,sample,implementation,elapsed_ns,checksum"); runtime.run(async |scope| { // 双方轮流使用同一连接;固定协议对端在另一 CPU,隔离连接差异与线程争抢。 let socket = ws::connect("127.0.0.1", i64::from(peer.port), "/bench", &ws::Limits::default(), scope).await.unwrap(); for bytes in [64, 65536] { for binary in [false, true] { let input = if binary { MESSAGE_TYPE::Variant1((0..bytes).map(|index| (index % 251) as u8).collect::>().into()) } else { MESSAGE_TYPE::Variant0("雪a".repeat(bytes / 4)) }; for borrowed in [false, true] { let name = format!("ws_{}_{}_{}", if binary { "binary" } else { "text" }, if borrowed { "borrowed" } else { "temporary" }, bytes); for generated in [true, false] { ready(&socket, &input, 20).await; for _ in 0..20 { send(generated, borrowed, &socket, &input).await; check(socket.receive().await.unwrap(), &input); } } for sample in 0..15 { let mut order = [("dever", true), ("rust_runtime", false), ("control", true)]; order.rotate_left(sample % 3); for (implementation, generated) in order { ready(&socket, &input, 200).await; let mut sent = 0; let mut roundtrip = 0; let mut checksum = 0; for _ in 0..200 { let start = Instant::now(); send(generated, borrowed, &socket, black_box(&input)).await; sent += start.elapsed().as_nanos(); let received = socket.receive().await.unwrap(); roundtrip += start.elapsed().as_nanos(); check(received, &input); checksum += payload_size(black_box(&input)); } assert_eq!(checksum, bytes * 200); println!("{name}_send,{sample},{implementation},{sent},{checksum}"); println!("{name}_roundtrip,{sample},{implementation},{roundtrip},{checksum}"); } } } } } socket.close(1000, "").await.unwrap(); }).unwrap(); peer.finish(); }