Skip to content

Commit 920ee6e

Browse files
author
codebot
committed
Update main
2 parents 00ff1e7 + 3fd35d9 commit 920ee6e

File tree

95 files changed

+2167
-652
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2167
-652
lines changed

.github/workflows/ccpp.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
sudo docker/scripts/install_dependencies.sh
2828
- name: Build srsRAN Project on x86 ${{ matrix.os }} with compiler ${{ matrix.compiler }}
2929
run: |
30-
docker/scripts/builder.sh -c ${{ matrix.compiler }} -m "-j$(nproc)" .
30+
docker/scripts/builder.sh -c ${{ matrix.compiler }} -m "-j$(nproc)" -DBUILD_TESTING=On .
3131
- name: Run unit tests
3232
run: |
3333
cd build && ctest -j$(nproc) --schedule-random --output-on-failure

apps/CMakeLists.txt

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

2121
add_subdirectory(cu)
2222
add_subdirectory(du)
23+
add_subdirectory(du_low)
2324
add_subdirectory(examples)
2425
add_subdirectory(gnb)
2526
add_subdirectory(helpers)

apps/du_low/CMakeLists.txt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#
2+
# Copyright 2021-2025 Software Radio Systems Limited
3+
#
4+
# This file is part of srsRAN
5+
#
6+
# srsRAN is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU Affero General Public License as
8+
# published by the Free Software Foundation, either version 3 of
9+
# the License, or (at your option) any later version.
10+
#
11+
# srsRAN is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU Affero General Public License for more details.
15+
#
16+
# A copy of the GNU Affero General Public License can be found in
17+
# the LICENSE file in the top-level directory of this distribution
18+
# and at http://www.gnu.org/licenses/.
19+
#
20+
21+
set(SOURCES
22+
du_low_appconfig_cli11_schema.cpp
23+
du_low_appconfig_validators.cpp
24+
du_low_appconfig_translators.cpp
25+
du_low_appconfig_yaml_writer.cpp)
26+
27+
28+
add_library(srsdu_low_base STATIC ${SOURCES})
29+
target_link_libraries(srsdu_low_base PRIVATE
30+
srsran_app_helpers
31+
srsran_app_services
32+
srsran_support
33+
srsran_versioning)
34+
35+
target_include_directories(srsdu_low_base PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/external)
36+
37+
add_executable(srsdu_low du_low.cpp)
38+
add_backward(srsdu_low)
39+
target_include_directories(srsdu_low PRIVATE ${CMAKE_SOURCE_DIR})
40+
install(TARGETS srsdu_low RUNTIME)
41+
target_link_libraries(srsdu_low PRIVATE srsdu_low_base)
42+
notify_binary_target(srsdu_low)

