diff options
author | Michael West <michael.west@ettus.com> | 2017-11-16 11:59:45 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-07-25 15:34:03 -0700 |
commit | cb9c97d643ac51279e61439c4e7caae9b1212c7d (patch) | |
tree | c6f7ff98dae9b979a75a924aab3c843963d7fd0c | |
parent | 7ed7b207735fee5f7bd055472e591935b5f96cf5 (diff) | |
download | uhd-cb9c97d643ac51279e61439c4e7caae9b1212c7d.tar.gz uhd-cb9c97d643ac51279e61439c4e7caae9b1212c7d.tar.bz2 uhd-cb9c97d643ac51279e61439c4e7caae9b1212c7d.zip |
X300: Change Ethernet buffering
Ethernet buffering is now done so that most of the buffering is done in
the socket buffers and multiple frames are only used to support the
receive side offload of the socket I/O. Eliminates dropped packets at
high full duplex rates.
-rw-r--r-- | host/include/uhd/rfnoc/sink_block_ctrl_base.hpp | 4 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/source_block_ctrl_base.hpp | 8 | ||||
-rw-r--r-- | host/include/uhd/transport/zero_copy.hpp | 10 | ||||
-rw-r--r-- | host/lib/rfnoc/graph_impl.cpp | 5 | ||||
-rw-r--r-- | host/lib/rfnoc/sink_block_ctrl_base.cpp | 4 | ||||
-rw-r--r-- | host/lib/rfnoc/source_block_ctrl_base.cpp | 10 | ||||
-rw-r--r-- | host/lib/transport/super_recv_packet_handler.hpp | 2 | ||||
-rw-r--r-- | host/lib/transport/super_send_packet_handler.hpp | 8 | ||||
-rw-r--r-- | host/lib/transport/udp_common.hpp | 9 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy.cpp | 54 | ||||
-rw-r--r-- | host/lib/usrp/device3/device3_impl.hpp | 18 | ||||
-rw-r--r-- | host/lib/usrp/device3/device3_io_impl.cpp | 163 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 347 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 31 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_io_impl.cpp | 16 |
15 files changed, 355 insertions, 334 deletions
diff --git a/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp b/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp index f90361cf1..57c398ce3 100644 --- a/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp +++ b/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp @@ -80,8 +80,8 @@ public: * \param block_port Set up flow control for a stream coming in on this particular block port. */ virtual void configure_flow_control_in( - size_t bytes, - size_t block_port=0 + const size_t bytes, + const size_t block_port=0 ); /*! Configure the behaviour for errors on incoming packets diff --git a/host/include/uhd/rfnoc/source_block_ctrl_base.hpp b/host/include/uhd/rfnoc/source_block_ctrl_base.hpp index 39e7411f3..c9976b774 100644 --- a/host/include/uhd/rfnoc/source_block_ctrl_base.hpp +++ b/host/include/uhd/rfnoc/source_block_ctrl_base.hpp @@ -111,10 +111,10 @@ public: * not sufficient to set the flow control, and as such is rarely used. */ virtual void configure_flow_control_out( - bool enable_output, - size_t buf_size_bytes, - size_t pkt_limit=0, - size_t block_port=0, + const bool enable_output, + const size_t buf_size_bytes, + const size_t pkt_limit=0, + const size_t block_port=0, const uhd::sid_t &sid=uhd::sid_t() ); diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 73d1686b8..4218ab2f9 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -128,10 +128,20 @@ namespace uhd{ namespace transport{ * Transport parameters */ struct zero_copy_xport_params { + zero_copy_xport_params() : + recv_frame_size(0), + send_frame_size(0), + num_recv_frames(0), + num_send_frames(0), + recv_buff_size(0), + send_buff_size(0) + { /* NOP */ } size_t recv_frame_size; size_t send_frame_size; size_t num_recv_frames; size_t num_send_frames; + size_t recv_buff_size; + size_t send_buff_size; }; /*! diff --git a/host/lib/rfnoc/graph_impl.cpp b/host/lib/rfnoc/graph_impl.cpp index a2e0e64f4..d9e069993 100644 --- a/host/lib/rfnoc/graph_impl.cpp +++ b/host/lib/rfnoc/graph_impl.cpp @@ -139,11 +139,12 @@ void graph_impl::connect( src_block_port ); // On the same crossbar, use lots of FC packets - size_t bytes_per_response = std::ceil<size_t>(buf_size_bytes / uhd::rfnoc::DEFAULT_FC_XBAR_RESPONSE_FREQ); + size_t bytes_per_response = buf_size_bytes / uhd::rfnoc::DEFAULT_FC_XBAR_RESPONSE_FREQ; // Over the network, use less or we'd flood the transport if (sid.get_src_addr() != sid.get_dst_addr()) { - bytes_per_response = std::ceil<size_t>(buf_size_bytes / uhd::rfnoc::DEFAULT_FC_TX_RESPONSE_FREQ); + bytes_per_response = buf_size_bytes / uhd::rfnoc::DEFAULT_FC_TX_RESPONSE_FREQ; } + UHD_ASSERT_THROW(bytes_per_response != 0); dst->configure_flow_control_in( bytes_per_response, dst_block_port diff --git a/host/lib/rfnoc/sink_block_ctrl_base.cpp b/host/lib/rfnoc/sink_block_ctrl_base.cpp index 1562e134b..d14fe2f38 100644 --- a/host/lib/rfnoc/sink_block_ctrl_base.cpp +++ b/host/lib/rfnoc/sink_block_ctrl_base.cpp @@ -52,8 +52,8 @@ size_t sink_block_ctrl_base::get_fifo_size(size_t block_port) const { } void sink_block_ctrl_base::configure_flow_control_in( - size_t bytes, - size_t block_port + const size_t bytes, + const size_t block_port ) { UHD_RFNOC_BLOCK_TRACE() << boost::format("sink_block_ctrl_base::configure_flow_control_in(bytes=%d)") % bytes; diff --git a/host/lib/rfnoc/source_block_ctrl_base.cpp b/host/lib/rfnoc/source_block_ctrl_base.cpp index afec6ba1b..0f1c31e4f 100644 --- a/host/lib/rfnoc/source_block_ctrl_base.cpp +++ b/host/lib/rfnoc/source_block_ctrl_base.cpp @@ -77,10 +77,10 @@ void source_block_ctrl_base::set_destination( } void source_block_ctrl_base::configure_flow_control_out( - bool enable_fc_output, - size_t buf_size_bytes, - size_t pkt_limit, - size_t block_port, + const bool enable_fc_output, + const size_t buf_size_bytes, + const size_t pkt_limit, + const size_t block_port, UHD_UNUSED(const uhd::sid_t &sid) ) { UHD_RFNOC_BLOCK_TRACE() << "source_block_ctrl_base::configure_flow_control_out() buf_size_bytes==" << buf_size_bytes; @@ -113,7 +113,7 @@ void source_block_ctrl_base::configure_flow_control_out( //based flow control const bool enable_byte_fc = (buf_size_bytes != 0); const bool enable_pkt_cnt_fc = (pkt_limit != 0); - const size_t config = enable_fc_output + (enable_byte_fc << 1) + (enable_pkt_cnt_fc << 2); + const uint32_t config = (enable_fc_output ? 1 : 0) | (enable_byte_fc << 1) | (enable_pkt_cnt_fc << 2); //Resize the FC window. //Precondition: No data can be buffered upstream. diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index fcb333a04..ea02f367d 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -392,7 +392,7 @@ private: #endif //bounds check before extract - size_t num_packet_words32 = buff->size()/sizeof(uint32_t); + const size_t num_packet_words32 = buff->size()/sizeof(uint32_t); if (num_packet_words32 <= _header_offset_words32){ throw std::runtime_error("recv buffer smaller than vrt packet offset"); } diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp index 5cba570a7..b90ea8afd 100644 --- a/host/lib/transport/super_send_packet_handler.hpp +++ b/host/lib/transport/super_send_packet_handler.hpp @@ -47,11 +47,11 @@ namespace sph { **********************************************************************/ class send_packet_handler{ public: - typedef boost::function<managed_send_buffer::sptr(double)> get_buff_type; - typedef boost::function<void(void)> post_send_cb_type; - typedef boost::function<bool(uhd::async_metadata_t &, const double)> async_receiver_type; + typedef std::function<managed_send_buffer::sptr(double)> get_buff_type; + typedef std::function<void(void)> post_send_cb_type; + typedef std::function<bool(uhd::async_metadata_t &, const double)> async_receiver_type; typedef void(*vrt_packer_type)(uint32_t *, vrt::if_packet_info_t &); - //typedef boost::function<void(uint32_t *, vrt::if_packet_info_t &)> vrt_packer_type; + //typedef std::function<void(uint32_t *, vrt::if_packet_info_t &)> vrt_packer_type; /*! * Make a new packet handler for send diff --git a/host/lib/transport/udp_common.hpp b/host/lib/transport/udp_common.hpp index e21d1fcc8..19457903b 100644 --- a/host/lib/transport/udp_common.hpp +++ b/host/lib/transport/udp_common.hpp @@ -13,8 +13,13 @@ namespace uhd{ namespace transport{ - // Jumbo frames are limited to 9000; - static const size_t MAX_ETHERNET_MTU = 9000; + // Jumbo frames can be up to 9600 bytes; + static const size_t MAX_ETHERNET_MTU = 9600; + +#if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + // MacOS limits socket buffer size to 1 Mib + static const size_t MAX_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib +#endif typedef boost::shared_ptr<boost::asio::ip::udp::socket> socket_sptr; diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index 29dbd6c1e..3b3760334 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -22,9 +22,6 @@ using namespace uhd; using namespace uhd::transport; namespace asio = boost::asio; -//A reasonable number of frames for send/recv and async/sync -//static const size_t DEFAULT_NUM_FRAMES = 32; - /*********************************************************************** * Check registry for correct fast-path setting (windows only) **********************************************************************/ @@ -211,7 +208,12 @@ public: } //set size for internal socket buffer - template <typename Opt> size_t resize_buff(size_t num_bytes){ + template <typename Opt> size_t resize_buff(size_t num_bytes) + { + #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + //limit buffer resize on macos or it will error + num_bytes = std::min(num_bytes, MAX_BUFF_SIZE_ETH_MACOS); + #endif Opt option(num_bytes); _socket->set_option(option); return get_buff_size<Opt>(); @@ -316,26 +318,31 @@ udp_zero_copy::sptr udp_zero_copy::make( xport_params.num_recv_frames = size_t(hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); xport_params.send_frame_size = size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); xport_params.num_send_frames = size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); + xport_params.recv_buff_size = size_t(hints.cast<double>("recv_buff_size", default_buff_args.recv_buff_size)); + xport_params.send_buff_size = size_t(hints.cast<double>("send_buff_size", default_buff_args.send_buff_size)); - //extract buffer size hints from the device addr - size_t usr_recv_buff_size = size_t(hints.cast<double>("recv_buff_size", xport_params.num_recv_frames * MAX_ETHERNET_MTU)); - size_t usr_send_buff_size = size_t(hints.cast<double>("send_buff_size", xport_params.num_send_frames * MAX_ETHERNET_MTU)); - - if (hints.has_key("recv_buff_size")) { - if (usr_recv_buff_size < xport_params.num_recv_frames * MAX_ETHERNET_MTU) { - throw uhd::value_error((boost::format( - "recv_buff_size must be equal to or greater than %d") - % (xport_params.num_recv_frames * MAX_ETHERNET_MTU)).str()); - } + // Preserve legacy defaults + if (xport_params.recv_buff_size == 0) { + xport_params.recv_buff_size = xport_params.num_recv_frames * xport_params.recv_frame_size; + } + if (xport_params.send_buff_size == 0) { + xport_params.send_buff_size = xport_params.num_recv_frames * xport_params.send_frame_size; } + + // Resize receive buffer due to known issue where Intel X710 uses full MTU for every packet regardless of actual size + xport_params.recv_buff_size = xport_params.recv_buff_size * MAX_ETHERNET_MTU / xport_params.recv_frame_size; - if (hints.has_key("send_buff_size")) { - if (usr_send_buff_size < xport_params.num_send_frames * MAX_ETHERNET_MTU) { - throw uhd::value_error((boost::format( - "send_buff_size must be equal to or greater than %d") - % (xport_params.num_send_frames * MAX_ETHERNET_MTU)).str()); + #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + //limit default buffer size on macos to avoid the warning issued by resize_buff_helper + if (not hints.has_key("recv_buff_size") and xport_params.recv_buff_size > MAX_BUFF_SIZE_ETH_MACOS) + { + xport_params.recv_buff_size = MAX_BUFF_SIZE_ETH_MACOS; } - } + if (not hints.has_key("send_buff_size") and xport_params.send_buff_size > MAX_BUFF_SIZE_ETH_MACOS) + { + xport_params.send_buff_size = MAX_BUFF_SIZE_ETH_MACOS; + } + #endif udp_zero_copy_asio_impl::sptr udp_trans( new udp_zero_copy_asio_impl(addr, port, xport_params) @@ -343,9 +350,12 @@ udp_zero_copy::sptr udp_zero_copy::make( //call the helper to resize send and recv buffers buff_params_out.recv_buff_size = - resize_buff_helper<asio::socket_base::receive_buffer_size>(udp_trans, usr_recv_buff_size, "recv"); + resize_buff_helper<asio::socket_base::receive_buffer_size>(udp_trans, xport_params.recv_buff_size, "recv"); buff_params_out.send_buff_size = - resize_buff_helper<asio::socket_base::send_buffer_size> (udp_trans, usr_send_buff_size, "send"); + resize_buff_helper<asio::socket_base::send_buffer_size> (udp_trans, xport_params.send_buff_size, "send"); + + // Resize usable amount of receive buffer due to known issue where Intel X710 uses full MTU for every packet regardless of actual size + buff_params_out.recv_buff_size = buff_params_out.recv_buff_size * xport_params.recv_frame_size / MAX_ETHERNET_MTU; return udp_trans; } diff --git a/host/lib/usrp/device3/device3_impl.hpp b/host/lib/usrp/device3/device3_impl.hpp index 580268e4a..11487b54c 100644 --- a/host/lib/usrp/device3/device3_impl.hpp +++ b/host/lib/usrp/device3/device3_impl.hpp @@ -56,13 +56,13 @@ public: _terminator(terminator), _data_xport(data_xport), _async_msg_xport(async_msg_xport) - {}; + {} ~device3_send_packet_streamer() { // Make sure the async task is destroyed before the transports _tx_async_msg_tasks.clear(); - }; + } uhd::rfnoc::tx_stream_terminator::sptr get_terminator() { @@ -92,9 +92,9 @@ public: ) : uhd::transport::sph::recv_packet_streamer(max_num_samps), _terminator(terminator), - _xport(xport) {}; + _xport(xport) {} - ~device3_recv_packet_streamer() {}; + ~device3_recv_packet_streamer() {} both_xports_t get_xport() { @@ -145,7 +145,7 @@ public: , rx_max_len_hdr(DEVICE3_RX_MAX_HDR_LEN) , rx_fc_request_freq(DEVICE3_RX_FC_REQUEST_FREQ) , tx_fc_response_freq(DEVICE3_TX_FC_RESPONSE_FREQ) - {}; + {} }; /*********************************************************************** @@ -165,7 +165,7 @@ protected: * Structors **********************************************************************/ device3_impl(); - virtual ~device3_impl() {}; + virtual ~device3_impl() {} /*********************************************************************** * Streaming-related @@ -196,11 +196,11 @@ protected: const uhd::device_addr_t& args ) = 0; - virtual uhd::device_addr_t get_tx_hints(size_t) { return uhd::device_addr_t(); }; - virtual uhd::device_addr_t get_rx_hints(size_t) { return uhd::device_addr_t(); }; + virtual uhd::device_addr_t get_tx_hints(size_t) { return uhd::device_addr_t(); } + virtual uhd::device_addr_t get_rx_hints(size_t) { return uhd::device_addr_t(); } //! Is called after a streamer is generated - virtual void post_streamer_hooks(uhd::direction_t) {}; + virtual void post_streamer_hooks(uhd::direction_t) {} /*********************************************************************** * Channel-related diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp index e4c38aca6..490f10c3c 100644 --- a/host/lib/usrp/device3/device3_io_impl.cpp +++ b/host/lib/usrp/device3/device3_io_impl.cpp @@ -158,7 +158,10 @@ struct rx_fc_cache_t uint64_t seq_num; sid_t sid; zero_copy_if::sptr xport; - endianness_t endianness; + std::function<uint32_t(uint32_t)> to_host; + std::function<uint32_t(uint32_t)> from_host; + std::function<void(const uint32_t *packet_buff, vrt::if_packet_info_t &)> unpack; + std::function<void(uint32_t *packet_buff, vrt::if_packet_info_t &)> pack; }; /*! Determine the size of the flow control window in number of packets. @@ -218,8 +221,8 @@ static size_t get_rx_flow_control_window( * skip the counter update. */ static bool rx_flow_ctrl( - boost::shared_ptr<rx_fc_cache_t> fc_cache, - managed_buffer::sptr buff + boost::shared_ptr<rx_fc_cache_t> fc_cache, + managed_buffer::sptr buff ) { // If the caller supplied a buffer if (buff) @@ -229,17 +232,12 @@ static bool rx_flow_ctrl( packet_info.num_packet_words32 = buff->size()/sizeof(uint32_t); const uint32_t *pkt = buff->cast<const uint32_t *>(); try { - if (fc_cache->endianness == ENDIANNESS_BIG) - { - vrt::chdr::if_hdr_unpack_be(pkt, packet_info); - } else { - vrt::chdr::if_hdr_unpack_le(pkt, packet_info); - } + fc_cache->unpack(pkt, packet_info); } catch(const std::exception &ex) { // Log and ignore - UHD_LOGGER_ERROR("RX FLOW CTRL") << "Error unpacking flow control packet: " << ex.what() << std::endl; + UHD_LOGGER_ERROR("RX FLOW CTRL") << "Error unpacking packet: " << ex.what() << std::endl; return true; } @@ -282,23 +280,13 @@ static bool rx_flow_ctrl( packet_info.has_tsf = false; packet_info.has_tlr = false; - if (fc_cache->endianness == ENDIANNESS_BIG) { - // Load Header: - vrt::chdr::if_hdr_pack_be(pkt, packet_info); - // Load Payload: Packet count, and byte count - pkt[packet_info.num_header_words32+DEVICE3_FC_PACKET_COUNT_OFFSET] = - uhd::htonx<uint32_t>(fc_cache->total_packets_consumed); - pkt[packet_info.num_header_words32+DEVICE3_FC_BYTE_COUNT_OFFSET] = - uhd::htonx<uint32_t>(fc_cache->total_bytes_consumed); - } else { - // Load Header: - vrt::chdr::if_hdr_pack_le(pkt, packet_info); - // Load Payload: Packet count, and byte count - pkt[packet_info.num_header_words32+DEVICE3_FC_PACKET_COUNT_OFFSET] = - uhd::htowx<uint32_t>(fc_cache->total_packets_consumed); - pkt[packet_info.num_header_words32+DEVICE3_FC_BYTE_COUNT_OFFSET] = - uhd::htowx<uint32_t>(fc_cache->total_bytes_consumed); - } + // Load Header: + fc_cache->pack(pkt, packet_info); + // Load Payload: Packet count, and byte count + pkt[packet_info.num_header_words32+DEVICE3_FC_PACKET_COUNT_OFFSET] = + fc_cache->from_host(fc_cache->total_packets_consumed); + pkt[packet_info.num_header_words32+DEVICE3_FC_BYTE_COUNT_OFFSET] = + fc_cache->from_host(fc_cache->total_bytes_consumed); //send the buffer over the interface fc_buff->commit(sizeof(uint32_t)*(packet_info.num_packet_words32)); @@ -313,15 +301,11 @@ static bool rx_flow_ctrl( * */ static void handle_rx_flowctrl_ack( - boost::shared_ptr<rx_fc_cache_t> fc_cache, - const uint32_t *payload + boost::shared_ptr<rx_fc_cache_t> fc_cache, + const uint32_t *payload ) { - const uint32_t pkt_count = (fc_cache->endianness == ENDIANNESS_BIG) ? - uhd::ntohx<uint32_t>(payload[0]) : - uhd::wtohx<uint32_t>(payload[0]); - const uint32_t byte_count = (fc_cache->endianness == ENDIANNESS_BIG) ? - uhd::ntohx<uint32_t>(payload[1]) : - uhd::wtohx<uint32_t>(payload[1]); + const uint32_t pkt_count = fc_cache->to_host(payload[0]); + const uint32_t byte_count = fc_cache->to_host(payload[1]); if (fc_cache->total_bytes_consumed != byte_count) { UHD_LOGGER_DEBUG("device3") @@ -362,13 +346,15 @@ struct tx_fc_cache_t uint32_t window_size; uint32_t fc_ack_seqnum; bool fc_received; + std::function<uint32_t(uint32_t)> to_host; + std::function<uint32_t(uint32_t)> from_host; + std::function<void(const uint32_t *packet_buff, vrt::if_packet_info_t &)> unpack; + std::function<void(uint32_t *packet_buff, vrt::if_packet_info_t &)> pack; }; static bool tx_flow_ctrl( boost::shared_ptr<tx_fc_cache_t> fc_cache, - zero_copy_if::sptr xport, - uint32_t (*to_host)(uint32_t), - void (*unpack)(const uint32_t *packet_buff, vrt::if_packet_info_t &), + zero_copy_if::sptr xport, managed_buffer::sptr buff ) { while (true) @@ -395,7 +381,7 @@ static bool tx_flow_ctrl( if_packet_info.num_packet_words32 = buff->size()/sizeof(uint32_t); const uint32_t *packet_buff = buff->cast<const uint32_t *>(); try { - unpack(packet_buff, if_packet_info); + fc_cache->unpack(packet_buff, if_packet_info); } catch(const std::exception &ex) { @@ -410,8 +396,8 @@ static bool tx_flow_ctrl( } const uint32_t *payload = &packet_buff[if_packet_info.num_header_words32]; - const uint32_t pkt_count = to_host(payload[0]); - const uint32_t byte_count = to_host(payload[1]); + const uint32_t pkt_count = fc_cache->to_host(payload[0]); + const uint32_t byte_count = fc_cache->to_host(payload[1]); // update the amount of space fc_cache->last_byte_ack = byte_count; @@ -426,9 +412,7 @@ static bool tx_flow_ctrl( static void tx_flow_ctrl_ack( boost::shared_ptr<tx_fc_cache_t> fc_cache, zero_copy_if::sptr send_xport, - sid_t send_sid, - uint32_t (*from_host)(uint32_t), - void (*pack)(uint32_t *packet_buff, vrt::if_packet_info_t &) + sid_t send_sid ) { if (not fc_cache->fc_received) { @@ -462,7 +446,7 @@ static void tx_flow_ctrl_ack( packet_info.has_tlr = false; // Load Header: - pack(pkt, packet_info); + fc_cache->pack(pkt, packet_info); // Update counters to include this packet size_t fc_ack_pkt_size = sizeof(uint32_t)*(packet_info.num_packet_words32); @@ -476,9 +460,9 @@ static void tx_flow_ctrl_ack( // Load Payload: Packet count, and byte count pkt[packet_info.num_header_words32+DEVICE3_FC_PACKET_COUNT_OFFSET] = - from_host(fc_cache->pkt_count); + fc_cache->from_host(fc_cache->pkt_count); pkt[packet_info.num_header_words32+DEVICE3_FC_BYTE_COUNT_OFFSET] = - from_host(fc_cache->byte_count); + fc_cache->from_host(fc_cache->byte_count); // Send the buffer over the interface fc_buff->commit(fc_ack_pkt_size); @@ -506,7 +490,8 @@ struct async_tx_info_t static void handle_tx_async_msgs( boost::shared_ptr<async_tx_info_t> async_info, zero_copy_if::sptr xport, - endianness_t endianness, + uint32_t (*to_host)(uint32_t), + void (*unpack)(const uint32_t *packet_buff, vrt::if_packet_info_t &), boost::function<double(void)> get_tick_rate ) { managed_recv_buffer::sptr buff = xport->get_recv_buff(); @@ -521,19 +506,9 @@ static void handle_tx_async_msgs( const uint32_t *packet_buff = buff->cast<const uint32_t *>(); //unpacking can fail - uint32_t (*endian_conv)(uint32_t) = uhd::ntohx; try { - if (endianness == ENDIANNESS_BIG) - { - vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info); - endian_conv = uhd::ntohx; - } - else - { - vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info); - endian_conv = uhd::wtohx; - } + unpack(packet_buff, if_packet_info); } catch(const std::exception &ex) { @@ -549,7 +524,7 @@ static void handle_tx_async_msgs( //fill in the async metadata async_metadata_t metadata; load_metadata_from_buff( - endian_conv, + to_host, metadata, if_packet_info, packet_buff, @@ -681,14 +656,29 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) boost::shared_ptr<rx_fc_cache_t> fc_cache(new rx_fc_cache_t()); fc_cache->sid = xport.send_sid; fc_cache->xport = xport.send; - fc_cache->endianness = xport.endianness; fc_cache->interval = fc_handle_window; + if (xport.endianness == ENDIANNESS_BIG) + { + fc_cache->to_host = uhd::ntohx<uint32_t>; + fc_cache->from_host = uhd::htonx<uint32_t>; + fc_cache->pack = vrt::chdr::if_hdr_pack_be; + fc_cache->unpack = vrt::chdr::if_hdr_unpack_be; + } + else + { + fc_cache->to_host = uhd::wtohx<uint32_t>; + fc_cache->from_host = uhd::htowx<uint32_t>; + fc_cache->pack = vrt::chdr::if_hdr_pack_le; + fc_cache->unpack = vrt::chdr::if_hdr_unpack_le; + } xport.recv = zero_copy_flow_ctrl::make ( xport.recv, NULL, - [=](managed_buffer::sptr buff) { - return rx_flow_ctrl(fc_cache, buff); + [fc_cache](managed_buffer::sptr buff) { + return rx_flow_ctrl( + fc_cache, + buff); } ); @@ -753,7 +743,7 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) // Give the streamer a functor to handle flow control ACK messages my_streamer->set_xport_handle_flowctrl_ack( stream_i, - [=](const uint32_t *payload) { + [fc_cache](const uint32_t *payload) { handle_rx_flowctrl_ack( fc_cache, payload @@ -764,7 +754,9 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) //Give the streamer a functor to get the recv_buffer my_streamer->set_xport_chan_get_buff( stream_i, - [=](double timeout) {return xport.recv->get_recv_buff(timeout);}, + [xport](double timeout) { + return xport.recv->get_recv_buff(timeout); + }, true /*flush*/ ); @@ -774,7 +766,7 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) boost::weak_ptr<uhd::rx_streamer> weak_ptr(my_streamer); my_streamer->set_overflow_handler( stream_i, - [=]() { + [recv_terminator, weak_ptr, stream_i]() { recv_terminator->handle_overrun( weak_ptr, stream_i); @@ -784,7 +776,9 @@ rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t &args_) //Give the streamer a functor issue stream cmd my_streamer->set_issue_stream_cmd( stream_i, - [=](const stream_cmd_t& stream_cmd) {blk_ctrl->issue_stream_cmd(stream_cmd, block_port);} + [blk_ctrl, block_port](const stream_cmd_t& stream_cmd) { + blk_ctrl->issue_stream_cmd(stream_cmd, block_port); + } ); } @@ -913,14 +907,24 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) ); // Add flow control transport boost::shared_ptr<tx_fc_cache_t> fc_cache(new tx_fc_cache_t(fc_window)); + if (xport.endianness == ENDIANNESS_BIG) + { + fc_cache->to_host = uhd::ntohx<uint32_t>; + fc_cache->from_host = uhd::htonx<uint32_t>; + fc_cache->pack = vrt::chdr::if_hdr_pack_be; + fc_cache->unpack = vrt::chdr::if_hdr_unpack_be; + } else { + fc_cache->to_host = uhd::wtohx<uint32_t>; + fc_cache->from_host = uhd::htowx<uint32_t>; + fc_cache->pack = vrt::chdr::if_hdr_pack_le; + fc_cache->unpack = vrt::chdr::if_hdr_unpack_le; + } xport.send = zero_copy_flow_ctrl::make( xport.send, - [=](managed_buffer::sptr buff) { + [fc_cache, xport](managed_buffer::sptr buff) { return tx_flow_ctrl( fc_cache, xport.recv, - (xport.endianness == ENDIANNESS_BIG ? uhd::ntohx<uint32_t> : uhd::wtohx<uint32_t>), - (xport.endianness == ENDIANNESS_BIG ? vrt::chdr::if_hdr_unpack_be : vrt::chdr::if_hdr_unpack_le), buff); }, NULL @@ -1004,12 +1008,13 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) async_tx_info->old_async_queue = _async_md; task::sptr async_task = task::make( - [=]() { + [async_tx_info, async_xport, xport, send_terminator]() { handle_tx_async_msgs( async_tx_info, async_xport.recv, - xport.endianness, - [=]() {return send_terminator->get_tick_rate();} + xport.endianness == ENDIANNESS_BIG ? uhd::ntohx<uint32_t> : uhd::wtohx<uint32_t>, + xport.endianness == ENDIANNESS_BIG ? vrt::chdr::if_hdr_unpack_be : vrt::chdr::if_hdr_unpack_le, + [send_terminator]() {return send_terminator->get_tick_rate();} ); } ); @@ -1018,13 +1023,13 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) //Give the streamer a functor to get the send buffer my_streamer->set_xport_chan_get_buff( stream_i, - [=](const double timeout) { + [xport](const double timeout) { return xport.send->get_send_buff(timeout); } ); //Give the streamer a functor handled received async messages my_streamer->set_async_receiver( - [=](uhd::async_metadata_t& md, const double timeout) { + [async_md](uhd::async_metadata_t& md, const double timeout) { return async_md->pop_with_timed_wait(md, timeout); } ); @@ -1034,15 +1039,13 @@ tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t &args_) my_streamer->set_xport_chan_post_send_cb( stream_i, - [=]() { + [fc_cache, xport]() { tx_flow_ctrl_ack( fc_cache, xport.send, - xport.send_sid, - (xport.endianness == ENDIANNESS_BIG ? uhd::htonx<uint32_t> : uhd::htowx<uint32_t>), - (xport.endianness == ENDIANNESS_BIG ? vrt::chdr::if_hdr_pack_be : vrt::chdr::if_hdr_pack_le) + xport.send_sid ); - } + } ); } diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 60be75f2b..d0915d592 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -473,8 +473,10 @@ void x300_impl::mboard_members_t::discover_eth( // Choose the interface based on the index parity if (i % 2 == 0) { conn_iface.type = X300_IFACE_ETH0; + conn_iface.link_rate = loaded_fpga_image == "HG" ? X300_MAX_RATE_1GIGE : X300_MAX_RATE_10GIGE; } else { conn_iface.type = X300_IFACE_ETH1; + conn_iface.link_rate = X300_MAX_RATE_10GIGE; } break; } @@ -492,15 +494,19 @@ void x300_impl::mboard_members_t::discover_eth( if (addr == boost::asio::ip::address_v4( uint32_t(X300_DEFAULT_IP_ETH0_1G)).to_string()) { conn_iface.type = X300_IFACE_ETH0; + conn_iface.link_rate = X300_MAX_RATE_1GIGE; } else if (addr == boost::asio::ip::address_v4( uint32_t(X300_DEFAULT_IP_ETH1_1G)).to_string()) { conn_iface.type = X300_IFACE_ETH1; + conn_iface.link_rate = X300_MAX_RATE_1GIGE; } else if (addr == boost::asio::ip::address_v4( uint32_t(X300_DEFAULT_IP_ETH0_10G)).to_string()) { conn_iface.type = X300_IFACE_ETH0; + conn_iface.link_rate = X300_MAX_RATE_10GIGE; } else if (addr == boost::asio::ip::address_v4( uint32_t(X300_DEFAULT_IP_ETH1_10G)).to_string()) { conn_iface.type = X300_IFACE_ETH1; + conn_iface.link_rate = X300_MAX_RATE_10GIGE; } else { throw uhd::assertion_error(str(boost::format( "X300 Initialization Error: Failed to match address %s with " @@ -624,91 +630,6 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) if (key.find("send") != std::string::npos) mb.send_args[key] = dev_addr[key]; } - if (mb.xport_path == "eth" ) { - /* This is an ETH connection. Figure out what the maximum supported frame - * size is for the transport in the up and down directions. The frame size - * depends on the host PIC's NIC's MTU settings. To determine the frame size, - * we test for support up to an expected "ceiling". If the user - * specified a frame size, we use that frame size as the ceiling. If no - * frame size was specified, we use the maximum UHD frame size. - * - * To optimize performance, the frame size should be greater than or equal - * to the frame size that UHD uses so that frames don't get split across - * multiple transmission units - this is why the limits passed into the - * 'determine_max_frame_size' function are actually frame sizes. */ - frame_size_t req_max_frame_size; - req_max_frame_size.recv_frame_size = (mb.recv_args.has_key("recv_frame_size")) \ - ? boost::lexical_cast<size_t>(mb.recv_args["recv_frame_size"]) \ - : X300_10GE_DATA_FRAME_MAX_SIZE; - req_max_frame_size.send_frame_size = (mb.send_args.has_key("send_frame_size")) \ - ? boost::lexical_cast<size_t>(mb.send_args["send_frame_size"]) \ - : X300_10GE_DATA_FRAME_MAX_SIZE; - - #if defined UHD_PLATFORM_LINUX - const std::string mtu_tool("ip link"); - #elif defined UHD_PLATFORM_WIN32 - const std::string mtu_tool("netsh"); - #else - const std::string mtu_tool("ifconfig"); - #endif - - // Detect the frame size on the path to the USRP - try { - frame_size_t pri_frame_sizes = determine_max_frame_size( - eth_addrs.at(0), req_max_frame_size - ); - - _max_frame_sizes = pri_frame_sizes; - if (eth_addrs.size() > 1) { - frame_size_t sec_frame_sizes = determine_max_frame_size( - eth_addrs.at(1), req_max_frame_size - ); - - // Choose the minimum of the max frame sizes - // to ensure we don't exceed any one of the links' MTU - _max_frame_sizes.recv_frame_size = std::min( - pri_frame_sizes.recv_frame_size, - sec_frame_sizes.recv_frame_size - ); - - _max_frame_sizes.send_frame_size = std::min( - pri_frame_sizes.send_frame_size, - sec_frame_sizes.send_frame_size - ); - } - } catch(std::exception &e) { - UHD_LOGGER_ERROR("X300") << e.what() ; - } - - if ((mb.recv_args.has_key("recv_frame_size")) - && (req_max_frame_size.recv_frame_size > _max_frame_sizes.recv_frame_size)) { - UHD_LOGGER_WARNING("X300") - << boost::format("You requested a receive frame size of (%lu) but your NIC's max frame size is (%lu).") - % req_max_frame_size.recv_frame_size - % _max_frame_sizes.recv_frame_size - << boost::format("Please verify your NIC's MTU setting using '%s' or set the recv_frame_size argument appropriately.") - % mtu_tool - << "UHD will use the auto-detected max frame size for this connection." - ; - } - - if ((mb.recv_args.has_key("send_frame_size")) - && (req_max_frame_size.send_frame_size > _max_frame_sizes.send_frame_size)) { - UHD_LOGGER_WARNING("X300") - << boost::format("You requested a send frame size of (%lu) but your NIC's max frame size is (%lu).") - % req_max_frame_size.send_frame_size - % _max_frame_sizes.send_frame_size - << boost::format("Please verify your NIC's MTU setting using '%s' or set the send_frame_size argument appropriately.") - % mtu_tool - << "UHD will use the auto-detected max frame size for this connection." - ; - } - - _tree->create<size_t>(mb_path / "mtu/recv").set(_max_frame_sizes.recv_frame_size); - _tree->create<size_t>(mb_path / "mtu/send").set(_max_frame_sizes.send_frame_size); - _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_10GIGE); - } - //create basic communication UHD_LOGGER_DEBUG("X300") << "Setting up basic communication..."; if (mb.xport_path == "nirio") { @@ -828,11 +749,129 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) _tree->create<std::string>(mb_path / "codename").set("Yetti"); //////////////////////////////////////////////////////////////////// - // determine routing based on address match + // discover ethernet interfaces, frame sizes, and link rates //////////////////////////////////////////////////////////////////// - if (mb.xport_path != "nirio") { + if (mb.xport_path == "eth" ) { + double link_max_rate = 0.0; + // Discover ethernet interfaces mb.discover_eth(mb_eeprom, eth_addrs); + + /* This is an ETH connection. Figure out what the maximum supported frame + * size is for the transport in the up and down directions. The frame size + * depends on the host PC's NIC's MTU settings. To determine the frame size, + * we test for support up to an expected "ceiling". If the user + * specified a frame size, we use that frame size as the ceiling. If no + * frame size was specified, we use the maximum UHD frame size. + * + * To optimize performance, the frame size should be greater than or equal + * to the frame size that UHD uses so that frames don't get split across + * multiple transmission units - this is why the limits passed into the + * 'determine_max_frame_size' function are actually frame sizes. */ + frame_size_t req_max_frame_size; + req_max_frame_size.recv_frame_size = (mb.recv_args.has_key("recv_frame_size")) \ + ? boost::lexical_cast<size_t>(mb.recv_args["recv_frame_size"]) \ + : X300_DATA_FRAME_MAX_SIZE; + req_max_frame_size.send_frame_size = (mb.send_args.has_key("send_frame_size")) \ + ? boost::lexical_cast<size_t>(mb.send_args["send_frame_size"]) \ + : X300_DATA_FRAME_MAX_SIZE; + + #if defined UHD_PLATFORM_LINUX + const std::string mtu_tool("ip link"); + #elif defined UHD_PLATFORM_WIN32 + const std::string mtu_tool("netsh"); + #else + const std::string mtu_tool("ifconfig"); + #endif + + // Detect the frame size on the path to the USRP + try { + frame_size_t pri_frame_sizes = determine_max_frame_size( + eth_addrs.at(0), req_max_frame_size + ); + + _max_frame_sizes = pri_frame_sizes; + if (eth_addrs.size() > 1) { + frame_size_t sec_frame_sizes = determine_max_frame_size( + eth_addrs.at(1), req_max_frame_size + ); + + // Choose the minimum of the max frame sizes + // to ensure we don't exceed any one of the links' MTU + _max_frame_sizes.recv_frame_size = std::min( + pri_frame_sizes.recv_frame_size, + sec_frame_sizes.recv_frame_size + ); + + _max_frame_sizes.send_frame_size = std::min( + pri_frame_sizes.send_frame_size, + sec_frame_sizes.send_frame_size + ); + } + } catch(std::exception &e) { + UHD_LOGGER_ERROR("X300") << e.what() ; + } + + if ((mb.recv_args.has_key("recv_frame_size")) + && (req_max_frame_size.recv_frame_size > _max_frame_sizes.recv_frame_size)) { + UHD_LOGGER_WARNING("X300") + << boost::format("You requested a receive frame size of (%lu) but your NIC's max frame size is (%lu).") + % req_max_frame_size.recv_frame_size + % _max_frame_sizes.recv_frame_size + + << boost::format("Please verify your NIC's MTU setting using '%s' or set the recv_frame_size argument appropriately.") + % mtu_tool + << "UHD will use the auto-detected max frame size for this connection." + ; + } + + if ((mb.send_args.has_key("send_frame_size")) + && (req_max_frame_size.send_frame_size > _max_frame_sizes.send_frame_size)) { + UHD_LOGGER_WARNING("X300") + << boost::format("You requested a send frame size of (%lu) but your NIC's max frame size is (%lu).") + % req_max_frame_size.send_frame_size + % _max_frame_sizes.send_frame_size + + << boost::format("Please verify your NIC's MTU setting using '%s' or set the send_frame_size argument appropriately.") + % mtu_tool + << "UHD will use the auto-detected max frame size for this connection." + ; + } + + // Check frame sizes + for (auto conn : mb.eth_conns) + { + link_max_rate += conn.link_rate; + + size_t rec_send_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_SEND_SIZE : X300_10GE_DATA_FRAME_SEND_SIZE; + size_t rec_recv_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_RECV_SIZE : X300_10GE_DATA_FRAME_RECV_SIZE; + + if (_max_frame_sizes.send_frame_size < rec_send_frame_size) + { + UHD_LOGGER_WARNING("X300") + << boost::format("For the %s connection, UHD recommends a send frame size of at least %lu for best\nperformance, but your configuration will only allow %lu.") + % conn.addr + % rec_send_frame_size + % _max_frame_sizes.send_frame_size + << "This may negatively impact your maximum achievable sample rate.\nCheck the MTU on the interface and/or the send_frame_size argument." + ; + } + + if (_max_frame_sizes.recv_frame_size < rec_recv_frame_size) + { + UHD_LOGGER_WARNING("X300") + << boost::format("For the %s connection, UHD recommends a receive frame size of at least %lu for best\nperformance, but your configuration will only allow %lu.") + % conn.addr + % rec_recv_frame_size + % _max_frame_sizes.recv_frame_size + << "This may negatively impact your maximum achievable sample rate.\nCheck the MTU on the interface and/or the recv_frame_size argument." + ; + } + } + + _tree->create<size_t>(mb_path / "mtu/recv").set(_max_frame_sizes.recv_frame_size); + _tree->create<size_t>(mb_path / "mtu/send").set(_max_frame_sizes.send_frame_size); + _tree->create<double>(mb_path / "link_max_rate").set(link_max_rate); } //////////////////////////////////////////////////////////////////// @@ -1264,97 +1303,66 @@ uhd::both_xports_t x300_impl::make_transport( xport_type == TX_DATA ? mb.next_tx_src_addr : xport_type == RX_DATA ? mb.next_rx_src_addr : mb.next_src_addr; - std::string interface_addr = mb.eth_conns[next_src_addr].addr; + x300_eth_conn_t conn = mb.eth_conns[next_src_addr]; const uint32_t xbar_src_addr = next_src_addr==0 ? X300_SRC_ADDR0 : X300_SRC_ADDR1; const uint32_t xbar_src_dst = - mb.eth_conns[next_src_addr].type==X300_IFACE_ETH0 ? X300_XB_DST_E0 : X300_XB_DST_E1; - next_src_addr = (next_src_addr + 1) % mb.eth_conns.size(); + conn.type==X300_IFACE_ETH0 ? X300_XB_DST_E0 : X300_XB_DST_E1; + if (xport_type != TX_DATA) next_src_addr = (next_src_addr + 1) % mb.eth_conns.size(); xports.send_sid = this->allocate_sid(mb, address, xbar_src_addr, xbar_src_dst); xports.recv_sid = xports.send_sid.reversed(); - /* Determine what the recommended frame size is for this - * connection type.*/ - size_t eth_data_rec_frame_size = 0; - - fs_path mboard_path = fs_path("/mboards") / mb_index / "link_max_rate"; - - if (mb.loaded_fpga_image == "HG") { - size_t max_link_rate = 0; - if (xbar_src_dst == X300_XB_DST_E0) { - eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE; - max_link_rate += X300_MAX_RATE_1GIGE; - } else if (xbar_src_dst == X300_XB_DST_E1) { - eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; - max_link_rate += X300_MAX_RATE_10GIGE; + // Set size and number of frames + size_t system_max_send_frame_size = (size_t) _max_frame_sizes.send_frame_size; + size_t system_max_recv_frame_size = (size_t) _max_frame_sizes.recv_frame_size; + default_buff_args.send_frame_size = std::min(system_max_send_frame_size, X300_ETH_MSG_FRAME_SIZE); + default_buff_args.recv_frame_size = std::min(system_max_recv_frame_size, X300_ETH_MSG_FRAME_SIZE); + default_buff_args.num_send_frames = 1; // never need multiple frames on send + default_buff_args.num_recv_frames = 1; // only need multiple frames with offload thread + default_buff_args.send_buff_size = conn.link_rate / 50; // 20ms + default_buff_args.recv_buff_size = std::max(conn.link_rate / 50, X300_ETH_MSG_NUM_FRAMES * X300_ETH_MSG_FRAME_SIZE); // enough to hold greater of 20ms or number of msg frames + if (xport_type == TX_DATA) + { + size_t default_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_SEND_SIZE : X300_10GE_DATA_FRAME_SEND_SIZE; + default_buff_args.send_frame_size = args.cast<size_t>("send_frame_size", std::min(default_frame_size, system_max_send_frame_size)); + if (default_buff_args.send_frame_size > system_max_send_frame_size) + { + UHD_LOGGER_WARNING("X300") + << boost::format("Requested send_frame_size of %d exceeds the maximum allowed on the %s connection. Using %d.") + % default_buff_args.send_frame_size + % conn.addr + % system_max_send_frame_size + ; + default_buff_args.send_frame_size = system_max_send_frame_size; } - _tree->access<double>(mboard_path).set(max_link_rate); - } else if (mb.loaded_fpga_image == "XG" or mb.loaded_fpga_image == "XA") { - eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; - size_t max_link_rate = X300_MAX_RATE_10GIGE; - max_link_rate *= mb.eth_conns.size(); - _tree->access<double>(mboard_path).set(max_link_rate); - } else if (mb.loaded_fpga_image == "HA") { - eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE; - size_t max_link_rate = X300_MAX_RATE_1GIGE; - max_link_rate *= mb.eth_conns.size(); - _tree->access<double>(mboard_path).set(max_link_rate); - } - - if (eth_data_rec_frame_size == 0) { - throw uhd::runtime_error("Unable to determine ETH link type."); } + else if (xport_type == RX_DATA) + { + size_t default_frame_size = conn.link_rate == X300_MAX_RATE_1GIGE ? X300_1GE_DATA_FRAME_RECV_SIZE : X300_10GE_DATA_FRAME_RECV_SIZE; + default_buff_args.recv_frame_size = args.cast<size_t>("recv_frame_size", std::min(default_frame_size, system_max_recv_frame_size)); + if (default_buff_args.recv_frame_size > system_max_recv_frame_size) + { + UHD_LOGGER_WARNING("X300") + << boost::format("Requested recv_frame_size of %d exceeds the maximum allowed on the %s connection. Using %d.") + % default_buff_args.recv_frame_size + % conn.addr + % system_max_recv_frame_size + ; + default_buff_args.recv_frame_size = system_max_recv_frame_size; + } + // set default buffering for data + default_buff_args.recv_buff_size = conn.link_rate / 10; // 100ms + default_buff_args.num_recv_frames = 2; // set some buffers so the offload thread actually offloads the socket I/O - /* Print a warning if the system's max available frame size is less than the most optimal - * frame size for this type of connection. */ - if (_max_frame_sizes.send_frame_size < eth_data_rec_frame_size) { - UHD_LOGGER_WARNING("X300") - << boost::format("For this connection, UHD recommends a send frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.") - % eth_data_rec_frame_size - % _max_frame_sizes.send_frame_size - << "This may negatively impact your maximum achievable sample rate." - ; + // set buffering for flow control messages + default_buff_args.num_send_frames = 1; } - if (_max_frame_sizes.recv_frame_size < eth_data_rec_frame_size) { - UHD_LOGGER_WARNING("X300") - << boost::format("For this connection, UHD recommends a receive frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.") - % eth_data_rec_frame_size - % _max_frame_sizes.recv_frame_size - << "This may negatively impact your maximum achievable sample rate." - ; - } - - size_t system_max_send_frame_size = (size_t) _max_frame_sizes.send_frame_size; - size_t system_max_recv_frame_size = (size_t) _max_frame_sizes.recv_frame_size; - - // Make sure frame sizes do not exceed the max available value supported by UHD - default_buff_args.send_frame_size = - (xport_type == TX_DATA) - ? std::min(system_max_send_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE) - : std::min(system_max_send_frame_size, X300_ETH_MSG_FRAME_SIZE); - - default_buff_args.recv_frame_size = - (xport_type == RX_DATA) - ? std::min(system_max_recv_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE) - : std::min(system_max_recv_frame_size, X300_ETH_MSG_FRAME_SIZE); - - default_buff_args.num_send_frames = - (xport_type == TX_DATA) - ? X300_ETH_DATA_NUM_FRAMES - : X300_ETH_MSG_NUM_FRAMES; - - default_buff_args.num_recv_frames = - (xport_type == RX_DATA) - ? X300_ETH_DATA_NUM_FRAMES - : X300_ETH_MSG_NUM_FRAMES; - //make a new transport - fpga has no idea how to talk to us on this yet udp_zero_copy::buff_params buff_params; - xports.recv = udp_zero_copy::make( - interface_addr, + conn.addr, BOOST_STRINGIZE(X300_VITA_UDP_PORT), default_buff_args, buff_params, @@ -1365,12 +1373,12 @@ uhd::both_xports_t x300_impl::make_transport( if (xport_type == RX_DATA) { xports.recv = zero_copy_recv_offload::make( xports.recv, - X300_THREAD_BUFFER_TIMEOUT + X300_RECV_OFFLOAD_BUFFER_TIMEOUT ); } xports.send = xports.recv; - //For the UDP transport the buffer size if the size of the socket buffer + //For the UDP transport the buffer size is the size of the socket buffer //in the kernel xports.recv_buff_size = buff_params.recv_buff_size; xports.send_buff_size = buff_params.send_buff_size; @@ -1381,9 +1389,8 @@ uhd::both_xports_t x300_impl::make_transport( //send a mini packet with SID into the ZPU //ZPU will reprogram the ethernet framer - UHD_LOGGER_TRACE("X300") - << "programming packet for new xport on " - << interface_addr << " sid " << xports.send_sid; + UHD_LOGGER_DEBUG("X300") << "programming packet for new xport on " + << conn.addr << " sid " << xports.send_sid ; //YES, get a __send__ buffer from the __recv__ socket //-- this is the only way to program the framer for recv: managed_send_buffer::sptr buff = xports.recv->get_send_buff(); @@ -1691,9 +1698,9 @@ x300_impl::frame_size_t x300_impl::determine_max_frame_size(const std::string &a //Reducing range of (min,max) by setting max value to 10gig max_frame_size as larger sizes are not supported size_t min_recv_frame_size = sizeof(x300_mtu_t); - size_t max_recv_frame_size = std::min(user_frame_size.recv_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE) & size_t(~3); + size_t max_recv_frame_size = std::min(user_frame_size.recv_frame_size, X300_DATA_FRAME_MAX_SIZE) & size_t(~3); size_t min_send_frame_size = sizeof(x300_mtu_t); - size_t max_send_frame_size = std::min(user_frame_size.send_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE) & size_t(~3); + size_t max_send_frame_size = std::min(user_frame_size.send_frame_size, X300_DATA_FRAME_MAX_SIZE) & size_t(~3); UHD_LOGGER_DEBUG("X300") << "Determining maximum frame size... "; while (min_recv_frame_size < max_recv_frame_size) diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index e67242aa3..dfe038107 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -39,9 +39,6 @@ static const std::string X300_DEFAULT_CLOCK_SOURCE = "internal"; static const double X300_DEFAULT_TICK_RATE = 200e6; //Hz static const double X300_BUS_CLOCK_RATE = 187.5e6; //Hz -static const size_t X300_RX_SW_BUFF_SIZE_ETH = 0x2000000;//32MiB For an ~8k frame size any size >32MiB is just wasted buffer space -static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib - //The FIFO closest to the DMA controller is 1023 elements deep for RX and 1029 elements deep for TX //where an element is 8 bytes. The buffers (number of frames * frame size) must be aligned to the //memory page size. For the control, we are getting lucky because 64 frames * 256 bytes each aligns @@ -50,22 +47,25 @@ static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib static const size_t X300_PCIE_RX_DATA_FRAME_SIZE = 4096; //bytes static const size_t X300_PCIE_RX_DATA_NUM_FRAMES = 4096; static const size_t X300_PCIE_TX_DATA_FRAME_SIZE = 4096; //bytes -static const size_t X300_PCIE_TX_DATA_NUM_FRAMES = 4096; +static const size_t X300_PCIE_TX_DATA_NUM_FRAMES = 4096; static const size_t X300_PCIE_MSG_FRAME_SIZE = 256; //bytes static const size_t X300_PCIE_MSG_NUM_FRAMES = 64; static const size_t X300_PCIE_MAX_CHANNELS = 6; static const size_t X300_PCIE_MAX_MUXED_CTRL_XPORTS = 32; static const size_t X300_PCIE_MAX_MUXED_ASYNC_XPORTS = 4; -//Reduced to 4000 to make sure flow control packets are not blocked for too long at high rates -static const size_t X300_10GE_DATA_FRAME_MAX_SIZE = 4000; // CHDR packet size in bytes -static const size_t X300_1GE_DATA_FRAME_MAX_SIZE = 1472; // CHDR packet size in bytes +static const size_t X300_DATA_FRAME_MAX_SIZE = 8000; // CHDR packet size in bytes + +// Ethernet frame sizes +static const size_t X300_10GE_DATA_FRAME_SEND_SIZE = 4000; // Reduced to make sure flow control packets are not blocked for too long at high rates +static const size_t X300_10GE_DATA_FRAME_RECV_SIZE = 8000; +static const size_t X300_1GE_DATA_FRAME_SEND_SIZE = 1472; +static const size_t X300_1GE_DATA_FRAME_RECV_SIZE = 1472; static const size_t X300_ETH_MSG_FRAME_SIZE = uhd::transport::udp_simple::mtu; //bytes +static const size_t X300_ETH_MSG_NUM_FRAMES = 64; -static const double X300_THREAD_BUFFER_TIMEOUT = 0.1; // Time in seconds +static const double X300_RECV_OFFLOAD_BUFFER_TIMEOUT = 0.1; //seconds -static const size_t X300_ETH_MSG_NUM_FRAMES = 64; -static const size_t X300_ETH_DATA_NUM_FRAMES = 32; static const double X300_DEFAULT_SYSREF_RATE = 10e6; // Limit the number of initialization threads @@ -74,12 +74,12 @@ static const size_t X300_MAX_INIT_THREADS = 10; static const size_t X300_MAX_RATE_PCIE = 800000000; // bytes/s static const size_t X300_MAX_RATE_10GIGE = (size_t)( // bytes/s 10e9 / 8 * // wire speed multiplied by percentage of packets that is sample data - ( float(X300_10GE_DATA_FRAME_MAX_SIZE - uhd::usrp::DEVICE3_TX_MAX_HDR_LEN) / - float(X300_10GE_DATA_FRAME_MAX_SIZE + 8 /* UDP header */ + 20 /* Ethernet header length */ ))); + ( float(X300_DATA_FRAME_MAX_SIZE - uhd::usrp::DEVICE3_TX_MAX_HDR_LEN) / + float(X300_DATA_FRAME_MAX_SIZE + 8 /* UDP header */ + 20 /* Ethernet header length */ ))); static const size_t X300_MAX_RATE_1GIGE = (size_t)( // bytes/s - 10e9 / 8 * // wire speed multiplied by percentage of packets that is sample data - ( float(X300_1GE_DATA_FRAME_MAX_SIZE - uhd::usrp::DEVICE3_TX_MAX_HDR_LEN) / - float(X300_1GE_DATA_FRAME_MAX_SIZE + 8 /* UDP header */ + 20 /* Ethernet header length */ ))); + 1e9 / 8 * // wire speed multiplied by percentage of packets that is sample data + ( float(X300_DATA_FRAME_MAX_SIZE - uhd::usrp::DEVICE3_TX_MAX_HDR_LEN) / + float(X300_DATA_FRAME_MAX_SIZE + 8 /* UDP header */ + 20 /* Ethernet header length */ ))); #define X300_RADIO_DEST_PREFIX_TX 0 @@ -106,6 +106,7 @@ struct x300_eth_conn_t { std::string addr; x300_eth_iface_t type; + size_t link_rate; }; diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index af5aa7c9e..d833b3715 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -17,22 +17,6 @@ using namespace uhd::usrp; device_addr_t x300_impl::get_rx_hints(size_t mb_index) { device_addr_t rx_hints = _mb[mb_index].recv_args; - // (default to a large recv buff) - if (not rx_hints.has_key("recv_buff_size")) - { - if (_mb[mb_index].xport_path != "nirio") { - //For the ethernet transport, the buffer has to be set before creating - //the transport because it is independent of the frame size and # frames - //For nirio, the buffer size is not configurable by the user - #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) - //limit buffer resize on macos or it will error - rx_hints["recv_buff_size"] = std::to_string(X300_RX_SW_BUFF_SIZE_ETH_MACOS); - #elif defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32) - //set to half-a-second of buffering at max rate - rx_hints["recv_buff_size"] = std::to_string(X300_RX_SW_BUFF_SIZE_ETH); - #endif - } - } return rx_hints; } |