use super::{Limits, Runtime, Socket, net}; use bytes::BufMut; use std::{io::ErrorKind, time::Instant}; use tokio::{io::AsyncWriteExt, net::TcpStream}; async fn independent_read(socket: &TcpStream, limit: usize) -> Option> { socket.readable().await.unwrap(); let mut bytes = Vec::new(); bytes.try_reserve_exact(limit).unwrap(); loop { let result = socket.try_read_buf(&mut (&mut bytes).limit(limit)); match result { Ok(count) => return (count != 0).then_some(bytes), Err(error) if error.kind() == ErrorKind::WouldBlock => { socket.readable().await.unwrap(); } Err(error) => panic!("independent TCP read failed: {error}"), } } } async fn sample( peer: &mut TcpStream, payload: &[u8], limit: usize, iterations: usize, mut read: impl AsyncFnMut() -> Option>, ) -> (u128, usize, usize) { let mut elapsed = 0; let mut reads = 0; let mut total = 0; for _ in 0..iterations { peer.write_all(payload).await.unwrap(); let mut received = 0; loop { let started = Instant::now(); let bytes = read().await; elapsed += started.elapsed().as_nanos(); reads += 1; let Some(bytes) = bytes else { assert!(payload.is_empty()); break; }; assert!(!bytes.is_empty() && bytes.len() <= limit); assert!(received + bytes.len() <= payload.len()); assert_eq!(bytes, payload[received..received + bytes.len()]); received += bytes.len(); total += bytes.len(); if received == payload.len() { break; } } } assert_eq!(total, payload.len() * iterations); (elapsed, reads, total) } #[test] #[ignore = "explicit release performance probe; http enables the independent bytes/io-util peer"] fn tcp_read_buffer_cost() { let runtime = Runtime::new(Limits { threads: 1, workers: 1, tasks: 8, }) .unwrap(); runtime .run(async |scope| { eprintln!( "tcp_read_buffer: 15 fixed rounds; one async worker; two persistent loopback pairs; \ peer writes, byte verification and result drops excluded from read timing; \ rust_independent uses Tokio try_read_buf and bytes::BufMut::limit directly; \ no shared Dever read implementation; direct peer excludes alias-close and read-lock checks; \ actual read counts are retained; empty payload cases measure established EOF" ); println!("\ncase,sample,implementation,iterations,elapsed_ns,reads,bytes"); for (limit, payload_size, iterations) in [ (64, 64, 4096), (65_536, 64, 2048), (1_048_576, 64, 512), (65_536, 65_536, 256), (1_048_576, 65_536, 128), (65_536, 0, 512), (1_048_576, 0, 128), ] { let listener = net::listen("127.0.0.1", 0, scope).await.unwrap(); let mut dever_peer = TcpStream::connect(("127.0.0.1", listener.port().unwrap() as u16)) .await .unwrap(); let socket: Socket = listener.accept().await.unwrap(); listener.close().unwrap(); let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)).await.unwrap(); let mut independent_peer = TcpStream::connect(listener.local_addr().unwrap()) .await .unwrap(); let independent = listener.accept().await.unwrap().0; independent.set_nodelay(true).unwrap(); dever_peer.set_nodelay(true).unwrap(); independent_peer.set_nodelay(true).unwrap(); drop(listener); if payload_size == 0 { dever_peer.shutdown().await.unwrap(); independent_peer.shutdown().await.unwrap(); } let payload = (0..payload_size) .map(|position| (position % 251) as u8) .collect::>(); sample(&mut dever_peer, &payload, limit, 16, async || { socket.read(limit as i64).await.unwrap() }) .await; sample(&mut independent_peer, &payload, limit, 16, async || { independent_read(&independent, limit).await }) .await; for round in 0..15 { let mut order = ["dever", "rust_independent", "control"]; order.rotate_left(round % 3); for label in order { let (elapsed, reads, total) = if label == "rust_independent" { sample(&mut independent_peer, &payload, limit, iterations, async || { independent_read(&independent, limit).await }) .await } else { sample(&mut dever_peer, &payload, limit, iterations, async || { socket.read(limit as i64).await.unwrap() }) .await }; println!( "tcp_read_{limit}_{payload_size},{round},{label},{iterations},{elapsed},{reads},{total}" ); } } socket.close().unwrap(); } }) .unwrap(); }