Skip to content

Commit

Permalink
Memfault Firmware SDK 1.12.0 (Build 10351)
Browse files Browse the repository at this point in the history
  • Loading branch information
Memfault Inc committed Sep 25, 2024
1 parent 00ff70f commit 47d69c5
Show file tree
Hide file tree
Showing 27 changed files with 747 additions and 198 deletions.
69 changes: 69 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,75 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.12.0] - 2024-09-25

### 📈 Added

- ESP-IDF:

- The SDK now supports being installed as an
[ESP Component](https://components.espressif.com/) from the Espressif
registry, by adding the following lines to an esp-idf project's
`idf_component.yml` manifest:

```yaml
dependencies:
memfault/memfault-firmware-sdk:
version: "1.12.0"
```
- [Heap Allocation Tracking](https://docs.memfault.com/docs/mcu/heap-stats) is
now enabled by default for ESP-IDF projects, controlled with the Kconfig
symbol `CONFIG_MEMFAULT_HEAP_STATS`. The Memfault Trace UI will show
information about the most recent heap allocations for `malloc()` calls.

### 🛠️ Changed

- ESP-IDF:

- The [Memfault Build ID](https://mflt.io/symbol-file-build-ids) will be
applied by default, controlled by the Kconfig setting
`CONFIG_MEMFAULT_USE_MEMFAULT_BUILD_ID`. This is _only_ valid for ESP-IDF
versions >= **4.2.5** , and will cause a build error on older versions,
requiring it to be set to `n`. Updating to this version of the SDK will
**require** removing the similar logic in the project's `CMakeLists.txt`
file (a build error will occur if both are present).

- The Memfault Core Vital for
[Periodic Connectivity](https://docs.memfault.com/docs/platform/memfault-core-metrics#periodic-connectivity)
will now count failures to sync Memfault data if the HTTP connection cannot
be established, but WiFi connectivity is available. This can occur when the
WAN connection is down but the access point is still up, or if there is an
external DNS failure. Previously this was not counted as a failure.

- Zephyr

- The Memfault HTTP client, enabled with Kconfig
`CONFIG_MEMFAULT_HTTP_ENABLE`, requires `POSIX_API` to be enabled on newer
versions of Zephyr. Previously, not explicitly enabling `POSIX_API` would
result in a build error. Update it to be enabled by default in the Zephyr
SDK, via Kconfig `imply POSIX_API`.

- Zephyr 3.7.0+ requires enabling `CONFIG_MBEDTLS_SHA1` when using Zephyr's
mbedtls implementation. Memfault added a build-time check for this setting
in Memfault SDK 1.11.2, but that check would also trip when not using
Zephyr's mbedtls implementation. Update the build check to be more precise.

- nRF-Connect SDK:

- Minor changes to provide compatibility with NCS versions > 2.7.0, which
target a Zephyr fork that is compatible with 3.7.0 but provides a
"development" version number, 3.6.99.

### 🐛 Fixed

- ESP-IDF:

- Corrected a theoretical integer overflow issue in the demo CLI `crash`
command, detected by static analysis tools. The impacted function was and is
exclusively called with an argument of `10`, so this issue was not
exploitable in practice.

## [1.11.5] - 2024-09-18

### 📈 Added
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.12.4)

if(ESP_PLATFORM)
include(${CMAKE_CURRENT_LIST_DIR}/ports/esp_idf/memfault/CMakeLists.txt)
else()
include(${CMAKE_CURRENT_LIST_DIR}/cmake/Memfault.cmake)
endif()
5 changes: 5 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# If the repo is being used as an ESP-IDF component, bring in the ESP-IDF specific
# Kconfig file. Otherwise this should be unused.
if IDF_TARGET != ""
rsource "ports/esp_idf/memfault/Kconfig"
endif
6 changes: 3 additions & 3 deletions VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
BUILD ID: 10200
GIT COMMIT: 432492ab6b
VERSION: 1.11.5
BUILD ID: 10351
GIT COMMIT: 1d3c51cd48
VERSION: 1.12.0
27 changes: 22 additions & 5 deletions components/core/src/memfault_heap_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
MEMFAULT_STATIC_ASSERT(MEMFAULT_HEAP_STATS_MAX_COUNT < MEMFAULT_HEAP_STATS_LIST_END,
"Number of entries in heap stats exceeds limits");

// By default, tally in use blocks and max in use blocks in the instrumentation
// functions. Disable this to perform manual tallying.
#if !defined(MEMFAULT_IN_USE_BLOCK_COUNT_AUTOMATIC)
#define MEMFAULT_IN_USE_BLOCK_COUNT_AUTOMATIC 1
#endif

sMfltHeapStats g_memfault_heap_stats = {
.version = MEMFAULT_HEAP_STATS_VERSION,
.stats_pool_head = MEMFAULT_HEAP_STATS_LIST_END,
Expand Down Expand Up @@ -111,14 +117,23 @@ static uint16_t prv_get_new_entry_index(void) {
return prv_get_previous_entry(MEMFAULT_HEAP_STATS_LIST_END);
}

void memfault_heap_stats_increment_in_use_block_count(void) {
g_memfault_heap_stats.in_use_block_count++;
if (g_memfault_heap_stats.in_use_block_count > g_memfault_heap_stats.max_in_use_block_count) {
g_memfault_heap_stats.max_in_use_block_count = g_memfault_heap_stats.in_use_block_count;
}
}
void memfault_heap_stats_decrement_in_use_block_count(void) {
g_memfault_heap_stats.in_use_block_count--;
}

void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
prv_heap_stats_lock();

if (ptr) {
g_memfault_heap_stats.in_use_block_count++;
if (g_memfault_heap_stats.in_use_block_count > g_memfault_heap_stats.max_in_use_block_count) {
g_memfault_heap_stats.max_in_use_block_count = g_memfault_heap_stats.in_use_block_count;
}
#if MEMFAULT_IN_USE_BLOCK_COUNT_AUTOMATIC
memfault_heap_stats_increment_in_use_block_count();
#endif
uint16_t new_entry_index = prv_get_new_entry_index();

// Ensure a valid entry index is returned. An invalid index can indicate a concurrency
Expand Down Expand Up @@ -156,7 +171,9 @@ void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
void memfault_heap_stats_free(const void *ptr) {
prv_heap_stats_lock();
if (ptr) {
g_memfault_heap_stats.in_use_block_count--;
#if MEMFAULT_IN_USE_BLOCK_COUNT_AUTOMATIC
memfault_heap_stats_decrement_in_use_block_count();
#endif

// if the pointer exists in the tracked stats, mark it as freed
for (size_t i = 0; i < MEMFAULT_ARRAY_SIZE(g_memfault_heap_stats_pool); i++) {
Expand Down
6 changes: 6 additions & 0 deletions components/include/memfault/core/heap_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ void memfault_heap_stats_free(const void *ptr);

#define MEMFAULT_HEAP_STATS_FREE(ptr_) memfault_heap_stats_free(ptr_)

//! These functions can be used to manually increment and decrement the
//! in_use_block_count. This is useful if the application has custom memory
//! tracing that provides more detailed information than just malloc/free.
void memfault_heap_stats_decrement_in_use_block_count(void);
void memfault_heap_stats_increment_in_use_block_count(void);

#ifdef __cplusplus
}
#endif
4 changes: 2 additions & 2 deletions components/include/memfault/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ typedef struct {
} sMfltSdkVersion;

#define MEMFAULT_SDK_VERSION \
{ .major = 1, .minor = 11, .patch = 5 }
#define MEMFAULT_SDK_VERSION_STR "1.11.5"
{ .major = 1, .minor = 12, .patch = 0 }
#define MEMFAULT_SDK_VERSION_STR "1.12.0"

#ifdef __cplusplus
}
Expand Down
66 changes: 46 additions & 20 deletions examples/esp32/apps/memfault_demo_app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,26 @@ if(DEFINED IDF_VERSION_MAJOR)
endif()
endif()

# Look for the Memfault SDK in a subdirectory first, when this app is used
# standalone (not from within the Memfault SDK)
get_filename_component(memfault_firmware_sdk_dir third-party/memfault-firmware-sdk ABSOLUTE)
if(NOT EXISTS ${memfault_firmware_sdk_dir})
get_filename_component(memfault_firmware_sdk_dir ../../../../ ABSOLUTE)
# If we found the Memfault SDK, include it in the build
if(EXISTS ${memfault_firmware_sdk_dir}/ports/esp_idf/memfault.cmake)
include(${memfault_firmware_sdk_dir}/ports/esp_idf/memfault.cmake)
else()
# Otherwise, append this to the main/idf_component.yml file:
# memfault/memfault-firmware-sdk: "*"
# Ideally we'd push an environment variable and use a conditional dependency
# https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/manifest_file.html#conditional-dependencies
# But that requires idf-component-manager v2+, which is not available on all
# esp-idf versions

# if the string "memfault/memfault-firmware-sdk" isn't in the file, append it:
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/main/idf_component.yml idf_component_yml)
if(NOT idf_component_yml MATCHES "memfault/memfault-firmware-sdk")
file(APPEND ${CMAKE_CURRENT_SOURCE_DIR}/main/idf_component.yml
" memfault/memfault-firmware-sdk: \"*\"\n"
)
endif()
endif()
include(${memfault_firmware_sdk_dir}/ports/esp_idf/memfault.cmake)

# NOTE: This include also applies global compiler options, make sure
# this happens first before defining other targets!
Expand Down Expand Up @@ -65,19 +78,32 @@ if (INVALID_PARTITION_TABLE)
endif()

if (CONFIG_MEMFAULT)
# Add the Memfault Build ID so each build can have a unique version.
set(IDF_PROJECT_EXECUTABLE ${PROJECT_NAME}.elf)
add_custom_command(TARGET ${IDF_PROJECT_EXECUTABLE}
POST_BUILD
# Compute and insert the build id
COMMAND python ${memfault_firmware_sdk_dir}/scripts/fw_build_id.py ${IDF_PROJECT_EXECUTABLE}
# Save a copy of the ELF that includes the 'log_fmt' section
BYPRODUCTS ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt
# Compress debug sections; this reduces the elf file size from ~10MB -> ~4.8MB
COMMAND ${CMAKE_OBJCOPY} --compress-debug-sections ${IDF_PROJECT_EXECUTABLE}
COMMAND ${CMAKE_COMMAND} -E copy ${IDF_PROJECT_EXECUTABLE} ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt
COMMAND ${CMAKE_COMMAND} -E echo "*** NOTE: the symbol file to upload to app.memfault.com is ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt ***"
# Remove the 'log_fmt' compact log section, which confuses elf2image
COMMAND ${CMAKE_OBJCOPY} --remove-section log_fmt ${IDF_PROJECT_EXECUTABLE}
)
# Set MEMFAULT_IDF_VERSION, used for version-specific logic later.
if (IDF_VERSION_MAJOR)
set(MEMFAULT_IDF_VERSION "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
else()
# pre-4.0 doesn't have version information available to cmake, so set it to
# the lowest compatible version
set(MEMFAULT_IDF_VERSION "3.3.5")
endif()

# As of Memfault SDK v1.12.0, adding the Memfault Build ID is done in the
# memfault component for ESP-IDF >=4.2.5.
if(MEMFAULT_IDF_VERSION VERSION_LESS "4.2.5")
# Add the Memfault Build ID so each build can have a unique version.
set(IDF_PROJECT_EXECUTABLE ${PROJECT_NAME}.elf)
add_custom_command(TARGET ${IDF_PROJECT_EXECUTABLE}
POST_BUILD
# Compute and insert the build id
COMMAND python ${memfault_firmware_sdk_dir}/scripts/fw_build_id.py ${IDF_PROJECT_EXECUTABLE}
# Save a copy of the ELF that includes the 'log_fmt' section
BYPRODUCTS ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt
# Compress debug sections; this reduces the elf file size from ~10MB -> ~4.8MB
COMMAND ${CMAKE_OBJCOPY} --compress-debug-sections ${IDF_PROJECT_EXECUTABLE}
COMMAND ${CMAKE_COMMAND} -E copy ${IDF_PROJECT_EXECUTABLE} ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt
COMMAND ${CMAKE_COMMAND} -E echo "*** NOTE: the symbol file to upload to app.memfault.com is ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt ***"
# Remove the 'log_fmt' compact log section, which confuses elf2image
COMMAND ${CMAKE_OBJCOPY} --remove-section log_fmt ${IDF_PROJECT_EXECUTABLE}
)
endif()
endif() # NOT CONFIG_MEMFAULT_DISABLE
3 changes: 2 additions & 1 deletion examples/esp32/apps/memfault_demo_app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ You can either follow the steps outlined here or use your own MQTT setup.

### Service Setup

1. Modify the script found in Docs->Best Practices->MQTT with Memfault with the the following:
1. Modify the script found in [Docs->Best Practices->MQTT](https://docs.memfault.com/docs/best-practices/mqtt-with-memfault#service-examples)
with Memfault with the the following:
1. The service client login information previously created
2. Connection info for your local broker
3. Map of Memfault projects to project keys
Expand Down
5 changes: 5 additions & 0 deletions examples/esp32/apps/memfault_demo_app/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ config MEMFAULT_APP_WIFI_AUTOJOIN
help
Automatically join if credentials are configured.

config MEMFAULT_APP_HEAP_TRACING
bool "Print allocation tracing information at runtime"
default n
depends on HEAP_USE_HOOKS

choice APP_MEMFAULT_TRANSPORT
prompt "Protocol to send chunks over"
default APP_MEMFAULT_TRANSPORT_HTTP
Expand Down
8 changes: 4 additions & 4 deletions examples/esp32/apps/memfault_demo_app/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
#endif

// Conditionally enable the logging tag variable only when it's used
#if defined(CONFIG_STORE_HISTORY) || defined(CONFIG_HEAP_USE_HOOKS)
#if defined(CONFIG_STORE_HISTORY) || defined(CONFIG_MEMFAULT_APP_HEAP_TRACING)
static const char *TAG = "main";
#endif

Expand Down Expand Up @@ -359,18 +359,18 @@ static void prv_initialize_task_watchdog(void) {

#endif // defined(CONFIG_MEMFAULT)

#if defined(CONFIG_HEAP_USE_HOOKS)
#if defined(CONFIG_MEMFAULT_APP_HEAP_TRACING)
// This callback is triggered when a heap allocation is made. It prints large
// allocations for debugging heap usage from the serial log.
void esp_heap_trace_alloc_hook(void *ptr, size_t size, uint32_t caps) {
// In our app, there's a periodic 1696 byte alloc. Filter out anything that
// size or smaller from this log, otherwise it's quite spammy
if (size > 1696) {
ESP_LOGI("main", "Large alloc: %p, size: %d, caps: %lu", ptr, size, caps);
ESP_LOGI(TAG, "Large alloc: %p, size: %d, caps: %lu", ptr, size, caps);

multi_heap_info_t heap_info = { 0 };
heap_caps_get_info(&heap_info, MALLOC_CAP_DEFAULT);
ESP_LOGI("main", "Total free bytes: %d", heap_info.total_free_bytes);
ESP_LOGI(TAG, "Total free bytes: %d", heap_info.total_free_bytes);
}
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CONFIG_NET_IPV6=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_POSIX_API=n

CONFIG_DNS_RESOLVER=y
CONFIG_DNS_SERVER_IP_ADDRESSES=y
Expand Down
5 changes: 5 additions & 0 deletions idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description: Memfault SDK for embedded systems. Observability, logging, crash reporting, and OTA all in one service
url: https://github.com/memfault/memfault-firmware-sdk
repository: https://github.com/memfault/memfault-firmware-sdk.git
documentation: https://docs.memfault.com/
issues: https://github.com/memfault/memfault-firmware-sdk/issues
Loading

0 comments on commit 47d69c5

Please sign in to comment.