From e32157e21b95b72e31536dfb8b6f5b8a698cf2d9 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 21 Jul 2022 15:43:58 +0200 Subject: [PATCH] nic_router: packet allocation w/o exceptions In overload situations, i.e. when a sender fills up the entire buffer, we land in situations where the sender receives an ack_avail signal, releases one packet, allocates and sends a packet and fails to allocate a second packet. This is especially relevant if the receiver does not batch ack_avail signals (such as vfs_lwip). In those ping-pong scheduling scenarios, the overhead from catching the Packet_alloc_failed exception becomes significant. In case of the NIC router, we will land in an overload situation if the sender is faster than the receiver. The packet buffer will be filled up at some point and the NIC router starts to drop packets. For every dropped packet, we currently have to catch the Packet_alloc_failed exception. This commit adds a new method alloc_packet_attempt to Packet_stream_source that has almost the same signature as the older alloc_packet method but returns an Attempt object. As the method already used the allocator back end exception-less, changes on lower levels were not needed. Furthermore, the NIC router was modified to use the new exception-less alloc_packet_attempt instead of alloc_packet. Ref #4555 --- repos/os/include/os/packet_stream.h | 27 +++++++++++++++++++ repos/os/src/server/nic_router/interface.cc | 9 ------- repos/os/src/server/nic_router/interface.h | 29 +++++++++------------ 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/repos/os/include/os/packet_stream.h b/repos/os/include/os/packet_stream.h index 7705670654..7a7a498b26 100644 --- a/repos/os/include/os/packet_stream.h +++ b/repos/os/include/os/packet_stream.h @@ -639,6 +639,10 @@ class Genode::Packet_stream_source : private Packet_stream_base class Saturated_submit_queue : Exception { }; class Empty_ack_queue : Exception { }; + enum class Alloc_packet_error { FAILED }; + + using Alloc_packet_result = Attempt; + /** * Constructor * @@ -726,6 +730,29 @@ class Genode::Packet_stream_source : private Packet_stream_base throw Packet_alloc_failed(); }); } + /** + * Allocate packet without throwing exceptions + * + * \param size size of packet in bytes + * \param align alignment of packet as log2 value, default is 1 byte + * \return an Attempt object that either contains an error or a + * packet descriptor with an assigned range within the + * bulk buffer shared between source and sink + */ + Alloc_packet_result alloc_packet_attempt(Genode::size_t size, unsigned align = PACKET_ALIGNMENT) + { + if (size == 0) + return Packet_descriptor(0, 0); + + return _packet_alloc.alloc_aligned(size, align).convert( + + [&] (void *base) { + return Packet_descriptor((Genode::off_t)base, size); }, + + [&] (Allocator::Alloc_error) { + return Alloc_packet_error::FAILED; }); + } + /** * Get pointer to the content of the specified packet * diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 24e6d7b270..f7a6282b52 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -1850,15 +1850,6 @@ void Interface::send(Ethernet_frame ð, } -void Interface::_send_alloc_pkt(Packet_descriptor &pkt, - void * &pkt_base, - size_t pkt_size) -{ - pkt = _source.alloc_packet(pkt_size); - pkt_base = _source.packet_content(pkt); -} - - void Interface::_send_submit_pkt(Packet_descriptor &pkt, void * &pkt_base, size_t pkt_size) diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index 117e1e2a73..9661c3f160 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -307,10 +307,6 @@ class Net::Interface : private Interface_list::Element void _ack_packet(Packet_descriptor const &pkt); - void _send_alloc_pkt(Genode::Packet_descriptor &pkt, - void * &pkt_base, - Genode::size_t pkt_size); - void _send_submit_pkt(Genode::Packet_descriptor &pkt, void * &pkt_base, Genode::size_t pkt_size); @@ -402,18 +398,19 @@ class Net::Interface : private Interface_list::Element _failed_to_send_packet_submit(); return; } - try { - Packet_descriptor pkt; - void *pkt_base; - - _send_alloc_pkt(pkt, pkt_base, pkt_size); - Size_guard size_guard(pkt_size); - write_to_pkt(pkt_base, size_guard); - _send_submit_pkt(pkt, pkt_base, pkt_size); - } - catch (Packet_stream_source::Packet_alloc_failed) { - _failed_to_send_packet_alloc(); - } + _source.alloc_packet_attempt(pkt_size).with_result( + [&] (Packet_descriptor pkt) + { + void *pkt_base { _source.packet_content(pkt) }; + Size_guard size_guard(pkt_size); + write_to_pkt(pkt_base, size_guard); + _send_submit_pkt(pkt, pkt_base, pkt_size); + }, + [&] (Packet_stream_source::Alloc_packet_error) + { + _failed_to_send_packet_alloc(); + } + ); } void send(Ethernet_frame ð,