perf(mpsc): use try_send fast path to skip semaphore overhead

MpscTunnelSender::send now tries try_send first, falling back to
send().await only when the channel is full. try_send bypasses the
tokio batch_semaphore Acquire::poll + add_permits_locked machinery
(~9.4% of CPU in samply profiling), which is pure overhead when the
channel has capacity.

In the ring-tunnel bench (4 threads, 1400B, 15s) the channel(32) fast
path hits >99%, so the fallback rarely triggers.

Benchmark improvement:
  pps:       230K -> 246K (+7.0%)
  send_msg_internal avg: 3.25us -> 3.13us (-120ns/pkt)
  forward_one_round calls: 2.46M -> 706K (-71%, bigger batches)

All mpsc tests pass.
This commit is contained in:
fanyang
2026-06-28 12:54:37 +08:00
parent 31c639f70c
commit e18387b06b
+8 -2
View File
@@ -20,8 +20,14 @@ pub struct MpscTunnelSender(Sender<ZCPacket>);
impl MpscTunnelSender {
pub async fn send(&self, item: ZCPacket) -> Result<(), TunnelError> {
self.0.send(item).await.with_context(|| "send error")?;
Ok(())
match self.0.try_send(item) {
Ok(()) => Ok(()),
Err(TrySendError::Full(item)) => {
self.0.send(item).await.with_context(|| "send error")?;
Ok(())
}
Err(TrySendError::Closed(_)) => Err(TunnelError::Shutdown),
}
}
pub fn try_send(&self, item: ZCPacket) -> Result<(), TunnelError> {