diff options
author | Josh Blum <josh@joshknows.com> | 2010-04-12 12:22:29 -0700 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-04-12 12:22:29 -0700 |
commit | 0021abf18aaf3831d8aaa40574f1876c4f346a92 (patch) | |
tree | d0385274110a646dd84838c198627721d1387ce9 /host/lib | |
parent | 8ee3d7200169983e7a20409ed5e8c37907fe66e1 (diff) | |
download | uhd-0021abf18aaf3831d8aaa40574f1876c4f346a92.tar.gz uhd-0021abf18aaf3831d8aaa40574f1876c4f346a92.tar.bz2 uhd-0021abf18aaf3831d8aaa40574f1876c4f346a92.zip |
Created zero copy interface/framework, made use of it in usrp2 udp transport stuff.
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 105 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 21 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 2 |
3 files changed, 84 insertions, 44 deletions
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 1fc8ce14a..13fd50f65 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -25,39 +25,74 @@ using namespace uhd::transport; /*********************************************************************** - * Smart buffer implementation for udp zerocopy none - * - * This smart buffer implemention houses a const buffer. - * When the smart buffer is deleted, the buffer is freed. - * The memory in the const buffer is allocated with new [], - * and so the destructor frees the buffer with delete []. + * Managed receive buffer implementation for udp zero-copy asio: + * Frees the memory held by the const buffer on done. **********************************************************************/ -class smart_buffer_impl : public smart_buffer{ +class managed_recv_buffer_impl : public managed_recv_buffer{ public: - smart_buffer_impl(const boost::asio::const_buffer &buff){ - _buff = buff; + managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ + _done = false; } - ~smart_buffer_impl(void){ + ~managed_recv_buffer_impl(void){ + if (not _done) this->done(); + } + + void done(void){ + _done = true; delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff); } - const boost::asio::const_buffer &get(void) const{ +private: + const boost::asio::const_buffer &get(void){ return _buff; } + const boost::asio::const_buffer _buff; + bool _done; +}; + +/*********************************************************************** + * Managed send buffer implementation for udp zero-copy asio: + * Sends and frees the memory held by the mutable buffer on done. + **********************************************************************/ +class managed_send_buffer_impl : public managed_send_buffer{ +public: + managed_send_buffer_impl( + const boost::asio::mutable_buffer &buff, + boost::asio::ip::udp::socket *socket + ) : _buff(buff){ + _done = false; + _socket = socket; + } + + ~managed_send_buffer_impl(void){ + if (not _done) this->done(0); + } + + void done(size_t num_bytes){ + _done = true; + boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff); + _socket->send(boost::asio::buffer(mem, num_bytes)); + delete [] mem; + } + private: - boost::asio::const_buffer _buff; + const boost::asio::mutable_buffer &get(void){ + return _buff; + } + + const boost::asio::mutable_buffer _buff; + boost::asio::ip::udp::socket *_socket; + bool _done; }; /*********************************************************************** - * UDP zero copy implementation class - * - * This is the portable zero copy implementation for systems - * where a faster, platform specific solution is not available. - * - * It uses boost asio udp sockets and the standard recv() class, - * and in-fact, is not actually doing a zero-copy implementation. + * Zero Copy UDP implementation with ASIO: + * This is the portable zero copy implementation for systems + * where a faster, platform specific solution is not available. + * However, it is not a true zero copy implementation as each + * send and recv requires a copy operation to/from userspace. **********************************************************************/ class udp_zero_copy_impl : public udp_zero_copy{ public: @@ -66,8 +101,8 @@ public: ~udp_zero_copy_impl(void); //send/recv - size_t send(const boost::asio::const_buffer &buff); - smart_buffer::sptr recv(void); + managed_recv_buffer::sptr get_recv_buff(void); + managed_send_buffer::sptr get_send_buff(void); private: boost::asio::ip::udp::socket *_socket; @@ -107,31 +142,33 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){ delete _socket; } -size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ - return _socket->send(boost::asio::buffer(buff)); -} - -smart_buffer::sptr udp_zero_copy_impl::recv(void){ - size_t available = 0; +managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ + boost::uint32_t *buff_mem = new boost::uint32_t[1500/sizeof(boost::uint32_t)]; //implement timeout through polling and sleeping + size_t available = 0; boost::asio::deadline_timer timer(_socket->get_io_service()); timer.expires_from_now(boost::posix_time::milliseconds(100)); while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } - //allocate memory and create buffer - boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; - boost::asio::mutable_buffer buff(buff_mem, available); - //receive only if data is available if (available){ - _socket->receive(boost::asio::buffer(buff)); + available = _socket->receive(boost::asio::buffer(buff_mem, available)); } - //create a new smart buffer to house the data - return smart_buffer::sptr(new smart_buffer_impl(buff)); + //create a new managed buffer to house the data + return managed_recv_buffer::sptr( + new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available)) + ); +} + +managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ + boost::uint32_t *buff_mem = new boost::uint32_t[1500/sizeof(boost::uint32_t)]; + return managed_send_buffer::sptr( + new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 1500), _socket) + ); } size_t udp_zero_copy_impl::get_recv_buff_size(void){ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index a58e32619..a54c0a409 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -42,11 +42,13 @@ void usrp2_impl::io_init(void){ //send a small data packet so the usrp2 knows the udp source port //and the maximum number of lines (32 bit words) per packet + managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data[2] = { htonl(USRP2_INVALID_VRT_HEADER), htonl(_max_rx_samples_per_packet) }; - _data_transport->send(asio::buffer(&data, sizeof(data))); + memcpy(send_buff->cast<void*>(), data, sizeof(data)); + send_buff->done(sizeof(data)); } #define unrolled_loop(__inst, __len){ \ @@ -127,15 +129,15 @@ static inline void usrp2_items_to_host_items( **********************************************************************/ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ //do a receive - _rx_smart_buff = _data_transport->recv(); + _rx_smart_buff = _data_transport->get_recv_buff(); //unpack the vrt header - size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(boost::uint32_t); + size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t); if (num_packet_words32 == 0){ _rx_copy_buff = boost::asio::buffer("", 0); return; //must exit here after setting the buffer } - const boost::uint32_t *vrt_hdr = asio::buffer_cast<const boost::uint32_t *>(_rx_smart_buff->get()); + const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>(); size_t num_header_words32_out, num_payload_words32_out, packet_count_out; try{ vrt::unpack( @@ -176,11 +178,12 @@ size_t usrp2_impl::send( ){ tx_metadata_t metadata = metadata_; //rw copy to change later - boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; + transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); + boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>(); size_t num_samps = std::min( - asio::buffer_size(buff)/io_type.size, - size_t(_max_tx_samples_per_packet) - ); + asio::buffer_size(buff), + send_buff->size() + )/io_type.size; //kill the end of burst flag if this is a fragment if (asio::buffer_size(buff)/io_type.size < num_samps) @@ -214,7 +217,7 @@ size_t usrp2_impl::send( } //send and return number of samples - _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t))); + send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); return num_samps; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index baa6530b8..be09c4ee1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -136,7 +136,7 @@ private: (_mtu - _hdrs)/sizeof(boost::uint32_t) - uhd::transport::vrt::max_header_words32 ; - uhd::transport::smart_buffer::sptr _rx_smart_buff; + uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; size_t _fragment_offset_in_samps; void io_init(void); |