From 47b80498dd572b5539743ba9c11349373f5784ae Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 15 Oct 2018 19:16:28 +0200 Subject: [PATCH] virtio: replace packet chain with deque, add stats --- src/drivers/virtionet.cpp | 94 ++++++++++++++++++++++++++++----------- src/drivers/virtionet.hpp | 14 +++++- test/stress/service.cpp | 22 ++++++--- 3 files changed, 97 insertions(+), 33 deletions(-) diff --git a/src/drivers/virtionet.cpp b/src/drivers/virtionet.cpp index 5f8d22a329..f6b8e0b3b7 100644 --- a/src/drivers/virtionet.cpp +++ b/src/drivers/virtionet.cpp @@ -65,10 +65,24 @@ VirtioNet::VirtioNet(hw::PCI_Device& d, const uint16_t /*mtu*/) Link(Link_protocol{{this, &VirtioNet::transmit}, mac()}), m_pcidev(d), bufstore_{VNET_TOT_BUFFERS(), 2048 /* half-page buffers */}, - packets_rx_{Statman::get().create(Stat::UINT64, - device_name() + ".packets_rx").get_uint64()}, - packets_tx_{Statman::get().create(Stat::UINT64, - device_name() + ".packets_tx").get_uint64()} + + stat_sendq_max_{Statman::get().create(Stat::UINT64, + device_name() + ".sendq_max").get_uint64()}, + stat_sendq_now_{Statman::get().create(Stat::UINT64, + device_name() + ".sendq_now").get_uint64()}, + stat_sendq_limit_dropped_{Statman::get().create(Stat::UINT64, + device_name() + ".sendq_dropped").get_uint64()}, + stat_rx_refill_dropped_{Statman::get().create(Stat::UINT64, + device_name() + ".rx_refill_dropped").get_uint64()}, + stat_bytes_rx_total_{Statman::get().create(Stat::UINT64, + device_name() + ".stat_rx_total_bytes").get_uint64()}, + stat_bytes_tx_total_{Statman::get().create(Stat::UINT64, + device_name() + ".stat_tx_total_bytes").get_uint64()}, + stat_packets_rx_total_{Statman::get().create(Stat::UINT64, + device_name() + ".stat_rx_total_packets").get_uint64()}, + stat_packets_tx_total_{Statman::get().create(Stat::UINT64, + device_name() + ".stat_tx_total_packets").get_uint64()} + { INFO("VirtioNet", "Driver initializing"); #undef VNET_TOT_BUFFERS @@ -216,7 +230,7 @@ void VirtioNet::msix_conf_handler() } void VirtioNet::msix_recv_handler() { - auto rx = packets_rx_; + auto rx = stat_packets_rx_total_; rx_q.disable_interrupts(); // handle incoming packets as long as bufstore has available buffers int max = 128; @@ -224,16 +238,24 @@ void VirtioNet::msix_recv_handler() { auto res = rx_q.dequeue(); VDBG_RX("[virtionet] Recv %u bytes\n", (uint32_t) res.size()); - Link::receive( recv_packet(res.data(), res.size()) ); - - // Requeue a new buffer - add_receive_buffer(bufstore().get_buffer()); + auto pckt = recv_packet(res.data(), res.size()); // Stat increase packets received - packets_rx_++; + stat_packets_rx_total_++; + stat_bytes_rx_total_ += pckt->size(); + + Link::receive(std::move(pckt)); + + // Requeue a new buffer unless threshold is reached + if (not Nic::buffers_still_available(bufstore().buffers_in_use())) + { + stat_rx_refill_dropped_++; + break; + } + add_receive_buffer(bufstore().get_buffer()); } rx_q.enable_interrupts(); - if (rx != packets_rx_) rx_q.kick(); + if (rx != stat_packets_rx_total_) rx_q.kick(); } void VirtioNet::msix_xmit_handler() { @@ -320,27 +342,47 @@ VirtioNet::create_packet(int link_offset) void VirtioNet::transmit(net::Packet_ptr pckt) { assert(pckt != nullptr); - if (transmit_queue == nullptr) - transmit_queue = std::move(pckt); - else - transmit_queue->chain(std::move(pckt)); + VDBG_TX("[virtionet] tx: Transmitting %#zu sized packet \n", + pckt->size()); + while (pckt != nullptr) { + if (not Nic::sendq_still_available(sendq.size())) { + stat_sendq_limit_dropped_++; + return; + } + auto tail = pckt->detach_tail(); + sendq.emplace_back(std::move(pckt)); + pckt = std::move(tail); + } + + // Update sendq stats + stat_sendq_now_ = sendq.size(); + if (sendq.size() > stat_sendq_max_) + stat_sendq_max_ = sendq.size(); + + auto tx = this->stat_packets_tx_total_; + + VDBG_TX("[virtionet] tx: packets in send queue %#zu\n", + sendq.size()); - auto tx = this->packets_tx_; // Transmit all we can directly - while (tx_q.num_free() > 1 and transmit_queue) + while (tx_q.num_free() > 1 and sendq.size() > 0) { - VDBG_TX("[virtionet] tx: %u tokens left in TX queue \n", + VDBG_TX("[virtionet] tx: %u tokens left in TX ring \n", tx_q.num_free()); - // next in line - auto next = transmit_queue->detach_tail(); - // explicitly release the data to prevent destructor being called - enqueue_tx(transmit_queue.release()); - transmit_queue = std::move(next); - // Stat increase packets transmitted - this->packets_tx_++; + + auto* next = sendq.front().release(); + sendq.pop_front(); + enqueue_tx(next); + + // Increase TX-stats + stat_packets_tx_total_++; + stat_bytes_tx_total_ += next->size(); + stat_packets_tx_total_++; } - if (tx != this->packets_tx_) { + VDBG_TX("[virtionet] tx: packet enqueued\n"); + + if (tx != this->stat_packets_tx_total_) { #ifdef NO_DEFERRED_KICK tx_q.kick(); #else diff --git a/src/drivers/virtionet.hpp b/src/drivers/virtionet.hpp index 51721b6144..7a4c59c1d6 100644 --- a/src/drivers/virtionet.hpp +++ b/src/drivers/virtionet.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -236,8 +237,17 @@ class VirtioNet : Virtio, public net::Link_layer { net::BufferStore bufstore_; /** Stats */ - uint64_t& packets_rx_; - uint64_t& packets_tx_; + uint64_t& stat_sendq_max_; + uint64_t& stat_sendq_now_; + uint64_t& stat_sendq_limit_dropped_; + uint64_t& stat_rx_refill_dropped_; + uint64_t& stat_bytes_rx_total_; + uint64_t& stat_bytes_tx_total_; + uint64_t& stat_packets_rx_total_; + uint64_t& stat_packets_tx_total_; + + std::deque sendq{}; + }; #endif diff --git a/test/stress/service.cpp b/test/stress/service.cpp index 1e603bed97..ed948a9c3a 100644 --- a/test/stress/service.cpp +++ b/test/stress/service.cpp @@ -21,6 +21,7 @@ #include // rand() #include #include +#include using namespace std::chrono; @@ -159,16 +160,27 @@ void Service::start(const std::string&) net::UDP::port_t port_mem = 4243; auto& conn_mem = inet.udp().bind(port_mem); -/* - Timers::periodic(10s, 10s, - [] (Timers::id_t) { - printf(" TCP STATUS:\n%s \n", inet.tcp().status().c_str()); + Timers::periodic(1s, 10s, + [] (Timers::id_t) { auto memuse = OS::heap_usage(); printf("Current memory usage: %i b, (%f MB) \n", memuse, float(memuse) / 1000000); printf("Recv: %llu Sent: %llu\n", TCP_BYTES_RECV, TCP_BYTES_SENT); + printf("eth0.sendq_max: %zu, eth0.sendq_now: %zu" + "eth0.stat_rx_total_packets: %zu, eth0.stat_rx_total_packets: %zu, " + "eth0.stat_rx_total_bytes: %zu, eth0.stat_tx_total_bytes: %zu, " + "eth0.sendq_dropped: %zu, eth0.rx_refill_dropped: %zu \n", + Statman::get().get_by_name("eth0.sendq_max").get_uint64(), + Statman::get().get_by_name("eth0.sendq_now").get_uint64(), + Statman::get().get_by_name("eth0.stat_rx_total_packets").get_uint64(), + Statman::get().get_by_name("eth0.stat_tx_total_packets").get_uint64(), + Statman::get().get_by_name("eth0.stat_rx_total_bytes").get_uint64(), + Statman::get().get_by_name("eth0.stat_tx_total_bytes").get_uint64(), + Statman::get().get_by_name("eth0.sendq_dropped").get_uint64(), + Statman::get().get_by_name("eth0.rx_refill_dropped").get_uint64() + ); }); -*/ + server_mem.on_connect([] (net::tcp::Connection_ptr conn) { conn->on_read(1024, [conn](net::tcp::buffer_t buf) { TCP_BYTES_RECV += buf->size();