Skip to content

Commit 964ca28

Browse files
committed
sched: wrote basic unit test for harq manager
1 parent 635be41 commit 964ca28

File tree

4 files changed

+145
-8
lines changed

4 files changed

+145
-8
lines changed

lib/scheduler/ue_scheduling/cell_harq_manager.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ cell_harq_repository<IsDl>::cell_harq_repository(unsigned max_ues,
3232
ues[i].free_harq_ids.reserve(MAX_NOF_HARQS);
3333
ues[i].harqs.resize(MAX_NOF_HARQS, INVALID_HARQ_REF_INDEX);
3434
}
35+
36+
const unsigned RING_SIZE = 40; // TODO: use function to define this value.
37+
harq_timeout_wheel.resize(RING_SIZE);
3538
}
3639

3740
template <bool IsDl>
@@ -240,7 +243,7 @@ unsigned cell_harq_repository<IsDl>::find_ue_harq_in_state(du_ue_index_t ue_idx,
240243
for (unsigned h_ref_idx : ues[ue_idx].harqs) {
241244
if (h_ref_idx != INVALID_HARQ_REF_INDEX) {
242245
const harq_type& h = harqs[h_ref_idx];
243-
if (h.status == harq_state_t::pending_retx) {
246+
if (h.status == state) {
244247
return h_ref_idx;
245248
}
246249
}
@@ -254,8 +257,8 @@ template struct harq_utils::cell_harq_repository<false>;
254257
// Cell HARQ manager.
255258

256259
cell_harq_manager::cell_harq_manager(unsigned max_ues,
257-
unsigned max_ack_wait_timeout,
258-
std::unique_ptr<harq_timeout_notifier> notifier) :
260+
std::unique_ptr<harq_timeout_notifier> notifier,
261+
unsigned max_ack_wait_timeout) :
259262
timeout_notifier(std::move(notifier)),
260263
logger(srslog::fetch_basic_logger("SCHED")),
261264
dl(max_ues, max_ack_wait_timeout, *timeout_notifier, logger),
@@ -403,7 +406,9 @@ unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noex
403406

404407
unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&& other) noexcept
405408
{
406-
cell_harq_mgr->destroy_ue(ue_index);
409+
if (cell_harq_mgr != nullptr) {
410+
cell_harq_mgr->destroy_ue(ue_index);
411+
}
407412
cell_harq_mgr = other.cell_harq_mgr;
408413
ue_index = other.ue_index;
409414
other.cell_harq_mgr = nullptr;
@@ -418,6 +423,14 @@ unique_ue_harq_entity::~unique_ue_harq_entity()
418423
}
419424
}
420425

426+
void unique_ue_harq_entity::reset()
427+
{
428+
if (cell_harq_mgr != nullptr) {
429+
cell_harq_mgr->destroy_ue(ue_index);
430+
cell_harq_mgr = nullptr;
431+
}
432+
}
433+
421434
std::optional<dl_harq_process_view>
422435
unique_ue_harq_entity::alloc_dl_harq(slot_point sl_tx, unsigned k1, unsigned max_harq_nof_retxs, unsigned harq_bit_idx)
423436
{

lib/scheduler/ue_scheduling/cell_harq_manager.h

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ class harq_timeout_notifier
3636
virtual void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) = 0;
3737
};
3838

