Add arguments to NR PHY test

master
Xavier Arteaga 3 years ago committed by Andre Puschmann
parent 64b7dfed65
commit 96cb25b868

@ -31,12 +31,10 @@ class worker_pool
public:
struct args_t {
uint32_t nof_phy_threads = 3;
uint32_t prio = 52;
std::string log_level = "info";
uint32_t log_hex_limit = 64;
std::string log_id_preamble = "";
uint32_t pusch_max_nof_iter = 10;
uint32_t nof_phy_threads = 3;
uint32_t prio = 52;
uint32_t pusch_max_nof_iter = 10;
srsran::phy_log_args_t log = {};
};
slot_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }

@ -26,11 +26,11 @@ worker_pool::worker_pool(srsran::phy_common_interface& common_,
bool worker_pool::init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_list)
{
// Add workers to workers pool and start threads
srslog::basic_levels log_level = srslog::str_to_basic_level(args.log_level);
srslog::basic_levels log_level = srslog::str_to_basic_level(args.log.phy_level);
for (uint32_t i = 0; i < args.nof_phy_threads; i++) {
auto& log = srslog::fetch_basic_logger(fmt::format("{}PHY{}-NR", args.log_id_preamble, i), log_sink);
auto& log = srslog::fetch_basic_logger(fmt::format("{}PHY{}-NR", args.log.id_preamble, i), log_sink);
log.set_level(log_level);
log.set_hex_dump_max_size(args.log_hex_limit);
log.set_hex_dump_max_size(args.log.phy_hex_limit);
auto w = new slot_worker(common, stack, log);
pool.init_worker(i, w, args.prio);

@ -21,5 +21,7 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB)
${Boost_LIBRARIES}
${ATOMIC_LIBS})
add_nr_test(nr_phy_test nr_phy_test)
add_nr_test(nr_phy_test_10MHz_dl_only nr_phy_test --duration=100 --gnb.stack.pusch.slots="")
add_nr_test(nr_phy_test_10MHz_ul_only nr_phy_test --duration=100 --gnb.stack.pdsch.slots="")
add_nr_test(nr_phy_test_10MHz_bidir nr_phy_test --duration=100)
endif ()

