sched,optimization,refactor - use of custom formatter that avoids mallocs for getting bitmasks strings in hex and binary formats

This commit is contained in:
Francisco 2021-03-08 22:36:32 +00:00 committed by Francisco Paisana
parent a03c78a777
commit d77b6e1d9c
8 changed files with 130 additions and 47 deletions

View File

@ -14,6 +14,7 @@
#define SRSLTE_DYN_BITSET_H
#include "adt_utils.h"
#include "srslte/srslog/bundled/fmt/format.h"
#include <cstdint>
#include <inttypes.h>
#include <string>
@ -219,24 +220,25 @@ public:
return ret;
}
std::string to_string() const
template <typename OutputIt>
OutputIt to_string(OutputIt&& mem_buffer) const
{
if (size() == 0) {
return mem_buffer;
}
std::string s;
s.assign(size(), '0');
if (not reversed) {
for (size_t i = size(); i > 0; --i) {
if (test(i - 1)) {
s[size() - i] = '1';
}
fmt::format_to(mem_buffer, "{}", test(i - 1) ? '1' : '0');
}
} else {
for (size_t i = 0; i < size(); ++i) {
if (test(i)) {
s[i] = '1';
}
fmt::format_to(mem_buffer, "{}", test(i) ? '1' : '0');
}
}
return s;
return mem_buffer;
}
uint64_t to_uint64() const
@ -248,19 +250,21 @@ public:
return get_word_(0);
}
std::string to_hex() const noexcept
template <typename OutputIt>
OutputIt to_hex(OutputIt&& mem_buffer) const noexcept
{
size_t nof_digits = (size() - 1) / 4 + 1;
char cstr[ceil_div(ceil_div(N, bits_per_word) * bits_per_word, 4) + 1];
size_t count = 0;
for (int i = nof_words_() - 1; i >= 0; --i) {
count += sprintf(&cstr[count], "%016" PRIx64, buffer[i]);
if (size() == 0) {
return mem_buffer;
}
size_t skip = nof_words_() * bits_per_word / 4 - nof_digits;
// printf("bitstring: %s\n", to_string().c_str());
return std::string(&cstr[skip], &cstr[nof_digits + skip + 1]);
// first word may not print 16 hex digits
int i = nof_words_() - 1;
size_t rem_symbols = ceil_div((size() - (size() / bits_per_word) * bits_per_word), 4U);
fmt::format_to(mem_buffer, "{:0>{}x}", buffer[i], rem_symbols);
// remaining words will occupy 16 hex digits
for (--i; i >= 0; --i) {
fmt::format_to(mem_buffer, "{:0>16x}", buffer[i]);
}
return mem_buffer;
}
private:
@ -318,7 +322,7 @@ private:
template <size_t N, bool reversed>
inline bounded_bitset<N, reversed> operator&(const bounded_bitset<N, reversed>& lhs,
const bounded_bitset<N, reversed>& rhs)noexcept
const bounded_bitset<N, reversed>& rhs) noexcept
{
bounded_bitset<N, reversed> res(lhs);
res &= rhs;
@ -348,4 +352,34 @@ inline bounded_bitset<N, reversed> fliplr(const bounded_bitset<N, reversed>& oth
} // namespace srslte
/// Custom formatter for bounded_bitset<N, reversed>
template <size_t N, bool reversed>
struct fmt::formatter<srslte::bounded_bitset<N, reversed> > {
enum { hexadecimal, binary } mode = binary;
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin())
{
auto it = ctx.begin();
while (*it != '\0' and *it != '}') {
if (*it == 'x') {
mode = hexadecimal;
}
++it;
}
return it;
}
template <typename FormatContext>
auto format(const srslte::bounded_bitset<N, reversed>& s, FormatContext& ctx)
-> decltype(std::declval<FormatContext>().out())
{
if (mode == hexadecimal) {
return s.template to_hex(ctx.out());
}
return s.template to_string(ctx.out());
}
};
#endif // SRSLTE_DYN_BITSET_H

View File

@ -27,6 +27,7 @@ public:
using iterator = T*;
using const_iterator = const T*;
using size_type = std::size_t;
using value_type = T;
bounded_vector() = default;
template <typename std::enable_if<std::is_default_constructible<T>::value, int>::type = 0>

View File

