diff --git a/lib/test/upper/rlc_am_stress_test.cc b/lib/test/upper/rlc_am_stress_test.cc index fb83e4cfd..52d4176de 100644 --- a/lib/test/upper/rlc_am_stress_test.cc +++ b/lib/test/upper/rlc_am_stress_test.cc @@ -30,10 +30,14 @@ #include "srslte/common/log_filter.h" #include "srslte/common/logger_stdout.h" #include "srslte/common/threads.h" +#include "srslte/common/rlc_pcap.h" #include "srslte/upper/rlc.h" #include #include #include +#include + +#define SDU_SIZE 1500 using namespace std; using namespace srsue; @@ -47,8 +51,13 @@ typedef struct { uint32_t pdu_tx_delay_usec; bool reestablish; uint32_t log_level; + bool single_tx; + bool write_pcap; + float opp_sdu_ratio; } stress_test_args_t; +boost::mutex mutex; + void parse_args(stress_test_args_t *args, int argc, char *argv[]) { // Command line only options @@ -65,8 +74,11 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) { ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(10), "SDU generation delay (usec)") ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(10), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") ("error_rate", bpo::value(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped") + ("opp_sdu_ratio", bpo::value(&args->opp_sdu_ratio)->default_value(0.0), "Ratio between MAC opportunity and SDU size (0==random)") ("reestablish", bpo::value(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution") - ("loglevel", bpo::value(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug"); + ("loglevel", bpo::value(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug)") + ("singletx", bpo::value(&args->single_tx)->default_value(false), "If set to true, only one node is generating data") + ("pcap", bpo::value(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file"); // these options are allowed on the command line bpo::options_description cmdline_options; @@ -94,14 +106,17 @@ class mac_reader :public thread { public: - mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay_usec_) + mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, uint32_t pdu_tx_delay_usec_, rlc_pcap *pcap_, bool is_dl_ = true) { rlc1 = rlc1_; rlc2 = rlc2_; fail_rate = fail_rate_; + opp_sdu_ratio = opp_sdu_ratio_; run_enable = true; running = false; pdu_tx_delay_usec = pdu_tx_delay_usec_; + pcap = pcap_; + is_dl = is_dl_; } void stop() @@ -129,14 +144,25 @@ private: } while(run_enable) { - float r = (float)rand()/RAND_MAX; - int opp_size = r*1500; - rlc1->get_buffer_state(1); - int read = rlc1->read_pdu(1, pdu->msg, opp_size); - if(((float)rand()/RAND_MAX > fail_rate) && read>0) { - rlc2->write_pdu(1, pdu->msg, opp_size); + // generate MAC opportunities of random size or with fixed ratio + float r = opp_sdu_ratio ? opp_sdu_ratio : (float)rand()/RAND_MAX; + int opp_size = r*SDU_SIZE; + mutex.lock(); + uint32_t buf_state = rlc1->get_buffer_state(1); + if (buf_state) { + int read = rlc1->read_pdu(1, pdu->msg, opp_size); + usleep(pdu_tx_delay_usec); + if(((float)rand()/RAND_MAX > fail_rate) && read>0) { + pdu->N_bytes = read; + rlc2->write_pdu(1, pdu->msg, pdu->N_bytes); + if (is_dl) { + pcap->write_dl_am_ccch(pdu->msg, pdu->N_bytes); + } else { + pcap->write_ul_am_ccch(pdu->msg, pdu->N_bytes); + } + } } - usleep(pdu_tx_delay_usec); + mutex.unlock(); } running = false; byte_buffer_pool::get_instance()->deallocate(pdu); @@ -145,7 +171,10 @@ private: rlc_interface_mac *rlc1; rlc_interface_mac *rlc2; float fail_rate; + float opp_sdu_ratio; uint32_t pdu_tx_delay_usec; + rlc_pcap *pcap; + bool is_dl; bool run_enable; bool running; @@ -155,9 +184,9 @@ class mac_dummy :public srslte::mac_interface_timers { public: - mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay) - :r1(rlc1_, rlc2_, fail_rate_, pdu_tx_delay) - ,r2(rlc2_, rlc1_, fail_rate_, pdu_tx_delay) + mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, int32_t pdu_tx_delay, rlc_pcap* pcap = NULL) + :r1(rlc1_, rlc2_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, true) + ,r2(rlc2_, rlc1_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, false) { } @@ -222,6 +251,7 @@ public: void write_pdu(uint32_t lcid, byte_buffer_t *sdu) { assert(lcid == 1); + assert(sdu->N_bytes==SDU_SIZE); byte_buffer_pool::get_instance()->deallocate(sdu); std::cout << "rlc_am_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl; } @@ -244,8 +274,11 @@ private: printf("Fatal Error: Could not allocate PDU in rlc_am_tester::run_thread\n"); exit(-1); } - pdu->N_bytes = 1500; - pdu->msg[0] = sn++; + for (uint32_t i = 0; i < SDU_SIZE; i++) { + pdu->msg[i] = sn; + } + sn++; + pdu->N_bytes = SDU_SIZE; rlc->write_sdu(1, pdu); usleep(sdu_gen_delay_usec); } @@ -271,13 +304,18 @@ void stress_test(stress_test_args_t args) log2.set_level((LOG_LEVEL_ENUM)args.log_level); log1.set_hex_limit(-1); log2.set_hex_limit(-1); + rlc_pcap pcap; + + if (args.write_pcap) { + pcap.open("rlc_stress_test.pcap", 0); + } rlc rlc1; rlc rlc2; rlc_am_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec); rlc_am_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec); - mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.pdu_tx_delay_usec); + mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.opp_sdu_ratio, args.pdu_tx_delay_usec, &pcap); ue_interface ue; rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); @@ -298,14 +336,21 @@ void stress_test(stress_test_args_t args) rlc2.add_bearer(1, cnfg_); tester1.start(7); - tester2.start(7); + if (!args.single_tx) { + tester2.start(7); + } mac.start(); for (uint32_t i = 0; i < args.test_duration_sec; i++) { // if enabled, mimic reestablishment every second if (args.reestablish) { + // lock mutex during reestablish to prevent a RLC PDU that is already been transmitted before + // resetting the tx'ing RLC entity, but not yet received before resetting the + // rx'ing RLC entity to screw the test + mutex.lock(); rlc1.reestablish(); rlc2.reestablish(); + mutex.unlock(); } usleep(1e6); } @@ -313,6 +358,9 @@ void stress_test(stress_test_args_t args) tester1.stop(); tester2.stop(); mac.stop(); + if (args.write_pcap) { + pcap.close(); + } }