perf(core): in-place AES-GCM seal + reused wire-buffer pool (host send)
The host sealed every packet with ~3 heap allocations: aes-gcm's convenience encrypt() allocates the ciphertext Vec, seal_for_wire allocates the seq||ct||tag wire Vec, and seal_frame allocated a fresh Vec<Vec<u8>> per frame. At line rate (~250k–500k pkt/s for 2.5–5 Gbps) that's the single-core allocator wall. - SessionCrypto::seal_in_place uses AeadInPlace::encrypt_in_place_detached to encrypt into the caller's buffer and write the detached tag at the end — byte-identical to seal's ciphertext||tag, no allocation (unit-tested for byte equality + decrypt). - Session keeps a wire_pool the caller returns via reclaim_wires; seal_frame seals each packet in place into the reused buffers (clear() keeps capacity), so after warmup there's no per-packet ciphertext/wire allocation. paced_submit and submit_frame reclaim the pool after sending. End-to-end encrypted/lossless multi-frame tests stay green (validates the pool reuse doesn't corrupt across frames). Next: write packetize directly into a contiguous send buffer (kills the remaining shard allocs + GSO's coalescing copy). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1588,10 +1588,10 @@ fn paced_submit(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(PaceStat {
|
||||
spread_us: start.elapsed().as_micros() as u32,
|
||||
paced,
|
||||
})
|
||||
let spread_us = start.elapsed().as_micros() as u32;
|
||||
drop(refs); // release the borrow of `wires` so it can return to the seal pool
|
||||
session.reclaim_wires(wires);
|
||||
Ok(PaceStat { spread_us, paced })
|
||||
}
|
||||
|
||||
/// Percentile of a slice (sorts it in place first). `q` in 0.0..=1.0.
|
||||
|
||||
Reference in New Issue
Block a user