aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/defaults.hpp3
-rw-r--r--host/include/uhd/rfnoc/noc_block_base.hpp49
-rw-r--r--host/include/uhd/rfnoc/replay_block_control.hpp3
-rw-r--r--host/lib/include/uhdlib/rfnoc/chdr_rx_data_xport.hpp41
-rw-r--r--host/lib/include/uhdlib/rfnoc/chdr_tx_data_xport.hpp37
-rw-r--r--host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp9
-rw-r--r--host/lib/include/uhdlib/transport/rx_streamer_impl.hpp19
-rw-r--r--host/lib/include/uhdlib/transport/tx_streamer_impl.hpp20
-rw-r--r--host/lib/rfnoc/chdr_rx_data_xport.cpp9
-rw-r--r--host/lib/rfnoc/chdr_tx_data_xport.cpp9
-rw-r--r--host/lib/rfnoc/noc_block_base.cpp15
-rw-r--r--host/lib/rfnoc/radio_control_impl.cpp34
-rw-r--r--host/lib/rfnoc/replay_block_control.cpp37
-rw-r--r--host/lib/rfnoc/rfnoc_rx_streamer.cpp10
-rw-r--r--host/lib/rfnoc/rfnoc_tx_streamer.cpp10
-rw-r--r--host/lib/rfnoc/siggen_block_control.cpp30
-rw-r--r--host/tests/rfnoc_block_tests/replay_block_test.cpp18
-rw-r--r--host/tests/rfnoc_block_tests/siggen_block_test.cpp14
-rw-r--r--host/tests/rx_streamer_test.cpp12
-rw-r--r--host/tests/streamer_benchmark.cpp25
-rw-r--r--host/tests/tx_streamer_test.cpp13
21 files changed, 321 insertions, 96 deletions
diff --git a/host/include/uhd/rfnoc/defaults.hpp b/host/include/uhd/rfnoc/defaults.hpp
index d0f6c2311..afc018810 100644
--- a/host/include/uhd/rfnoc/defaults.hpp
+++ b/host/include/uhd/rfnoc/defaults.hpp
@@ -44,9 +44,6 @@ static const std::string DEFAULT_BLOCK_NAME = "Block";
//! This NOC-ID is used to look up the default block
static const uint32_t DEFAULT_NOC_ID = 0xFFFFFFFF;
static const double DEFAULT_TICK_RATE = 1.0;
-// Whenever we need a default spp value use this, unless there are some
-// block/device-specific constraints. It will keep the frame size below 1500.
-static const int DEFAULT_SPP = 1996;
/*! The NoC ID is the unique identifier of the block type. All blocks of the
* same type have the same NoC ID.
diff --git a/host/include/uhd/rfnoc/noc_block_base.hpp b/host/include/uhd/rfnoc/noc_block_base.hpp
index ab002841c..6b1ac5bcd 100644
--- a/host/include/uhd/rfnoc/noc_block_base.hpp
+++ b/host/include/uhd/rfnoc/noc_block_base.hpp
@@ -115,6 +115,10 @@ public:
/*! Return the current MTU on a given edge
*
+ * Note: The MTU is the maximum size of a CHDR packet, including header. In
+ * order to find out the maximum payload size, calling get_max_payload_size()
+ * is the recommended alternative.
+ *
* The MTU is determined by the block itself (i.e., how big of a packet can
* this block handle on this edge), but also the neighboring block, and
* possibly the transport medium between the blocks. This value can thus be
@@ -127,6 +131,51 @@ public:
*/
size_t get_mtu(const res_source_info& edge);
+ /*! Return the size of a CHDR packet header, in bytes.
+ *
+ * This helper function factors in the CHDR width for this block.
+ *
+ * \param account_for_ts If true (default), the assumption is that we reserve
+ * space for a timestamp. It is possible to increase
+ * the payload if no timestamp is used (only for 64
+ * bit CHDR widths!), however, this is advanced usage
+ * and should only be used in special circumstances,
+ * as downstream blocks might not be able to handle
+ * such packets.
+ * \returns the length of a CHDR header in bytes
+ */
+ size_t get_chdr_hdr_len(const bool account_for_ts = true) const;
+
+ /*! Return the maximum usable payload size on a given edge, in bytes.
+ *
+ * This is very similar to get_mtu(), except it also accounts for the
+ * header.
+ *
+ * Example: Say the MTU on a given edge is 8192 bytes. The CHDR width is
+ * 64 bits. If we wanted to add a timestamp, we would thus require 16 bytes
+ * for the total header, leaving only 8192-16=8176 bytes for a payload,
+ * which is what this function would return.
+ * The same MTU, with a CHDR width of 512 bits however, would require leaving
+ * 64 bytes for the header (regardless of whether or not a timestamp is
+ * included). In that case, this function would return 8192-64=8128 bytes
+ * max payload size.
+ *
+ * \param edge The edge on which the max payload size is queried. edge.type
+ * must be INPUT_EDGE or OUTPUT_EDGE! See also get_mtu().
+ * \param account_for_ts If true (default), the assumption is that we reserve
+ * space for a timestamp. It is possible to increase
+ * the payload if no timestamp is used (only for 64
+ * bit CHDR widths!), however, this is advanced usage
+ * and should only be used in special circumstances,
+ * as downstream blocks might not be able to handle
+ * such packets.
+ * \returns the max payload size as determined by the overall graph on this
+ * edge, as well as the CHDR width.
+ * \throws uhd::value_error if edge is not referring to a valid edge
+ */
+ size_t get_max_payload_size(
+ const res_source_info& edge, const bool account_for_ts = true);
+
/*! Return the arguments that were passed into this block from the framework
*/
uhd::device_addr_t get_block_args() const
diff --git a/host/include/uhd/rfnoc/replay_block_control.hpp b/host/include/uhd/rfnoc/replay_block_control.hpp
index dc56d59e0..c7624d044 100644
--- a/host/include/uhd/rfnoc/replay_block_control.hpp
+++ b/host/include/uhd/rfnoc/replay_block_control.hpp
@@ -297,7 +297,8 @@ public:
/*! Set the maximum size of a packet
*
- * Sets the maximum packet size, inclusive of headers and payload.
+ * Sets the maximum packet size, inclusive of headers and payload. Cannot
+ * exceed the MTU for this block.
*
* \param size The size of the packet
* \param port Which output port of the replay block to use
diff --git a/host/lib/include/uhdlib/rfnoc/chdr_rx_data_xport.hpp b/host/lib/include/uhdlib/rfnoc/chdr_rx_data_xport.hpp
index cb0987446..08930f9f3 100644
--- a/host/lib/include/uhdlib/rfnoc/chdr_rx_data_xport.hpp
+++ b/host/lib/include/uhdlib/rfnoc/chdr_rx_data_xport.hpp
@@ -177,13 +177,41 @@ public:
*/
~chdr_rx_data_xport();
- /*! Returns maximum number payload bytes
+ /*! Returns MTU for this transport in bytes
*
- * \return maximum payload bytes per packet
+ * MTU is the max size for CHDR packets, including headers. For most
+ * applications, get_max_payload_size() is probably the more useful method.
+ * Compare also noc_block_base::get_mtu().
+ *
+ * \return MTU in bytes
+ */
+ size_t get_mtu() const
+ {
+ return _mtu;
+ }
+
+ /*! Return the size of a CHDR packet header, in bytes.
+ *
+ * This helper function factors in the CHDR width for this transport.
+ * Compare also noc_block_base::get_chdr_hdr_len().
+ *
+ * \returns the length of a CHDR header in bytes
+ */
+ size_t get_chdr_hdr_len() const
+ {
+ return _hdr_len;
+ }
+
+ /*! Returns maximum number of payload bytes
+ *
+ * This is smaller than the MTU. Compare also
+ * noc_block_base::get_max_payload_size().
+ *
+ * \return maximum number of payload bytes
*/
size_t get_max_payload_size() const
{
- return _max_payload_size;
+ return _mtu - _hdr_len;
}
/*!
@@ -389,8 +417,11 @@ private:
// Flow control state
rx_flow_ctrl_state _fc_state;
- // Maximum data payload in bytes
- size_t _max_payload_size = 0;
+ // MTU in bytes
+ size_t _mtu = 0;
+
+ // Size of CHDR headers
+ size_t _hdr_len = 0;
// Sequence number for data packets
uint16_t _data_seq_num = 0;
diff --git a/host/lib/include/uhdlib/rfnoc/chdr_tx_data_xport.hpp b/host/lib/include/uhdlib/rfnoc/chdr_tx_data_xport.hpp
index 4e8ebe24d..e0887db6c 100644
--- a/host/lib/include/uhdlib/rfnoc/chdr_tx_data_xport.hpp
+++ b/host/lib/include/uhdlib/rfnoc/chdr_tx_data_xport.hpp
@@ -175,13 +175,41 @@ public:
*/
~chdr_tx_data_xport();
+ /*! Returns MTU for this transport in bytes
+ *
+ * MTU is the max size for CHDR packets, including headers. For most
+ * applications, get_max_payload_size() is probably the more useful method.
+ * Compare also noc_block_base::get_mtu().
+ *
+ * \return MTU in bytes
+ */
+ size_t get_mtu() const
+ {
+ return _mtu;
+ }
+
+ /*! Return the size of a CHDR packet header, in bytes.
+ *
+ * This helper function factors in the CHDR width for this transport.
+ * Compare also noc_block_base::get_chdr_hdr_len().
+ *
+ * \returns the length of a CHDR header in bytes
+ */
+ size_t get_chdr_hdr_len() const
+ {
+ return _hdr_len;
+ }
+
/*! Returns maximum number of payload bytes
*
+ * This is smaller than the MTU. Compare also
+ * noc_block_base::get_max_payload_size().
+ *
* \return maximum number of payload bytes
*/
size_t get_max_payload_size() const
{
- return _max_payload_size;
+ return _mtu - _hdr_len;
}
/*!
@@ -373,8 +401,11 @@ private:
// Flow control state
tx_flow_ctrl_state _fc_state;
- // Maximum data payload in bytes
- size_t _max_payload_size = 0;
+ // MTU in bytes
+ size_t _mtu = 0;
+
+ // Size of CHDR headers
+ size_t _hdr_len = 0;
// Sequence number for data packets
uint16_t _data_seq_num = 0;
diff --git a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
index b60b0f2a2..e268dbc07 100644
--- a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
+++ b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
@@ -356,6 +356,15 @@ private:
const std::vector<uint32_t>& data,
boost::optional<uint64_t> timestamp);
+ //! Return the maximum samples per packet of size \p bytes
+ //
+ // Given a packet of size \p bytes, how many samples can we fit in there?
+ // This gives the answer, factoring in item size and samples per clock.
+ //
+ // \param bytes Number of bytes we can fill with samples (excluding bytes
+ // required for CHDR headers!)
+ int get_max_spp(const size_t bytes);
+
//! FPGA compat number
const uint32_t _fpga_compat;
diff --git a/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp b/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp
index 79c196f3f..f776d9373 100644
--- a/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp
+++ b/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp
@@ -88,7 +88,6 @@ public:
if (stream_args.args.has_key("spp")) {
_spp = stream_args.args.cast<size_t>("spp", _spp);
- _mtu = _spp * _convert_info.bytes_per_otw_item;
}
}
@@ -97,7 +96,8 @@ public:
// them
virtual void connect_channel(const size_t channel, typename transport_t::uptr xport)
{
- const size_t mtu = xport->get_max_payload_size();
+ const size_t mtu = xport->get_mtu();
+ _hdr_len = std::max(_hdr_len, xport->get_chdr_hdr_len());
_zero_copy_streamer.connect_channel(channel, std::move(xport));
if (mtu < _mtu) {
@@ -201,11 +201,15 @@ protected:
return _mtu;
}
- //! Sets the MTU and calculates spp
+ //! Sets the MTU and checks spp. If spp would exceed the new MTU, it is
+ // reduced accordingly.
void set_mtu(const size_t mtu)
{
_mtu = mtu;
- _spp = _mtu / _convert_info.bytes_per_otw_item;
+ const size_t spp_from_mtu = (_mtu - _hdr_len) / _convert_info.bytes_per_otw_item;
+ if (spp_from_mtu < _spp) {
+ _spp = spp_from_mtu;
+ }
}
//! Configures sample rate for conversion of timestamp
@@ -401,7 +405,12 @@ private:
// MTU, determined when xport is connected and modifiable by subclass
size_t _mtu = std::numeric_limits<std::size_t>::max();
- // Maximum number of samples per packet
+ // Size of CHDR header in bytes
+ size_t _hdr_len = 0;
+
+ // Maximum number of samples per packet. Note that this is not necessarily
+ // related to the MTU, it is a user-chosen value. However, it is always
+ // bounded by the MTU.
size_t _spp = std::numeric_limits<std::size_t>::max();
// Num samps remaining in buffer currently held by zero copy streamer
diff --git a/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp b/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp
index f814c8192..9dc3b0c35 100644
--- a/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp
+++ b/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp
@@ -11,6 +11,7 @@
#include <uhd/stream.hpp>
#include <uhd/types/metadata.hpp>
#include <uhd/utils/tasks.hpp>
+#include <uhd/utils/log.hpp>
#include <uhdlib/transport/tx_streamer_zero_copy.hpp>
#include <limits>
#include <vector>
@@ -111,13 +112,13 @@ public:
if (stream_args.args.has_key("spp")) {
_spp = stream_args.args.cast<size_t>("spp", _spp);
- _mtu = _spp * _convert_info.bytes_per_otw_item;
}
}
virtual void connect_channel(const size_t channel, typename transport_t::uptr xport)
{
- const size_t mtu = xport->get_max_payload_size();
+ const size_t mtu = xport->get_mtu();
+ _hdr_len = std::max(_hdr_len, xport->get_chdr_hdr_len());
_zero_copy_streamer.connect_channel(channel, std::move(xport));
if (mtu < _mtu) {
@@ -323,11 +324,15 @@ protected:
return _mtu;
}
- //! Sets the MTU and calculates spp
+ //! Sets the MTU and checks spp. If spp would exceed the new MTU, it is
+ // reduced accordingly.
void set_mtu(const size_t mtu)
{
_mtu = mtu;
- _spp = _mtu / _convert_info.bytes_per_otw_item;
+ const size_t spp_from_mtu = (_mtu - _hdr_len) / _convert_info.bytes_per_otw_item;
+ if (spp_from_mtu < _spp) {
+ _spp = spp_from_mtu;
+ }
}
//! Configures scaling factor for conversion
@@ -444,7 +449,12 @@ private:
// MTU, determined when xport is connected and modifiable by subclass
size_t _mtu = std::numeric_limits<std::size_t>::max();
- // Maximum number of samples per packet
+ // Size of CHDR header in bytes
+ size_t _hdr_len = 0;
+
+ // Maximum number of samples per packet. Note that this is not necessarily
+ // related to the MTU, it is a user-chosen value. However, it is always
+ // bounded by the MTU.
size_t _spp = std::numeric_limits<std::size_t>::max();
// Metadata cache for send calls with no data
diff --git a/host/lib/rfnoc/chdr_rx_data_xport.cpp b/host/lib/rfnoc/chdr_rx_data_xport.cpp
index 7089c9071..37b3ffb89 100644
--- a/host/lib/rfnoc/chdr_rx_data_xport.cpp
+++ b/host/lib/rfnoc/chdr_rx_data_xport.cpp
@@ -5,6 +5,7 @@
//
#include <uhd/rfnoc/chdr_types.hpp>
+#include <uhd/utils/log.hpp>
#include <uhdlib/rfnoc/chdr_rx_data_xport.hpp>
#include <uhdlib/rfnoc/mgmt_portal.hpp>
#include <uhdlib/rfnoc/rfnoc_common.hpp>
@@ -39,6 +40,7 @@ chdr_rx_data_xport::chdr_rx_data_xport(uhd::transport::io_service::sptr io_srv,
const fc_params_t& fc_params,
disconnect_callback_t disconnect)
: _fc_state(epids, fc_params.freq)
+ , _mtu(recv_link->get_recv_frame_size())
, _fc_sender(pkt_factory, epids)
, _epid(epids.second)
, _chdr_w_bytes(chdr_w_to_bits(pkt_factory.get_chdr_w()) / 8)
@@ -52,10 +54,9 @@ chdr_rx_data_xport::chdr_rx_data_xport(uhd::transport::io_service::sptr io_srv,
_recv_packet_cb = pkt_factory.make_generic();
_fc_sender.set_capacity(fc_params.buff_capacity);
- // Calculate max payload size
- const size_t pyld_offset =
- _recv_packet->calculate_payload_offset(chdr::PKT_TYPE_DATA_WITH_TS);
- _max_payload_size = recv_link->get_recv_frame_size() - pyld_offset;
+ // Calculate header size
+ _hdr_len = _recv_packet->calculate_payload_offset(chdr::PKT_TYPE_DATA_WITH_TS);
+ UHD_ASSERT_THROW(_hdr_len);
// Make data transport
auto recv_cb =
diff --git a/host/lib/rfnoc/chdr_tx_data_xport.cpp b/host/lib/rfnoc/chdr_tx_data_xport.cpp
index 7e926a163..618fffe5a 100644
--- a/host/lib/rfnoc/chdr_tx_data_xport.cpp
+++ b/host/lib/rfnoc/chdr_tx_data_xport.cpp
@@ -5,6 +5,7 @@
//
#include <uhd/rfnoc/chdr_types.hpp>
+#include <uhd/utils/log.hpp>
#include <uhdlib/rfnoc/chdr_tx_data_xport.hpp>
#include <uhdlib/rfnoc/mgmt_portal.hpp>
#include <uhdlib/rfnoc/rfnoc_common.hpp>
@@ -34,6 +35,7 @@ chdr_tx_data_xport::chdr_tx_data_xport(uhd::transport::io_service::sptr io_srv,
const fc_params_t fc_params,
disconnect_callback_t disconnect)
: _fc_state(fc_params.buff_capacity)
+ , _mtu(send_link->get_send_frame_size())
, _fc_sender(pkt_factory, epids)
, _epid(epids.first)
, _chdr_w_bytes(chdr_w_to_bits(pkt_factory.get_chdr_w()) / 8)
@@ -48,10 +50,9 @@ chdr_tx_data_xport::chdr_tx_data_xport(uhd::transport::io_service::sptr io_srv,
_send_packet = pkt_factory.make_generic();
_recv_packet = pkt_factory.make_generic();
- // Calculate max payload size
- const size_t pyld_offset =
- _send_packet->calculate_payload_offset(chdr::PKT_TYPE_DATA_WITH_TS);
- _max_payload_size = send_link->get_send_frame_size() - pyld_offset;
+ // Calculate header length
+ _hdr_len = _send_packet->calculate_payload_offset(chdr::PKT_TYPE_DATA_WITH_TS);
+ UHD_ASSERT_THROW(_hdr_len);
// Now create the send I/O we will use for data
auto send_cb = [this](buff_t::uptr buff, transport::send_link_if* send_link) {
diff --git a/host/lib/rfnoc/noc_block_base.cpp b/host/lib/rfnoc/noc_block_base.cpp
index c2db597cb..9719e739b 100644
--- a/host/lib/rfnoc/noc_block_base.cpp
+++ b/host/lib/rfnoc/noc_block_base.cpp
@@ -316,6 +316,21 @@ size_t noc_block_base::get_mtu(const res_source_info& edge)
return _mtu.at(edge);
}
+size_t noc_block_base::get_chdr_hdr_len(const bool account_for_ts) const
+{
+ const size_t header_len_bytes = chdr_w_to_bits(_chdr_w) / 8;
+ // 64-bit CHDR requires two lines for the header if we use a timestamp,
+ // everything else requires one line
+ const size_t num_hdr_lines = (account_for_ts && _chdr_w == CHDR_W_64) ? 2 : 1;
+ return header_len_bytes * num_hdr_lines;
+}
+
+size_t noc_block_base::get_max_payload_size(
+ const res_source_info& edge, const bool account_for_ts)
+{
+ return get_mtu(edge) - get_chdr_hdr_len(account_for_ts);
+}
+
property_base_t* noc_block_base::get_mtu_prop_ref(const res_source_info& edge)
{
for (size_t mtu_prop_idx = 0; mtu_prop_idx < _mtu_props.size(); mtu_prop_idx++) {
diff --git a/host/lib/rfnoc/radio_control_impl.cpp b/host/lib/rfnoc/radio_control_impl.cpp
index 3c4c28d11..697bb2549 100644
--- a/host/lib/rfnoc/radio_control_impl.cpp
+++ b/host/lib/rfnoc/radio_control_impl.cpp
@@ -139,8 +139,11 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
_type_in.reserve(get_num_input_ports());
_type_out.reserve(get_num_output_ports());
for (size_t chan = 0; chan < get_num_output_ports(); ++chan) {
+ // Default SPP is the maximum value we can fit through the edge, given our MTU
+ const int default_spp =
+ get_max_spp(get_max_payload_size({res_source_info::OUTPUT_EDGE, chan}));
_spp_prop.push_back(
- property_t<int>(PROP_KEY_SPP, DEFAULT_SPP, {res_source_info::USER, chan}));
+ property_t<int>(PROP_KEY_SPP, default_spp, {res_source_info::USER, chan}));
_samp_rate_in.push_back(property_t<double>(
PROP_KEY_SAMP_RATE, get_tick_rate(), {res_source_info::INPUT_EDGE, chan}));
_samp_rate_out.push_back(property_t<double>(
@@ -166,17 +169,15 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
{&_spp_prop.back()},
[this, chan, &spp = _spp_prop.back()]() {
RFNOC_LOG_TRACE("Calling resolver for spp@" << chan);
- // MTU is max payload size, header with timestamp is already
- // accounted for
- const int mtu =
- static_cast<int>(get_mtu({res_source_info::OUTPUT_EDGE, chan}));
- const int mtu_samps = mtu / (_samp_width / 8);
- const int max_spp_per_mtu = mtu_samps - (mtu_samps % _spc);
- if (spp.get() > max_spp_per_mtu) {
- RFNOC_LOG_DEBUG("spp value " << spp.get() << " exceeds MTU of "
- << mtu << "! Coercing to "
- << max_spp_per_mtu);
- spp = max_spp_per_mtu;
+ const size_t max_pyld =
+ get_max_payload_size({res_source_info::OUTPUT_EDGE, chan});
+ const int max_spp = get_max_spp(max_pyld);
+ if (spp.get() > max_spp) {
+ RFNOC_LOG_DEBUG("spp value "
+ << spp.get() << " exceeds MTU of "
+ << get_mtu({res_source_info::OUTPUT_EDGE, chan})
+ << "! Coercing to " << max_spp);
+ spp = max_spp;
}
if (spp.get() % _spc) {
spp = spp.get() - (spp.get() % _spc);
@@ -185,7 +186,7 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
<< spp.get());
}
if (spp.get() <= 0) {
- spp = DEFAULT_SPP;
+ spp = max_spp;
RFNOC_LOG_WARNING(
"spp must be greater than zero! Coercing to " << spp.get());
}
@@ -198,7 +199,6 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
chan,
&samp_rate_in = _samp_rate_in.at(chan),
&samp_rate_out = _samp_rate_out.at(chan)]() {
- const auto UHD_UNUSED(log_chan) = chan;
RFNOC_LOG_TRACE("Calling resolver for samp_rate@" << chan);
samp_rate_in = coerce_rate(samp_rate_in.get());
samp_rate_out = samp_rate_in.get();
@@ -1109,3 +1109,9 @@ void radio_control_impl::async_message_handler(
boost::format("Received async message to invalid addr 0x%08X!") % addr));
}
}
+
+int radio_control_impl::get_max_spp(const size_t bytes)
+{
+ const int packet_samps = bytes / (_samp_width / 8);
+ return packet_samps - (packet_samps % _spc);
+}
diff --git a/host/lib/rfnoc/replay_block_control.cpp b/host/lib/rfnoc/replay_block_control.cpp
index e2d2523da..79e7446e4 100644
--- a/host/lib/rfnoc/replay_block_control.cpp
+++ b/host/lib/rfnoc/replay_block_control.cpp
@@ -124,7 +124,7 @@ public:
_replay_reg_iface.poke64(
REG_PLAY_BUFFER_SIZE_LO_ADDR, _play_size.at(port).get(), port);
_replay_reg_iface.poke32(REG_PLAY_WORDS_PER_PKT_ADDR,
- (_packet_size.at(port).get() - CHDR_MAX_LEN_HDR) / _word_size,
+ (_packet_size.at(port).get() - get_chdr_hdr_len()) / _word_size,
port);
}
}
@@ -226,7 +226,7 @@ public:
uint32_t get_max_items_per_packet(const size_t port) const override
{
- return (_packet_size.at(port).get() - CHDR_MAX_LEN_HDR)
+ return (_packet_size.at(port).get() - get_chdr_hdr_len())
/ get_play_item_size(port);
}
@@ -274,7 +274,7 @@ public:
void set_max_items_per_packet(const uint32_t ipp, const size_t port) override
{
- set_max_packet_size(CHDR_MAX_LEN_HDR + ipp * get_play_item_size(port), port);
+ set_max_packet_size(get_chdr_hdr_len() + ipp * get_play_item_size(port), port);
}
void set_max_packet_size(const uint32_t size, const size_t port) override
@@ -460,17 +460,26 @@ private:
void _set_packet_size(const uint32_t packet_size, const size_t port)
{
- // MTU is max payload size, header with timestamp is already accounted for
const size_t mtu = get_mtu({res_source_info::OUTPUT_EDGE, port});
- const uint32_t item_size = get_play_item_size(port);
- const uint32_t mtu_payload = mtu - CHDR_MAX_LEN_HDR;
- const uint32_t mtu_items = mtu_payload / item_size;
- const uint32_t ipc = _word_size / item_size; // items per cycle
- const uint32_t max_ipp_per_mtu = mtu_items - (mtu_items % ipc);
- const uint32_t payload_size = packet_size - CHDR_MAX_LEN_HDR;
- uint32_t ipp = payload_size / item_size;
- if (ipp > max_ipp_per_mtu) {
- ipp = max_ipp_per_mtu;
+ uint32_t requested_packet_size = packet_size;
+ if (requested_packet_size > mtu) {
+ requested_packet_size = mtu;
+ RFNOC_LOG_WARNING("Requested packet size exceeds MTU! Coercing to "
+ << requested_packet_size);
+ }
+ const size_t max_payload_bytes =
+ get_max_payload_size({res_source_info::OUTPUT_EDGE, port});
+ const uint32_t item_size = get_play_item_size(port);
+ const uint32_t ipc = _word_size / item_size; // items per cycle
+ const uint32_t max_items = max_payload_bytes / item_size;
+ const uint32_t max_ipp = max_items - (max_items % ipc);
+ const uint32_t requested_payload_size =
+ requested_packet_size - (mtu - max_payload_bytes);
+ uint32_t ipp = requested_payload_size / item_size;
+ if (ipp > max_ipp) {
+ RFNOC_LOG_DEBUG("ipp value " << ipp << " exceeds MTU of " << mtu
+ << "! Coercing to " << max_ipp);
+ ipp = max_ipp;
}
if ((ipp % ipc) != 0) {
ipp = ipp - (ipp % ipc);
@@ -478,7 +487,7 @@ private:
"ipp must be a multiple of the block bus width! Coercing to " << ipp);
}
if (ipp <= 0) {
- ipp = DEFAULT_SPP;
+ ipp = max_ipp;
RFNOC_LOG_WARNING("ipp must be greater than zero! Coercing to " << ipp);
}
// Packet size must be a multiple of word size
diff --git a/host/lib/rfnoc/rfnoc_rx_streamer.cpp b/host/lib/rfnoc/rfnoc_rx_streamer.cpp
index 7acdf357d..d57b8aab2 100644
--- a/host/lib/rfnoc/rfnoc_rx_streamer.cpp
+++ b/host/lib/rfnoc/rfnoc_rx_streamer.cpp
@@ -164,11 +164,15 @@ void rfnoc_rx_streamer::connect_channel(
{
UHD_ASSERT_THROW(channel < _mtu_in.size());
- // Update MTU property based on xport limits
- const size_t mtu = xport->get_max_payload_size();
- set_property<size_t>(PROP_KEY_MTU, mtu, {res_source_info::INPUT_EDGE, channel});
+ // Stash away the MTU before we lose access to xports
+ const size_t mtu = xport->get_mtu();
rx_streamer_impl<chdr_rx_data_xport>::connect_channel(channel, std::move(xport));
+
+ // Update MTU property based on xport limits. We need to do this after
+ // connect_channel(), because that's where the chdr_rx_data_xport object
+ // learns its header size.
+ set_property<size_t>(PROP_KEY_MTU, mtu, {res_source_info::INPUT_EDGE, channel});
}
void rfnoc_rx_streamer::_register_props(const size_t chan, const std::string& otw_format)
diff --git a/host/lib/rfnoc/rfnoc_tx_streamer.cpp b/host/lib/rfnoc/rfnoc_tx_streamer.cpp
index b4aea202d..969c41ae6 100644
--- a/host/lib/rfnoc/rfnoc_tx_streamer.cpp
+++ b/host/lib/rfnoc/rfnoc_tx_streamer.cpp
@@ -125,9 +125,8 @@ void rfnoc_tx_streamer::connect_channel(
{
UHD_ASSERT_THROW(channel < _mtu_out.size());
- // Update MTU property based on xport limits
- const size_t mtu = xport->get_max_payload_size();
- set_property<size_t>(PROP_KEY_MTU, mtu, {res_source_info::OUTPUT_EDGE, channel});
+ // Stash away the MTU before we lose access to xports
+ const size_t mtu = xport->get_mtu();
xport->set_enqueue_async_msg_fn(
[this, channel](
@@ -145,6 +144,11 @@ void rfnoc_tx_streamer::connect_channel(
});
tx_streamer_impl<chdr_tx_data_xport>::connect_channel(channel, std::move(xport));
+
+ // Update MTU property based on xport limits. We need to do this after
+ // connect_channel(), because that's where the chdr_tx_data_xport object
+ // learns its header size.
+ set_property<size_t>(PROP_KEY_MTU, mtu, {res_source_info::OUTPUT_EDGE, channel});
}
bool rfnoc_tx_streamer::recv_async_msg(
diff --git a/host/lib/rfnoc/siggen_block_control.cpp b/host/lib/rfnoc/siggen_block_control.cpp
index 2628d66ab..8dcc68319 100644
--- a/host/lib/rfnoc/siggen_block_control.cpp
+++ b/host/lib/rfnoc/siggen_block_control.cpp
@@ -154,9 +154,12 @@ private:
PROP_KEY_CONSTANT_Q, 1.0, {res_source_info::USER, port}});
_prop_phase_inc.emplace_back(property_t<double>{
PROP_KEY_SINE_PHASE_INC, 1.0, {res_source_info::USER, port}});
+ const int default_spp =
+ static_cast<int>(
+ get_max_payload_size({res_source_info::OUTPUT_EDGE, port}))
+ / uhd::convert::get_bytes_per_item(_prop_type_out.at(port).get());
_prop_spp.emplace_back(property_t<int>{
- PROP_KEY_SPP, DEFAULT_SPP, {res_source_info::USER, port}});
-
+ PROP_KEY_SPP, default_spp, {res_source_info::USER, port}});
register_property(&_prop_enable.back(), [this, port]() {
_siggen_reg_iface.poke32(REG_ENABLE_OFFSET,
uint32_t(_prop_enable.at(port).get() ? 1 : 0),
@@ -256,21 +259,20 @@ private:
get_mtu_prop_ref({res_source_info::OUTPUT_EDGE, port})},
{&_prop_spp.back()},
[this, port]() {
- // MTU is max payload size, header with timestamp is already
- // accounted for
- int spp = _prop_spp.at(port).get();
- const int mtu =
- static_cast<int>(get_mtu({res_source_info::OUTPUT_EDGE, port}));
- const int mtu_samps =
- mtu
+ int spp = _prop_spp.at(port).get();
+ const int max_payload = static_cast<int>(
+ get_max_payload_size({res_source_info::OUTPUT_EDGE, port}));
+ const int max_samps =
+ max_payload
/ uhd::convert::get_bytes_per_item(_prop_type_out.at(port).get());
- if (spp > mtu_samps) {
- RFNOC_LOG_WARNING("spp value " << spp << " exceeds MTU of " << mtu
- << "! Coercing to " << mtu_samps);
- spp = mtu_samps;
+ if (spp > max_samps) {
+ RFNOC_LOG_WARNING("spp value " << spp << " exceeds MTU of "
+ << max_payload << "! Coercing to "
+ << max_samps);
+ spp = max_samps;
}
if (spp <= 0) {
- spp = DEFAULT_SPP;
+ spp = max_samps;
RFNOC_LOG_WARNING(
"spp must be greater than zero! Coercing to " << spp);
}
diff --git a/host/tests/rfnoc_block_tests/replay_block_test.cpp b/host/tests/rfnoc_block_tests/replay_block_test.cpp
index f84b98ac8..db9f8c177 100644
--- a/host/tests/rfnoc_block_tests/replay_block_test.cpp
+++ b/host/tests/rfnoc_block_tests/replay_block_test.cpp
@@ -157,7 +157,7 @@ BOOST_FIXTURE_TEST_CASE(replay_test_construction, replay_block_fixture)
BOOST_CHECK_EQUAL(reg_iface->write_memory[reg_play_base_addr], 0);
BOOST_CHECK_EQUAL(reg_iface->write_memory[reg_play_base_addr + 4], 0);
BOOST_CHECK_EQUAL(reg_iface->write_memory[reg_words_per_pkt],
- (DEFAULT_MTU - CHDR_MAX_LEN_HDR) / word_size);
+ (DEFAULT_MTU - test_replay->get_chdr_hdr_len()) / word_size);
BOOST_CHECK_EQUAL(reg_iface->write_memory[reg_play_item_size], default_item_size);
}
}
@@ -353,18 +353,20 @@ BOOST_FIXTURE_TEST_CASE(replay_test_configure_play, replay_block_fixture)
}
/*
- * This test case ensures that the hardware is programmed correctly throough the playback
+ * This test case ensures that the hardware is programmed correctly through the playback
* packet API calls.
*/
BOOST_FIXTURE_TEST_CASE(replay_test_packet_size, replay_block_fixture)
{
for (size_t port = 0; port < num_output_ports; port++) {
// Test the defaults
- const uint32_t default_ipp = DEFAULT_SPP;
- BOOST_CHECK_EQUAL(test_replay->get_max_items_per_packet(port), default_ipp);
-
- const uint32_t item_size = test_replay->get_play_item_size(port);
- const uint32_t default_packet_size = default_ipp * item_size + CHDR_MAX_LEN_HDR;
+ const uint32_t item_size = test_replay->get_play_item_size(port);
+ const uint32_t expected_ipp =
+ test_replay->get_max_payload_size({res_source_info::OUTPUT_EDGE, port})
+ / item_size;
+ BOOST_CHECK_EQUAL(test_replay->get_max_items_per_packet(port), expected_ipp);
+ const uint32_t default_packet_size =
+ expected_ipp * item_size + test_replay->get_chdr_hdr_len();
BOOST_CHECK_EQUAL(test_replay->get_max_packet_size(port), default_packet_size);
}
@@ -374,7 +376,7 @@ BOOST_FIXTURE_TEST_CASE(replay_test_packet_size, replay_block_fixture)
BOOST_CHECK_EQUAL(test_replay->get_max_items_per_packet(port), ipp);
const uint32_t item_size = test_replay->get_play_item_size(port);
- const uint32_t packet_size = ipp * item_size + CHDR_MAX_LEN_HDR;
+ const uint32_t packet_size = ipp * item_size + test_replay->get_chdr_hdr_len();
BOOST_CHECK_EQUAL(test_replay->get_max_packet_size(port), packet_size);
const uint32_t wpp = ipp * item_size / word_size;
diff --git a/host/tests/rfnoc_block_tests/siggen_block_test.cpp b/host/tests/rfnoc_block_tests/siggen_block_test.cpp
index ea52530e0..d453e898e 100644
--- a/host/tests/rfnoc_block_tests/siggen_block_test.cpp
+++ b/host/tests/rfnoc_block_tests/siggen_block_test.cpp
@@ -191,7 +191,10 @@ BOOST_FIXTURE_TEST_CASE(siggen_test_construction, siggen_block_fixture)
BOOST_CHECK_EQUAL(reg_iface->phase_increments.at(port), siggen_mock_reg_iface_t::phase_increment_to_register(1.0));
BOOST_CHECK_EQUAL(reg_iface->phasors.at(port),
siggen_mock_reg_iface_t::phasor_to_register({0.0, 0.0}));
- BOOST_CHECK_EQUAL(reg_iface->spps.at(port), DEFAULT_SPP);
+ constexpr int bpi = 4; // sc16 has 4 bytes per item
+ const int expected_spp =
+ test_siggen->get_max_payload_size({res_source_info::OUTPUT_EDGE, port}) / bpi;
+ BOOST_CHECK_EQUAL(reg_iface->spps.at(port), expected_spp);
}
}
@@ -315,10 +318,11 @@ BOOST_FIXTURE_TEST_CASE(siggen_test_ranges, siggen_block_fixture)
*/
BOOST_FIXTURE_TEST_CASE(siggen_test_spp_coercion, siggen_block_fixture)
{
- constexpr size_t mtu_in_samps = DEFAULT_MTU / 4 /* bytes/samp */;
- size_t high_spp = mtu_in_samps + 10;
- test_siggen->set_samples_per_packet(high_spp, 0);
- BOOST_CHECK_EQUAL(test_siggen->get_samples_per_packet(0), mtu_in_samps);
+ const size_t max_samps =
+ (DEFAULT_MTU - test_siggen->get_chdr_hdr_len()) / 4 /* bytes/samp */;
+ const size_t too_high_spp = max_samps + 10;
+ test_siggen->set_samples_per_packet(too_high_spp, 0);
+ BOOST_CHECK_EQUAL(test_siggen->get_samples_per_packet(0), max_samps);
}
/*
diff --git a/host/tests/rx_streamer_test.cpp b/host/tests/rx_streamer_test.cpp
index 03ab3f456..a2969d608 100644
--- a/host/tests/rx_streamer_test.cpp
+++ b/host/tests/rx_streamer_test.cpp
@@ -95,9 +95,19 @@ public:
_recv_link->release_recv_buff(std::move(buff));
}
+ size_t get_mtu() const
+ {
+ return _recv_link->get_recv_frame_size();
+ }
+
+ size_t get_chdr_hdr_len() const
+ {
+ return sizeof(mock_header_t);
+ }
+
size_t get_max_payload_size() const
{
- return _recv_link->get_recv_frame_size() - sizeof(packet_info_t);
+ return get_mtu() - get_chdr_hdr_len();
}
private:
diff --git a/host/tests/streamer_benchmark.cpp b/host/tests/streamer_benchmark.cpp
index a11db3e68..b180e7393 100644
--- a/host/tests/streamer_benchmark.cpp
+++ b/host/tests/streamer_benchmark.cpp
@@ -76,11 +76,21 @@ public:
_buff = std::move(buff);
}
- size_t get_max_payload_size() const
+ size_t get_mtu() const
{
return _buff_size;
}
+ size_t get_chdr_hdr_len() const
+ {
+ return sizeof(packet_info_t);
+ }
+
+ size_t get_max_payload_size() const
+ {
+ return get_mtu() - sizeof(packet_info_t);
+ }
+
private:
size_t _buff_size;
buff_t::uptr _buff;
@@ -137,11 +147,22 @@ public:
_buff = std::move(buff);
}
+ size_t get_mtu() const
+ {
+ return _buff_size;
+ }
+
+ size_t get_chdr_hdr_len() const
+ {
+ return sizeof(packet_info_t);
+ }
+
size_t get_max_payload_size() const
{
- return _buff_size - sizeof(packet_info_t);
+ return get_mtu() - sizeof(packet_info_t);
}
+
private:
size_t _buff_size;
buff_t::uptr _buff;
diff --git a/host/tests/tx_streamer_test.cpp b/host/tests/tx_streamer_test.cpp
index 75511c329..11e33d413 100644
--- a/host/tests/tx_streamer_test.cpp
+++ b/host/tests/tx_streamer_test.cpp
@@ -53,10 +53,19 @@ public:
_send_link->release_send_buff(std::move(buff));
}
+ size_t get_mtu() const
+ {
+ return _send_link->get_send_frame_size();
+ }
+
+ size_t get_chdr_hdr_len() const
+ {
+ return sizeof(packet_info_t);
+ }
+
size_t get_max_payload_size() const
{
- return _send_link->get_send_frame_size() - sizeof(packet_info_t);
- ;
+ return get_mtu() - get_chdr_hdr_len();
}
private: