gnb,nr: add metrics for ack'd TBS in the gNB.

This commit is contained in:
Francisco 2021-10-08 18:05:38 +01:00 committed by Francisco Paisana
parent 479df12775
commit 877b995a4d
13 changed files with 123 additions and 40 deletions

View File

@ -123,7 +123,9 @@ private:
srsran::task_multiqueue::queue_handle sync_task_queue, ue_task_queue, gtpu_task_queue, mac_task_queue,
metrics_task_queue;
srsran::dyn_blocking_queue<stack_metrics_t> pending_stack_metrics;
// metrics waiting condition
std::mutex metrics_mutex;
std::condition_variable metrics_cvar;
// derived
srsenb::mac_nr mac;

View File

@ -82,6 +82,9 @@ private:
// PDU processing
int handle_pdu(srsran::unique_byte_buffer_t pdu);
// Metrics processing
void get_metrics_nolock(srsenb::mac_metrics_t& metrics);
// Encoding
srsran::byte_buffer_t* assemble_rar(srsran::const_span<sched_nr_interface::sched_rar_grant_t> grants);
srsran::unique_byte_buffer_t rar_pdu_buffer = nullptr;
@ -124,6 +127,11 @@ private:
// Number of rach preambles detected for a CC
std::vector<uint32_t> detected_rachs;
// Metrics
std::mutex metrics_mutex;
std::condition_variable metrics_condvar;
srsenb::mac_metrics_t* metrics_pending = nullptr;
};
} // namespace srsenb

View File

@ -51,7 +51,7 @@ public:
void ul_bsr(uint16_t rnti, uint32_t lcg_id, uint32_t bsr) override;
void dl_buffer_state(uint16_t rnti, uint32_t lcid, uint32_t newtx, uint32_t retx);
int get_dl_sched(slot_point pdsch_tti, uint32_t cc, dl_sched_res_t& result) override;
int run_slot(slot_point pdsch_tti, uint32_t cc, dl_sched_res_t& result, mac_metrics_t* metrics = nullptr) override;
int get_ul_sched(slot_point pusch_tti, uint32_t cc, ul_sched_t& result) override;
private:

View File

@ -33,6 +33,8 @@ const static size_t SCHED_NR_MAX_BWP_PER_CELL = 2;
const static size_t SCHED_NR_MAX_LCID = 32;
const static size_t SCHED_NR_MAX_LC_GROUP = 7;
struct mac_metrics_t;
class sched_nr_interface
{
public:
@ -123,7 +125,7 @@ public:
virtual void ue_cfg(uint16_t rnti, const ue_cfg_t& ue_cfg) = 0;
virtual void ue_rem(uint16_t rnti) = 0;
virtual bool ue_exists(uint16_t rnti) = 0;
virtual int get_dl_sched(slot_point slot_rx, uint32_t cc, dl_sched_res_t& result) = 0;
virtual int run_slot(slot_point slot_rx, uint32_t cc, dl_sched_res_t& result, mac_metrics_t* metrics = nullptr) = 0;
virtual int get_ul_sched(slot_point slot_rx, uint32_t cc, ul_sched_t& result) = 0;
virtual void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) = 0;

View File

@ -16,6 +16,7 @@
#include "sched_nr_cfg.h"
#include "sched_nr_harq.h"
#include "sched_nr_interface.h"
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsenb/hdr/stack/mac/common/ue_buffer_manager.h"
#include "srsran/adt/circular_map.h"
#include "srsran/adt/move_callback.h"
@ -73,6 +74,9 @@ public:
harq_entity harq_ent;
// metrics
mac_ue_metrics_t metrics = {};
private:
bwp_ue_cfg bwp_cfg;
const sched_cell_params& cell_params;

View File

