diff --git a/include/logging/log_ctrl.h b/include/logging/log_ctrl.h index 9afa0723232..ef0169741cd 100644 --- a/include/logging/log_ctrl.h +++ b/include/logging/log_ctrl.h @@ -220,6 +220,32 @@ static inline bool log_data_pending(void) */ int log_set_tag(const char *tag); +/** + * @brief Get current memory usage. + * + * @param[out] buf_size Capacity of the buffer used for storing log messages. + * @param[out] usage Number of bytes currently containing pending log messages. + * + * @retval -EINVAL if logging mode does not use the buffer. + * @retval 0 successfully collected usage data. + */ +int log_mem_get_usage(uint32_t *buf_size, uint32_t *usage); + +/** + * @brief Get maximum memory usage. + * + * Requires CONFIG_LOG_MEM_UTILIZATION option. + * + * @param[out] max Maximum number of bytes used for pending log messages. + * + * @retval -EINVAL if logging mode does not use the buffer. + * @retval -ENOTSUP if instrumentation is not enabled. + * not been enabled. + * + * @retval 0 successfully collected usage data. + */ +int log_mem_get_max_usage(uint32_t *max); + #if defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL) #define LOG_CORE_INIT() log_core_init() #define LOG_INIT() log_init() diff --git a/include/logging/log_msg.h b/include/logging/log_msg.h index 570a8347ede..eab86cc6a4b 100644 --- a/include/logging/log_msg.h +++ b/include/logging/log_msg.h @@ -482,7 +482,12 @@ uint32_t log_msg_mem_get_used(void); */ uint32_t log_msg_mem_get_max_used(void); - +/** + * @brief Get slab size + * + * @return Size of a slab used in slab pool for log messages. + */ +size_t log_msg_get_slab_size(void); /** * @} */ diff --git a/subsys/logging/Kconfig.misc b/subsys/logging/Kconfig.misc index 804ef88a74a..6c2ccdb4c9c 100644 --- a/subsys/logging/Kconfig.misc +++ b/subsys/logging/Kconfig.misc @@ -53,4 +53,13 @@ config LOG2_FMT_SECTION removing strings from final binary and should be used for dictionary logging. +config LOG_MEM_UTILIZATION + bool "Enable tracking maximum memory utilization" + depends on LOG_MODE_DEFERRED + default y if LOG_CMDS + select MEM_SLAB_TRACE_MAX_UTILIZATION if LOG1 + help + When enabled, maximum usage of memory used for log messages in deferred + mode is tracked. It can be used to trim LOG_BUFFER_SIZE. + endmenu diff --git a/subsys/logging/log_cmds.c b/subsys/logging/log_cmds.c index 9619c09f28f..e47aa84e4a3 100644 --- a/subsys/logging/log_cmds.c +++ b/subsys/logging/log_cmds.c @@ -404,26 +404,28 @@ static int cmd_log_strdup_utilization(const struct shell *shell, return 0; } -static int cmd_log_memory_slabs(const struct shell *sh, size_t argc, char **argv) +static int cmd_log_mem(const struct shell *sh, size_t argc, char **argv) { - uint32_t slabs_free; + uint32_t size; uint32_t used; uint32_t max; + int err; - slabs_free = log_msg_mem_get_free(); - used = log_msg_mem_get_used(); - - shell_print(sh, "Blocks used:\t%d", used); - shell_print(sh, "Blocks free:\t%d", slabs_free); - if (IS_ENABLED(CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION)) { - max = log_msg_mem_get_max_used(); - shell_print(sh, "Blocks max:\t%d", max); - } else { - shell_print( - sh, - "Enable CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION to get max memory utilization"); + err = log_mem_get_usage(&size, &used); + if (err < 0) { + shell_error(sh, "Failed to get usage (mode does not support it?)"); } + shell_print(sh, "Log message buffer utilization report:"); + shell_print(sh, "\tCapacity: %u bytes", size); + shell_print(sh, "\tCurrently in use: %u bytes", used); + err = log_mem_get_max_usage(&max); + if (err < 0) { + shell_print(sh, "Enable CONFIG_LOG_MEM_UTILIZATION to get maximum usage"); + } + + shell_print(sh, "\tMaximum usage: %u bytes", max); + return 0; } @@ -479,7 +481,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "Get utilization of string duplicates pool", cmd_log_strdup_utilization, 1, 0), SHELL_COND_CMD(CONFIG_LOG_MODE_DEFERRED, mem, NULL, "Logger memory usage", - cmd_log_memory_slabs), + cmd_log_mem), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(log, &sub_log_stat, "Commands for controlling logger", diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index 391b9bf87d4..4af16c9e4d1 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -105,8 +105,10 @@ static const struct mpsc_pbuf_buffer_config mpsc_config = { .size = ARRAY_SIZE(buf32), .notify_drop = notify_drop, .get_wlen = log_msg2_generic_get_wlen, - .flags = IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW) ? - MPSC_PBUF_MODE_OVERWRITE : 0 + .flags = (IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW) ? + MPSC_PBUF_MODE_OVERWRITE : 0) | + (IS_ENABLED(CONFIG_LOG_MEM_UTILIZATION) ? + MPSC_PBUF_MAX_UTILIZATION : 0) }; /* Check that default tag can fit in tag buffer. */ @@ -1259,6 +1261,42 @@ int log_set_tag(const char *str) return 0; } +int log_mem_get_usage(uint32_t *buf_size, uint32_t *usage) +{ + __ASSERT_NO_MSG(buf_size != NULL); + __ASSERT_NO_MSG(usage != NULL); + + if (!IS_ENABLED(CONFIG_LOG_MODE_DEFERRED)) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_LOG1)) { + *buf_size = CONFIG_LOG_BUFFER_SIZE; + *usage = log_msg_mem_get_used() * log_msg_get_slab_size(); + return 0; + } + + mpsc_pbuf_get_utilization(&log_buffer, buf_size, usage); + + return 0; +} + +int log_mem_get_max_usage(uint32_t *max) +{ + __ASSERT_NO_MSG(max != NULL); + + if (!IS_ENABLED(CONFIG_LOG_MODE_DEFERRED)) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_LOG1)) { + *max = log_msg_mem_get_max_used() * log_msg_get_slab_size(); + return 0; + } + + return mpsc_pbuf_get_max_utilization(&log_buffer, max); +} + static void log_process_thread_timer_expiry_fn(struct k_timer *timer) { k_sem_give(&log_process_thread_sem); diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index 522f47abd35..7ebf4f7f692 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -498,3 +498,8 @@ uint32_t log_msg_mem_get_max_used(void) { return k_mem_slab_max_used_get(&log_msg_pool); } + +size_t log_msg_get_slab_size(void) +{ + return MSG_SIZE; +}