The last thread got a little long and kind of died, so I decided to make a new
thread summarizing all the findings thus far.
I'm running on an x310 across dual 10 Gigabit ethernet, outfitted with twin
basic tx rx daughbords. I'm running on UHD version 3.11.0. Ideally, I would
like two simultaneous transmit and receive streams, utilizing both channels to
transmit and receive. I don't want to have to use 2 x310s for 2 receive and
transmit streams
When I transmit and receive at the same time on the same channel, I get a lot
of U's printed out to console signaling underflows, no matter what the rate.
HOWEVER, if I transmit and receive on separate channels, say tx_streamer has
stream_args at channel 1 and rx_streamer has stream_args at channel 0, it works
just fine.
I've attached the source code of a complete but simple program that will
hopefully demonstrate my problem. In this program, two threads are created: a
transmit thread and a receive thread. The receive thread is constantly
receiving data to a buffer and overwriting that buffer with new data. The
transmit thread is constantly transmitting 0's from a prefilled buffer.
If anyone has an x310 running across 10Gbps ethernet, can you compile and run
my program to test if this problem occurs not just for me?
Here's what we have already tested:
- I'm running on a server system rocking two 12 core intel xeon processors.
(https://ark.intel.com/products/91767/Intel-Xeon-Processor-E5-2650-v4-30M-Cache-2_20-GHz).
My network card is the recommended x520 da2. Someone had previously suggested
NUMA to be an issue, but I don't think this is the case as the program works
when we switch to transmitting and receiving on separate channels.
- I've tested only transmitting and only receiving. We can transmit at 200MS/s
across both channels and we can receive at 200MS/s across both channels, but we
cannot transmit and receive from the same channel. This suggests our network
card is working properly and we can handle the high rate.
- I've tried my program on UHD 3.10.2 and the problem still occurs
- I've tried setting the tx_metadata waiting 2 second before transmitting. The
problem still occurs.
- I've tried running the example program txrx_loopback_from_file and that works
for simultaneous receive and transmit, but I have no idea why.
>From the last point, I'm lead to believe that I am somehow calling the uhd API
>wrong, but I have no idea where the error is. Any help would be greatly
>appreciated.
Thanks,
Jason
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <vector>
#include <csignal>
#include <boost/date_time.hpp>
#include <boost/thread/thread.hpp>
#include <thread>
//#include <unistd.h>
#include <time.h>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/types/tune_request.hpp>
typedef std::complex<short> Complex;
// Constants and signal variables
static bool stop_signal_called = false;
const int NUM_CHANNELS = 1;
const int BUFF_SIZE = 64000;
//function prototypes here
void recvTask(Complex *buff, uhd::rx_streamer::sptr rx_stream);
void txTask(Complex *buff, uhd::tx_streamer::sptr tx_stream, uhd::tx_metadata_t
md);
void sig_int_handler(int){
std::cout << "Interrupt Signal Received" << std::endl;
stop_signal_called = true;
}
int UHD_SAFE_MAIN(int argc, char *argv[]) {
uhd::set_thread_priority_safe();
//type=x300,addr=192.168.30.2,second_addr=192.168.40.2
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device") << std::endl;
uhd::usrp::multi_usrp::sptr usrp =
uhd::usrp::multi_usrp::make(std::string("type=x300,addr=192.168.30.2,second_addr=192.168.40.2"));
std::cout << std::endl;
//set stream args
uhd::stream_args_t stream_args("sc16");
double samp_rate_tx = 100e6;
double samp_rate_rx = 100e6;
uhd::tune_request_t tune_request(0);
//Lock mboard clocks
usrp->set_clock_source(std::string("internal"));
//set rx parameters
usrp->set_rx_rate(samp_rate_rx);
usrp->set_rx_freq(tune_request);
usrp->set_rx_gain(0);
//set tx parameters
usrp->set_tx_rate(samp_rate_tx);
usrp->set_tx_freq(tune_request);
usrp->set_tx_gain(0);
std::signal(SIGINT, &sig_int_handler);
std::cout << "Press Ctrl + C to stop streaming..." << std::endl;
//create buffers, 2 per channel (1 for tx, 1 for rx)
// transmitting complex shorts -> typedef as Complex
Complex *rx_buffs[NUM_CHANNELS];
Complex *tx_buffs[NUM_CHANNELS];
for (int i = 0; i < NUM_CHANNELS; i++){
rx_buffs[i] = new Complex[BUFF_SIZE];
tx_buffs[i] = new Complex[BUFF_SIZE];
// only transmitting 0's
std::fill(tx_buffs[i], tx_buffs[i]+BUFF_SIZE, 0);
}
//////////////////////////////////////////////////////////////////////////////
////////////////START RECEIVE AND TRANSMIT THREADS////////////////////////////
//////////////////////////////////////////////////////////////////////////////
printf("setting up threading\n");
usrp -> set_time_now(uhd::time_spec_t(0.0));
// set up RX streams and threads
std::thread rx_threads[NUM_CHANNELS];
uhd::rx_streamer::sptr rx_streams[NUM_CHANNELS];
for (int i = 0; i < NUM_CHANNELS; i++){
stream_args.channels = std::vector<size_t>(1,i);
rx_streams[i] = usrp->get_rx_stream(stream_args);
//setup streaming
auto stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
uhd::stream_cmd_t stream_cmd(stream_mode);
stream_cmd.num_samps = 0;
stream_cmd.stream_now = true;
stream_cmd.time_spec = uhd::time_spec_t();
rx_streams[i]->issue_stream_cmd(stream_cmd);
//start rx thread
std::cout << "Starting rx thread " << i << std::endl;
rx_threads[i] = std::thread(recvTask,rx_buffs[i],rx_streams[i]);
}
// set up TX streams and threads
std::thread tx_threads[NUM_CHANNELS];
uhd::tx_streamer::sptr tx_streams[NUM_CHANNELS];
// set up TX metadata
uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst = false;
md.has_time_spec = true;
md.time_spec = uhd::time_spec_t(0.1);
for (int i = 0; i < NUM_CHANNELS; i++){
//does not work when we transmit and receive on same channel,
//if we change to stream_args.channels = std::vector<size_t> (1,1),
this works for 1 channel.
stream_args.channels = std::vector<size_t>(1,i);
tx_streams[i] = usrp->get_tx_stream(stream_args);
//start the thread
std::cout << "Starting tx thread " << i << std::endl;
tx_threads[i] = std::thread(txTask,tx_buffs[i],tx_streams[i],md);
}
printf("Waiting to join threads\n");
for (int i = 0; i < NUM_CHANNELS; i++){
//join threads
tx_threads[i].join();
rx_threads[i].join();
}
return EXIT_SUCCESS;
}
void recvTask(Complex *buff, uhd::rx_streamer::sptr rx_stream){
uhd::rx_metadata_t md;
size_t num_acc_samps = 0;
size_t amount_received = 0;
unsigned overflows = 0;
struct timespec start_time;
clock_gettime(CLOCK_MONOTONIC, &start_time);
//receive loop
while(!stop_signal_called){
amount_received = rx_stream->recv(buff,BUFF_SIZE,md,3.0);
if (amount_received != BUFF_SIZE){ printf("receive not equal\n");}
//handle the error codes
switch(md.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
break;
case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
std::cerr << "T";
continue;
case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
overflows++;
std::cerr << "Got an Overflow Indication" << std::endl;
continue;
default:
std::cout << boost::format(
"Got error code 0x%x, exiting loop..."
) % md.error_code << std::endl;
goto done_loop;
}
num_acc_samps += amount_received;
} done_loop:
// tell receive to stop streaming
auto stream_cmd =
uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
rx_stream->issue_stream_cmd(stream_cmd);
// timing stuff
struct timespec end_time;
clock_gettime(CLOCK_MONOTONIC, &end_time);
double runtime = (end_time.tv_sec - start_time.tv_sec) +
(end_time.tv_nsec - start_time.tv_nsec ) / 1000000000.0;
std::cout << std::endl << "Received " << num_acc_samps
<< " samples in " << runtime << "s"
<< " Throughput = " << num_acc_samps / 1e6 /runtime << " Msps"
<< std::endl;
//finished
std::cout << "Overflows=" << overflows << std::endl << std::endl;
}
void txTask(Complex *buff, uhd::tx_streamer::sptr tx_stream, uhd::tx_metadata_t
md){
size_t num_acc_samps = 0;
struct timespec start_time;
clock_gettime(CLOCK_MONOTONIC, &start_time);
//transmit loop
while(!stop_signal_called){
size_t samples_sent = tx_stream->send(buff,BUFF_SIZE,md);
num_acc_samps += samples_sent;
md.start_of_burst = false;
md.has_time_spec = false;
}
//timing stuff
struct timespec end_time;
clock_gettime(CLOCK_MONOTONIC, &end_time);
double runtime = (end_time.tv_sec - start_time.tv_sec) +
(end_time.tv_nsec - start_time.tv_nsec ) / 1000000000.0;
std::cout << std::endl << "Sent " << num_acc_samps
<< " samples in " << runtime << "s"
<< " Throughput = " << num_acc_samps / 1e6 /runtime << " Msps"
<< std::endl;
//send a mini EOB packet
md.end_of_burst = true;
tx_stream -> send("",0,md);
printf("End transmit \n");
}
_______________________________________________
USRP-users mailing list
[email protected]
http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com