aboutsummaryrefslogtreecommitdiffstats
path: root/host/tests
diff options
context:
space:
mode:
authorAaron Rossetto <aaron.rossetto@ni.com>2019-09-27 14:56:25 -0500
committerMartin Braun <martin.braun@ettus.com>2019-11-26 12:21:32 -0800
commit2f97f8bd0167d4179427efa8a955046fbf417e91 (patch)
tree255c660b8bdff86047937a75a0f3b3798b1da73b /host/tests
parent41f142050fb39ad533f82256b574b5c08c160bc1 (diff)
downloaduhd-2f97f8bd0167d4179427efa8a955046fbf417e91.tar.gz
uhd-2f97f8bd0167d4179427efa8a955046fbf417e91.tar.bz2
uhd-2f97f8bd0167d4179427efa8a955046fbf417e91.zip
transport: Implement eov indications for Rx and Tx streams
Diffstat (limited to 'host/tests')
-rw-r--r--host/tests/rx_streamer_test.cpp109
-rw-r--r--host/tests/streamer_benchmark.cpp2
-rw-r--r--host/tests/tx_streamer_test.cpp273
3 files changed, 384 insertions, 0 deletions
diff --git a/host/tests/rx_streamer_test.cpp b/host/tests/rx_streamer_test.cpp
index 1b1311908..953b82028 100644
--- a/host/tests/rx_streamer_test.cpp
+++ b/host/tests/rx_streamer_test.cpp
@@ -18,6 +18,7 @@ namespace uhd { namespace transport {
struct mock_header_t
{
bool eob = false;
+ bool eov = false;
bool has_tsf = false;
uint64_t tsf = 0;
size_t payload_bytes = 0;
@@ -39,6 +40,7 @@ public:
struct packet_info_t
{
bool eob = false;
+ bool eov = false;
bool has_tsf = false;
uint64_t tsf = 0;
size_t payload_bytes = 0;
@@ -55,6 +57,7 @@ public:
packet_info_t info;
info.eob = header.eob;
+ info.eov = header.eov;
info.has_tsf = header.has_tsf;
info.tsf = header.tsf;
info.payload_bytes = header.payload_bytes;
@@ -742,3 +745,109 @@ BOOST_AUTO_TEST_CASE(test_recv_alignment_error)
BOOST_CHECK_EQUAL(num_samps_ret, 0);
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_ALIGNMENT);
}
+
+BOOST_AUTO_TEST_CASE(test_recv_one_channel_one_eov)
+{
+ const size_t NUM_PACKETS = 5;
+ const std::string format("fc64");
+
+ auto recv_links = make_links(1);
+ auto streamer = make_rx_streamer(recv_links, format);
+
+ const size_t spp = streamer->get_max_num_samps();
+ const size_t num_samps = spp * NUM_PACKETS;
+ std::vector<std::complex<double>> buff(num_samps);
+
+ for (size_t i = 0; i < NUM_PACKETS; i++) {
+ mock_header_t header;
+ header.eob = false;
+ header.has_tsf = true;
+ header.tsf = i;
+
+ for (size_t j = 0; j < NUM_PACKETS; j++) {
+ header.eov = (i == j);
+ push_back_recv_packet(recv_links[0], header, spp);
+ }
+
+ uhd::rx_metadata_t metadata;
+ // Create a vector with storage for two EOVs even though we expect
+ // only one, since filling the EOV vector results in an early
+ // termination of `recv()` (which we don't want here).
+ std::vector<size_t> eov_positions(2);
+ metadata.eov_positions = eov_positions.data();
+ metadata.eov_positions_size = eov_positions.size();
+
+ std::cout << "receiving packet " << i << std::endl;
+
+ size_t num_samps_ret =
+ streamer->recv(buff.data(), buff.size(), metadata, 1.0, false);
+
+ BOOST_CHECK_EQUAL(num_samps_ret, num_samps);
+ BOOST_CHECK_EQUAL(metadata.eov_positions, eov_positions.data());
+ BOOST_CHECK_EQUAL(metadata.eov_positions_size, eov_positions.size());
+ BOOST_CHECK_EQUAL(metadata.eov_positions_count, 1);
+ BOOST_CHECK_EQUAL(eov_positions[0], (i + 1) * spp);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_recv_two_channel_aggregate_eov)
+{
+ const size_t NUM_PACKETS = 20;
+ const std::string format("fc64");
+
+ // This vector defines which packets in each channel's mock link will
+ // signal EOV in their packet headers.
+ //
+ // For example, for a vector with 3 values, [3, 5, 8]:
+ // Link 0 packets with EOV: 3rd, 6th, 9th, 12th, 15th, ...
+ // Link 1 packets with EOV: 5th, 10th, 15th, 20th, ...
+ // Link 2 packets with EOV: 8th, 16th, 24th, 32nd, ...
+ const std::vector<size_t> eov_every_nth_packet{3, 5};
+
+ const size_t num_chans = eov_every_nth_packet.size();
+ auto recv_links = make_links(num_chans);
+ auto streamer = make_rx_streamer(recv_links, format);
+
+ const size_t spp = streamer->get_max_num_samps();
+ const size_t num_samps = spp * NUM_PACKETS;
+
+ std::vector<std::vector<std::complex<double>>> buffer(num_chans);
+ std::vector<void*> buffers;
+ for (size_t i = 0; i < num_chans; i++) {
+ buffer[i].resize(num_samps);
+ buffers.push_back(&buffer[i].front());
+ }
+
+ mock_header_t header;
+ std::vector<size_t> expected_eov_offsets;
+ for (size_t i = 0; i < NUM_PACKETS; i++) {
+ bool eov = false;
+ for (size_t ch = 0; ch < num_chans; ch++) {
+ header.eob = false;
+ header.has_tsf = false;
+ header.eov = ((i + 1) % eov_every_nth_packet[ch]) == 0;
+
+ push_back_recv_packet(recv_links[ch], header, spp);
+
+ eov |= header.eov;
+ }
+ if(eov) {
+ expected_eov_offsets.push_back(spp * (i + 1));
+ }
+ }
+
+ uhd::rx_metadata_t metadata;
+
+ std::vector<size_t> eov_positions(expected_eov_offsets.size() + 1);
+ metadata.eov_positions = eov_positions.data();
+ metadata.eov_positions_size = eov_positions.size();
+
+ size_t num_samps_ret =
+ streamer->recv(buffers, num_samps, metadata, 1.0, false);
+
+ BOOST_CHECK_EQUAL(num_samps_ret, num_samps);
+ BOOST_CHECK_EQUAL(metadata.eov_positions_count, expected_eov_offsets.size());
+ for(size_t i = 0; i < metadata.eov_positions_count; i++) {
+ BOOST_CHECK_EQUAL(expected_eov_offsets[i], metadata.eov_positions[i]);
+ }
+}
diff --git a/host/tests/streamer_benchmark.cpp b/host/tests/streamer_benchmark.cpp
index 02aa102a0..0c11441ed 100644
--- a/host/tests/streamer_benchmark.cpp
+++ b/host/tests/streamer_benchmark.cpp
@@ -47,6 +47,7 @@ public:
struct packet_info_t
{
bool eob = false;
+ bool eov = false;
bool has_tsf = false;
uint64_t tsf = 0;
size_t payload_bytes = 0;
@@ -108,6 +109,7 @@ public:
struct packet_info_t
{
bool eob = false;
+ bool eov = false;
bool has_tsf = false;
uint64_t tsf = 0;
size_t payload_bytes = 0;
diff --git a/host/tests/tx_streamer_test.cpp b/host/tests/tx_streamer_test.cpp
index 09c8357df..2288bd029 100644
--- a/host/tests/tx_streamer_test.cpp
+++ b/host/tests/tx_streamer_test.cpp
@@ -26,6 +26,7 @@ public:
struct packet_info_t
{
bool eob = false;
+ bool eov = false;
bool has_tsf = false;
uint64_t tsf = 0;
size_t payload_bytes = 0;
@@ -158,6 +159,34 @@ pop_send_packet(mock_send_link::sptr send_link)
return std::make_tuple(info, data, packet_samps, packet.first);
}
+//! Generates a non-biased random number in the range (low, high).
+static size_t generate_rand(size_t low, size_t high)
+{
+ return (std::rand() % (high - low + 1)) + low;
+}
+
+/*!
+ * Generates a vector of legal random EOV positions.
+ * `eovs` is a vector already sized to the desired number of EOV positions.
+ * The range [1, num_samps) will be broken into N=`eov.size()`
+ * non-overlapping adjacent ranges, and a random value within each range will
+ * be generated and stored in the vector.
+ */
+static void generate_random_eov_positions(
+ std::vector<size_t>& eovs, const size_t num_samps)
+{
+ UHD_ASSERT_THROW(!eovs.empty());
+
+ const size_t num_eovs = eovs.size();
+ const size_t range_size = (num_samps - 1) / num_eovs;
+ size_t low = 1;
+ for (size_t i = 0; i < num_eovs; i++) {
+ const size_t high = low + range_size - 1;
+ eovs[i] = generate_rand(low, high);
+ low = high + 1;
+ }
+}
+
/*!
* Tests
*/
@@ -216,6 +245,250 @@ BOOST_AUTO_TEST_CASE(test_send_one_channel_one_packet)
}
}
+BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_lte_spp)
+{
+ const size_t NUM_PKTS_TO_TEST = 30;
+ const std::string format("fc32");
+
+ auto send_links = make_links(1);
+ auto streamer = make_tx_streamer(send_links, format);
+
+ // Allocate metadata
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = uhd::time_spec_t(0.0);
+
+ // Allocate buffer
+ const size_t num_samps = streamer->get_max_num_samps();
+ std::vector<std::complex<float>> buff(num_samps);
+
+ // Send buffer and check resultant packets
+ size_t num_accum_samps = 0;
+
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++) {
+ std::cout << "sending packet " << i << std::endl;
+
+ // Vary number of EOVs for each send
+ const size_t num_eovs = (i % 10) + 1;
+ std::vector<size_t> eovs(num_eovs);
+ generate_random_eov_positions(eovs, num_samps);
+
+ metadata.eov_positions = eovs.data();
+ metadata.eov_positions_size = eovs.size();
+
+ const size_t num_sent = streamer->send(&buff.front(), num_samps, metadata, 1.0);
+ BOOST_CHECK_EQUAL(num_sent, num_samps);
+ metadata.time_spec += uhd::time_spec_t(0, num_sent, SAMP_RATE);
+
+ mock_tx_data_xport::packet_info_t info;
+ std::complex<uint16_t>* data;
+ size_t packet_samps;
+ boost::shared_array<uint8_t> frame_buff;
+
+ // Check number of packets written (should be # of EOVs plus one)
+ size_t num_packets_written = send_links[0]->get_num_packets();
+ BOOST_CHECK_EQUAL(num_packets_written, eovs.size() + 1);
+
+ // Pop each packets and check size of each relative to EOV positions
+ size_t total_samps_popped = 0;
+ size_t eov_index = 0;
+ size_t last_eov_position = 0;
+ while (total_samps_popped < num_samps) {
+ std::tie(info, data, packet_samps, frame_buff) =
+ pop_send_packet(send_links[0]);
+
+ // All but the last packet should have an EOV indication
+ if (eov_index < eovs.size()) {
+ BOOST_CHECK_EQUAL(eovs[eov_index] - last_eov_position, packet_samps);
+ BOOST_CHECK(info.eov);
+ last_eov_position = eovs[eov_index];
+ } else {
+ BOOST_CHECK_EQUAL(num_samps - last_eov_position, packet_samps);
+ BOOST_CHECK(not info.eov);
+ }
+
+ // Verify correctness of TSF data
+ BOOST_CHECK(info.has_tsf);
+ BOOST_CHECK_EQUAL(info.tsf, num_accum_samps * TICK_RATE / SAMP_RATE);
+
+ eov_index++;
+ num_accum_samps += packet_samps;
+ total_samps_popped += packet_samps;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_gt_spp)
+{
+ const size_t NUM_PKTS_TO_TEST = 30;
+ const std::string format("fc32");
+
+ auto send_links = make_links(1);
+ auto streamer = make_tx_streamer(send_links, format);
+
+ // Allocate metadata
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = uhd::time_spec_t(0.0);
+
+ // Allocate buffer
+ const size_t spp = streamer->get_max_num_samps();
+ const size_t num_samps = spp * 50;
+ std::vector<std::complex<float>> buff(num_samps);
+
+ // Send buffer and check resultant packets
+ size_t num_accum_samps = 0;
+
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++) {
+ std::cout << "sending packet " << i << std::endl;
+
+ // Vary number of EOVs for each send
+ const size_t num_eovs = (i % 5) + 1;
+ std::vector<size_t> eovs(num_eovs);
+ generate_random_eov_positions(eovs, num_samps);
+
+ metadata.eov_positions = eovs.data();
+ metadata.eov_positions_size = eovs.size();
+
+ const size_t num_sent = streamer->send(&buff.front(), num_samps, metadata, 1.0);
+ BOOST_CHECK_EQUAL(num_sent, num_samps);
+ metadata.time_spec += uhd::time_spec_t(0, num_sent, SAMP_RATE);
+
+ mock_tx_data_xport::packet_info_t info;
+ std::complex<uint16_t>* data;
+ size_t packet_samps;
+ boost::shared_array<uint8_t> frame_buff;
+
+ size_t total_samps_popped = 0;
+ size_t eov_index = 0;
+ size_t last_eov_position = 0;
+ size_t distance_to_next_eov = eovs[eov_index] - last_eov_position;
+ size_t distance_to_end = num_samps;
+ while (total_samps_popped < num_samps) {
+ std::tie(info, data, packet_samps, frame_buff) =
+ pop_send_packet(send_links[0]);
+
+ if (distance_to_next_eov <= spp) {
+ // Next EOV is within a single SPP: ensure packet is EOV
+ BOOST_CHECK_EQUAL(distance_to_next_eov, packet_samps);
+ BOOST_CHECK(info.eov);
+ last_eov_position = eovs[eov_index];
+ eov_index++;
+ if (eov_index < eovs.size()) {
+ // NOTE: Addition of `packet_samps` is to compensate for
+ // its subtraction below
+ distance_to_next_eov =
+ eovs[eov_index] - last_eov_position + packet_samps;
+ } else {
+ // No more EOVs
+ distance_to_next_eov = std::numeric_limits<size_t>::max();
+ }
+ } else if (distance_to_end <= spp) {
+ // End of data within a single SPP
+ BOOST_CHECK_EQUAL(distance_to_end, packet_samps);
+ BOOST_CHECK(not info.eov);
+ } else {
+ BOOST_CHECK(not info.eov);
+ }
+
+ // Verify correctness of TSF data
+ BOOST_CHECK(info.has_tsf);
+ BOOST_CHECK_EQUAL(info.tsf, num_accum_samps * TICK_RATE / SAMP_RATE);
+
+ distance_to_end -= packet_samps;
+ distance_to_next_eov -= packet_samps;
+ total_samps_popped += packet_samps;
+ num_accum_samps += packet_samps;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_corner_case)
+{
+ const std::string format("fc32");
+
+ auto send_links = make_links(1);
+ auto streamer = make_tx_streamer(send_links, format);
+
+ // Allocate metadata
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = uhd::time_spec_t(0.0);
+
+ // Allocate buffer
+ const size_t spp = streamer->get_max_num_samps();
+ const size_t num_samps = spp * 2;
+ std::vector<std::complex<float>> buff(num_samps);
+
+ // Mark every sample as an EOV :D
+ std::vector<size_t> eovs(num_samps);
+ for (size_t i = 0; i < num_samps; i++) {
+ eovs[i] = i + 1;
+ }
+
+ metadata.eov_positions = eovs.data();
+ metadata.eov_positions_size = eovs.size();
+
+ const size_t num_sent = streamer->send(&buff.front(), num_samps, metadata, 1.0);
+ BOOST_CHECK_EQUAL(num_sent, num_samps);
+
+ mock_tx_data_xport::packet_info_t info;
+ std::complex<uint16_t>* data;
+ size_t packet_samps;
+ boost::shared_array<uint8_t> frame_buff;
+
+ // Check all packets for EOV
+ BOOST_CHECK_EQUAL(send_links[0]->get_num_packets(), num_samps);
+
+ for (size_t i = 0; i < num_samps; i++) {
+ std::tie(info, data, packet_samps, frame_buff) = pop_send_packet(send_links[0]);
+ BOOST_CHECK_EQUAL(packet_samps, 1);
+ BOOST_CHECK(info.eov);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_error_cases)
+{
+ const std::string format("fc32");
+
+ auto send_links = make_links(1);
+ auto streamer = make_tx_streamer(send_links, format);
+
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = uhd::time_spec_t(0.0);
+
+ const size_t spp = streamer->get_max_num_samps();
+ const size_t num_samps = spp;
+ std::vector<std::complex<float>> buff(num_samps);
+
+ // Error case: EOV of 0
+ size_t eov = 0;
+ metadata.eov_positions = &eov;
+ metadata.eov_positions_size = 1;
+
+ BOOST_CHECK_THROW(
+ streamer->send(&buff.front(), num_samps, metadata, 1.0), uhd::value_error);
+
+ // Error case: Adjacent EOV values that are the same
+ std::vector<size_t> eovs{100, 100};
+ metadata.eov_positions = eovs.data();
+ metadata.eov_positions_size = eovs.size();
+
+ BOOST_CHECK_THROW(
+ streamer->send(&buff.front(), num_samps, metadata, 1.0), uhd::value_error);
+
+ // Error case: EOV values not monotonically increasing
+ eovs = {50, 25};
+
+ BOOST_CHECK_THROW(
+ streamer->send(&buff.front(), num_samps, metadata, 1.0), uhd::value_error);
+
+ // Error case: EOV values greater than nsamps_per_buff
+ BOOST_CHECK_THROW(
+ streamer->send(&buff.front(), 1, metadata, 1.0), uhd::value_error);
+}
+
BOOST_AUTO_TEST_CASE(test_send_one_channel_multi_packet)
{
const size_t NUM_BUFFS_TO_TEST = 5;