@ -16,10 +16,12 @@
#include "dummy_rx_harq_proc.h"
#include "dummy_tx_harq_proc.h"
#include <mutex>
#include <set>
#include <srsenb/hdr/stack/mac/mac_metrics.h>
#include <srsran/adt/circular_array.h>
#include <srsran/common/phy_cfg_nr.h>
#include <srsran/common/standard_streams.h>
#include <srsran/common/string_helpers.h>
#include <srsran/interfaces/gnb_interfaces.h>
class gnb_dummy_stack : public srsenb::stack_interface_phy_nr
@ -33,12 +35,12 @@ private:
srsran::circular_array<uint32_t, SRSRAN_NOF_SF_X_FRAME> dl_data_to_ul_ack;
uint32_t ss_id = 0;
uint32_t dl_freq_res = 0;
uint32_t dl_time_res = 0;
uint32_t ul_freq_res = 0;
uint32_t ul_time_res = 0;
srsran_random_t random_gen = nullptr;
srsran::phy_cfg_nr_t phy_cfg = {};
bool valid = false;
std::set<uint32_t> dl_slots;
std::set<uint32_t> ul_slots;
std::mutex mac_metrics_mutex;
srsenb::mac_ue_metrics_t mac_metrics = {};
@ -118,6 +120,10 @@ private:
bool schedule_pdsch(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
{
if (dl_slots.count(SRSRAN_SLOT_NR_MOD(srsran_subcarrier_spacing_15kHz, slot_cfg.idx)) == 0) {
return true;
}
// Instantiate PDCCH and PDSCH
pdcch_dl_t pdcch = {};
pdsch_t pdsch = {};
@ -140,7 +146,7 @@ private:
// Fill DCI fields
srsran_dci_dl_nr_t& dci = pdcch.dci;
dci.freq_domain_assigment = dl_freq_res;
dci.time_domain_assigment = dl_time_res;
dci.time_domain_assigment = 0;
dci.mcs = mcs;
dci.rv = 0;
dci.ndi = (slot_cfg.idx / SRSRAN_NOF_SF_X_FRAME) % 2;
@ -192,6 +198,10 @@ private:
bool schedule_pusch(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
{
if (ul_slots.count(SRSRAN_SLOT_NR_MOD(srsran_subcarrier_spacing_15kHz, slot_cfg.idx + 4)) == 0) {
return true;
}
// Instantiate PDCCH
pdcch_ul_t pdcch = {};
@ -207,7 +217,7 @@ private:
// Fill DCI fields
srsran_dci_ul_nr_t& dci = pdcch.dci;
dci.freq_domain_assigment = ul_freq_res;
dci.time_domain_assigment = ul_time_res;
dci.time_domain_assigment = 0;
dci.freq_hopping_flag = 0;
dci.mcs = mcs;
dci.rv = 0;
@ -255,27 +265,30 @@ private:
public:
struct args_t {
srsran::phy_cfg_nr_t phy_cfg; ///< Physical layer configuration
uint16_t rnti = 0x1234; ///< C-RNTI
uint32_t mcs = 10; ///< Modulation code scheme
uint32_t ss_id = 1; ///< Search Space identifier
uint32_t pdcch_aggregation_level = 0; ///< PDCCH aggregation level
uint32_t pdcch_dl_candidate_index = 0; ///< PDCCH DL DCI candidate index
uint32_t pdcch_ul_candidate_index = 1; ///< PDCCH UL DCI candidate index
uint32_t dl_start_rb = 0; ///< Start resource block
uint32_t dl_length_rb = 0; ///< Number of resource blocks
uint32_t ul_start_rb = 0; ///< Start resource block
uint32_t ul_length_rb = 0; ///< Number of resource blocks
uint32_t dl_time_res = 0; ///< PDSCH time resource
std::string log_level = "debug";
srsran::phy_cfg_nr_t phy_cfg; ///< Physical layer configuration
uint16_t rnti = 0x1234; ///< C-RNTI
uint32_t mcs = 10; ///< Modulation code scheme
uint32_t ss_id = 1; ///< Search Space identifier
uint32_t pdcch_aggregation_level = 0; ///< PDCCH aggregation level
uint32_t pdcch_dl_candidate = 0; ///< PDCCH DL DCI candidate index
uint32_t pdcch_ul_candidate = 1; ///< PDCCH UL DCI candidate index
uint32_t dl_start_rb = 0; ///< Start resource block
uint32_t dl_length_rb = 0; ///< Number of resource blocks
std::string dl_sched_slots = "0,1,2,3,4,5"; ///< PDCH Slot list
uint32_t ul_start_rb = 0; ///< Start resource block
uint32_t ul_length_rb = 0; ///< Number of resource blocks
std::string ul_sched_slots = "6,7,8,9"; ///< Slot list
std::string log_level = "warning";
};
gnb_dummy_stack(args_t args) :
mcs(args.mcs), rnti(args.rnti), dl_time_res(args.dl_time_res), phy_cfg(args.phy_cfg), ss_id(args.ss_id)
gnb_dummy_stack(const args_t& args) : mcs(args.mcs), rnti(args.rnti), phy_cfg(args.phy_cfg), ss_id(args.ss_id)
{
random_gen = srsran_random_init(0x1234);
logger.set_level(srslog::str_to_basic_level(args.log_level));
srsran::string_parse_list(args.dl_sched_slots, ',', dl_slots);
srsran::string_parse_list(args.ul_sched_slots, ',', ul_slots);
// Select DCI locations
for (uint32_t slot = 0; slot < SRSRAN_NOF_SF_X_FRAME; slot++) {
srsran::bounded_vector<srsran_dci_location_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR> locations;
@ -287,24 +300,24 @@ public:
}
// DCI DL
if (args.pdcch_dl_candidate_index >= locations.size()) {
if (args.pdcch_dl_candidate >= locations.size()) {
logger.error("Candidate index %d exceeds the number of candidates %d for aggregation level %d",
args.pdcch_dl_candidate_index,
args.pdcch_dl_candidate,
(uint32_t)locations.size(),
args.pdcch_aggregation_level);
return;
}
dci_dl_location[slot] = locations[args.pdcch_dl_candidate_index];
dci_dl_location[slot] = locations[args.pdcch_dl_candidate];
// DCI UL
if (args.pdcch_ul_candidate_index >= locations.size()) {
if (args.pdcch_ul_candidate >= locations.size()) {
logger.error("Candidate index %d exceeds the number of candidates %d for aggregation level %d",
args.pdcch_ul_candidate_index,
args.pdcch_ul_candidate,
(uint32_t)locations.size(),
args.pdcch_aggregation_level);
return;
}
dci_ul_location[slot] = locations[args.pdcch_ul_candidate_index];
dci_ul_location[slot] = locations[args.pdcch_ul_candidate];
}
// Select DL frequency domain resources

@ -15,11 +15,77 @@
#include "srsran/common/phy_cfg_nr_default.h"
#include "srsran/common/test_common.h"
#include "test_bench.h"
#include <boost/program_options.hpp>
#include <iostream>
// shorten boost program options namespace
namespace bpo = boost::program_options;
test_bench::args_t::args_t(int argc, char** argv)
{
// Flag configuration as valid
valid = true;
bpo::options_description options("Test bench options");
bpo::options_description options_gnb_stack("gNb stack and scheduling related options");
bpo::options_description options_gnb_phy("gNb PHY related options");
bpo::options_description options_ue_stack("UE stack options");
bpo::options_description options_ue_phy("UE stack options");
uint16_t rnti = 0x1234;
// clang-format off
options.add_options()
("rnti", bpo::value<uint16_t>(&rnti)->default_value(rnti), "UE RNTI")
("duration", bpo::value<uint64_t>(&durations_slots)->default_value(durations_slots), "Test duration in slots")
;
options_gnb_stack.add_options()
("gnb.stack.pdcch.aggregation_level", bpo::value<uint32_t>(&gnb_stack.pdcch_aggregation_level)->default_value(gnb_stack.pdcch_aggregation_level), "PDCCH aggregation level")
("gnb.stack.pdsch.candidate", bpo::value<uint32_t>(&gnb_stack.pdcch_dl_candidate)->default_value(gnb_stack.pdcch_dl_candidate), "PDCCH candidate index for PDSCH")
("gnb.stack.pdsch.start", bpo::value<uint32_t>(&gnb_stack.dl_start_rb)->default_value(0), "PDSCH scheduling frequency allocation start")
("gnb.stack.pdsch.length", bpo::value<uint32_t>(&gnb_stack.dl_length_rb)->default_value(gnb_stack.dl_length_rb), "PDSCH scheduling frequency allocation length")
("gnb.stack.pdsch.slots", bpo::value<std::string>(&gnb_stack.dl_sched_slots)->default_value(gnb_stack.dl_sched_slots), "Slots enabled for PDSCH")
("gnb.stack.pusch.candidate", bpo::value<uint32_t>(&gnb_stack.pdcch_ul_candidate)->default_value(gnb_stack.pdcch_ul_candidate), "PDCCH candidate index for PUSCH")
("gnb.stack.pusch.start", bpo::value<uint32_t>(&gnb_stack.ul_start_rb)->default_value(0), "PUSCH scheduling frequency allocation start")
("gnb.stack.pusch.length", bpo::value<uint32_t>(&gnb_stack.ul_length_rb)->default_value(gnb_stack.ul_length_rb), "PUSCH scheduling frequency allocation length")
("gnb.stack.pusch.slots", bpo::value<std::string>(&gnb_stack.ul_sched_slots)->default_value(gnb_stack.ul_sched_slots), "Slots enabled for PUSCH")
("gnb.stack.mcs", bpo::value<uint32_t>(&gnb_stack.mcs)->default_value(gnb_stack.mcs), "PDSCH/PUSCH scheduling modulation code scheme")
("gnb.stack.log_level", bpo::value<std::string>(&gnb_stack.log_level)->default_value(gnb_stack.log_level), "Stack log level")
;
options_gnb_phy.add_options()
("gnb.phy.nof_threads", bpo::value<uint32_t>(&gnb_phy.nof_phy_threads)->default_value(1), "Number of threads")
("gnb.phy.log.level", bpo::value<std::string>(&gnb_phy.log.phy_level)->default_value("warning"), "gNb PHY log level")
("gnb.phy.log.hex_limit", bpo::value<int>(&gnb_phy.log.phy_hex_limit)->default_value(0), "gNb PHY log hex limit")
("gnb.phy.log.id_preamble", bpo::value<std::string>(&gnb_phy.log.id_preamble)->default_value("GNB/"), "gNb PHY log ID preamble")
("gnb.phy.pusch.max_iter", bpo::value<uint32_t>(&gnb_phy.pusch_max_nof_iter)->default_value(10), "PUSCH LDPC max number of iterations")
;
options_ue_phy.add_options()
("ue.phy.nof_threads", bpo::value<uint32_t>(&ue_phy.nof_phy_threads)->default_value(1), "Number of threads")
("ue.phy.log.level", bpo::value<std::string>(&ue_phy.log.phy_level)->default_value("warning"), "UE PHY log level")
("ue.phy.log.hex_limit", bpo::value<int>(&ue_phy.log.phy_hex_limit)->default_value(0), "UE PHY log hex limit")
("ue.phy.log.id_preamble", bpo::value<std::string>(&ue_phy.log.id_preamble)->default_value(" UE/"), "UE PHY log ID preamble")
;
options.add(options_gnb_stack).add(options_gnb_phy).add(options_ue_stack).add(options_ue_phy).add_options()
("help", "Show this message")
;
// clang-format on
bpo::variables_map vm;
try {
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
bpo::notify(vm);
} catch (bpo::error& e) {
std::cerr << e.what() << std::endl;
return;
}
// help option was given or error - print usage and exit
if (vm.count("help")) {
std::cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << std::endl << std::endl;
std::cout << options << std::endl << std::endl;
return;
}
// Load default reference configuration
srsran::phy_cfg_nr_default_t::reference_cfg_t reference_cfg;
@ -30,6 +96,22 @@ test_bench::args_t::args_t(int argc, char** argv)
cell_list[0].rf_port = 0;
cell_list[0].cell_id = 0;
cell_list[0].pdcch = phy_cfg.pdcch;
ue_stack.rnti = rnti;
gnb_stack.rnti = rnti;
gnb_stack.phy_cfg = phy_cfg;
if (gnb_stack.dl_length_rb == 0) {
gnb_stack.dl_length_rb = phy_cfg.carrier.nof_prb;
}
if (gnb_stack.ul_length_rb == 0) {
gnb_stack.ul_length_rb = phy_cfg.carrier.nof_prb;
}
// Flag configuration as valid
valid = true;
}
int main(int argc, char** argv)
@ -38,48 +120,19 @@ int main(int argc, char** argv)
// Parse test bench arguments
test_bench::args_t args(argc, argv);
args.gnb_args.log_id_preamble = "GNB/";
args.gnb_args.log_level = "info";
args.gnb_args.nof_phy_threads = 1;
args.ue_args.log.id_preamble = " UE/";
args.ue_args.log.phy_level = "info";
args.ue_args.log.phy_hex_limit = 1;
args.ue_args.nof_phy_threads = 1;
// Parse arguments
TESTASSERT(args.valid);
// Create UE stack arguments
ue_dummy_stack::args_t ue_stack_args = {};
ue_stack_args.rnti = 0x1234;
// Create UE stack
ue_dummy_stack ue_stack(ue_stack_args);
TESTASSERT(ue_stack.is_valid());
// Create GNB stack arguments
gnb_dummy_stack::args_t gnb_stack_args = {};
gnb_stack_args.rnti = 0x1234;
gnb_stack_args.mcs = 10;
gnb_stack_args.phy_cfg = args.phy_cfg;
gnb_stack_args.dl_start_rb = 0;
gnb_stack_args.dl_length_rb = args.phy_cfg.carrier.nof_prb;
gnb_stack_args.ul_start_rb = 0;
gnb_stack_args.ul_length_rb = args.phy_cfg.carrier.nof_prb;
// Create GNB stack
gnb_dummy_stack gnb_stack(gnb_stack_args);
TESTASSERT(gnb_stack.is_valid());
// Create test bench
test_bench tb(args, gnb_stack, ue_stack);
test_bench tb(args);
// Assert bench is initialised correctly
TESTASSERT(tb.is_initialised());
// Run per TTI basis
for (uint32_t i = 0; i < 1000; i++) {
TESTASSERT(tb.run_tti());
while (tb.run_tti()) {
; // Do nothing
}
// Stop test bench
@ -89,7 +142,7 @@ int main(int argc, char** argv)
srslog::flush();
// Retrieve MAC metrics
srsenb::mac_ue_metrics_t mac_metrics = gnb_stack.get_metrics();
srsenb::mac_ue_metrics_t mac_metrics = tb.get_gnb_metrics();
// Print metrics
float pdsch_bler = 0.0f;

@ -22,9 +22,13 @@ class test_bench
private:
const std::string UE_PHY_COM_LOG_NAME = "UE /PHY/COM";
const std::string GNB_PHY_COM_LOG_NAME = "GNB/PHY/COM";
uint32_t tti = 0;
uint32_t slot_idx = 0;
uint64_t slot_count = 0;
uint64_t duration_slots;
gnb_dummy_stack gnb_stack;
srsenb::nr::worker_pool gnb_phy;
phy_common gnb_phy_com;
ue_dummy_stack ue_stack;
srsue::nr::worker_pool ue_phy;
phy_common ue_phy_com;
bool initialised = false;
@ -38,32 +42,38 @@ public:
bool valid = false;
srsran::phy_cfg_nr_t phy_cfg = {};
srsenb::phy_cell_cfg_list_nr_t cell_list = {};
srsenb::nr::worker_pool::args_t gnb_args;
srsue::phy_args_nr_t ue_args;
uint16_t rnti = 0x1234;
srsenb::nr::worker_pool::args_t gnb_phy;
gnb_dummy_stack::args_t gnb_stack;
srsue::phy_args_nr_t ue_phy;
ue_dummy_stack::args_t ue_stack;
std::string phy_com_log_level = "info";
uint64_t durations_slots = 100;
args_t(int argc, char** argv);
};
test_bench(const args_t& args, srsenb::stack_interface_phy_nr& gnb_stack, srsue::stack_interface_phy_nr& ue_stack) :
ue_phy(args.ue_args.nof_phy_threads),
gnb_phy(gnb_phy_com, gnb_stack, srslog::get_default_sink(), args.gnb_args.nof_phy_threads),
test_bench(const args_t& args) :
gnb_stack(args.gnb_stack),
gnb_phy(gnb_phy_com, gnb_stack, srslog::get_default_sink(), args.gnb_phy.nof_phy_threads),
ue_stack(args.ue_stack),
ue_phy(args.ue_phy.nof_phy_threads),
ue_phy_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels),
srslog::fetch_basic_logger(UE_PHY_COM_LOG_NAME, srslog::get_default_sink(), false)),
gnb_phy_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels),
srslog::fetch_basic_logger(GNB_PHY_COM_LOG_NAME, srslog::get_default_sink(), false)),
sf_sz((uint32_t)std::round(args.srate_hz * 1e-3))
sf_sz((uint32_t)std::round(args.srate_hz * 1e-3)),
duration_slots(args.durations_slots)
{
srslog::fetch_basic_logger(UE_PHY_COM_LOG_NAME).set_level(srslog::str_to_basic_level(args.phy_com_log_level));
srslog::fetch_basic_logger(GNB_PHY_COM_LOG_NAME).set_level(srslog::str_to_basic_level(args.phy_com_log_level));
if (not gnb_phy.init(args.gnb_args, args.cell_list)) {
if (not gnb_phy.init(args.gnb_phy, args.cell_list)) {
return;
}
// Initialise UE PHY
if (not ue_phy.init(args.ue_args, ue_phy_com, &ue_stack, 31)) {
if (not ue_phy.init(args.ue_phy, ue_phy_com, &ue_stack, 31)) {
return;
}
@ -85,12 +95,12 @@ public:
~test_bench() = default;
bool is_initialised() const { return initialised; }
bool is_initialised() const { return ue_stack.is_valid() and gnb_stack.is_valid() and initialised; }
bool run_tti()
{
// Get gNb worker
srsenb::nr::slot_worker* gnb_worker = gnb_phy.wait_worker(tti);
srsenb::nr::slot_worker* gnb_worker = gnb_phy.wait_worker(slot_idx);
if (gnb_worker == nullptr) {
return false;
}
@ -103,14 +113,14 @@ public:
// Set gNb time
gnb_time.add(TX_ENB_DELAY * 1e-3);
gnb_worker->set_time(tti, gnb_time);
gnb_worker->set_time(slot_idx, gnb_time);
// Start gNb work
gnb_phy_com.push_semaphore(gnb_worker);
gnb_phy.start_worker(gnb_worker);
// Get UE worker
srsue::nr::sf_worker* ue_worker = ue_phy.wait_worker(tti);
srsue::nr::sf_worker* ue_worker = ue_phy.wait_worker(slot_idx);
if (ue_worker == nullptr) {
return false;
}
@ -123,16 +133,19 @@ public:
// Set UE time
ue_time.add(TX_ENB_DELAY * 1e-3);
ue_worker->set_tti(tti);
ue_worker->set_tti(slot_idx);
ue_worker->set_tx_time(ue_time);
// Start gNb work
ue_phy_com.push_semaphore(ue_worker);
ue_phy.start_worker(ue_worker);
tti++;
return true;
slot_count++;
slot_idx = slot_count % (1024 * SRSRAN_NSLOTS_PER_FRAME_NR(srsran_subcarrier_spacing_15kHz));
return slot_count <= duration_slots;
}
srsenb::mac_ue_metrics_t get_gnb_metrics() { return gnb_stack.get_metrics(); }
};
#endif // SRSRAN_TEST_BENCH_H

Loading…
Cancel
Save