kernel: pipe reads copy slices and zero only what is buffered

Pipe::read popped a byte at a time, and k_pipe_read zeroed the whole
request (128 KiB for wc) on every call. In the single-thread build's
profile of yes | head -c 20M | wc -c these were 14% of the run
(Pipe::read 182 ms, alloc_zeroed 240 ms of 2970 ms). Both builds gain.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_781bad2ec05143db9067c86b4b2678e2
This commit is contained in:
velzieandClaude Opus 5.5 committed 2026-10-10 17:01:51 -04:00
1 parent 5e702a4233
commit 4fcc6417af
2 files changed
+12 -4

No files matched your search

+7 -3
View File
@@ -103,9 +103,13 @@ impl Pipe {
loop {
if !s.buf.is_empty() {
let n = buf.len().min(s.buf.len());
for slot in buf.iter_mut().take(n) {
*slot = s.buf.pop_front().unwrap();
}
// Two slice copies, not a pop per byte: a pipeline moves
// megabytes through here.
let (front, back) = s.buf.as_slices();
let k = n.min(front.len());
buf[..k].copy_from_slice(&front[..k]);
buf[k..n].copy_from_slice(&back[..n - k]);
s.buf.drain(..n);
self.ready.notify_all();
return Ok(n as u64);
}
+5 -1
View File
@@ -1442,7 +1442,11 @@ pub extern "C" fn k_pipe_write(id: i32, at: gex_kmem::PAddr, len: u32) -> i32 {
#[no_mangle]
pub extern "C" fn k_pipe_read(id: i32, at: gex_kmem::PAddr, len: u32) -> i32 {
let Some(p) = pipe_at(id) else { return -9 };
let mut buf = vec![0u8; len as usize];
// No bigger than what is buffered (at least one byte, so an empty pipe
// still answers EOF or EAGAIN): a reader asking for 128 KiB of a pipe
// holding a few bytes zeroed the whole request on every call.
let want = (len as usize).min(p.buffered().max(1));
let mut buf = vec![0u8; want];
match p.read(&mut buf) {
Ok(n) => {
unsafe { gex_kmem::push_checked(at, buf.as_ptr(), n as u32) };