@ -95,7 +95,7 @@ int test_bitset_bitwise_oper()
try {
mask2 |= mask;
} catch (srslte::bad_type_access& c) {
printf("Received exception \"%s\"\n", c.what());
printf("Received exception \"%s\" as expected\n", c.what());
caught = true;
}
TESTASSERT(caught);
@ -104,11 +104,46 @@ int test_bitset_bitwise_oper()
return SRSLTE_SUCCESS;
}
int test_bitset_print()
{
{
srslte::bounded_bitset<100> bitset(100);
bitset.set(0);
bitset.set(5);
TESTASSERT(fmt::format("{:x}", bitset) == "0000000000000000000000021");
TESTASSERT(fmt::format("{:b}", bitset) ==
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001");
bitset.set(99);
TESTASSERT(fmt::format("{:x}", bitset) == "8000000000000000000000021");
TESTASSERT(fmt::format("{:b}", bitset) ==
"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001");
}
{
srslte::bounded_bitset<100> bitset(25);
bitset.set(0);
bitset.set(4);
TESTASSERT(fmt::format("{:x}", bitset) == "0000011");
TESTASSERT(fmt::format("{:b}", bitset) == "0000000000000000000010001");
bitset.set(24);
TESTASSERT(fmt::format("{:x}", bitset) == "1000011");
TESTASSERT(fmt::format("{:b}", bitset) == "1000000000000000000010001");
}
return SRSLTE_SUCCESS;
}
int main()
{
TESTASSERT(test_zero_bitset() == SRSLTE_SUCCESS);
TESTASSERT(test_ones_bitset() == SRSLTE_SUCCESS);
TESTASSERT(test_bitset_set() == SRSLTE_SUCCESS);
TESTASSERT(test_bitset_bitwise_oper() == SRSLTE_SUCCESS);
TESTASSERT(test_bitset_print() == SRSLTE_SUCCESS);
printf("Success\n");
return 0;
}

View File

@ -32,7 +32,7 @@ public:
pdcch_mask_t total_mask; ///< Accumulation of all PDCCH masks for the current solution (tree route)
prbmask_t total_pucch_mask; ///< Accumulation of all PUCCH masks for the current solution/tree route
};
using alloc_result_t = std::vector<const alloc_t*>;
using alloc_result_t = srslte::bounded_vector<const alloc_t*, 16>;
sf_cch_allocator() : logger(srslog::fetch_basic_logger("MAC")) {}

View File