@ -25,6 +25,9 @@
#include <mutex>
namespace srsenb {
struct mac_metrics_t;
namespace sched_nr_impl {
using dl_sched_t = sched_nr_interface::dl_sched_t;
@ -92,7 +95,7 @@ public:
sched_worker_manager(sched_worker_manager&&) = delete;
~sched_worker_manager();
void run_slot(slot_point slot_tx, uint32_t cc, dl_sched_res_t& dl_res, ul_sched_t& ul_res);
void run_slot(slot_point slot_tx, uint32_t cc, dl_sched_res_t& dl_res, ul_sched_t& ul_res, mac_metrics_t* metrics);
void enqueue_event(uint16_t rnti, srsran::move_callback<void()> ev);
void enqueue_cc_event(uint32_t cc, srsran::move_callback<void()> ev);
@ -103,7 +106,7 @@ public:
private:
void update_ue_db(slot_point slot_tx, bool locked_context);
void get_metrics(mac_metrics_t& metrics);
bool save_sched_result(slot_point pdcch_slot, uint32_t cc, dl_sched_res_t& dl_res, ul_sched_t& ul_res);
const sched_params& cfg;

View File

@ -25,7 +25,6 @@ gnb_stack_nr::gnb_stack_nr(srslog::sink& log_sink) :
pdcp_logger(srslog::fetch_basic_logger("PDCP-NR", log_sink, false)),
rrc_logger(srslog::fetch_basic_logger("RRC-NR", log_sink, false)),
stack_logger(srslog::fetch_basic_logger("STCK-NR", log_sink, false)),
pending_stack_metrics(64),
mac(&task_sched),
rrc(&task_sched),
pdcp(&task_sched, pdcp_logger),
@ -141,22 +140,28 @@ void gnb_stack_nr::process_pdus() {}
bool gnb_stack_nr::get_metrics(srsenb::stack_metrics_t* metrics)
{
// use stack thread to query metrics
auto ret = metrics_task_queue.try_push([this]() {
srsenb::stack_metrics_t metrics{};
mac.get_metrics(metrics.mac);
rrc.get_metrics(metrics.rrc);
if (not pending_stack_metrics.try_push(std::move(metrics))) {
stack_logger.error("Unable to push metrics to queue");
}
});
bool metrics_ready = false;
if (ret.has_value()) {
// wait for result
*metrics = pending_stack_metrics.pop_blocking();
return true;
// use stack thread to query RRC metrics
auto ret = metrics_task_queue.try_push([this, metrics, &metrics_ready]() {
rrc.get_metrics(metrics->rrc);
{
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics_ready = true;
}
metrics_cvar.notify_one();
});
if (not ret.has_value()) {
return false;
}
// obtain MAC metrics (do not use stack thread)
mac.get_metrics(metrics->mac);
// wait for RRC result
std::unique_lock<std::mutex> lock(metrics_mutex);
metrics_cvar.wait(lock, [&metrics_ready]() { return metrics_ready; });
return true;
}
// Temporary GW interface

View File

@ -588,7 +588,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list)
return 0;
}
trace_threshold_complete_event("mac::get_dl_sched", "total_time", std::chrono::microseconds(100));
trace_threshold_complete_event("mac::run_slot", "total_time", std::chrono::microseconds(100));
logger.set_context(TTI_SUB(tti_tx_dl, FDD_HARQ_DELAY_UL_MS));
if (do_padding) {
add_padding();

View File

@ -76,7 +76,18 @@ void mac_nr::stop()
}
}
/// Called from metrics thread
void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics)
{
// Requests asynchronously MAC metrics
std::unique_lock<std::mutex> lock(metrics_mutex);
metrics_pending = &metrics;
// Blocks waiting for results
metrics_condvar.wait(lock, [this]() { return metrics_pending == nullptr; });
}
void mac_nr::get_metrics_nolock(srsenb::mac_metrics_t& metrics)
{
srsran::rwlock_read_guard lock(rwlock);
metrics.ues.reserve(ue_db.size());
@ -274,10 +285,26 @@ int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched
slot_point pdsch_slot = srsran::slot_point{NUMEROLOGY_IDX, slot_cfg.idx};
sched_nr_interface::dl_sched_res_t dl_res;
int ret = sched.get_dl_sched(pdsch_slot, 0, dl_res);
// Get metrics if requested
{
std::unique_lock<std::mutex> metrics_lock(metrics_mutex);
if (metrics_pending != nullptr) {
get_metrics_nolock(*metrics_pending);
}
// Run Scheduler
int ret = sched.run_slot(pdsch_slot, 0, dl_res, metrics_pending);
// Notify metrics are filled, if requested
if (metrics_pending != nullptr) {
metrics_pending = nullptr;
metrics_condvar.notify_one();
}
if (ret != SRSRAN_SUCCESS) {
return ret;
}
}
dl_sched = dl_res.dl_sched;
uint32_t rar_count = 0;

View File

@ -11,6 +11,7 @@
*/
#include "srsenb/hdr/stack/mac/nr/sched_nr.h"
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsenb/hdr/stack/mac/nr/harq_softbuffer.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_cell.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_worker.h"
@ -123,13 +124,13 @@ void sched_nr::ue_cfg_impl(uint16_t rnti, const ue_cfg_t& uecfg)
}
/// Generate {pdcch_slot,cc} scheduling decision
int sched_nr::get_dl_sched(slot_point slot_dl, uint32_t cc, dl_sched_res_t& result)
int sched_nr::run_slot(slot_point slot_dl, uint32_t cc, dl_sched_res_t& result, mac_metrics_t* metrics)
{
// Copy UL results to intermediate buffer
ul_sched_t& ul_res = pending_results->add_ul_result(slot_dl, cc);
// Generate {slot_idx,cc} result
sched_workers->run_slot(slot_dl, cc, result, ul_res);
sched_workers->run_slot(slot_dl, cc, result, ul_res, metrics);
return SRSRAN_SUCCESS;
}
@ -156,7 +157,15 @@ int sched_nr::dl_rach_info(uint32_t cc, const dl_sched_rar_info_t& rar_info)
void sched_nr::dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack)
{
sched_workers->enqueue_cc_feedback(rnti, cc, [this, pid, tb_idx, ack](ue_carrier& ue_cc) {
if (ue_cc.harq_ent.dl_ack_info(pid, tb_idx, ack) != SRSRAN_SUCCESS) {
int tbs = ue_cc.harq_ent.dl_ack_info(pid, tb_idx, ack);
if (tbs >= 0) {
if (ack) {
ue_cc.metrics.tx_brate += tbs * 8;
} else {
ue_cc.metrics.tx_errors++;
}
ue_cc.metrics.tx_pkts++;
} else {
logger->warning("SCHED: rnti=0x%x, received DL HARQ-ACK for empty pid=%d", ue_cc.rnti, pid);
}
});

View File

@ -25,7 +25,7 @@ int harq_proc::ack_info(uint32_t tb_idx, bool ack)
if (ack) {
tb[tb_idx].active = false;
}
return SRSRAN_SUCCESS;
return tb[tb_idx].tbs;
}
void harq_proc::new_slot(slot_point slot_rx)

View File

@ -11,6 +11,7 @@
*/
#include "srsenb/hdr/stack/mac/nr/sched_nr_worker.h"
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_signalling.h"
#include "srsran/common/string_helpers.h"
@ -255,7 +256,11 @@ void sched_worker_manager::update_ue_db(slot_point slot_tx, bool locked_context)
}
}
void sched_worker_manager::run_slot(slot_point slot_tx, uint32_t cc, dl_sched_res_t& dl_res, ul_sched_t& ul_res)
void sched_worker_manager::run_slot(slot_point slot_tx,
uint32_t cc,
dl_sched_res_t& dl_res,
ul_sched_t& ul_res,
mac_metrics_t* metrics)
{
// Fill DL signalling messages that do not depend on UEs state
serv_cell_manager& serv_cell = *cells[cc];
@ -284,6 +289,11 @@ void sched_worker_manager::run_slot(slot_point slot_tx, uint32_t cc, dl_sched_re
}
update_ue_db(slot_tx, true);
// Obtain MAC metrics if requested
if (metrics != nullptr) {
get_metrics(*metrics);
}
// mark the start of slot. awake remaining workers if locking on the mutex
current_slot = slot_tx;
worker_count.store(static_cast<int>(cc_worker_list.size()), std::memory_order_relaxed);
@ -359,5 +369,18 @@ bool sched_worker_manager::save_sched_result(slot_point pdcch_slot,
return true;
}
void sched_worker_manager::get_metrics(mac_metrics_t& metrics)
{
for (mac_ue_metrics_t& ue_metric : metrics.ues) {
if (ue_db.contains(ue_metric.rnti) and ue_db[ue_metric.rnti]->carriers[0] != nullptr) {
auto& ue_cc = *ue_db[ue_metric.rnti]->carriers[0];
ue_metric.tx_brate = ue_cc.metrics.tx_brate;
ue_metric.tx_errors = ue_cc.metrics.tx_errors;
ue_metric.tx_pkts = ue_cc.metrics.tx_pkts;
ue_cc.metrics = {};
}
}
}
} // namespace sched_nr_impl
} // namespace srsenb

