-
Notifications
You must be signed in to change notification settings - Fork 75
Open
Description
So I am having some issues with performance when reading interrupted byte streams from the serial port. Consider this example:
Cargo.toml
[package]
name = "async-serial-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1", features = ["io-util", "macros", "rt-multi-thread"]}
tokio-serial = "5.4.1"main.rs
use std::time;
use tokio::{task, io::{self, AsyncReadExt, AsyncWriteExt}};
use tokio_serial::SerialPortBuilderExt;
#[tokio::main]
async fn main() {
let mut args = std::env::args();
let path = args.nth(1).expect("specify the serial port to connect to!");
let bytes = args.next()
.map_or(Ok(1024), |s| usize::from_str_radix(s.as_str(), 10))
.expect("expected a number of bytes as the second argument");
let port = tokio_serial::new(&path, 115200)
.open_native_async()
.expect("failed to open the system serial port");
let (mut reader, mut writer) = io::split(port);
let message = vec![13u8; bytes];
let expected = message.len();
let read = task::spawn(async move {
let mut buf = [0u8; 1];
let mut total = 0;
let mut timestamp;
let now = time::Instant::now();
loop {
match reader.read(&mut buf).await {
Ok(n) => {
total += n;
timestamp = now.elapsed().as_secs_f32();
// println!("[{}] read {} bytes: {:?}", timestamp, n, &buf[..n])
if total >= expected { break; }
},
Err(e) => {
println!("serial read encountered an error: {:?}", e);
panic!("failed to read any data from the io device");
}
}
}
println!("read {} bytes in {}s --> {}b/s", total, timestamp, total as f32 / timestamp);
});
writer.write(&message).await
.expect("failed to write to the serial port");
println!("waiting for read to complete...");
tokio::try_join!(read)
.expect("failed to join read task");
}If we run this program we can see the following:
C:\>.\build\async-serial-test.exe COM1 8192
waiting for read to complete...
read 8192 bytes in 0.7650555s --> 10707.72b/s
C:\>.\build\async-serial-test.exe COM1 8191
waiting for read to complete...
read 8191 bytes in 0.78255415s --> 10467.007b/s
It takes longer (by ~17ms (!)) to write/read one byte less of data! If we examine the syscalls, I think we can find the culprit:
The serial library is issuing read requests for 4096 bytes, which of course time out when only 4095 bytes are available -- the problem is that this timeout should* be 1ms, but in practice appears to be quite long.
So this leaves me with two questions:
- Do you know how/why COMMTIMEOUTS seems to be basically ignored? I have done some searching, and it seems like the answer to this question is that no-one actually knows what this windows code really does.
- How is the read-request size set? Can I use an different API to poll for smaller chunks of bytes? PuTTy polls for 1-byte reads, for instance; this way the
pendingread is returned as soon as there is more data.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
