diff options
-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; } |