View File

@ -103,7 +103,7 @@ void sched_nr_cfg_serialized_test()
sched_nr_interface::dl_sched_res_t dl_res;
sched_nr_interface::ul_sched_t ul_res;
auto tp1 = std::chrono::steady_clock::now();
TESTASSERT(sched_tester.get_sched()->get_dl_sched(slot_tx, cc, dl_res) == SRSRAN_SUCCESS);
TESTASSERT(sched_tester.get_sched()->run_slot(slot_tx, cc, dl_res) == SRSRAN_SUCCESS);
TESTASSERT(sched_tester.get_sched()->get_ul_sched(slot_tx, cc, ul_res) == SRSRAN_SUCCESS);
auto tp2 = std::chrono::steady_clock::now();
count_per_cc[cc] += std::chrono::duration_cast<std::chrono::nanoseconds>(tp2 - tp1).count();
@ -155,7 +155,7 @@ void sched_nr_cfg_parallel_cc_test()
sched_nr_interface::dl_sched_res_t dl_res;
sched_nr_interface::ul_sched_t ul_res;
auto tp1 = std::chrono::steady_clock::now();
TESTASSERT(sched_tester.get_sched()->get_dl_sched(slot_tx, cc, dl_res) == SRSRAN_SUCCESS);
TESTASSERT(sched_tester.get_sched()->run_slot(slot_tx, cc, dl_res) == SRSRAN_SUCCESS);
TESTASSERT(sched_tester.get_sched()->get_ul_sched(slot_tx, cc, ul_res) == SRSRAN_SUCCESS);
auto tp2 = std::chrono::steady_clock::now();
nano_count[cc].fetch_add(std::chrono::duration_cast<std::chrono::nanoseconds>(tp2 - tp1).count(),