39+
class noop_harq_timeout_notifier : public harq_timeout_notifier
40+
{
41+
public:
42+
void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override
43+
{ /* do nothing */
44+
}
45+
};
46+
3947
namespace harq_utils {
4048

4149
const static unsigned INVALID_HARQ_REF_INDEX = std::numeric_limits<unsigned>::max();
@@ -156,7 +164,13 @@ struct cell_harq_repository {
156164
class cell_harq_manager
157165
{
158166
public:
159-
cell_harq_manager(unsigned max_ues, unsigned max_ack_wait_timeout, std::unique_ptr<harq_timeout_notifier> notifier);
167+
/// \brief Default timeout in slots after which the HARQ process assumes that the CRC/ACK went missing
168+
/// (implementation-defined).
169+
constexpr static unsigned DEFAULT_ACK_TIMEOUT_SLOTS = 256U;
170+
171+
cell_harq_manager(unsigned max_ues = MAX_NOF_DU_UES,
172+
std::unique_ptr<harq_timeout_notifier> notifier = std::make_unique<noop_harq_timeout_notifier>(),
173+
unsigned max_ack_wait_timeout = DEFAULT_ACK_TIMEOUT_SLOTS);
160174

161175
/// Update slot, and checks if there are HARQ processes that have reached maxReTx with no ACK
162176
void slot_indication(slot_point sl_tx);
@@ -168,8 +182,10 @@ class cell_harq_manager
168182
/// Values: {2, 4, 6, 10, 12, 16}.
169183
/// \param nof_ul_harq_procs Number of UL HARQ processes that gNB can support. This value is implementation-defined
170184
/// and can up to 16 (there are up to 4 bits for HARQ-Id signalling).
171-
unique_ue_harq_entity
172-
add_ue(du_ue_index_t ue_idx, rnti_t crnti, unsigned nof_dl_harq_procs, unsigned nof_ul_harq_procs);
185+
unique_ue_harq_entity add_ue(du_ue_index_t ue_idx,
186+
rnti_t crnti,
187+
unsigned nof_dl_harq_procs = MAX_NOF_HARQS,
188+
unsigned nof_ul_harq_procs = MAX_NOF_HARQS);
173189

174190
/// Checks whether an UE with the provided ue index exists.
175191
bool contains(du_ue_index_t ue_idx) const;
@@ -223,6 +239,17 @@ class dl_harq_process_view
223239
dl_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) :
224240
cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx)
225241
{
242+
srsran_sanity_check(cell_harq_mng->dl.harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty,
243+
"Empty HARQ process created");
244+
}
245+
246+
bool is_waiting_ack() const
247+
{
248+
return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack;
249+
}
250+
bool has_pending_retx() const
251+
{
252+
return cell_harq_mng->dl.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx;
226253
}
227254

228255
/// \brief Update the state of the DL HARQ process waiting for an HARQ-ACK.
@@ -233,6 +260,12 @@ class dl_harq_process_view
233260

234261
const grant_params& get_grant_params() const { return cell_harq_mng->dl.harqs[harq_ref_idx].prev_tx_params; }
235262

263+
bool operator==(const dl_harq_process_view& other) const
264+
{
265+
return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx;
266+
}
267+
bool operator!=(const dl_harq_process_view& other) const { return !(*this == other); }
268+
236269
private:
237270
cell_harq_manager* cell_harq_mng = nullptr;
238271
unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ;
@@ -244,12 +277,29 @@ class ul_harq_process_view
244277
ul_harq_process_view(cell_harq_manager& cell_harq_mng_, unsigned h_ref_idx) :
245278
cell_harq_mng(&cell_harq_mng_), harq_ref_idx(h_ref_idx)
246279
{
280+
srsran_sanity_check(cell_harq_mng->ul.harqs[harq_ref_idx].status != harq_utils::harq_state_t::empty,
281+
"Empty HARQ process created");
282+
}
283+
284+
bool is_waiting_ack() const
285+
{
286+
return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::waiting_ack;
287+
}
288+
bool has_pending_retx() const
289+
{
290+
return cell_harq_mng->ul.harqs[harq_ref_idx].status == harq_utils::harq_state_t::pending_retx;
247291
}
248292

249293
/// Update UL HARQ state given the received CRC indication.
250294
/// \return Transport Block size of the HARQ whose state was updated.
251295
int ul_crc_info(bool ack);
252296

297+
bool operator==(const ul_harq_process_view& other) const
298+
{
299+
return cell_harq_mng == other.cell_harq_mng and harq_ref_idx == other.harq_ref_idx;
300+
}
301+
bool operator!=(const ul_harq_process_view& other) const { return !(*this == other); }
302+
253303
private:
254304
cell_harq_manager* cell_harq_mng = nullptr;
255305
unsigned harq_ref_idx = cell_harq_manager::INVALID_HARQ;
@@ -258,9 +308,11 @@ class ul_harq_process_view
258308
class unique_ue_harq_entity
259309
{
260310
public:
311+
unique_ue_harq_entity() = default;
261312
unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index_t ue_idx, rnti_t crnti_) :
262313
cell_harq_mgr(mgr), ue_index(ue_idx), crnti(crnti_)
263314
{
315+
(void)crnti;
264316
}
265317
~unique_ue_harq_entity();
266318
unique_ue_harq_entity(const unique_ue_harq_entity&) = delete;
@@ -274,6 +326,8 @@ class unique_ue_harq_entity
274326
bool has_empty_dl_harqs() const { return not get_dl_ue().free_harq_ids.empty(); }
275327
bool has_empty_ul_harqs() const { return not get_ul_ue().free_harq_ids.empty(); }
276328

329+
void reset();
330+
277331
std::optional<dl_harq_process_view> dl_harq(harq_id_t h_id)
278332
{
279333
if (cell_harq_mgr->dl.ues[ue_index].harqs[h_id] != harq_utils::INVALID_HARQ_REF_INDEX) {
@@ -318,7 +372,7 @@ class unique_ue_harq_entity
318372

319373
cell_harq_manager* cell_harq_mgr = nullptr;
320374
du_ue_index_t ue_index = INVALID_DU_UE_INDEX;
321-
rnti_t crnti;
375+
rnti_t crnti = rnti_t::INVALID_RNTI;
322376
};
323377

324378
} // namespace srsran

tests/unittests/scheduler/ue_scheduling/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
add_executable(ue_scheduler_test
1010
logical_channel_test.cpp
11+
harq_manager_test.cpp
1112
harq_entity_test.cpp
1213
harq_process_test.cpp
1314
fallback_scheduler_test.cpp
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
*
3+
* Copyright 2021-2024 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#include "lib/scheduler/ue_scheduling/cell_harq_manager.h"
12+
#include "srsran/support/test_utils.h"
13+
#include <gtest/gtest.h>
14+
15+
using namespace srsran;
16+
17+
class harq_entity_test : public ::testing::Test
18+
{
19+
protected:
20+
cell_harq_manager cell_harqs{1};
21+
du_ue_index_t ue_index = to_du_ue_index(0);
22+
rnti_t rnti = to_rnti(0x4601);
23+
unsigned max_retxs = 4;
24+
25+
unique_ue_harq_entity harq_ent;
26+
};
27+
28+
TEST_F(harq_entity_test, when_ue_harq_entity_is_created_cell_harq_manager_is_updated)
29+
{
30+
ASSERT_FALSE(cell_harqs.contains(ue_index));
31+
harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16);
32+
ASSERT_TRUE(cell_harqs.contains(ue_index));
33+
harq_ent.reset();
34+
ASSERT_FALSE(cell_harqs.contains(ue_index));
35+
}
36+
37+
TEST_F(harq_entity_test, when_harq_entity_is_created_all_harqs_are_empty)
38+
{
39+
harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16);
40+
ASSERT_EQ(harq_ent.nof_dl_harqs(), 16);
41+
ASSERT_EQ(harq_ent.nof_ul_harqs(), 16);
42+
ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), std::nullopt);
43+
ASSERT_EQ(harq_ent.find_pending_dl_retx(), std::nullopt);
44+
ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), std::nullopt);
45+
ASSERT_EQ(harq_ent.find_pending_ul_retx(), std::nullopt);
46+
ASSERT_TRUE(harq_ent.has_empty_dl_harqs());
47+
ASSERT_TRUE(harq_ent.has_empty_ul_harqs());
48+
for (unsigned i = 0; i != 16; ++i) {
49+
ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(i)).has_value());
50+
ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(i)).has_value());
51+
}
52+
}
53+
54+
TEST_F(harq_entity_test, when_harq_is_allocated_then_it_enters_waiting_ack_state)
55+
{
56+
harq_ent = cell_harqs.add_ue(ue_index, rnti, 16, 16);
57+
slot_point sl_tx{0, 0};
58+
unsigned k1 = 4;
59+
auto h_dl = harq_ent.alloc_dl_harq(sl_tx, k1, max_retxs, 0);
60+
ASSERT_TRUE(h_dl.has_value());
61+
ASSERT_TRUE(h_dl.value().is_waiting_ack());
62+
ASSERT_FALSE(h_dl.value().has_pending_retx());
63+
ASSERT_EQ(harq_ent.find_dl_harq_waiting_ack(), h_dl);
64+
auto h_ul = harq_ent.alloc_ul_harq(sl_tx, max_retxs);
65+
ASSERT_TRUE(h_ul.has_value());
66+
ASSERT_TRUE(h_ul.value().is_waiting_ack());
67+
ASSERT_FALSE(h_ul.value().has_pending_retx());
68+
ASSERT_EQ(harq_ent.find_ul_harq_waiting_ack(), h_ul);
69+
}

0 commit comments

Comments
 (0)