From 203fa64580f4ecfa98afbaedb28473e6b58dcc73 Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Mon, 18 Sep 2017 23:26:16 +0300 Subject: [PATCH] Add BufferPool. --- src/smolnetd/buffer_pool.rs | 92 +++++++++++++++++++++++++++++++++++++ src/smolnetd/device.rs | 7 +-- src/smolnetd/main.rs | 1 + src/smolnetd/scheme.rs | 31 +++++++------ 4 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 src/smolnetd/buffer_pool.rs diff --git a/src/smolnetd/buffer_pool.rs b/src/smolnetd/buffer_pool.rs new file mode 100644 index 0000000000..2bd2e475c5 --- /dev/null +++ b/src/smolnetd/buffer_pool.rs @@ -0,0 +1,92 @@ +use std::ops::{Deref, DerefMut, Drop}; +use std::rc::Rc; +use std::cell::RefCell; +use std::mem::swap; + +type BufferStack = Rc>>>; + +pub struct Buffer { + buffer: Vec, + stack: BufferStack, +} + +impl Buffer { + pub fn resize(&mut self, new_len: usize) { + self.buffer.resize(new_len, 0u8); + } +} + +impl AsRef<[u8]> for Buffer { + fn as_ref(&self) -> &[u8] { + &self.buffer + } +} + +impl AsMut<[u8]> for Buffer { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.buffer + } +} + +impl Deref for Buffer { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.buffer + } +} + +impl DerefMut for Buffer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buffer + } +} + +impl Drop for Buffer { + fn drop(&mut self) { + let mut tmp = vec![]; + swap(&mut tmp, &mut self.buffer); + { + let mut stack = self.stack.borrow_mut(); + trace!("Returning buffer: {}", stack.len()); + stack.push(tmp); + } + } +} + +pub struct BufferPool { + buffers_size: usize, + stack: BufferStack, +} + +impl BufferPool { + pub fn new(buffers_size: usize) -> BufferPool { + BufferPool { + buffers_size, + stack: Rc::new(RefCell::new(vec![])), + } + } + + pub fn get_buffer(&mut self) -> Buffer { + let buffer = match self.stack.borrow_mut().pop() { + None => { + trace!("Allocating ingress buffer"); + vec![0u8; self.buffers_size] + } + Some(mut v) => { + trace!("Reusing ingress buffer"); + // memsetting the buffer with `resize` would be a waste of time + let capacity = v.capacity(); + unsafe { + v.set_len(capacity); + } + v + } + }; + + Buffer { + buffer, + stack: self.stack.clone(), + } + } +} diff --git a/src/smolnetd/device.rs b/src/smolnetd/device.rs index 9ac0705aef..5589fc51b9 100644 --- a/src/smolnetd/device.rs +++ b/src/smolnetd/device.rs @@ -4,10 +4,11 @@ use std::cell::RefCell; use std::io::Write; use std::collections::VecDeque; use smoltcp; +use buffer_pool::Buffer; pub struct NetworkDevice { network_file: Rc>, - input_queue: Rc>>>, + input_queue: Rc>>, } impl NetworkDevice { @@ -15,7 +16,7 @@ impl NetworkDevice { pub fn new( network_file: Rc>, - input_queue: Rc>>>, + input_queue: Rc>>, ) -> NetworkDevice { NetworkDevice { network_file, @@ -48,7 +49,7 @@ impl Drop for TxBuffer { } impl smoltcp::phy::Device for NetworkDevice { - type RxBuffer = Vec; + type RxBuffer = Buffer; type TxBuffer = TxBuffer; fn limits(&self) -> smoltcp::phy::DeviceLimits { diff --git a/src/smolnetd/main.rs b/src/smolnetd/main.rs index cfa84de487..4b84242e03 100644 --- a/src/smolnetd/main.rs +++ b/src/smolnetd/main.rs @@ -15,6 +15,7 @@ use std::process; use std::rc::Rc; mod error; +mod buffer_pool; mod device; mod scheme; mod logger; diff --git a/src/smolnetd/scheme.rs b/src/smolnetd/scheme.rs index 74cc29cdf3..ac8596128d 100644 --- a/src/smolnetd/scheme.rs +++ b/src/smolnetd/scheme.rs @@ -1,5 +1,3 @@ -use device::NetworkDevice; -use error::{Error, Result}; use netutils::{getcfg, MacAddr}; use smoltcp; use std::collections::{BTreeMap, VecDeque}; @@ -15,6 +13,10 @@ use smoltcp::socket::AsSocket; use syscall::SchemeMut; use syscall; +use device::NetworkDevice; +use error::{Error, Result}; +use buffer_pool::{Buffer, BufferPool}; + struct RawHandle { flags: usize, events: usize, @@ -43,14 +45,16 @@ pub struct Smolnetd { raw_sockets: BTreeMap, udp_sockets: BTreeMap, - input_queue: Rc>>>, + input_queue: Rc>>, + input_buffer_pool: BufferPool, } struct IpScheme<'a>(&'a mut Smolnetd); struct UdpScheme<'a>(&'a mut Smolnetd); impl Smolnetd { - const IP_BUFFER_SIZE: usize = 128; + const INGRESS_PACKET_SIZE: usize = 2048; + const SOCKET_BUFFER_SIZE: usize = 128; //packets const CHECK_TIMEOUT_MS: i64 = 1000; pub fn new(network_file: File, ip_file: File, udp_file: File, time_file: File) -> Smolnetd { @@ -93,6 +97,7 @@ impl Smolnetd { next_fd: 0, input_queue, network_file, + input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE), } } @@ -155,7 +160,7 @@ impl Smolnetd { fn read_frames(&mut self) -> Result { let mut total_frames = 0; loop { - let mut buffer = vec![0; 65536]; + let mut buffer = self.input_buffer_pool.get_buffer(); let count = self.network_file .borrow_mut() .read(&mut buffer) @@ -166,7 +171,7 @@ impl Smolnetd { break; } trace!("got frame {}", count); - buffer.resize(count, 0); + buffer.resize(count); self.input_queue.borrow_mut().push_back(buffer); total_frames += 1; } @@ -206,9 +211,9 @@ impl<'a> syscall::SchemeMut for IpScheme<'a> { let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?; let proto = u8::from_str_radix(path, 16).or(Err(syscall::Error::new(syscall::ENOENT)))?; - let mut rx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE); - let mut tx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE); - for _ in 0..Smolnetd::IP_BUFFER_SIZE { + let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE { rx_packets.push(smoltcp::socket::RawPacketBuffer::new( vec![0; NetworkDevice::MTU], )); @@ -269,7 +274,6 @@ impl<'a> syscall::SchemeMut for IpScheme<'a> { } fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { - trace!("Read {}", fd); use smoltcp::socket::AsSocket; let handle = self.0 @@ -280,6 +284,7 @@ impl<'a> syscall::SchemeMut for IpScheme<'a> { self.0.socket_set.get_mut(handle.socket_handle).as_socket(); if socket.can_recv() { let length = socket.recv_slice(buf).expect("Can't receive slice"); + trace!("Read fd {} len {}", fd, length); Ok(length) } else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Ok(0) @@ -322,9 +327,9 @@ impl<'a> syscall::SchemeMut for UdpScheme<'a> { let (remote_ip, remote_port) = parse_socket(parts.next().unwrap_or("")); let (local_ip, local_port) = parse_socket(parts.next().unwrap_or("")); - let mut rx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE); - let mut tx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE); - for _ in 0..Smolnetd::IP_BUFFER_SIZE { + let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE { rx_packets.push(smoltcp::socket::UdpPacketBuffer::new( vec![0; NetworkDevice::MTU], ));