feat(log): Add test for constrained environment usage config

This commit is contained in:
Guillaume Souchere
2026-03-23 12:37:07 +01:00
parent 0cba1db0ed
commit ea1af7c141
8 changed files with 106 additions and 6 deletions
+2 -3
View File
@@ -13,7 +13,6 @@
#include "esp_log_level.h"
#include "esp_assert.h"
#include "sdkconfig.h"
#include "esp_rom_caps.h"
#ifdef __cplusplus
extern "C" {
@@ -122,10 +121,10 @@ extern "C" {
* 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
#if BOOTLOADER_BUILD || CONFIG_ESP_ROM_HAS_VPRINTF_FUNC
#define ESP_LOG_API_CONSTRAINED_ENV_SAFE (1)
#else
#ifdef CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
#if defined(CONFIG_LOG_API_CONSTRAINED_ENV_SAFE) || defined(CONFIG_LOG_MODE_BINARY_EN)
#define ESP_LOG_API_CONSTRAINED_ENV_SAFE (1)
#else
#define ESP_LOG_API_CONSTRAINED_ENV_SAFE (0)
+7
View File
@@ -13,6 +13,8 @@
#include "esp_timer.h"
#include "sdkconfig.h"
#if CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
#if CONFIG_LOG_TAG_LEVEL_IMPL_NONE
#define EXPECTED_US 3
#define DELTA_US 3
@@ -51,7 +53,11 @@ TEST_CASE("test master logging level performance", "[log]")
#if ESP_LOG_VERSION == 1
const int typical_value = 150;
#else // ESP_LOG_VERSION == 2
#if CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
const int typical_value = 400;
#else
const int typical_value = 250;
#endif // CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
#endif // ESP_LOG_VERSION == 2
TEST_ASSERT_INT_WITHIN(100, typical_value, calc_time_of_logging(ITERATIONS));
#else
@@ -68,3 +74,4 @@ TEST_CASE("test master logging level performance", "[log]")
esp_log_level_set("*", ESP_LOG_INFO);
ESP_LOGI(TAG, "End");
}
#endif // CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
+82 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,7 @@
#include <string.h>
#include <inttypes.h>
#include "unity.h"
#include "unity_test_utils.h"
#include "esp_rom_serial_output.h"
#include "sdkconfig.h"
@@ -152,3 +153,83 @@ TEST_CASE("LOG_LOCAL_LEVEL can be re-defined", "[log]")
esp_rom_install_uart_printf();
esp_log_level_set("*", ESP_LOG_INFO);
}
#if CONFIG_LOG_VERSION_2
/*
* Test ESP_LOG behavior in constrained environments (ISR, cache disabled).
*
* CONFIG_LOG_API_CONSTRAINED_ENV_SAFE controls how esp_log_vprintf() prints
* when the constrained_env flag is set:
* - Enabled: esp_log() uses esp_rom_vprintf (in IRAM) for output.
* ESP_LOG is safe to call from ISR or with cache disabled.
* - Disabled: esp_log() uses the standard vprintf callback (typically in flash).
* ESP_LOG from ISR or with cache disabled will crash because the
* print function is not in internal memory.
*
* We install print_to_buffer as the vprintf callback and disconnect the putc
* channel (used by esp_rom_vprintf). Then we call esp_log() with
* constrained_env=true and check where the output went:
* - Enabled: output goes to esp_rom_vprintf -> putc channel (disconnected)
* -> buffer stays empty.
* - Disabled: output goes to the vprintf callback (print_to_buffer)
* -> buffer contains the message.
*/
TEST_CASE("ESP_LOG constrained_env uses rom vprintf only when constrained_env_safe is enabled", "[log]")
{
vprintf_like_t old_vprintf = esp_log_set_vprintf(print_to_buffer);
/* Simulate a log call from a constrained environment (ISR / cache disabled) */
esp_log_config_t cfg = ESP_LOG_CONFIG_INIT(ESP_LOG_INFO
| ESP_LOG_CONFIG_CONSTRAINED_ENV);
/* Disconnect the putc channel so esp_rom_vprintf output is not captured.
* esp_rom_install_uart_printf() alone does not reset the software _putc1
* on chips without ESP_ROM_HAS_ETS_PRINTF_BUG (e.g. ESP32), so explicitly
* restore the default putc via esp_rom_install_channel_putc(). */
esp_rom_install_channel_putc(1, esp_rom_output_putc);
esp_rom_install_uart_printf();
reset_buffer();
esp_log(cfg, TAG1, "constrained %d", 42);
#if CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
/* esp_rom_vprintf was used (IRAM-safe) -> nothing in our vprintf buffer */
TEST_ASSERT_EQUAL(0, get_counter());
#else
/* Standard vprintf was used (flash-based, would crash in real ISR/cache-off) */
TEST_ASSERT_NOT_NULL(strstr(get_buffer(), "constrained 42"));
#endif
/* Restore */
esp_log_set_vprintf(old_vprintf);
esp_log_level_set("*", ESP_LOG_INFO);
}
#if CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
/*
* When constrained_env_safe is enabled and LOG_IN_IRAM=y (default), esp_log()
* code is in IRAM and uses esp_rom_vprintf (ROM) for output. This means
* esp_log() can safely be called with cache disabled, as long as the format
* string and tag are also in DRAM/IRAM.
*
* Verify this by actually disabling flash cache and calling esp_log() with
* constrained_env=true and a DRAM format string. If it doesn't crash, the
* IRAM path is correctly used.
*/
static void IRAM_ATTR test_log_cache_disabled_cb(void *arg)
{
/* All strings must be in DRAM since flash is inaccessible */
static const DRAM_ATTR char tag[] = "test";
static const DRAM_ATTR char fmt[] = "cache_off %d\n";
esp_log_config_t cfg = ESP_LOG_CONFIG_INIT(ESP_LOG_INFO
| ESP_LOG_CONFIG_CONSTRAINED_ENV);
esp_log(cfg, tag, fmt, 99);
}
TEST_CASE("ESP_LOG with constrained_env_safe works when cache is disabled", "[log]")
{
/* If esp_log() tries to use a flash-resident vprintf, this will crash */
unity_utils_run_cache_disable_stub(test_log_cache_disabled_cb, NULL);
/* Reaching here without a crash proves the IRAM/ROM path was used */
}
#endif // CONFIG_LOG_API_CONSTRAINED_ENV_SAFE
#endif // CONFIG_LOG_VERSION_2
+10 -1
View File
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
@@ -6,6 +6,15 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'default',
'v2_constrained_env_safe',
'v2_constrained_env_unsafe',
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_esp_log(dut: Dut) -> None:
dut.run_all_single_board_cases()
@@ -0,0 +1 @@
# This is left intentionally blank. It inherits all configurations from sdkconfig.defaults
@@ -0,0 +1 @@
CONFIG_LOG_VERSION_2=y
@@ -0,0 +1,2 @@
CONFIG_LOG_VERSION_2=y
CONFIG_LOG_API_CONSTRAINED_ENV_SAFE=n
+1 -1
View File
@@ -671,7 +671,7 @@ Enabling **Log V2** increases IRAM usage while reducing the overall application
- 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.
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 for early/DRAM logs.
Logging to Host via JTAG
------------------------