feat(oran_fhlib_5g): BFP compression and decompression for Arm targets

The fronthaul library ships with BFP compression for AVX512 enabled targets.
This commit adds BFP compression for Arm targets by using the ArmRAL library.
This commit is contained in:
Romain Beurdouche
2025-04-04 13:25:53 +00:00
parent 047e80f070
commit 54fd8ed9df
5 changed files with 330 additions and 6 deletions
@@ -0,0 +1,123 @@
#
# Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The OpenAirInterface Software Alliance licenses this file to You under
# the OAI Public License, Version 1.1 (the "License"); you may not use this file
# except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.openairinterface.org/?page_id=698
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ------------------------------------------------------------------------------
# For more information about the OpenAirInterface (OAI) Software Alliance:
# contact@openairinterface.org
#
# FindArmral
# -------
#
# Finds the armral library.
# the version is currently hardcoded to 25.01
#
# Optional options
# ^^^^^^^^^^^^^^^^
#
# ``armral_LOCATION``
# The location of the library.
#
# Imported Targets
# ^^^^^^^^^^^^^^^^
#
# This module provides the following imported targets, if found:
#
# ``armral``
# The armral library
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This will define the following variables:
#
# ``armral_FOUND``
# True if the system has the armral library.
# ``armral_VERSION``
# The version of the armral library which was found.
# ``armral_INCLUDE_DIRS``
# Include directories needed to use armral.
# ``armral_LIBRARIES``
# Libraries needed to link to armral.
#
# Cache Variables
# ^^^^^^^^^^^^^^^
#
# The following cache variables may also be set:
#
# ``armral_INCLUDE_DIR``
# The directory containing ``armral.h``.
# ``armral_LIBRARY``
# The path to the armral library.
option(armral_LOCATION "directory of ArmRAL library" "")
if (NOT armral_LOCATION)
set(armral_LOCATION "/usr/local")
endif()
if (NOT EXISTS ${armral_LOCATION})
message(FATAL_ERROR "no such directory: ${armral_LOCATION}")
endif()
find_path(armral_INCLUDE_DIR
NAMES
armral.h
HINTS ${armral_LOCATION}
PATH_SUFFIXES include
NO_DEFAULT_PATH
)
if (NOT armral_INCLUDE_DIR)
message(FATAL_ERROR "could not detect armral header at ${armral_LOCATION}/include")
endif()
find_library(armral_LIBRARY
NAMES armral
HINTS ${armral_LOCATION}
PATH_SUFFIXES lib build
NO_DEFAULT_PATH
)
if (NOT armral_LIBRARY)
message(FATAL_ERROR "could not detect armral build artifacts at neither ${armral_LOCATION}/lib nor ${armral_LOCATION}/build")
endif()
# No way to retrieve the version from header or library
set(armral_VERSION 25.01)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(armral
FOUND_VAR armral_FOUND
REQUIRED_VARS
armral_LIBRARY
armral_INCLUDE_DIR
VERSION_VAR armral_VERSION
)
if(armral_FOUND)
set(armral_LIBRARIES ${armral_LIBRARY})
set(armral_INCLUDE_DIRS ${armral_INCLUDE_DIR})
endif()
if(armral_FOUND AND NOT TARGET armral)
add_library(armral UNKNOWN IMPORTED)
set_target_properties(armral PROPERTIES
IMPORTED_LOCATION "${armral_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${armral_INCLUDE_DIRS}"
)
endif()
mark_as_advanced(
armral_INCLUDE_DIR
armral_LIBRARY
)
+5
View File
@@ -32,6 +32,11 @@ add_compile_options(-Wno-packed-not-aligned)
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa)
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
find_package(armral REQUIRED)
target_sources(oran_fhlib_5g PRIVATE armral_bfp_compression.c)
target_link_libraries(oran_fhlib_5g PRIVATE armral)
endif()
add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON)
+116
View File
@@ -0,0 +1,116 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file radio/fhi_72/armral_bfp_compression.c
* \brief BFP compression for the O-RAN 7.2 FrontHaul Interface for Arm systems using the Arm RAN Acceleration Library
* \author Romain Beurdouche
* \date 2025
* \company EURECOM
* \email romain.beurdouche@eurecom.fr
* \note ArmRAL available at https://git.gitlab.arm.com/networking/ral.git
* \warning
*/
#include "armral.h"
#include <rte_branch_prediction.h>
#include "armral_bfp_compression.h"
#include "common/utils/LOG/log.h"
/**
* The function operates on a fixed block size of one Physical Resource Block
* (PRB). Each block consists of 12 16-bit complex resource elements. Each block
* taken as input is compressed into 24 samples with a common unsigned scaling factor.
*
* @param[in] iq_width Width in bits of compressed samples.
* @param[in] n_prb The number of input resource blocks.
* @param[in] src Points to the input complex samples sequence.
* @param[out] dst Points to the output compressed data.
*/
void armral_bfp_compression(uint32_t iq_width, uint32_t n_prb, int16_t *src, int8_t *dst)
{
armral_status ret = ARMRAL_ARGUMENT_ERROR;
switch (iq_width) {
case 8:
ret = armral_block_float_compr_8bit(n_prb, (armral_cmplx_int16_t *)src, (armral_compressed_data_8bit *)dst, NULL);
if (unlikely(ret != ARMRAL_SUCCESS)) {
LOG_E(HW, "armral_block_scaling_compr_8bit returned an error: %d\n", (int)ret);
}
break;
case 9:
ret = armral_block_float_compr_9bit(n_prb, (armral_cmplx_int16_t *)src, (armral_compressed_data_9bit *)dst, NULL);
if (unlikely(ret != ARMRAL_SUCCESS)) {
LOG_E(HW, "armral_block_scaling_compr_9bit returned an error: %d\n", (int)ret);
}
break;
case 14:
ret = armral_block_float_compr_14bit(n_prb, (armral_cmplx_int16_t *)src, (armral_compressed_data_14bit *)dst, NULL);
if (unlikely(ret != ARMRAL_SUCCESS)) {
LOG_E(HW, "armral_block_scaling_compr_14bit returned an error: %d\n", (int)ret);
}
break;
default:
LOG_E(HW, "Unsupported IQ width in BFP compression: %d\n", iq_width);
}
}
/**
* The function operates on a fixed block size of one Physical Resource Block
* (PRB). Each block consists of 12 compressed complex resource elements.
* Each block taken as input is expanded into 12 16-bit complex samples.
*
* @param[in] iq_width Width in bits of compressed samples.
* @param[in] n_prb The number of input resource blocks.
* @param[in] src Points to the input compressed data.
* @param[out] dst Points to the output complex samples sequence.
*/
void armral_bfp_decompression(uint32_t iq_width, uint32_t n_prb, int8_t *src, int16_t *dst)
{
armral_status ret = ARMRAL_ARGUMENT_ERROR;
switch (iq_width) {
case 8:
ret = armral_block_float_decompr_8bit(n_prb, (armral_compressed_data_8bit *)src, (armral_cmplx_int16_t *)dst, NULL);
if (unlikely(ret != ARMRAL_SUCCESS)) {
LOG_E(HW, "armral_block_scaling_decompr_8bit returned an error: %d\n", (int)ret);
}
break;
case 9:
ret = armral_block_float_decompr_9bit(n_prb, (armral_compressed_data_9bit *)src, (armral_cmplx_int16_t *)dst, NULL);
if (unlikely(ret != ARMRAL_SUCCESS)) {
LOG_E(HW, "armral_block_scaling_decompr_9bit returned an error: %d\n", (int)ret);
}
break;
case 14:
ret = armral_block_float_decompr_14bit(n_prb, (armral_compressed_data_14bit *)src, (armral_cmplx_int16_t *)dst, NULL);
if (unlikely(ret != ARMRAL_SUCCESS)) {
LOG_E(HW, "armral_block_scaling_decompr_14bit returned an error: %d\n", (int)ret);
}
break;
default:
LOG_E(HW, "Unsupported IQ width in BFP decompression: %d\n", iq_width);
}
}
+59
View File
@@ -0,0 +1,59 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file radio/fhi_72/armral_bfp_compression.h
* \brief BFP compression for the O-RAN 7.2 FrontHaul Interface for Arm systems using the Arm RAN Acceleration Library
* \author Romain Beurdouche
* \date 2025
* \company EURECOM
* \email romain.beurdouche@eurecom.fr
* \note ArmRAL available at https://git.gitlab.arm.com/networking/ral.git
* \warning
*/
#ifndef __ARMRAL_BFP_COMPRESSION_H__
#define __ARMRAL_BFP_COMPRESSION_H__
/**
* The function operates on a fixed block size of one Physical Resource Block
* (PRB). Each block consists of 12 16-bit complex resource elements. Each block
* taken as input is compressed into 24 samples with a common unsigned scaling factor.
*
* @param[in] iq_width Width in bits of compressed samples.
* @param[in] n_prb The number of input resource blocks.
* @param[in] src Points to the input complex samples sequence.
* @param[out] dst Points to the output compressed data.
*/
void armral_bfp_compression(uint32_t iq_width, uint32_t n_prb, int16_t *src, int8_t *dst);
/**
* The function operates on a fixed block size of one Physical Resource Block
* (PRB). Each block consists of 12 compressed complex resource elements.
* Each block taken as input is expanded into 12 16-bit complex samples.
*
* @param[in] iq_width Width in bits of compressed samples.
* @param[in] n_prb The number of input resource blocks.
* @param[in] src Points to the input compressed data.
* @param[out] dst Points to the output complex samples sequence.
*/
void armral_bfp_decompression(uint32_t iq_width, uint32_t n_prb, int8_t *src, int16_t *dst);
#endif
+27 -6
View File
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include "xran_fh_o_du.h"
#include "xran_compression.h"
#include "armral_bfp_compression.h"
#if defined(__arm__) || defined(__aarch64__)
#else
@@ -215,12 +216,14 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
}
}
} else if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_BLKFLOAT) {
struct xranlib_decompress_request bfp_decom_req = {};
struct xranlib_decompress_response bfp_decom_rsp = {};
int16_t local_dst[12 * 2 * N_SC_PER_PRB] __attribute__((aligned(64)));
#if defined(__i386__) || defined(__x86_64__)
struct xranlib_decompress_request bfp_decom_req = {};
struct xranlib_decompress_response bfp_decom_rsp = {};
int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * 12; // 12 = closest number of PRBs to 139 REs
bfp_decom_req.data_in = (int8_t *)src;
bfp_decom_req.numRBs = 12; // closest number of PRBs to 139 REs
bfp_decom_req.len = payload_len;
@@ -230,6 +233,11 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
bfp_decom_rsp.data_out = (int16_t *)local_dst;
bfp_decom_rsp.len = 0;
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
#elif defined(__arm__) || defined(__aarch64__)
armral_bfp_decompression(ru_conf->iqWidth_PRACH, 12, (int8_t *)src, (int16_t *)local_dst);
#else
AssertFatal(1 == 0, "BFP decompression not supported on this architecture");
#endif
// note: this is hardwired for 139 point PRACH sequence, kbar=2
if (sym_idx == 0) //
for (idx = 0; idx < (139 * 2); idx++)
@@ -380,8 +388,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
uint32_t idxElm = 0;
uint8_t *src = (uint8_t *)ptr;
int16_t payload_len = 0;
LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
@@ -412,10 +418,12 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
} else if (pRbElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
#if defined(__i386__) || defined(__x86_64__)
struct xranlib_decompress_request bfp_decom_req = {};
struct xranlib_decompress_response bfp_decom_rsp = {};
payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize;
int16_t payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize;
bfp_decom_req.data_in = (int8_t *)src;
bfp_decom_req.numRBs = pRbElm->nRBSize;
bfp_decom_req.len = payload_len;
@@ -426,6 +434,11 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
bfp_decom_rsp.len = 0;
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
#elif defined(__arm__) || defined(__aarch64__)
armral_bfp_decompression(pRbElm->iqWidth, pRbElm->nRBSize, (int8_t *)src, (int16_t *)local_dst);
#else
AssertFatal(1 == 0, "BFP compression not supported on this architecture");
#endif
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
outcnt++;
@@ -552,9 +565,12 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
for (idx = 0; idx < (pos_len + neg_len) * 2; idx++)
((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx]);
} else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize;
#if defined(__i386__) || defined(__x86_64__)
struct xranlib_compress_request bfp_com_req = {};
struct xranlib_compress_response bfp_com_rsp = {};
payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize;
bfp_com_req.data_in = (int16_t *)local_src;
bfp_com_req.numRBs = p_prbMapElm->nRBSize;
bfp_com_req.len = payload_len;
@@ -565,6 +581,11 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
bfp_com_rsp.len = 0;
xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp);
#elif defined(__arm__) || defined(__aarch64__)
armral_bfp_compression(p_prbMapElm->iqWidth, p_prbMapElm->nRBSize, (int16_t *)local_src, (int8_t *)dst);
#else
AssertFatal(1 == 0, "BFP compression not supported on this architecture");
#endif
} else {
printf("p_prbMapElm->compMethod == %d is not supported\n", p_prbMapElm->compMethod);