virtio: batch transmitted packets

Instead of placing packets directly into the virtio ring, add them to
a temporary queue, and flush it when we are polled.  This reduces
cross-cpu writes and kicks.
This commit is contained in:
Avi Kivity
2014-12-11 19:19:09 +02:00
parent 97dff83461
commit 503f1bf4d0

View File

@@ -270,6 +270,7 @@ private:
semaphore _available_descriptors = { 0 };
int _free_head = -1;
int _free_last = -1;
std::vector<uint16_t> _batch;
std::experimental::optional<reactor::poller> _poller;
bool _poll_mode = false;
public:
@@ -300,6 +301,8 @@ public:
template <typename Iterator>
void post(Iterator begin, Iterator end);
void flush_batch();
semaphore& available_descriptors() { return _available_descriptors; }
private:
// Let host know about interrupt delivery
@@ -412,12 +415,25 @@ void vring::run() {
complete();
} else {
_poller = reactor::poller([this] {
flush_batch();
do_complete();
return true;
});
}
}
void vring::flush_batch() {
if (_batch.empty()) {
return;
}
for (auto desc_head : _batch) {
_avail._shared->_ring[masked(_avail._head++)] = desc_head;
}
_batch.clear();
_avail._shared->_idx.store(_avail._head, std::memory_order_release);
kick();
}
template <typename Iterator>
void vring::post(Iterator begin, Iterator end) {
// Note: buffer_chain here is any container of buffer, not
@@ -443,13 +459,19 @@ void vring::post(Iterator begin, Iterator end) {
}
auto desc_head = pseudo_head._next;
_completions[desc_head] = std::move(bc.completed);
_avail._shared->_ring[masked(_avail._head++)] = desc_head;
if (!_poll_mode) {
_avail._shared->_ring[masked(_avail._head++)] = desc_head;
} else {
_batch.push_back(desc_head);
}
_avail._avail_added_since_kick++;
});
_avail._shared->_idx.store(_avail._head, std::memory_order_release);
kick();
if (!_poll_mode) {
_avail._shared->_idx.store(_avail._head, std::memory_order_release);
kick();
do_complete();
} else if (_batch.size() >= 16) {
flush_batch();
}
}