@ -156,9 +156,9 @@ void sf_grid_t::new_tti(tti_point tti_rx_)
prbmask_t prach_mask{cc_cfg->nof_prb()};
prach_mask.fill(cc_cfg->cfg.prach_freq_offset, cc_cfg->cfg.prach_freq_offset + 6);
reserve_ul_prbs(prach_mask, false); // TODO: set to true once test sib.conf files are updated
logger.debug("SCHED: Allocated PRACH RBs for tti_tx_ul=%d. Mask: 0x%s",
to_tx_ul(tti_rx).to_uint(),
prach_mask.to_hex().c_str());
fmt::memory_buffer buffer;
prach_mask.to_hex(buffer);
logger.debug("SCHED: Allocated PRACH RBs for tti_tx_ul=%d. Mask: 0x%s", to_tx_ul(tti_rx).to_uint(), buffer.data());
}
// internal state
@ -281,9 +281,12 @@ alloc_outcome_t sf_grid_t::reserve_ul_prbs(const prbmask_t& prbmask, bool strict
{
alloc_outcome_t ret = alloc_outcome_t::SUCCESS;
if (strict and (ul_mask & prbmask).any()) {
fmt::memory_buffer ulmask_buffer, prbmask_buffer;
ul_mask.to_hex(ulmask_buffer);
prbmask.to_hex(prbmask_buffer);
logger.error("There was a collision in UL channel. current mask=0x%s, new alloc mask=0x%s",
ul_mask.to_hex().c_str(),
prbmask.to_hex().c_str());
ulmask_buffer.data(),
prbmask_buffer.data());
ret = alloc_outcome_t::ERROR;
}
ul_mask |= prbmask;
@ -826,23 +829,27 @@ void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t&
data_alloc.pid, data, get_tti_tx_dl(), cc_cfg->enb_cc_idx, tti_alloc.get_cfi(), data_alloc.user_mask);
if (tbs <= 0) {
fmt::memory_buffer buffer;
data_alloc.user_mask.to_hex(buffer);
logger.warning("SCHED: DL %s failed rnti=0x%x, pid=%d, mask=%s, tbs=%d, buffer=%d",
is_newtx ? "tx" : "retx",
user->get_rnti(),
data_alloc.pid,
data_alloc.user_mask.to_hex().c_str(),
buffer.data(),
tbs,
user->get_requested_dl_bytes(cc_cfg->enb_cc_idx).stop());
continue;
}
// Print Resulting DL Allocation
logger.info("SCHED: DL %s rnti=0x%x, cc=%d, pid=%d, mask=0x%s, dci=(%d,%d), n_rtx=%d, tbs=%d, buffer=%d/%d",
fmt::memory_buffer buffer;
data_alloc.user_mask.to_hex(buffer);
logger.info("SCHED: DL %s rnti=0x%x, cc=%d, pid=%d, mask=%s, dci=(%d,%d), n_rtx=%d, tbs=%d, buffer=%d/%d",
!is_newtx ? "retx" : "tx",
user->get_rnti(),
cc_cfg->enb_cc_idx,
data_alloc.pid,
data_alloc.user_mask.to_hex().c_str(),
buffer.data(),
data->dci.location.L,
data->dci.location.ncce,
dl_harq.nof_retx(0) + dl_harq.nof_retx(1),

View File

@ -15,10 +15,10 @@
#include "srslte/srslog/bundled/fmt/format.h"
#include <array>
#define Debug(fmt, ...) srslog::fetch_basic_logger("MAC").debug(fmt, ##__VA_ARGS__)
#define Info(fmt, ...) srslog::fetch_basic_logger("MAC").info(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) srslog::fetch_basic_logger("MAC").warning(fmt, ##__VA_ARGS__)
#define Error(fmt, ...) srslog::fetch_basic_logger("MAC").error(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) get_mac_logger().debug(fmt, ##__VA_ARGS__)
#define Info(fmt, ...) get_mac_logger().info(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) get_mac_logger().warning(fmt, ##__VA_ARGS__)
#define Error(fmt, ...) get_mac_logger().error(fmt, ##__VA_ARGS__)
namespace srsenb {
@ -26,6 +26,12 @@ using dl_sched_res_t = sched_interface::dl_sched_res_t;
using dl_sched_data_t = sched_interface::dl_sched_data_t;
using custom_mem_buffer = fmt::basic_memory_buffer<char, 1024>;
srslog::basic_logger& get_mac_logger()
{
static srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("MAC");
return mac_logger;
}
const char* to_string_short(srslte_dci_format_t dcifmt)
{
switch (dcifmt) {

View File

@ -307,15 +307,15 @@ std::string sf_cch_allocator::alloc_tree_t::result_to_string(bool verbose) const
pdcch_mask_t tot_mask;
get_allocs(&vec, &tot_mask, i - prev_start);
fmt::format_to(strbuf, "[{}]: total mask=0x{}", count, tot_mask.to_hex().c_str());
fmt::format_to(strbuf, "[{}]: total mask=0x{:x}", count, tot_mask);
if (verbose) {
fmt::format_to(strbuf, ", allocations:\n");
for (const auto& dci_alloc : vec) {
fmt::format_to(strbuf,
" > rnti=0x{:0x}: 0x{} / 0x{}\n",
" > rnti=0x{:0x}: 0x{:x} / 0x{:x}\n",
dci_alloc->rnti,
dci_alloc->current_mask.to_hex().c_str(),
dci_alloc->total_mask.to_hex().c_str());
dci_alloc->current_mask,
dci_alloc->total_mask);
}
} else {
fmt::format_to(strbuf, "\n");

View File

@ -32,7 +32,7 @@ int test_pusch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co
TESTERROR("Collision Detected of %s alloc=%s and cumulative_mask=0x%s",
ch_str,
alloc.to_string().c_str(),
ul_allocs.to_hex().c_str());
fmt::format("{:x}", ul_allocs).c_str());
}
ul_allocs.fill(alloc.start(), alloc.stop(), true);
return SRSLTE_SUCCESS;
@ -64,8 +64,8 @@ int test_pusch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co
CONDERROR(expected_ul_mask != nullptr and *expected_ul_mask != ul_allocs,
"The derived UL PRB mask %s does not match the expected one %s",
ul_allocs.to_string().c_str(),
expected_ul_mask->to_string().c_str());
fmt::format("{}", ul_allocs).c_str(),
fmt::format("{}", *expected_ul_mask).c_str());
return SRSLTE_SUCCESS;
}
@ -105,8 +105,8 @@ int test_pdsch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co
if ((dl_allocs & alloc_mask).any()) {
TESTERROR("Detected collision in the DL %s allocation (%s intersects %s)",
channel,
dl_allocs.to_string().c_str(),
alloc_mask.to_string().c_str());
fmt::format("{}", dl_allocs).c_str(),
fmt::format("{}", alloc_mask).c_str());
}
dl_allocs |= alloc_mask;
return SRSLTE_SUCCESS;
@ -150,8 +150,8 @@ int test_pdsch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co
CONDERROR(expected_rbgmask != nullptr and *expected_rbgmask != rbgmask,
"The derived DL RBG mask %s does not match the expected one %s",
rbgmask.to_string().c_str(),
expected_rbgmask->to_string().c_str());
fmt::format("{}", rbgmask).c_str(),
fmt::format("{}", *expected_rbgmask).c_str());
return SRSLTE_SUCCESS;
}
@ -246,8 +246,8 @@ int test_pdcch_collisions(const sf_output_res_t& sf_out,
CONDERROR(expected_cce_mask != nullptr and *expected_cce_mask != used_cce,
"The derived PDCCH mask %s does not match the expected one %s",
used_cce.to_string().c_str(),
expected_cce_mask->to_string().c_str());
fmt::format("{}", used_cce).c_str(),
fmt::format("{}", *expected_cce_mask).c_str());
return SRSLTE_SUCCESS;
}