diff --git a/lib/include/srsran/adt/bounded_bitset.h b/lib/include/srsran/adt/bounded_bitset.h index 37226db90..3faa87c0c 100644 --- a/lib/include/srsran/adt/bounded_bitset.h +++ b/lib/include/srsran/adt/bounded_bitset.h @@ -27,28 +27,109 @@ constexpr uint32_t ceil_div(uint32_t x, uint32_t y) } template -Integer mask_trailing_ones(size_t N) +Integer mask_msb_zeros(size_t N) { static_assert(std::is_unsigned::value, "T must be unsigned integer"); - return N == 0 ? 0 : (static_cast(-1) >> (sizeof(Integer) * 8U - N)); + return (N == 0) ? static_cast(-1) : (N == sizeof(Integer) * 8U) ? 0 : (static_cast(-1) >> (N)); } template -Integer mask_leading_ones(size_t N) +Integer mask_lsb_ones(size_t N) { - return ~mask_trailing_ones(8U * sizeof(Integer) - N); + return mask_msb_zeros(sizeof(Integer) * 8U - N); } template -Integer mask_trailing_zeros(size_t N) +Integer mask_msb_ones(size_t N) { - return mask_leading_ones(8U * sizeof(Integer) - N); + return ~mask_msb_zeros(N); } template -Integer mask_leading_zeros(size_t N) +Integer mask_lsb_zeros(size_t N) { - return mask_trailing_ones(8U * sizeof(Integer) - N); + return ~mask_lsb_ones(N); +} + +namespace detail { + +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + if (value == 0) { + return std::numeric_limits::digits; + } + Integer ret = 0; + for (Integer shift = std::numeric_limits::digits >> 1; shift != 0; shift >>= 1) { + Integer tmp = value >> shift; + if (tmp != 0) { + value = tmp; + } else { + ret |= shift; + } + } + return ret; + } + static Integer lsb_count(Integer value) + { + if (value == 0) { + return std::numeric_limits::digits; + } + Integer ret = 0; + for (Integer shift = std::numeric_limits::digits >> 1, mask = std::numeric_limits::max() >> shift; + shift != 0; + shift >>= 1, mask >>= shift) { + if ((value & mask) == 0) { + value >>= shift; + ret |= shift; + } + } + return ret; + } +}; + +/// Specializations for unsigned +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + return (value) ? __builtin_clz(value) : std::numeric_limits::digits; + } + static Integer lsb_count(Integer value) + { + return (value) ? __builtin_ctz(value) : std::numeric_limits::digits; + } +}; + +/// Specializations for unsigned long +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + return (value) ? __builtin_clzl(value) : std::numeric_limits::digits; + } + static Integer lsb_count(Integer value) + { + return (value) ? __builtin_ctzl(value) : std::numeric_limits::digits; + } +}; + +} // namespace detail + +/// uses lsb as zero position +template +Integer find_first_msb_one(Integer value) +{ + return (value) ? (sizeof(Integer) * 8U - 1 - detail::zerobit_counter::msb_count(value)) + : std::numeric_limits::digits; +} + +/// uses lsb as zero position +template +Integer find_first_lsb_one(Integer value) +{ + return detail::zerobit_counter::lsb_count(value); } template @@ -139,35 +220,17 @@ public: return *this; } - int find_first(size_t startpos, size_t endpos, bool value = true) const noexcept + int find_lowest(size_t startpos, size_t endpos, bool value = true) const noexcept { assert_range_bounds_(startpos, endpos); if (startpos == endpos) { return -1; } - size_t startword = startpos / bits_per_word; - size_t lastword = (endpos - 1) / bits_per_word; - - for (size_t i = startword; i <= lastword; ++i) { - word_t w = buffer[i]; - if (not value) { - w = ~w; - } - - if (i == startword) { - size_t offset = startpos % bits_per_word; - w &= mask_trailing_zeros(offset); - } - if (i == lastword) { - size_t offset = (endpos - 1) % bits_per_word; - w &= mask_trailing_ones(offset + 1); - } - if (w != 0) { - return static_cast(i * bits_per_word + (bits_per_word - __builtin_clzl(w) - 1)); - } + if (not reversed) { + return find_first_(startpos, endpos, value); } - return -1; + return find_first_reversed_(startpos, endpos, value); } bool all() const noexcept @@ -328,33 +391,35 @@ private: } } - bool test_(size_t pos) const noexcept + size_t get_bitidx_(size_t bitpos) const noexcept { return reversed ? size() - 1 - bitpos : bitpos; } + + bool test_(size_t bitpos) const noexcept { - pos = reversed ? size() - 1 - pos : pos; - return ((get_word_(pos) & maskbit(pos)) != static_cast(0)); + bitpos = get_bitidx_(bitpos); + return ((get_word_(bitpos) & maskbit(bitpos)) != static_cast(0)); } - void set_(size_t pos) noexcept + void set_(size_t bitpos) noexcept { - pos = reversed ? size() - 1 - pos : pos; - get_word_(pos) |= maskbit(pos); + bitpos = get_bitidx_(bitpos); + get_word_(bitpos) |= maskbit(bitpos); } - void reset_(size_t pos) noexcept + void reset_(size_t bitpos) noexcept { - pos = reversed ? size() - 1 - pos : pos; - get_word_(pos) &= ~(maskbit(pos)); + bitpos = get_bitidx_(bitpos); + get_word_(bitpos) &= ~(maskbit(bitpos)); } size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; } - word_t& get_word_(size_t pos) noexcept { return buffer[pos / bits_per_word]; } + word_t& get_word_(size_t bitidx) noexcept { return buffer[bitidx / bits_per_word]; } - const word_t& get_word_(size_t pos) const { return buffer[pos / bits_per_word]; } + const word_t& get_word_(size_t bitidx) const { return buffer[bitidx / bits_per_word]; } size_t word_idx_(size_t pos) const { return pos / bits_per_word; } - void assert_within_bounds_(size_t pos, bool strict) const + void assert_within_bounds_(size_t pos, bool strict) const noexcept { srsran_assert(pos < size() or (not strict and pos == size()), "ERROR: index=%zd is out-of-bounds for bitset of size=%zd", @@ -362,7 +427,7 @@ private: size()); } - void assert_range_bounds_(size_t startpos, size_t endpos) const + void assert_range_bounds_(size_t startpos, size_t endpos) const noexcept { srsran_assert(startpos <= endpos and endpos <= size(), "ERROR: range [%zd, %zd) out-of-bounds for bitsize of size=%zd", @@ -371,9 +436,89 @@ private: size()); } - static word_t maskbit(size_t pos) { return (static_cast(1)) << (pos % bits_per_word); } + static word_t maskbit(size_t pos) noexcept { return (static_cast(1)) << (pos % bits_per_word); } - static size_t max_nof_words_() { return (N - 1) / bits_per_word + 1; } + static size_t max_nof_words_() noexcept { return (N - 1) / bits_per_word + 1; } + + int find_last_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; + + for (size_t i = lastword; i != startpos - 1; --i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= (reversed) ? mask_msb_zeros(offset) : mask_lsb_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= (reversed) ? mask_msb_ones(offset + 1) : mask_lsb_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + find_first_msb_one(w)); + } + } + return -1; + } + + int find_first_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; + + for (size_t i = startword; i <= lastword; ++i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= mask_lsb_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= mask_lsb_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + find_first_lsb_one(w)); + } + } + return -1; + } + + int find_first_reversed_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startbitpos = get_bitidx_(startpos), lastbitpos = get_bitidx_(endpos - 1); + size_t startword = startbitpos / bits_per_word; + size_t lastword = lastbitpos / bits_per_word; + + for (size_t i = startword; i != lastword - 1; --i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startbitpos % bits_per_word; + w &= mask_lsb_ones(offset + 1); + } + if (i == lastword) { + size_t offset = lastbitpos % bits_per_word; + w &= mask_lsb_zeros(offset); + } + if (w != 0) { + word_t pos = find_first_msb_one(w); + return static_cast(size() - 1 - (pos + i * bits_per_word)); + } + } + return -1; + } }; template diff --git a/lib/test/adt/bounded_bitset_test.cc b/lib/test/adt/bounded_bitset_test.cc index 2790880ee..4034e334f 100644 --- a/lib/test/adt/bounded_bitset_test.cc +++ b/lib/test/adt/bounded_bitset_test.cc @@ -15,10 +15,35 @@ void test_bit_operations() { - TESTASSERT(0 == srsran::mask_trailing_ones(0)); - TESTASSERT(0b11 == srsran::mask_trailing_ones(2)); - TESTASSERT(0b11111111 == srsran::mask_trailing_ones(8)); - TESTASSERT(0b1111 == srsran::mask_trailing_ones(4)); + TESTASSERT(0 == srsran::mask_lsb_ones(0)); + TESTASSERT(0 == srsran::mask_msb_ones(0)); + TESTASSERT(0 == srsran::mask_lsb_ones(0)); + TESTASSERT(0 == srsran::mask_msb_ones(0)); + TESTASSERT(0b11111111 == srsran::mask_lsb_zeros(0)); + TESTASSERT(0b11111111 == srsran::mask_msb_zeros(0)); + TESTASSERT((uint32_t)-1 == srsran::mask_lsb_zeros(0)); + TESTASSERT((uint32_t)-1 == srsran::mask_msb_zeros(0)); + + TESTASSERT(0b11 == srsran::mask_lsb_ones(2)); + TESTASSERT(0b11000000 == srsran::mask_msb_ones(2)); + TESTASSERT(0b11111100 == srsran::mask_lsb_zeros(2)); + TESTASSERT(0b00111111 == srsran::mask_msb_zeros(2)); + + TESTASSERT(0b11111111 == srsran::mask_lsb_ones(8)); + TESTASSERT(0b1111 == srsran::mask_lsb_ones(4)); + + TESTASSERT(srsran::find_first_lsb_one(0) == std::numeric_limits::digits); + TESTASSERT(srsran::find_first_msb_one(0) == std::numeric_limits::digits); + TESTASSERT(srsran::find_first_lsb_one(1) == 0); + TESTASSERT(srsran::find_first_msb_one(1) == 0); + TESTASSERT(srsran::find_first_lsb_one(0b11) == 0); + TESTASSERT(srsran::find_first_lsb_one(0b10) == 1); + TESTASSERT(srsran::find_first_msb_one(0b11) == 1); + TESTASSERT(srsran::find_first_msb_one(0b10) == 1); + TESTASSERT(srsran::find_first_lsb_one(0b11) == 0); + TESTASSERT(srsran::find_first_lsb_one(0b10) == 1); + TESTASSERT(srsran::find_first_msb_one(0b11) == 1); + TESTASSERT(srsran::find_first_msb_one(0b10) == 1); } int test_zero_bitset() @@ -184,21 +209,63 @@ int test_bitset_resize() return SRSRAN_SUCCESS; } +template void test_bitset_find() { { - srsran::bounded_bitset<25> bitset(6); + srsran::bounded_bitset<25, reversed> bitset(6); + + // 0b000000 + TESTASSERT(bitset.find_lowest(0, bitset.size(), false) == 0); + TESTASSERT(bitset.find_lowest(0, bitset.size(), true) == -1); + + // 0b000100 bitset.set(2); - TESTASSERT(bitset.find_first(0, 6) == 2); - TESTASSERT(bitset.find_first(3, 6) == -1); + TESTASSERT(bitset.find_lowest(0, 6) == 2); + TESTASSERT(bitset.find_lowest(0, 6, false) == 0); + TESTASSERT(bitset.find_lowest(3, 6) == -1); + TESTASSERT(bitset.find_lowest(3, 6, false) == 3); + + // 0b000101 + bitset.set(0); + TESTASSERT(bitset.find_lowest(0, 6) == 0); + TESTASSERT(bitset.find_lowest(0, 6, false) == 1); + TESTASSERT(bitset.find_lowest(3, 6) == -1); + TESTASSERT(bitset.find_lowest(3, 6, false) == 3); + + // 0b100101 bitset.set(5); - TESTASSERT(bitset.find_first(3, 6) == 5); + TESTASSERT(bitset.find_lowest(0, 6) == 0); + TESTASSERT(bitset.find_lowest(0, 6, false) == 1); + TESTASSERT(bitset.find_lowest(3, 6) == 5); + + // 0b111111 + bitset.fill(0, 6); + TESTASSERT(bitset.find_lowest(0, 6) == 0); + TESTASSERT(bitset.find_lowest(0, 6, false) == -1); + TESTASSERT(bitset.find_lowest(3, 6, false) == -1); } { - srsran::bounded_bitset<100> bitset(95); + srsran::bounded_bitset<100, reversed> bitset(95); + + // 0b0...0 + TESTASSERT(bitset.find_lowest(0, bitset.size()) == -1); + + // 0b1000... bitset.set(94); - TESTASSERT(bitset.find_first(0, 93) == -1); - TESTASSERT(bitset.find_first(0, bitset.size()) == 94); + TESTASSERT(bitset.find_lowest(0, 93) == -1); + TESTASSERT(bitset.find_lowest(0, bitset.size()) == 94); + + // 0b1000...010 + bitset.set(1); + TESTASSERT(bitset.find_lowest(0, bitset.size()) == 1); + TESTASSERT(bitset.find_lowest(1, bitset.size()) == 1); + TESTASSERT(bitset.find_lowest(2, bitset.size()) == 94); + + // 0b11..11 + bitset.fill(0, bitset.size()); + TESTASSERT(bitset.find_lowest(0, bitset.size()) == 0); + TESTASSERT(bitset.find_lowest(5, bitset.size()) == 5); } } @@ -211,7 +278,8 @@ int main() TESTASSERT(test_bitset_bitwise_oper() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_print() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_resize() == SRSRAN_SUCCESS); - test_bitset_find(); + test_bitset_find(); + test_bitset_find(); printf("Success\n"); return 0; } diff --git a/srsenb/src/stack/mac/schedulers/sched_base.cc b/srsenb/src/stack/mac/schedulers/sched_base.cc index 96edc0014..123eccf8f 100644 --- a/srsenb/src/stack/mac/schedulers/sched_base.cc +++ b/srsenb/src/stack/mac/schedulers/sched_base.cc @@ -23,22 +23,25 @@ template ::value, prb_interval, rbg_interval>::type> RBInterval find_contiguous_interval(const RBMask& in_mask, uint32_t max_size) { - RBInterval interv, max_interv; + RBInterval max_interv; - for (uint32_t n = 0; n < in_mask.size() and interv.length() < max_size; n++) { - if (not in_mask.test(n) and interv.empty()) { - // new interval - interv.set(n, n + 1); - } else if (not in_mask.test(n)) { - // extend current interval - interv.resize_by(1); - } else if (not interv.empty()) { - // reset interval - max_interv = interv.length() > max_interv.length() ? interv : max_interv; - interv = {}; + for (size_t n = 0; n < in_mask.size(); n++) { + int pos = in_mask.find_lowest(n, in_mask.size(), false); + if (pos < 0) { + break; + } + + size_t max_pos = std::min(in_mask.size(), (size_t)pos + max_size); + int pos2 = in_mask.find_lowest(pos, max_pos, true); + RBInterval interv(pos, pos2 < 0 ? max_pos : pos2); + if (interv.length() >= max_size) { + return interv; + } + if (interv.length() > max_interv.length()) { + max_interv = interv; } } - return interv.length() > max_interv.length() ? interv : max_interv; + return max_interv; } /****************************