apps/du_low/du_low.cpp

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
/*
2+
*
3+
* Copyright 2021-2025 Software Radio Systems Limited
4+
*
5+
* This file is part of srsRAN.
6+
*
7+
* srsRAN is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as
9+
* published by the Free Software Foundation, either version 3 of
10+
* the License, or (at your option) any later version.
11+
*
12+
* srsRAN is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* A copy of the GNU Affero General Public License can be found in
18+
* the LICENSE file in the top-level directory of this distribution
19+
* and at http://www.gnu.org/licenses/.
20+
*
21+
*/
22+
23+
#include "apps/helpers/metrics/metrics_helpers.h"
24+
#include "apps/services/app_resource_usage/app_resource_usage.h"
25+
#include "apps/services/application_message_banners.h"
26+
#include "apps/services/application_tracer.h"
27+
#include "apps/services/cmdline/cmdline_command_dispatcher.h"
28+
#include "apps/services/core_isolation_manager.h"
29+
#include "apps/services/metrics/metrics_manager.h"
30+
#include "apps/services/metrics/metrics_notifier_proxy.h"
31+
#include "apps/services/remote_control/remote_server.h"
32+
#include "apps/services/worker_manager/worker_manager.h"
33+
#include "du_low_appconfig.h"
34+
#include "du_low_appconfig_cli11_schema.h"
35+
#include "du_low_appconfig_translators.h"
36+
#include "du_low_appconfig_validators.h"
37+
#include "du_low_appconfig_yaml_writer.h"
38+
#include "srsran/support/backtrace.h"
39+
#include "srsran/support/config_parsers.h"
40+
#include "srsran/support/cpu_features.h"
41+
#include "srsran/support/io/io_broker_factory.h"
42+
#include "srsran/support/signal_handling.h"
43+
#include "srsran/support/signal_observer.h"
44+
#include "srsran/support/tracing/event_tracing.h"
45+
#include "srsran/support/versioning/build_info.h"
46+
#include "srsran/support/versioning/version.h"
47+
#include <atomic>
48+
// Include ThreadSanitizer (TSAN) options if thread sanitization is enabled.
49+
// This include is not unused - it helps prevent false alarms from the thread sanitizer.
50+
#include "apps/units/application_unit.h"
51+
#include "srsran/support/tsan_options.h"
52+
53+
using namespace srsran;
54+
55+
/// \file
56+
/// \brief Application of a distributed unit (DU) that runs the low part (PHY) of the split 6.
57+
58+
static std::string config_file;
59+
60+
/// Flag that indicates if the application is running or being shutdown.
61+
static std::atomic<bool> is_app_running = {true};
62+
/// Maximum number of configuration files allowed to be concatenated in the command line.
63+
static constexpr unsigned MAX_CONFIG_FILES = 10;
64+
65+
static void populate_cli11_generic_args(CLI::App& app)
66+
{
67+
fmt::memory_buffer buffer;
68+
format_to(std::back_inserter(buffer), "srsRAN 5G DU low version {} ({})", get_version(), get_build_hash());
69+
app.set_version_flag("-v,--version", srsran::to_c_str(buffer));
70+
app.set_config("-c,", config_file, "Read config from file", false)->expected(1, MAX_CONFIG_FILES);
71+
}
72+
73+
/// Function to call when the application is interrupted.
74+
static void interrupt_signal_handler(int signal)
75+
{
76+
is_app_running = false;
77+
}
78+
79+
static signal_dispatcher cleanup_signal_dispatcher;
80+
81+
/// Function to call when the application is going to be forcefully shutdown.
82+
static void cleanup_signal_handler(int signal)
83+
{
84+
cleanup_signal_dispatcher.notify_signal(signal);
85+
srslog::flush();
86+
}
87+
88+
/// Function to call when an error is reported by the application.
89+
static void app_error_report_handler()
90+
{
91+
srslog::flush();
92+
}
93+
94+
static void initialize_log(const std::string& filename)
95+
{
96+
srslog::sink* log_sink = (filename == "stdout") ? srslog::create_stdout_sink() : srslog::create_file_sink(filename);
97+
if (log_sink == nullptr) {
98+
report_error("Could not create application main log sink.\n");
99+
}
100+
srslog::set_default_sink(*log_sink);
101+
srslog::init();
102+
}
103+
104+
static void register_app_logs(const du_low_appconfig& du_cfg /*, application_unit& du_low_app_unit*/)
105+
{
106+
const logger_appconfig& log_cfg = du_cfg.log_cfg;
107+
// Set log-level of app and all non-layer specific components to app level.
108+
109+
auto& logger = srslog::fetch_basic_logger("ALL", false);
110+
logger.set_level(log_cfg.lib_level);
111+
logger.set_hex_dump_max_size(log_cfg.hex_max_size);
112+
113+
auto& app_logger = srslog::fetch_basic_logger("APP", false);
114+
app_logger.set_level(srslog::basic_levels::info);
115+
app_services::application_message_banners::log_build_info(app_logger);
116+
app_logger.set_level(log_cfg.all_level);
117+
app_logger.set_hex_dump_max_size(log_cfg.hex_max_size);
118+
119+
auto& config_logger = srslog::fetch_basic_logger("CONFIG", false);
120+
config_logger.set_level(log_cfg.config_level);
121+
config_logger.set_hex_dump_max_size(log_cfg.hex_max_size);
122+
123+
// Metrics log channels.
124+
const app_helpers::metrics_config& metrics_cfg = du_cfg.metrics_cfg.rusage_config.metrics_consumers_cfg;
125+
app_helpers::initialize_metrics_log_channels(metrics_cfg, log_cfg.hex_max_size);
126+
127+
// Register units logs.
128+
// du_low_app_unit.on_loggers_registration();
129+
}
130+
131+
int main(int argc, char** argv)
132+
{
133+
// Set the application error handler.
134+
set_error_handler(app_error_report_handler);
135+
136+
static constexpr std::string_view app_name = "DU low";
137+
app_services::application_message_banners::announce_app_and_version(app_name);
138+
139+
// Set interrupt and cleanup signal handlers.
140+
register_interrupt_signal_handler(interrupt_signal_handler);
141+
register_cleanup_signal_handler(cleanup_signal_handler);
142+
143+
// Enable backtrace.
144+
enable_backtrace();
145+
146+
// Setup and configure config parsing.
147+
CLI::App app("srsDU low application");
148+
app.config_formatter(create_yaml_config_parser());
149+
app.allow_config_extras(CLI::config_extras_mode::error);
150+
// Fill the generic application arguments to parse.
151+
populate_cli11_generic_args(app);
152+
153+
du_low_appconfig du_low_cfg;
154+
// Configure CLI11 with the DU application configuration schema.
155+
configure_cli11_with_du_low_appconfig_schema(app, du_low_cfg);
156+
157+
// :TODO: create the app unit.
158+
// auto o_du_app_unit = create_flexible_o_du_application_unit("du");
159+
// o_du_app_unit->on_parsing_configuration_registration(app);
160+
161+
// Set the callback for the app calling all the autoderivation functions.
162+
app.callback([&app, &du_low_cfg /*, &o_du_app_unit*/]() {
163+
autoderive_du_low_parameters_after_parsing(app, du_low_cfg);
164+
// o_du_app_unit->on_configuration_parameters_autoderivation(app);
165+
});
166+
167+
// Parse arguments.
168+
CLI11_PARSE(app, argc, argv);
169+
170+
// Dry run mode, exit.
171+
if (du_low_cfg.enable_dryrun) {
172+
return 0;
173+
}
174+
175+
// Check the modified configuration.
176+
if (!validate_du_low_appconfig(du_low_cfg) /*||
177+
!o_du_app_unit->on_configuration_validation((du_low_cfg.expert_execution_cfg.affinities.isolated_cpus)
178+
? du_low_cfg.expert_execution_cfg.affinities.isolated_cpus.value()
179+
: os_sched_affinity_bitmask::available_cpus())*/) {
180+
report_error("Invalid configuration detected.\n");
181+
}
182+
183+
// Set up logging.
184+
initialize_log(du_low_cfg.log_cfg.filename);
185+
register_app_logs(du_low_cfg /*, *o_du_app_unit*/);
186+
187+
// Check the metrics and metrics consumers.
188+
srslog::basic_logger& app_logger = srslog::fetch_basic_logger("APP");
189+
bool metrics_enabled =
190+
/*o_du_app_unit->are_metrics_enabled() || */ du_low_cfg.metrics_cfg.rusage_config.enable_app_usage;
191+
192+
if (!metrics_enabled && du_low_cfg.metrics_cfg.rusage_config.metrics_consumers_cfg.enabled()) {
193+
app_logger.warning("Logger or JSON metrics output enabled but no metrics will be reported as no layer was enabled");
194+
fmt::println("Logger or JSON metrics output enabled but no metrics will be reported as no layer was enabled");
195+
}
196+
197+
// Log input configuration.
198+
srslog::basic_logger& config_logger = srslog::fetch_basic_logger("CONFIG");
199+
if (config_logger.debug.enabled()) {
200+
YAML::Node node;
201+
fill_du_low_appconfig_in_yaml_schema(node, du_low_cfg);
202+
// o_du_app_unit->dump_config(node);
203+
config_logger.debug("Input configuration (all values): \n{}", YAML::Dump(node));
204+
} else {
205+
config_logger.info("Input configuration (only non-default values): \n{}", app.config_to_str(false, false));
206+
}
207+
208+
app_services::application_tracer app_tracer;
209+
if (not du_low_cfg.log_cfg.tracing_filename.empty()) {
210+
app_tracer.enable_tracer(du_low_cfg.log_cfg.tracing_filename, app_logger);
211+
}
212+
213+
app_services::core_isolation_manager core_isolation_mngr;
214+
if (du_low_cfg.expert_execution_cfg.affinities.isolated_cpus) {
215+
if (!core_isolation_mngr.isolate_cores(*du_low_cfg.expert_execution_cfg.affinities.isolated_cpus)) {
216+
report_error("Failed to isolate specified CPUs");
217+
}
218+
}
219+
220+
// Log CPU architecture.
221+
cpu_architecture_info::get().print_cpu_info(app_logger);
222+
223+
// Check and log included CPU features and check support by current CPU
224+
if (cpu_supports_included_features()) {
225+
app_logger.debug("Required CPU features: {}", get_cpu_feature_info());
226+
} else {
227+
// Quit here until we complete selection of the best matching implementation for the current CPU at runtime.
228+
app_logger.error("The CPU does not support the required CPU features that were configured during compile time: {}",
229+
get_cpu_feature_info());
230+
report_error("The CPU does not support the required CPU features that were configured during compile time: {}\n",
231+
get_cpu_feature_info());
232+
}
233+
234+
// Check some common causes of performance issues and print a warning if required.
235+
check_cpu_governor(app_logger);
236+
check_drm_kms_polling(app_logger);
237+
238+
// Create manager of timers for DU, which will be driven by the PHY slot ticks.
239+
timer_manager app_timers{256};
240+
241+
// Instantiate worker manager.
242+
worker_manager_config worker_manager_cfg;
243+
// o_du_app_unit->fill_worker_manager_config(worker_manager_cfg);
244+
fill_du_low_worker_manager_config(worker_manager_cfg, du_low_cfg);
245+
worker_manager_cfg.app_timers = &app_timers;
246+
247+
worker_manager workers{worker_manager_cfg};
248+
249+
// Set layer-specific pcap options.
250+
const auto& low_prio_cpu_mask = du_low_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg.mask;
251+
252+
// Create IO broker.
253+
io_broker_config io_broker_cfg(low_prio_cpu_mask);
254+
std::unique_ptr<io_broker> epoll_broker = create_io_broker(io_broker_type::epoll, io_broker_cfg);
255+
256+
// Register the commands.
257+
app_services::cmdline_command_dispatcher command_parser(*epoll_broker, *workers.non_rt_low_prio_exec, {});
258+
259+
// :TODO: how to manage metrics from the DU low?
260+
app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder;
261+
262+
// Create app-level resource usage service and metrics.
263+
auto app_resource_usage_service = app_services::build_app_resource_usage_service(
264+
metrics_notifier_forwarder, du_low_cfg.metrics_cfg.rusage_config, srslog::fetch_basic_logger("GNB"));
265+
266+
std::vector<app_services::metrics_config> app_metrics = std::move(app_resource_usage_service.metrics);
267+
268+
// Only DU has metrics now.
269+
app_services::metrics_manager metrics_mngr(
270+
srslog::fetch_basic_logger("GNB"),
271+
*workers.metrics_exec,
272+
app_metrics,
273+
app_timers,
274+
std::chrono::milliseconds(du_low_cfg.metrics_cfg.metrics_service_cfg.app_usage_report_period));
275+
276+
// Connect the forwarder to the metrics manager.
277+
metrics_notifier_forwarder.connect(metrics_mngr);
278+
279+
// :TODO: how to manage cmdline and remote commands??
280+
281+
metrics_mngr.start();
282+
{
283+
app_services::application_message_banners app_banner(app_name, du_low_cfg.log_cfg.filename);
284+
285+
while (is_app_running) {
286+
std::this_thread::sleep_for(std::chrono::milliseconds(250));
287+
}
288+
}
289+
metrics_mngr.stop();
290+
291+
workers.stop();
292+
293+
srslog::flush();
294+
295+
return 0;
296+
}

0 commit comments

Comments
 (0)