Skip to content

Commit 0db05d0

Browse files
authored
dlt-qnx-system: prevent message loss in high load situations (#490)
* Add wait method, which waits up to 5 seconds for buffer space to become available. This method tries to flush the buffer via tcp every 10ms. An error will be logged when there was not enough space. The error shows up in dlt to simplify debugging. * improve cmake that more qnx compilers are detected * log missing context mapping only once, this greatly reduces noise and the load of the system, as previously the message was logged with every log of an unmapped application Signed-off-by: Alexander Mohr <[email protected]>
1 parent 9285147 commit 0db05d0

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

CMakeLists.txt

+4-2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ option(WITH_DLT_LOG_LEVEL_APP_CONFIG "Set to ON to enable default log levels bas
8282

8383
set(DLT_IPC "FIFO" CACHE STRING "UNIX_SOCKET,FIFO")
8484
set(DLT_USER "genivi" CACHE STRING "Set user for process not run as root")
85+
set(DLT_QNX_SLOG_ADAPTER_WAIT_BUFFER_TIMEOUT_MS "100" CACHE STRING "Timeout in milliseconds to wait before messages are dropped when input buffer is full")
8586

8687
option(WITH_DLT_PKGCONFIG "Set to ON to generate pkgconfig .pc files" ON)
8788
option(WITH_DLT_CXX11_EXT "Set to ON to build C++11 extensions" OFF)
@@ -142,6 +143,7 @@ include_directories(
142143
add_definitions(-D_GNU_SOURCE)
143144
add_definitions(-DDLT_WRITEV_TIMEOUT_SEC=${DLT_WRITEV_TIMEOUT_SEC})
144145
add_definitions(-DDLT_WRITEV_TIMEOUT_USEC=${DLT_WRITEV_TIMEOUT_USEC})
146+
add_definitions(-DDLT_QNX_SLOG_ADAPTER_WAIT_BUFFER_TIMEOUT_MS=${DLT_QNX_SLOG_ADAPTER_WAIT_BUFFER_TIMEOUT_MS})
145147

146148
if(NOT DLT_IPC STREQUAL "UNIX_SOCKET" AND NOT DLT_IPC STREQUAL "FIFO")
147149
message(FATAL_ERROR "${DLT_IPC} is not a valid value for DLT_IPC")
@@ -180,8 +182,8 @@ if(WITH_DLT_USE_IPv6)
180182
add_definitions(-DDLT_USE_IPv6)
181183
endif()
182184

183-
if(WITH_DLT_QNX_SYSTEM AND NOT "${CMAKE_C_COMPILER}" MATCHES "nto-qnx|qcc")
184-
message(FATAL_ERROR "Can only compile for QNX with a QNX compiler.")
185+
if(WITH_DLT_QNX_SYSTEM AND NOT "${CMAKE_C_COMPILER}" MATCHES "nto-qnx|qcc|ntoaarch64-gcc|ntox86_64-gcc")
186+
message(FATAL_ERROR "Can only compile for QNX with a QNX compiler, but found '${CMAKE_C_COMPILER}'.")
185187
endif()
186188

187189
if (WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK)

doc/dlt_build_options.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ WITH\_DLT\_DBUS | OFF | Set to ON to build src/dbus
5959
Option | Value | Comment
6060
:--- | :--- | :---
6161
WITH\_DLT\_QNX\_SYSTEM | OFF | Set to ON to build QNX system binary dlt-qnx-system
62+
DLT\_QNX\_SLOG\_ADAPTER\_WAIT\_BUFFER\_TIMEOUT\_MS | 100 | Maximum time in milliseconds to wait for buffer space in dlt before messages from the slog will be discarded.
6263

6364
## Documentation Options
6465

src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp

+44-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@
2828
#include <sys/slog2.h>
2929
#include <sys/json.h>
3030
#include <slog2_parse.h>
31+
#include <thread>
32+
#include <set>
3133

3234
#include "dlt-qnx-system.h"
3335
#include "dlt_cpp_extension.hpp"
36+
using std::chrono_literals::operator""ms;
37+
using std::chrono_literals::operator""s;
3438

3539
/* Teach dlt about json_decoder_error_t */
3640
template<>
@@ -42,6 +46,7 @@ inline int32_t logToDlt(DltContextData &log, const json_decoder_error_t &value)
4246
extern DltContext dltQnxSystem;
4347

4448
static DltContext dltQnxSlogger2Context;
49+
static std::set<std::string> dltWarnedMissingMappings;
4550

4651
extern DltQnxSystemThreads g_threads;
4752

@@ -121,14 +126,49 @@ static DltContext *dlt_context_from_slog2file(const char *file_name) {
121126

122127
auto search = g_slog2file.find(name);
123128
if (search == g_slog2file.end()) {
124-
DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_VERBOSE,
125-
"slog2 filename not found in mapping: ", name.c_str());
129+
// Only warn once about missing mapping.
130+
auto it = dltWarnedMissingMappings.find(name);
131+
if (it == dltWarnedMissingMappings.end()) {
132+
dltWarnedMissingMappings.insert(name);
133+
DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_INFO,
134+
"slog2 filename not found in mapping: ", name.c_str());
135+
}
136+
126137
return &dltQnxSlogger2Context;
127138
} else {
128139
return search->second;
129140
}
130141
}
131142

143+
template <class time, class period>
144+
static void wait_for_buffer_space(const double max_usage_threshold,
145+
const std::chrono::duration<time, period> max_wait_time) {
146+
int total_size = 0;
147+
int used_size = 0;
148+
double used_percent = 100.0;
149+
bool timeout = false;
150+
const auto end_time = std::chrono::steady_clock::now() + max_wait_time;
151+
152+
do {
153+
dlt_user_check_buffer(&total_size, &used_size);
154+
used_percent = static_cast<double>(used_size) / total_size;
155+
if (used_percent < max_usage_threshold) {
156+
break;
157+
}
158+
159+
dlt_user_log_resend_buffer();
160+
161+
std::this_thread::sleep_for(10ms);
162+
timeout = std::chrono::steady_clock::now() < end_time;
163+
} while (!timeout);
164+
165+
if (timeout) {
166+
DLT_LOG(dltQnxSystem, DLT_LOG_ERROR,
167+
DLT_STRING("failed to get enough buffer space"));
168+
169+
}
170+
}
171+
132172
/**
133173
* Function which is invoked by slog2_parse_all()
134174
* See slog2_parse_all api docs on qnx.com for details
@@ -177,6 +217,8 @@ static int sloggerinfo_callback(slog2_packet_info_t *info, void *payload, void *
177217
DltContextData log_local; /* Used in DLT_* macros, do not rename */
178218
DltContext *ctxt = dlt_context_from_slog2file(info->file_name);
179219

220+
wait_for_buffer_space(0.8, std::chrono::milliseconds(DLT_QNX_SLOG_ADAPTER_WAIT_BUFFER_TIMEOUT_MS));
221+
180222
int ret;
181223
ret = dlt_user_log_write_start(ctxt, &log_local, loglevel);
182224

0 commit comments

Comments
 (0)