From e518e96fbeea09adb0d6889c27fdb800b2a4acb6 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 29 Apr 2026 07:53:01 +0200 Subject: [PATCH 1/4] fix(imscope): fix build for imscope This commit moves certain functions and structs around to prevent including functions taking VLA arguments in imscope C++ source files. Signed-off-by: Bartosz Podrygajlo --- common/utils/bits.c | 68 +++++++++++++++++ common/utils/bits.h | 12 +++ openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 2 +- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 1 + openair1/PHY/defs_gNB.h | 2 +- .../PHY/nr_phy_common/inc/nr_phy_common.h | 11 --- .../PHY/nr_phy_common/src/nr_phy_common.c | 73 ------------------- 7 files changed, 83 insertions(+), 86 deletions(-) diff --git a/common/utils/bits.c b/common/utils/bits.c index d329660821..db9bca2c41 100644 --- a/common/utils/bits.c +++ b/common/utils/bits.c @@ -3,6 +3,7 @@ */ #include "bits.h" +#include "utils.h" // we avoid assertions.h as it necessitates othe dependencies (e.g., exit_function) #include #include @@ -73,3 +74,70 @@ uint64_t reverse_bits(uint64_t in, int n_bits) return rev_bits; } +/** + * Finds the next contiguous block of set bits. + * @param bitmap The bit buffer + * @param size Total bits in the buffer + * @param pos Pointer to current bit index (updated by function) + * @param start Output: Start index of the found block + * @param end Output: End index of the found block + * @return true if a block was found, false if no more bits are set + */ +bool find_next_rb_block(const uint32_t *bitmap, int size, int *pos, int *start, int *end) +{ + const int words = (size + 31) / 32; + + // Find start of next block + int idx = get_first_bit_index_mask(bitmap, words, *pos, size - *pos); + if (idx < 0) + return false; + *start = idx; + + // Find end of block: first zero bit after idx + // Reuse get_first_bit_index_from on the inverted bitmap + idx++; + int word_idx = idx / 32; + int n = words - word_idx; + uint32_t inv[n]; + for (int i = 0; i < n; i++) + inv[i] = ~bitmap[word_idx + i]; + if (size % 32 != 0) + inv[n - 1] &= (1u << (size % 32)) - 1; + + int end_off = get_first_bit_index_mask(inv, n, idx - word_idx * 32, size - idx); + idx = (end_off < 0) ? size : word_idx * 32 + end_off; + + *end = (idx > size) ? size - 1 : idx - 1; + *pos = idx; // Update position for the next call + return true; +} + +bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb) +{ + return (alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01; +} + +freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t *bitmap) +{ + freq_alloc_bitmap_t alloc = {0}; + int num_words = (size + 31) / 32; + memcpy(alloc.bitmap, bitmap, alloc_size); + alloc.num_rbs = count_bits(alloc.bitmap, num_words); + alloc.first_rb = get_first_bit_index(alloc.bitmap, num_words); + alloc.last_rb = get_last_bit_index(alloc.bitmap, num_words); + AssertFatal(alloc.first_rb >= 0 && alloc.last_rb >=0 , "No valid RB set, no bit set in bitmap\n"); + return alloc; +} + +freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size) +{ + freq_alloc_bitmap_t alloc = { + .num_rbs = size, + .first_rb = start, + .last_rb = start + size - 1 + }; + memset(alloc.bitmap, 0, sizeof(alloc.bitmap)); + for (int i = start; i < size + start; i++) + alloc.bitmap[i / 32] |= (1U << (i % 32)); + return alloc; +} diff --git a/common/utils/bits.h b/common/utils/bits.h index 88ca05edd2..6ca03298bc 100644 --- a/common/utils/bits.h +++ b/common/utils/bits.h @@ -73,4 +73,16 @@ static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t uint64_t mask = ((1LL << num) - 1) << start; return count_bits64(v & mask); } + +bool find_next_rb_block(const uint32_t *bitmap, int size, int *pos, int *start, int *end); +typedef struct { + int first_rb; + int last_rb; + int num_rbs; + uint32_t bitmap[9]; +} freq_alloc_bitmap_t; +bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb); +freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t *bitmap); +freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size); + #endif /* BITS_H_ */ diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index d7c33e033e..5b9f1eca69 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -5,7 +5,7 @@ #ifndef __NR_ESTIMATION_DEFS__H__ #define __NR_ESTIMATION_DEFS__H__ -#include "PHY/nr_phy_common/inc/nr_phy_common.h" +#include "common/utils/bits.h" #include "PHY/defs_nr_UE.h" /** @addtogroup _PHY_PARAMETER_ESTIMATION_BLOCKS_ diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index dd91c00283..5d6d83875e 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -13,6 +13,7 @@ #include #include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h" +#include "common/utils/bits.h" #define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1 #define NR_PUSCH_y 3 // UCI placeholder bit diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ba0cca29ea..f0240c98b4 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -11,7 +11,7 @@ #include "common/platform_constants.h" #include "defs_nr_common.h" -#include "PHY/nr_phy_common/inc/nr_phy_common.h" +#include "common/utils/bits.h" #include "CODING/nrPolar_tools/nr_polar_pbch_defs.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" #include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 74beb9e02b..63137d81f1 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -376,15 +376,4 @@ int nr_get_ssb_start_sc(int scs, int ssb_offset_point_a, int ssb_sco, frequency_range_t freq_range); - -bool find_next_rb_block(const uint32_t *bitmap, int size, int *pos, int *start, int *end); -typedef struct { - int first_rb; - int last_rb; - int num_rbs; - uint32_t bitmap[9]; -} freq_alloc_bitmap_t; -bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb); -freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]); -freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size); #endif diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c index 5239aa2c00..f7e6592b0e 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -428,79 +428,6 @@ void nr_scale_channel(int size, int ch_estimates_ext[][size], int symb, uint32_t } } -freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]) -{ - freq_alloc_bitmap_t alloc = {0}; - int num_words = (size + 31) / 32; - AssertFatal(num_words <= sizeofArray(alloc.bitmap), - "freq_alloc_bitmap.bitmap %lu words < %d\n", - sizeofArray(alloc.bitmap), - num_words); - memcpy(alloc.bitmap, bitmap, alloc_size); - alloc.num_rbs = count_bits(alloc.bitmap, num_words); - alloc.first_rb = get_first_bit_index(alloc.bitmap, num_words); - alloc.last_rb = get_last_bit_index(alloc.bitmap, num_words); - AssertFatal(alloc.first_rb >= 0 && alloc.last_rb >=0 , "No valid RB set, no bit set in bitmap\n"); - return alloc; -} - -freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size) -{ - freq_alloc_bitmap_t alloc = { - .num_rbs = size, - .first_rb = start, - .last_rb = start + size - 1 - }; - memset(alloc.bitmap, 0, sizeof(alloc.bitmap)); - for (int i = start; i < size + start; i++) - alloc.bitmap[i / 32] |= (1U << (i % 32)); - return alloc; -} - -bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb) -{ - return (alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01; -} - -/** - * Finds the next contiguous block of set bits. - * @param bitmap The bit buffer - * @param size Total bits in the buffer - * @param pos Pointer to current bit index (updated by function) - * @param start Output: Start index of the found block - * @param end Output: End index of the found block - * @return true if a block was found, false if no more bits are set - */ -bool find_next_rb_block(const uint32_t *bitmap, int size, int *pos, int *start, int *end) -{ - AssertFatal(*pos >= 0 && *pos <= size, "Invalid combination of bit index %d and size %d\n", *pos, size); - const int words = (size + 31) / 32; - - // Find start of next block - int idx = get_first_bit_index_mask(bitmap, words, *pos, size - *pos); - if (idx < 0) - return false; - *start = idx; - - // Find end of block: first zero bit after idx - // Reuse get_first_bit_index_from on the inverted bitmap - idx++; - int word_idx = idx / 32; - int n = words - word_idx; - uint32_t inv[n]; - for (int i = 0; i < n; i++) - inv[i] = ~bitmap[word_idx + i]; - if (size % 32 != 0) - inv[n - 1] &= (1u << (size % 32)) - 1; - - int end_off = get_first_bit_index_mask(inv, n, idx - word_idx * 32, size - idx); - idx = (end_off < 0) ? size : word_idx * 32 + end_off; - - *end = (idx > size) ? size - 1 : idx - 1; - *pos = idx; // Update position for the next call - return true; -} - void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size) { const double phase_inc = -fo_Hz / (samples_per_ms * 1000); From f1043aecfd07e2a4cfbca97ad27dc4e27048e7ec Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 May 2026 17:16:48 +0200 Subject: [PATCH 2/4] pbch: tracy: moving TracyCZone() to right function The TracyCZone() macro stayed, but the function containing it changed in a previous commit. Fixes: e4b2125f1e17 ("Refactor PBCH & PSBCH UE procedures") Signed-off-by: Robert Schmidt --- openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index dea3b1fd0b..efb4c59865 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -286,7 +286,6 @@ void nr_generate_pbch_llr(const PHY_VARS_NR_UE *ue, const c16_t dl_ch_estimates[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size], int16_t pbch_e_rx[NR_POLAR_PBCH_E]) { - TracyCZone(ctx, true); const int symbol_offset = nr_get_ssb_start_symbol(frame_parms, i_ssb) % (NR_SYMBOLS_PER_SLOT); const int nb_re = (symbolSSB == 2) ? 72 : 180; @@ -377,6 +376,7 @@ int nr_pbch_decode(PHY_VARS_NR_UE *ue, int *ret_symbol_offset, fapiPbch_t *result) { + TracyCZone(ctx, true); if (ue) { UEscopeCopy(ue, pbchLlr, pbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, NR_POLAR_PBCH_E, 0); } From 49b9a151058ce0ae093e14d994e89c280dc586ee Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 27 Apr 2026 18:56:03 +0200 Subject: [PATCH 3/4] feat(ci): add dockerfile for imscope builds Add a new Dockerfile for optional features of OAI. Currently only imscope is added but other features could be added in separate stages. Build using: docker build . -f ci-scripts/docker/Dockerfile.build.optional.ubuntu Signed-off-by: Bartosz Podrygajlo --- .../docker/Dockerfile.build.optional.ubuntu | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 ci-scripts/docker/Dockerfile.build.optional.ubuntu diff --git a/ci-scripts/docker/Dockerfile.build.optional.ubuntu b/ci-scripts/docker/Dockerfile.build.optional.ubuntu new file mode 100644 index 0000000000..2ebcf5a157 --- /dev/null +++ b/ci-scripts/docker/Dockerfile.build.optional.ubuntu @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: LicenseRef-CSSL-1.0 + +FROM ran-base:latest AS optional-base + +RUN DEBIAN_FRONTEND=noninteractive + +RUN apt update && \ + apt upgrade --yes && \ + apt install --yes \ + libglfw3-dev + +WORKDIR /oai-src +COPY . . + +FROM optional-base AS build-imscope + +# Consider using sharing=locked in case more stages are added in the future +RUN \ + # Mount CCache cache directory + --mount=type=cache,target=/root/.cache/ccache/ \ + # Mount CPM package cache + --mount=type=cache,target=/root/.cache/cpm/ \ + mkdir -p /build-imscope && \ + cd /build-imscope && \ + cmake /oai-src/ -DENABLE_IMSCOPE=ON -GNinja && \ + ninja imscope nr-softmodem nr-uesoftmodem + From 4ad9bac90fcd3de9bff0257a5575921955de8a2e Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 27 Apr 2026 22:01:10 +0200 Subject: [PATCH 4/4] feat(ci): build tracy-enabled softmodems Add tracy-enabled softmodems build as part of the optional features build pipeline. To build: docker build . -f ci-scripts/docker/Dockerfile.build.optional.ubuntu --target build-tracy docker build . -f ci-scripts/docker/Dockerfile.build.optional.ubuntu --target build-imscope Signed-off-by: Bartosz Podrygajlo --- .../docker/Dockerfile.build.optional.ubuntu | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ci-scripts/docker/Dockerfile.build.optional.ubuntu b/ci-scripts/docker/Dockerfile.build.optional.ubuntu index 2ebcf5a157..44acdfe34e 100644 --- a/ci-scripts/docker/Dockerfile.build.optional.ubuntu +++ b/ci-scripts/docker/Dockerfile.build.optional.ubuntu @@ -14,14 +14,24 @@ COPY . . FROM optional-base AS build-imscope -# Consider using sharing=locked in case more stages are added in the future RUN \ # Mount CCache cache directory - --mount=type=cache,target=/root/.cache/ccache/ \ + --mount=type=cache,target=/root/.cache/ccache/,id=ccache_imscope \ # Mount CPM package cache - --mount=type=cache,target=/root/.cache/cpm/ \ + --mount=type=cache,target=/root/.cache/cpm/,id=cpmcache_imscope \ mkdir -p /build-imscope && \ cd /build-imscope && \ cmake /oai-src/ -DENABLE_IMSCOPE=ON -GNinja && \ ninja imscope nr-softmodem nr-uesoftmodem +FROM optional-base AS build-tracy + +RUN \ + # Mount CCache cache directory + --mount=type=cache,target=/root/.cache/ccache/,id=ccache_tracy \ + # Mount CPM package cache + --mount=type=cache,target=/root/.cache/cpm/,id=cpmcache_tracy \ + mkdir -p /build-tracy && \ + cd /build-tracy && \ + cmake /oai-src/ -DTRACY_ENABLE=ON -GNinja && \ + ninja nr-softmodem nr-uesoftmodem