mirror of https://github.com/PentHertz/srsLTE.git
rlc_stress_test: make pedantic operation the default
among cleaning up the the stress test, it does: * remove optional pedantic flag and make it the default to catch resegmentation issues * use random SDU and MAC grant size the default * use factory functions to create RLC configs (make maxretx configurable) * remove reestablishment and print error when maxRetx is triggered * fix NR PCAP usage and removes PCAP ifdef
This commit is contained in:
parent
1a59f2d5ba
commit
5e345df439
|
@ -26,34 +26,29 @@
|
|||
|
||||
#define LOG_HEX_LIMIT (-1)
|
||||
|
||||
#define PCAP 0
|
||||
#define PCAP_CRNTI (0x1001)
|
||||
#define PCAP_TTI (666)
|
||||
|
||||
#if PCAP
|
||||
#include "srslte/common/mac_nr_pcap.h"
|
||||
#include "srslte/mac/mac_nr_pdu.h"
|
||||
static std::unique_ptr<srslte::mac_nr_pcap> pcap_handle = nullptr;
|
||||
#endif
|
||||
#include "srslte/common/mac_pcap.h"
|
||||
#include "srslte/mac/mac_sch_pdu_nr.h"
|
||||
static std::unique_ptr<srslte::mac_pcap> pcap_handle = nullptr;
|
||||
|
||||
int write_pdu_to_pcap(const bool is_dl, const uint32_t lcid, const uint8_t* payload, const uint32_t len)
|
||||
{
|
||||
#if PCAP
|
||||
if (pcap_handle) {
|
||||
srslte::byte_buffer_t tx_buffer;
|
||||
srslte::mac_nr_sch_pdu tx_pdu;
|
||||
srslte::mac_sch_pdu_nr tx_pdu;
|
||||
tx_pdu.init_tx(&tx_buffer, len + 10);
|
||||
tx_pdu.add_sdu(lcid, payload, len);
|
||||
tx_pdu.pack();
|
||||
if (is_dl) {
|
||||
pcap_handle->write_dl_crnti(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI);
|
||||
pcap_handle->write_dl_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI);
|
||||
} else {
|
||||
pcap_handle->write_ul_crnti(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI);
|
||||
pcap_handle->write_ul_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -62,25 +57,27 @@ using namespace srsue;
|
|||
using namespace srslte;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
#define MIN_SDU_SIZE (5)
|
||||
#define MAX_SDU_SIZE (1500)
|
||||
|
||||
typedef struct {
|
||||
std::string rat;
|
||||
std::string mode;
|
||||
uint32_t sdu_size;
|
||||
int32_t sdu_size;
|
||||
uint32_t test_duration_sec;
|
||||
float pdu_drop_rate;
|
||||
float pdu_cut_rate;
|
||||
float pdu_duplicate_rate;
|
||||
uint32_t sdu_gen_delay_usec;
|
||||
uint32_t pdu_tx_delay_usec;
|
||||
bool reestablish;
|
||||
uint32_t log_level;
|
||||
bool single_tx;
|
||||
bool write_pcap;
|
||||
uint32_t avg_opp_size;
|
||||
bool random_opp;
|
||||
bool zero_seed;
|
||||
bool pedantic_sdu_check;
|
||||
uint32_t nof_pdu_tti;
|
||||
uint32_t max_retx;
|
||||
} stress_test_args_t;
|
||||
|
||||
void parse_args(stress_test_args_t* args, int argc, char* argv[])
|
||||
|
@ -98,20 +95,19 @@ void parse_args(stress_test_args_t* args, int argc, char* argv[])
|
|||
("rat", bpo::value<std::string>(&args->rat)->default_value("LTE"), "The RLC version to use (LTE/NR)")
|
||||
("mode", bpo::value<std::string>(&args->mode)->default_value("AM"), "Whether to test RLC acknowledged or unacknowledged mode (AM/UM)")
|
||||
("duration", bpo::value<uint32_t>(&args->test_duration_sec)->default_value(5), "Duration (sec)")
|
||||
("sdu_size", bpo::value<uint32_t>(&args->sdu_size)->default_value(1500), "Size of SDUs")
|
||||
("avg_opp_size", bpo::value<uint32_t>(&args->avg_opp_size)->default_value(1505), "Size of the MAC opportunity (if not random)")
|
||||
("sdu_size", bpo::value<int32_t>(&args->sdu_size)->default_value(-1), "Size of SDUs (-1 means random)")
|
||||
("random_opp", bpo::value<bool>(&args->random_opp)->default_value(true), "Whether to generate random MAC opportunities")
|
||||
("avg_opp_size", bpo::value<uint32_t>(&args->avg_opp_size)->default_value(1505), "Size of the MAC opportunity (if not random)")
|
||||
("sdu_gen_delay", bpo::value<uint32_t>(&args->sdu_gen_delay_usec)->default_value(0), "SDU generation delay (usec)")
|
||||
("pdu_tx_delay", bpo::value<uint32_t>(&args->pdu_tx_delay_usec)->default_value(0), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)")
|
||||
("pdu_drop_rate", bpo::value<float>(&args->pdu_drop_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped")
|
||||
("pdu_cut_rate", bpo::value<float>(&args->pdu_cut_rate)->default_value(0.0), "Rate at which RLC PDUs are chopped in length")
|
||||
("pdu_duplicate_rate", bpo::value<float>(&args->pdu_duplicate_rate)->default_value(0.0), "Rate at which RLC PDUs are duplicated")
|
||||
("reestablish", bpo::value<bool>(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution")
|
||||
("loglevel", bpo::value<uint32_t>(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug)")
|
||||
("singletx", bpo::value<bool>(&args->single_tx)->default_value(false), "If set to true, only one node is generating data")
|
||||
("pcap", bpo::value<bool>(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file")
|
||||
("zeroseed", bpo::value<bool>(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero")
|
||||
("pedantic", bpo::value<bool>(&args->pedantic_sdu_check)->default_value(false), "Whether to check SDU length and exit on error")
|
||||
("max_retx", bpo::value<uint32_t>(&args->max_retx)->default_value(8), "Maximum number of RLC retransmission attempts")
|
||||
("nof_pdu_tti", bpo::value<uint32_t>(&args->nof_pdu_tti)->default_value(1), "Number of PDUs processed in a TTI");
|
||||
// clang-format on
|
||||
|
||||
|
@ -135,9 +131,14 @@ void parse_args(stress_test_args_t* args, int argc, char* argv[])
|
|||
args->log_level = 4;
|
||||
printf("Set log level to %d (%s)\n", args->log_level, srslte::log_level_text[args->log_level]);
|
||||
}
|
||||
|
||||
// convert mode to upper case
|
||||
for (auto& c : args->mode) {
|
||||
c = toupper(c);
|
||||
}
|
||||
}
|
||||
|
||||
class mac_dummy : public thread
|
||||
class mac_dummy : public srslte::thread
|
||||
{
|
||||
public:
|
||||
mac_dummy(rlc_interface_mac* rlc1_,
|
||||
|
@ -145,7 +146,8 @@ public:
|
|||
stress_test_args_t args_,
|
||||
uint32_t lcid_,
|
||||
timer_handler* timers_,
|
||||
rlc_pcap* pcap_ = NULL) :
|
||||
rlc_pcap* pcap_,
|
||||
uint32_t seed_) :
|
||||
run_enable(true),
|
||||
rlc1(rlc1_),
|
||||
rlc2(rlc2_),
|
||||
|
@ -156,8 +158,7 @@ public:
|
|||
logger(srslog::fetch_basic_logger("MAC", false)),
|
||||
thread("MAC_DUMMY"),
|
||||
real_dist(0.0, 1.0),
|
||||
mt19937(1234),
|
||||
pool(byte_buffer_pool::get_instance())
|
||||
mt19937(seed_)
|
||||
{
|
||||
logger.set_level(static_cast<srslog::basic_levels>(args.log_level));
|
||||
logger.set_hex_dump_max_size(LOG_HEX_LIMIT);
|
||||
|
@ -209,7 +210,7 @@ private:
|
|||
{
|
||||
// Sleep if necessary
|
||||
if (args.pdu_tx_delay_usec > 0) {
|
||||
usleep(args.pdu_tx_delay_usec);
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(args.pdu_tx_delay_usec));
|
||||
}
|
||||
|
||||
auto it = pdu_list.begin(); // PDU iterator
|
||||
|
@ -293,13 +294,13 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
rlc_interface_mac* rlc1;
|
||||
rlc_interface_mac* rlc2;
|
||||
rlc_interface_mac* rlc1 = nullptr;
|
||||
rlc_interface_mac* rlc2 = nullptr;
|
||||
|
||||
bool run_enable;
|
||||
stress_test_args_t args;
|
||||
rlc_pcap* pcap;
|
||||
uint32_t lcid;
|
||||
bool run_enable = false;
|
||||
stress_test_args_t args = {};
|
||||
rlc_pcap* pcap = nullptr;
|
||||
uint32_t lcid = 0;
|
||||
srslog::basic_logger& logger;
|
||||
srslte::timer_handler* timers = nullptr;
|
||||
|
||||
|
@ -307,22 +308,25 @@ private:
|
|||
|
||||
std::mt19937 mt19937;
|
||||
std::uniform_real_distribution<float> real_dist;
|
||||
byte_buffer_pool* pool = nullptr;
|
||||
};
|
||||
|
||||
class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public thread
|
||||
class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public srslte::thread
|
||||
{
|
||||
public:
|
||||
rlc_tester(rlc_interface_pdcp* rlc_, std::string name_, stress_test_args_t args_, uint32_t lcid_) :
|
||||
rlc_tester(rlc_interface_pdcp* rlc_pdcp_,
|
||||
std::string name_,
|
||||
stress_test_args_t args_,
|
||||
uint32_t lcid_,
|
||||
uint32_t seed_) :
|
||||
log("TEST"),
|
||||
logger(srslog::fetch_basic_logger("TEST", false)),
|
||||
rlc(rlc_),
|
||||
run_enable(true),
|
||||
rx_pdus(),
|
||||
rlc_pdcp(rlc_pdcp_),
|
||||
name(name_),
|
||||
args(args_),
|
||||
lcid(lcid_),
|
||||
thread("RLC_TESTER")
|
||||
thread("RLC_TESTER"),
|
||||
int_dist(MIN_SDU_SIZE, MAX_SDU_SIZE),
|
||||
mt19937(seed_)
|
||||
{
|
||||
logger.set_level(srslog::basic_levels::error);
|
||||
logger.set_hex_dump_max_size(LOG_HEX_LIMIT);
|
||||
|
@ -338,13 +342,26 @@ public:
|
|||
void write_pdu(uint32_t rx_lcid, unique_byte_buffer_t sdu)
|
||||
{
|
||||
assert(rx_lcid == lcid);
|
||||
if (sdu->N_bytes != args.sdu_size) {
|
||||
logger.error(sdu->msg, sdu->N_bytes, "Received SDU with size %d, expected %d.", sdu->N_bytes, args.sdu_size);
|
||||
if (args.pedantic_sdu_check) {
|
||||
if (args.mode != "AM") {
|
||||
// Only AM will guarantee to deliver SDUs, take first byte as reference for other modes
|
||||
next_expected_sdu = sdu->msg[0];
|
||||
}
|
||||
|
||||
// check SDU content (consider faster alternative)
|
||||
for (uint32_t i = 0; i < sdu->N_bytes; ++i) {
|
||||
if (sdu->msg[i] != next_expected_sdu) {
|
||||
logger.error(sdu->msg,
|
||||
sdu->N_bytes,
|
||||
"Received malformed SDU with size %d, expected data 0x%X",
|
||||
sdu->N_bytes,
|
||||
next_expected_sdu);
|
||||
fprintf(stderr, "Received malformed SDU with size %d\n", sdu->N_bytes);
|
||||
fprintf(stdout, "Received malformed SDU with size %d\n", sdu->N_bytes);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1)); // give some time to flush logs
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
next_expected_sdu += 1;
|
||||
rx_pdus++;
|
||||
}
|
||||
void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {}
|
||||
|
@ -355,7 +372,13 @@ public:
|
|||
void notify_failure(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns) {}
|
||||
|
||||
// RRC interface
|
||||
void max_retx_attempted() {}
|
||||
void max_retx_attempted()
|
||||
{
|
||||
logger.error(
|
||||
"Maximum number of RLC retransmission reached. Consider increasing threshold or lowering channel drop rate.");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
}
|
||||
std::string get_rb_name(uint32_t rx_lcid) { return std::string("DRB1"); }
|
||||
|
||||
int get_nof_rx_pdus() { return rx_pdus; }
|
||||
|
@ -364,11 +387,11 @@ private:
|
|||
const static size_t max_pdcp_sn = 262143u; // 18bit SN
|
||||
void run_thread()
|
||||
{
|
||||
uint32_t pdcp_sn = 0;
|
||||
byte_buffer_pool* pool = byte_buffer_pool::get_instance();
|
||||
uint32_t pdcp_sn = 0;
|
||||
uint32_t sdu_size = 0;
|
||||
while (run_enable) {
|
||||
// SDU queue is full, don't assign PDCP SN
|
||||
if (rlc->sdu_queue_is_full(lcid)) {
|
||||
if (rlc_pdcp->sdu_queue_is_full(lcid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -376,33 +399,49 @@ private:
|
|||
if (pdu == NULL) {
|
||||
printf("Error: Could not allocate PDU in rlc_tester::run_thread\n\n\n");
|
||||
// backoff for a bit
|
||||
usleep(1000);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
pdu->md.pdcp_sn = pdcp_sn;
|
||||
for (uint32_t i = 0; i < args.sdu_size; i++) {
|
||||
|
||||
// random or fixed SDU size
|
||||
if (args.sdu_size < 1) {
|
||||
sdu_size = int_dist(mt19937);
|
||||
} else {
|
||||
sdu_size = args.sdu_size;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sdu_size; i++) {
|
||||
pdu->msg[i] = pdcp_sn & 0xFF;
|
||||
}
|
||||
pdu->N_bytes = args.sdu_size;
|
||||
rlc->write_sdu(lcid, std::move(pdu));
|
||||
pdu->N_bytes = sdu_size;
|
||||
|
||||
logger.info(pdu->msg, pdu->N_bytes, "Generated SDU with %d B", pdu->N_bytes);
|
||||
|
||||
rlc_pdcp->write_sdu(lcid, std::move(pdu));
|
||||
pdcp_sn = (pdcp_sn + 1) % max_pdcp_sn;
|
||||
if (args.sdu_gen_delay_usec > 0) {
|
||||
usleep(args.sdu_gen_delay_usec);
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(args.sdu_gen_delay_usec));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool run_enable;
|
||||
uint64_t rx_pdus;
|
||||
uint32_t lcid;
|
||||
bool run_enable = true;
|
||||
/// Tx uses thread-local PDCP SN to set SDU content, the Rx uses this variable to check received SDUs
|
||||
uint8_t next_expected_sdu = 0;
|
||||
uint64_t rx_pdus = 0;
|
||||
uint32_t lcid = 0;
|
||||
srslte::log_filter log;
|
||||
srslog::basic_logger& logger;
|
||||
|
||||
std::string name;
|
||||
|
||||
stress_test_args_t args;
|
||||
stress_test_args_t args = {};
|
||||
|
||||
rlc_interface_pdcp* rlc;
|
||||
rlc_interface_pdcp* rlc_pdcp = nullptr; // used by run_thread to push PDCP SDUs to RLC
|
||||
|
||||
std::mt19937 mt19937;
|
||||
std::uniform_int_distribution<> int_dist;
|
||||
};
|
||||
|
||||
void stress_test(stress_test_args_t args)
|
||||
|
@ -421,22 +460,11 @@ void stress_test(stress_test_args_t args)
|
|||
if (args.rat == "LTE") {
|
||||
if (args.mode == "AM") {
|
||||
// config RLC AM bearer
|
||||
cnfg_.rlc_mode = rlc_mode_t::am;
|
||||
cnfg_.am.max_retx_thresh = 4;
|
||||
cnfg_.am.poll_byte = 25 * 1000;
|
||||
cnfg_.am.poll_pdu = 4;
|
||||
cnfg_.am.t_poll_retx = 5;
|
||||
cnfg_.am.t_reordering = 5;
|
||||
cnfg_.am.t_status_prohibit = 5;
|
||||
cnfg_ = rlc_config_t::default_rlc_am_config();
|
||||
cnfg_.am.max_retx_thresh = args.max_retx;
|
||||
} else if (args.mode == "UM") {
|
||||
// config UM bearer
|
||||
cnfg_.rlc_mode = rlc_mode_t::um;
|
||||
cnfg_.um.t_reordering = 5;
|
||||
cnfg_.um.rx_mod = 32;
|
||||
cnfg_.um.rx_sn_field_length = rlc_umd_sn_size_t::size5bits;
|
||||
cnfg_.um.rx_window_size = 16;
|
||||
cnfg_.um.tx_sn_field_length = rlc_umd_sn_size_t::size5bits;
|
||||
cnfg_.um.tx_mod = 32;
|
||||
cnfg_ = rlc_config_t::default_rlc_um_config();
|
||||
} else if (args.mode == "TM") {
|
||||
// use default LCID in TM
|
||||
lcid = 0;
|
||||
|
@ -445,12 +473,9 @@ void stress_test(stress_test_args_t args)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
#if PCAP
|
||||
if (args.write_pcap) {
|
||||
pcap.open("rlc_stress_test.pcap", cnfg_);
|
||||
}
|
||||
#endif
|
||||
|
||||
} else if (args.rat == "NR") {
|
||||
if (args.mode == "UM") {
|
||||
cnfg_ = rlc_config_t::default_rlc_um_nr_config(6);
|
||||
|
@ -459,25 +484,30 @@ void stress_test(stress_test_args_t args)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
#if PCAP
|
||||
if (args.write_pcap) {
|
||||
pcap_handle = std::unique_ptr<srslte::mac_nr_pcap>(new srslte::mac_nr_pcap());
|
||||
pcap_handle = std::unique_ptr<srslte::mac_pcap>(new srslte::mac_pcap());
|
||||
pcap_handle->open("rlc_stress_test_nr.pcap");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
cout << "Unsupported RAT mode " << args.rat << ", exiting." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// generate random seed if needed
|
||||
uint32_t seed = 0;
|
||||
if (not args.zero_seed) {
|
||||
std::random_device rd;
|
||||
seed = rd();
|
||||
}
|
||||
|
||||
srslte::timer_handler timers(8);
|
||||
|
||||
rlc rlc1(log1.id().c_str());
|
||||
rlc rlc2(log2.id().c_str());
|
||||
|
||||
rlc_tester tester1(&rlc1, "tester1", args, lcid);
|
||||
rlc_tester tester2(&rlc2, "tester2", args, lcid);
|
||||
mac_dummy mac(&rlc1, &rlc2, args, lcid, &timers, &pcap);
|
||||
rlc_tester tester1(&rlc1, "tester1", args, lcid, seed);
|
||||
rlc_tester tester2(&rlc2, "tester2", args, lcid, seed);
|
||||
mac_dummy mac(&rlc1, &rlc2, args, lcid, &timers, &pcap, seed);
|
||||
|
||||
rlc1.init(&tester1, &tester1, &timers, 0);
|
||||
rlc2.init(&tester2, &tester2, &timers, 0);
|
||||
|
@ -494,18 +524,8 @@ void stress_test(stress_test_args_t args)
|
|||
}
|
||||
mac.start();
|
||||
|
||||
if (args.test_duration_sec < 1) {
|
||||
args.test_duration_sec = 1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < args.test_duration_sec; i++) {
|
||||
// if enabled, mimic reestablishment every second
|
||||
if (args.reestablish) {
|
||||
rlc1.reestablish();
|
||||
rlc2.reestablish();
|
||||
}
|
||||
usleep(1e6);
|
||||
}
|
||||
// wait until test is over
|
||||
std::this_thread::sleep_for(std::chrono::seconds(args.test_duration_sec));
|
||||
|
||||
printf("Test finished, tearing down ..\n");
|
||||
|
||||
|
@ -558,12 +578,6 @@ int main(int argc, char** argv)
|
|||
|
||||
srslog::init();
|
||||
|
||||
if (args.zero_seed) {
|
||||
srand(0);
|
||||
} else {
|
||||
srand(time(NULL));
|
||||
}
|
||||
|
||||
stress_test(args);
|
||||
|
||||
exit(0);
|
||||
|
|
Loading…
Reference in New Issue