fix(esp_log): add Kconfig to optionally bypass esp_rom_vprintf

In Log V2, ESP_LOG macros are using the runtime
constrained-environment path in esp_log_vprintf() reference
esp_rom_vprintf as the fallback formatter. On chips where ets_vprintf
is not in ROM (all targets except ESP32-S2 and ESP32-C2), this pulls
~1.2 KB of printf implementation into IRAM.

Add a new Kconfig option LOG_API_CONSTRAINED_ENV_SAFE (default y) that
controls whether this IRAM-resident fallback is used:

Also update the logging and RAM-usage documentation accordingly.

Closes https://github.com/espressif/esp-idf/issues/18346
This commit is contained in:
Guillaume Souchere
2026-03-23 11:16:47 +01:00
parent 23298ce2df
commit 0cba1db0ed
6 changed files with 72 additions and 6 deletions
+24
View File
@@ -52,6 +52,30 @@ menu "Log"
rsource "./Kconfig.settings"
config LOG_API_CONSTRAINED_ENV_SAFE
bool "Enable safe ESP_LOGx fallback in constrained environments (ISR, cache disabled)"
depends on LOG_VERSION_2 && !ESP_ROM_HAS_VPRINTF_FUNC && !LOG_MODE_BINARY_EN
default y
help
This option is only relevant on chips where ets_vprintf is NOT in ROM
When enabled, Log V2 routes ESP_DRAM_LOGx, ESP_EARLY_LOGx, and runtime
constrained-environment log calls (ISR, cache disabled) through esp_log(),
which uses esp_rom_vprintf for formatting.
When disabled, ESP_DRAM_LOGx and ESP_EARLY_LOGx expand directly
to esp_rom_printf (a true ROM function with zero IRAM cost), bypassing
esp_log(). Normal ESP_LOGx calls that happen to run in a constrained
environment (ISR, cache disabled) will use the standard vprintf function
instead of esp_rom_vprintf; if the standard vprintf resides in flash,
such calls may crash. Use ESP_DRAM_LOGx for any logging that must work
with cache disabled or from an ISR.
Disable this option to save ~1.2 KB of IRAM on memory-constrained devices.
Enable it if you need ESP_LOGx to safely fall back to ROM-based printing
in ISRs or with cache disabled, or if you need constrained-environment
logs in binary log format.
config LOG_IN_IRAM
bool "Place logging functions in IRAM" if SPI_FLASH_AUTO_SUSPEND
default y
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -247,14 +247,14 @@ void esp_log_va(esp_log_config_t config, const char *tag, const char *format, va
#if defined(__cplusplus) && (__cplusplus > 201703L)
#define ESP_LOG_EARLY_IMPL(tag, format, configs, log_tag_letter, ...) do { \
if (ESP_LOG_VERSION == 1) { \
if (ESP_LOG_VERSION == 1 || (ESP_LOG_VERSION == 2 && !ESP_LOG_API_CONSTRAINED_ENV_SAFE)) { \
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(LOG_FORMAT(log_tag_letter, format), esp_log_timestamp(), tag __VA_OPT__(,) __VA_ARGS__); } \
} else { \
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
} } while(0)
#else // !(defined(__cplusplus) && (__cplusplus > 201703L))
#define ESP_LOG_EARLY_IMPL(tag, format, configs, log_tag_letter, ...) do { \
if (ESP_LOG_VERSION == 1) { \
if (ESP_LOG_VERSION == 1 || (ESP_LOG_VERSION == 2 && !ESP_LOG_API_CONSTRAINED_ENV_SAFE)) { \
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(LOG_FORMAT(log_tag_letter, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \
} else { \
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV), tag, ESP_LOG_ATTR_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
@@ -263,14 +263,14 @@ void esp_log_va(esp_log_config_t config, const char *tag, const char *format, va
#if defined(__cplusplus) && (__cplusplus > 201703L)
#define ESP_DRAM_LOG_IMPL(tag, format, configs, log_tag_letter, ...) do { \
if (ESP_LOG_VERSION == 1) { \
if (ESP_LOG_VERSION == 1 || (ESP_LOG_VERSION == 2 && !ESP_LOG_API_CONSTRAINED_ENV_SAFE)) { \
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(_ESP_LOG_DRAM_LOG_FORMAT(log_tag_letter, format), tag __VA_OPT__(,) __VA_ARGS__); } \
} else { \
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV | ESP_LOG_CONFIG_DIS_COLOR | ESP_LOG_CONFIG_DIS_TIMESTAMP), tag, ESP_LOG_ATTR_DRAM_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
} } while(0)
#else // !(defined(__cplusplus) && (__cplusplus > 201703L))
#define ESP_DRAM_LOG_IMPL(tag, format, configs, log_tag_letter, ...) do { \
if (ESP_LOG_VERSION == 1) { \
if (ESP_LOG_VERSION == 1 || (ESP_LOG_VERSION == 2 && !ESP_LOG_API_CONSTRAINED_ENV_SAFE)) { \
if (_ESP_LOG_EARLY_ENABLED(configs)) { esp_rom_printf(_ESP_LOG_DRAM_LOG_FORMAT(log_tag_letter, format), tag, ##__VA_ARGS__); } \
} else { \
if (ESP_LOG_ENABLED(configs)) { esp_log(ESP_LOG_CONFIG_INIT((configs) | ESP_LOG_CONFIGS_DEFAULT | ESP_LOG_CONFIG_CONSTRAINED_ENV | ESP_LOG_CONFIG_DIS_COLOR | ESP_LOG_CONFIG_DIS_TIMESTAMP), tag, ESP_LOG_ATTR_DRAM_STR(format) ESP_LOG_ARGS(__VA_ARGS__)); } \
+21 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,6 +13,7 @@
#include "esp_log_level.h"
#include "esp_assert.h"
#include "sdkconfig.h"
#include "esp_rom_caps.h"
#ifdef __cplusplus
extern "C" {
@@ -111,6 +112,25 @@ extern "C" {
#ifndef ESP_LOG_FORMATTING_DISABLED
#define ESP_LOG_FORMATTING_DISABLED (0)
#endif
/**
* This define controls whether esp_rom_vprintf is used as the fallback print function in constrained
* environments (ISR, cache disabled, early startup). When set to 0, esp_rom_vprintf is never referenced,
* saving ~1.2 KB of IRAM on chips where it is not a true ROM function.
* ESP_DRAM_LOGx and ESP_EARLY_LOGx will use esp_rom_printf directly instead.
*
* On chips where ets_vprintf is in ROM (ESP32-S2, ESP32-C2), this is always enabled
* since there is no IRAM cost.
*/
#if BOOTLOADER_BUILD || ESP_ROM_HAS_VPRINTF_FUNC
#define ESP_LOG_API_CONSTRAINED_ENV_SAFE (1)
#else
#ifdef CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
#define ESP_LOG_API_CONSTRAINED_ENV_SAFE (1)
#else
#define ESP_LOG_API_CONSTRAINED_ENV_SAFE (0)
#endif
#endif
/** @endcond */
/**
@@ -32,11 +32,15 @@ __attribute__((always_inline)) static inline void esp_log_vprintf(esp_log_config
#else // APP
extern vprintf_like_t esp_log_vprint_func;
#if ESP_LOG_VERSION == 2
#if CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
vprintf_like_t vprint_func[2] = {
esp_log_vprint_func,
esp_rom_vprintf,
};
vprint_func[config.opts.constrained_env](format, args);
#else
esp_log_vprint_func(format, args);
#endif // CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
#else // ESP_LOG_VERSION == 1
esp_log_vprint_func(format, args);
#endif // ESP_LOG_VERSION == 1
@@ -194,6 +194,7 @@ The following options will reduce IRAM usage of some ESP-IDF features:
- Disable :ref:`CONFIG_LIBC_LOCKS_PLACE_IN_IRAM` if no ISRs that run while cache is disabled (i.e. IRAM ISRs) use libc lock APIs.
:CONFIG_ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY: - Disable :ref:`CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS` to save approximately 1000 bytes of IRAM, at the cost of reduced performance.
:SOC_SPIRAM_SUPPORTED: - Enable :ref:`CONFIG_ESP_EVENT_LOOP_IN_EXT_RAM` to force ``esp_event`` to place event loop related allocations in external RAM instead of internal RAM.
:not CONFIG_ESP_ROM_HAS_VPRINTF_FUNC: - When using **Log V2**, disable :ref:`CONFIG_LOG_API_CONSTRAINED_ENV_SAFE` to remove ``esp_rom_vprintf`` from IRAM, saving ~1.2 KB. This means ``ESP_LOGx`` will no longer safely fall back to ROM-based printing in ISRs or with cache disabled. Use ``ESP_DRAM_LOGx`` explicitly for constrained-environment logging. See :doc:`/api-reference/system/log` for details.
.. only:: esp32
+17
View File
@@ -656,6 +656,23 @@ The following measurements were performed using the ``esp_timer`` example with d
Enabling **Log V2** increases IRAM usage while reducing the overall application binary size, Flash code, and data usage.
.. only:: not CONFIG_ESP_ROM_HAS_VPRINTF_FUNC
Reducing IRAM Usage in Log V2
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The IRAM increase in **Log V2** is primarily caused by ``esp_rom_vprintf``, which is compiled into IRAM (~1.2 KB) on {IDF_TARGET_NAME}. This function is referenced as the fallback formatter for constrained environments (ISR, cache disabled) in the ``esp_log_vprintf()`` inline function.
On chips where IRAM and DRAM share the same memory pool, this also reduces available heap by the same amount.
To eliminate this cost, disable :ref:`CONFIG_LOG_API_CONSTRAINED_ENV_SAFE` (enabled by default). When disabled:
- ``ESP_DRAM_LOGx`` and ``ESP_EARLY_LOGx`` expand directly to ``esp_rom_printf()`` (a true ROM function, zero IRAM cost), bypassing the ``esp_log()`` pipeline entirely.
- Normal ``ESP_LOGx`` calls in constrained environments (ISR, cache disabled) will use the standard ``vprintf`` function. If ``vprintf`` resides in flash, such calls may crash. Use ``ESP_DRAM_LOGx`` for any logging that must work with cache disabled or from an ISR.
- ``esp_rom_vprintf`` is never referenced, so the linker excludes it from the binary.
When enabled, the original **Log V2** behavior is preserved: all constrained-environment logs route through ``esp_log()`` and use ``esp_rom_vprintf`` as the formatter, supporting features like binary log format for early/DRAM logs.
Logging to Host via JTAG
------------------------