Skip to content

Commit

Permalink
Disable EPOLLOUT if triggered while txbuf is empty
Browse files Browse the repository at this point in the history
Currently the vsock connection always triggers on EPOLLOUT. When a host
applicationlistens to the UDS, it's almost always writable, and thus
keeps triggering backend events with EPOLLOUT on the connection. As a
result, vhost-device-vsock daemon consumes 100% CPU.

To make it more CPU efficient, it can instead unsubscribe EPOLLOUT
whenever there is no more data to send. It can re-subscribe if the
connection cannot write out all bytes. This change causes the CPU util
to drop to negligible level.

Signed-off-by: Leon Yang <[email protected]>
  • Loading branch information
lnyng authored and vireshk committed Feb 4, 2025
1 parent ec0f309 commit 99ec307
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 3 deletions.
1 change: 1 addition & 0 deletions vhost-device-vsock/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Changed

### Fixed
- [#800](https://github.com/rust-vmm/vhost-device/pull/800) Disable EPOLLOUT if triggered while txbuf is empty

### Deprecated

Expand Down
13 changes: 10 additions & 3 deletions vhost-device-vsock/src/vhu_vsock_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ use std::{
thread,
};

#[cfg(feature = "backend_vsock")]
use log::error;
use log::warn;
use log::{error, warn};
use vhost_user_backend::{VringEpollHandler, VringRwLock, VringT};
use virtio_queue::QueueOwnedT;
use virtio_vsock::packet::{VsockPacket, PKT_HEADER_SIZE};
Expand Down Expand Up @@ -431,6 +429,9 @@ impl VhostUserVsockThread {
}
} else {
// Previously connected connection

// Get epoll fd before getting conn as that takes self mut ref
let epoll_fd = self.get_epoll_fd();
let key = self.thread_backend.listener_map.get(&fd).unwrap();
let conn = self.thread_backend.conn_map.get_mut(key).unwrap();

Expand All @@ -441,6 +442,12 @@ impl VhostUserVsockThread {
if cnt > 0 {
conn.fwd_cnt += Wrapping(cnt as u32);
conn.rx_queue.enqueue(RxOps::CreditUpdate);
} else {
// If no remaining data to flush, try to disable EPOLLOUT
if Self::epoll_modify(epoll_fd, fd, epoll::Events::EPOLLIN).is_err()
{
error!("Failed to disable EPOLLOUT");
}
}
self.thread_backend
.backend_rxq
Expand Down
10 changes: 10 additions & 0 deletions vhost-device-vsock/src/vsock_conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,16 @@ impl<S: AsRawFd + ReadVolatile + Write + WriteVolatile + IsHybridVsock> VsockCon
}

if written_count != buf.len() {
// Try to re-enable EPOLLOUT in case it is disabled when txbuf is empty.
if VhostUserVsockThread::epoll_modify(
self.epoll_fd,
self.stream.as_raw_fd(),
epoll::Events::EPOLLIN | epoll::Events::EPOLLOUT,
)
.is_err()
{
error!("Failed to re-enable EPOLLOUT");
}
return self.tx_buf.push(&buf.offset(written_count).unwrap());
}

Expand Down

0 comments on commit 99ec307

Please sign in to comment.