Skip to content

Commit

Permalink
Memfault Firmware SDK 1.15.0 (Build 10752)
Browse files Browse the repository at this point in the history
  • Loading branch information
Memfault Inc committed Oct 15, 2024
1 parent 6652e81 commit 72f52c0
Show file tree
Hide file tree
Showing 28 changed files with 551 additions and 45 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@ 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.15.0] - 2024-10-13

### 📈 Added

- General:

- **EXPERIMENTAL**: Metrics Sessions now include a built-in metric for the
[Stable Sessions Device Vital](https://docs.memfault.com/docs/platform/memfault-core-metrics#stable-sessions)
(`session.operational_crashes`) which tracks crashes that occurred when a
session is active.

### 🛠️ Changed

- General:

- Minor changes to support compiling with GCC ARM v4.9.3.

### 🐛 Fixed

- Corrected a spelling error, renamed
<!-- spellchecker:off -->
`MEMFAULT_METRIS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE()` to
<!-- spellchecker:on -->
`MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE()`

## [1.14.0] - 2024-10-09

### 📈 Added
Expand Down
6 changes: 3 additions & 3 deletions VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
BUILD ID: 10647
GIT COMMIT: 8448e7acf8
VERSION: 1.14.0
BUILD ID: 10752
GIT COMMIT: 1904cdb3cb
VERSION: 1.15.0
28 changes: 28 additions & 0 deletions components/core/src/memfault_ram_reboot_info_tracking.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,31 @@ bool memfault_reboot_tracking_booted(void) {
return ((s_mflt_reboot_info != NULL) &&
(s_mflt_reboot_info->magic == MEMFAULT_REBOOT_INFO_MAGIC));
}

void memfault_reboot_tracking_metrics_session(bool active, uint32_t index) {
if (!prv_check_or_init_struct()) {
return;
}

if (active) {
s_mflt_reboot_info->active_sessions |= (1 << index);
} else {
s_mflt_reboot_info->active_sessions &= ~(1 << index);
}
}

void memfault_reboot_tracking_clear_metrics_sessions(void) {
if (!prv_check_or_init_struct()) {
return;
}

s_mflt_reboot_info->active_sessions = 0;
}

bool memfault_reboot_tracking_metrics_session_was_active(uint32_t index) {
if (!prv_check_or_init_struct()) {
return false;
}

return (s_mflt_reboot_info->active_sessions & (1 << index)) != 0;
}
4 changes: 3 additions & 1 deletion components/core/src/memfault_reboot_tracking_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ typedef MEMFAULT_PACKED_STRUCT MfltRebootInfo {
//! (where no coredump was saved or no user initiated reset took place). Examples
//! of this include brown out resets (BORs) & hardware watchdog resets.
uint32_t reset_reason_reg0;
//! Bitfield tracking sessions that were active prior to reboot
uint32_t active_sessions;
// Reserved for future additions
uint32_t rsvd2[10];
uint32_t rsvd2[9];
}
sMfltRebootInfo;

Expand Down
17 changes: 17 additions & 0 deletions components/include/memfault/core/reboot_tracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,23 @@ int memfault_reboot_tracking_get_unexpected_reboot_occurred(bool *unexpected_reb
//! @returns true if reboot tracking component booted or false if not
bool memfault_reboot_tracking_booted(void);

//! Set or clear the "active" property for a Metrics Session. This is used when
//! a session starts and stops, for tracking which sessions were active when a
//! reboot occurred.
//!
//! @param activate True if the session is active, false if it is not
//! @param index The index of the session
void memfault_reboot_tracking_metrics_session(bool activate, uint32_t index);

//! Clear the reboot tracking data for "active" Metrics Sessions. This is used
//! on reboot to reset the persisted active state of all sessions.
void memfault_reboot_tracking_clear_metrics_sessions(void);

//! Check if a Metrics Session was active when a reboot occurred
//!
//! @param index The index of the session
bool memfault_reboot_tracking_metrics_session_was_active(uint32_t index);

#if MEMFAULT_REBOOT_REASON_CUSTOM_ENABLE == 1
//! Defines a customer specific reboot reason.
//!
Expand Down
6 changes: 6 additions & 0 deletions components/include/memfault/default_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,12 @@ extern "C" {
#define MEMFAULT_METRICS_BATTERY_SOC_PCT_SCALE_VALUE 1
#endif

//! Disable Metrics Sessions at compile time. This saves a small amount of
//! memory but prevents the use of Metrics Sessions.
#ifndef MEMFAULT_METRICS_SESSIONS_ENABLED
#define MEMFAULT_METRICS_SESSIONS_ENABLED 1
#endif

//
// Panics Component Configs
//
Expand Down
6 changes: 4 additions & 2 deletions components/include/memfault/metrics/ids_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ extern "C" {

//! Sessions have the following built-in keys:
//! - "<session name>__MemfaultSdkMetric_IntervalMs"
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(session_name) \
kMfltMetricsIndex_##session_name##__##MemfaultSdkMetric_IntervalMs,
//! - "<session name>__operational_crashes"
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(session_name) \
kMfltMetricsIndex_##session_name##__##MemfaultSdkMetric_IntervalMs, \
kMfltMetricsIndex_##session_name##__##operational_crashes,

#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION(key_name, value_type, session_name) \
MEMFAULT_METRICS_KEY_DEFINE_(session_name, key_name)
Expand Down
4 changes: 2 additions & 2 deletions components/include/memfault/metrics/metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ typedef enum MemfaultMetricValueType {
MEMFAULT_METRICS_KEY_DEFINE_TRAP_()

//! Same as 'MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE', with session specified
#define MEMFAULT_METRIS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE(key_name, value_type, session_key, \
scale_value) \
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE(key_name, value_type, \
session_key, scale_value) \
MEMFAULT_METRICS_KEY_DEFINE_TRAP_()

//! Define a metric session.
Expand Down
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 = 14, .patch = 0 }
#define MEMFAULT_SDK_VERSION_STR "1.14.0"
{ .major = 1, .minor = 15, .patch = 0 }
#define MEMFAULT_SDK_VERSION_STR "1.15.0"

#ifdef __cplusplus
}
Expand Down
144 changes: 129 additions & 15 deletions components/metrics/src/memfault_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static MemfaultMetricsSessionEndCb s_session_end_cbs[] = {
max_value, session_key)
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION(key_name, value_type, session_key)
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(key_name) \
MEMFAULT_METRICS_KEY_WITH_SESSION(MemfaultSdkMetric_IntervalMs, key_name),
_MEMFAULT_METRICS_ID_CREATE(MemfaultSdkMetric_IntervalMs, key_name),
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE(key_name, value_type, scale_value)
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE(key_name, value_type, \
session_key, scale_value)
Expand All @@ -111,6 +111,44 @@ static MemfaultMetricId s_memfault_metrics_session_timer_keys[] = {
{ 0 } // dummy entry to prevent empty array
};

#if MEMFAULT_METRICS_SESSIONS_ENABLED
// Generate session key to operational_crashes metric key mapping
#define MEMFAULT_METRICS_KEY_DEFINE(key_name, value_type)
#define MEMFAULT_METRICS_STRING_KEY_DEFINE(key_name, max_length)
#define MEMFAULT_METRICS_STRING_KEY_DEFINE_WITH_SESSION(key_name, max_length, session_key)
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE(key_name, value_type, min_value, max_value)
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE_AND_SESSION(key_name, value_type, min_value, \
max_value, session_key)
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION(key_name, value_type, session_key)
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(session_name) \
_MEMFAULT_METRICS_ID_CREATE(operational_crashes, session_name),
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE(key_name, value_type, scale_value)
#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE(key_name, value_type, \
session_key, scale_value)

static MemfaultMetricId s_memfault_metrics_operational_crashes_keys[] = {
#include "memfault/metrics/heartbeat_config.def"
#include MEMFAULT_METRICS_USER_HEARTBEAT_DEFS_FILE
#undef MEMFAULT_METRICS_KEY_DEFINE
#undef MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE
#undef MEMFAULT_METRICS_STRING_KEY_DEFINE
#undef MEMFAULT_METRICS_STRING_KEY_DEFINE_WITH_SESSION
#undef MEMFAULT_METRICS_SESSION_KEY_DEFINE
#undef MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION
#undef MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE_AND_SESSION
#undef MEMFAULT_METRICS_SESSION_KEY_DEFINE_
#undef MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE
#undef MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION_AND_SCALE_VALUE
{ 0 } // dummy entry to prevent empty array
};

// Active sessions are tracked in a single 32-bit word in the reboot tracking
// data. This limits the maximum sessions to 32.
MEMFAULT_STATIC_ASSERT(MEMFAULT_ARRAY_SIZE(s_memfault_metrics_operational_crashes_keys) <= 32,
"Too many sessions defined. Max allowed defined sessions is 32.");

#endif

typedef struct MemfaultMetricKVPair {
MemfaultMetricId key;
eMemfaultMetricType type;
Expand Down Expand Up @@ -166,9 +204,11 @@ typedef struct MemfaultMetricKVPair {
MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE_AND_SESSION(key_name, kMemfaultMetricType_String, 0, \
max_length, session_key)

#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(session_name) \
MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION(MemfaultSdkMetric_IntervalMs, \
kMemfaultMetricType_Timer, session_name)
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(session_name) \
MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION(MemfaultSdkMetric_IntervalMs, \
kMemfaultMetricType_Timer, session_name) \
MEMFAULT_METRICS_KEY_DEFINE_WITH_SESSION(operational_crashes, kMemfaultMetricType_Unsigned, \
session_name)

#define MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE(key_name, value_type, scale_value) \
MEMFAULT_KV_PAIR_ENTRY(key_name, value_type, 0, 0, \
Expand Down Expand Up @@ -209,7 +249,8 @@ static const sMemfaultMetricKVPair s_memfault_heartbeat_keys[] = {

#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(session_name) \
MEMFAULT_METRICS_KEY_DEFINE(session_name##__##MemfaultSdkMetric_IntervalMs, \
kMemfaultMetricType_Unsigned)
kMemfaultMetricType_Timer) \
MEMFAULT_METRICS_KEY_DEFINE(session_name##__##operational_crashes, kMemfaultMetricType_Unsigned)

#define MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE_AND_SESSION(key_name, value_type, min_value, \
max_value, session_key) \
Expand Down Expand Up @@ -262,8 +303,11 @@ static const sMemfaultMetricKVPair s_memfault_heartbeat_keys[] = {

//! Sessions have the following built-in keys:
//! - "<session name>__MemfaultSdkMetric_IntervalMs"
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(key_name) \
MEMFAULT_METRICS_KEY_DEFINE(key_name##__##MemfaultSdkMetric_IntervalMs, kMemfaultMetricType_Timer)
//! - "<session name>__operational_crashes"
#define MEMFAULT_METRICS_SESSION_KEY_DEFINE(key_name) \
MEMFAULT_METRICS_KEY_DEFINE(key_name##__##MemfaultSdkMetric_IntervalMs, \
kMemfaultMetricType_Timer) \
MEMFAULT_METRICS_KEY_DEFINE(key_name##__##operational_crashes, kMemfaultMetricType_Unsigned)

#define MEMFAULT_METRICS_KEY_DEFINE_WITH_RANGE_AND_SESSION(key_name, value_type, min_value, \
max_value, session_key) \
Expand Down Expand Up @@ -1006,16 +1050,21 @@ int memfault_metrics_heartbeat_read_string(MemfaultMetricId key, char *read_val,
return rv;
}

int memfault_metrics_session_start(eMfltMetricsSessionIndex session_key) {
int rv;
static int prv_metrics_session_start(eMfltMetricsSessionIndex session_key, bool start_timer) {
int rv = 0;
memfault_lock();
{
// Reset all metrics for the session. Any changes that happened before the
// session was started don't matter and can be discarded.
prv_reset_metrics(false, session_key);

MemfaultMetricId key = s_memfault_metrics_session_timer_keys[session_key];
rv = prv_find_timer_metric_and_update(key, kMemfaultTimerOp_Start);
if (start_timer) {
MemfaultMetricId key = s_memfault_metrics_session_timer_keys[session_key];
rv = prv_find_timer_metric_and_update(key, kMemfaultTimerOp_Start);
}

// Mark the session as active for tracking operational_crashes
memfault_reboot_tracking_metrics_session(true, session_key);
}
memfault_unlock();

Expand All @@ -1027,17 +1076,23 @@ int memfault_metrics_session_start(eMfltMetricsSessionIndex session_key) {
return rv;
}

int memfault_metrics_session_end(eMfltMetricsSessionIndex session_key) {
int memfault_metrics_session_start(eMfltMetricsSessionIndex session_key) {
return prv_metrics_session_start(session_key, true);
}

static int prv_metrics_session_end(eMfltMetricsSessionIndex session_key, bool stop_timer) {
MemfaultMetricsSessionEndCb session_end_cb = s_session_end_cbs[session_key];
if (session_end_cb != NULL) {
session_end_cb();
}

int rv;
int rv = 0;
memfault_lock();
{
MemfaultMetricId key = s_memfault_metrics_session_timer_keys[session_key];
rv = prv_find_timer_metric_and_update(key, kMemfaultTimerOp_Stop);
if (stop_timer) {
MemfaultMetricId key = s_memfault_metrics_session_timer_keys[session_key];
rv = prv_find_timer_metric_and_update(key, kMemfaultTimerOp_Stop);
}

if (rv == 0) {
bool serialize_result =
Expand All @@ -1046,12 +1101,18 @@ int memfault_metrics_session_end(eMfltMetricsSessionIndex session_key) {
rv = MEMFAULT_METRICS_STORAGE_TOO_SMALL;
}
}
// Mark the session as inactive for tracking operational_crashes
memfault_reboot_tracking_metrics_session(false, session_key);
}
memfault_unlock();

return rv;
}

int memfault_metrics_session_end(eMfltMetricsSessionIndex session_key) {
return prv_metrics_session_end(session_key, true);
}

void memfault_metrics_session_register_start_cb(eMfltMetricsSessionIndex session_key,
MemfaultMetricsSessionStartCb session_start_cb) {
memfault_lock();
Expand Down Expand Up @@ -1231,6 +1292,55 @@ void memfault_metrics_heartbeat_debug_trigger(void) {
prv_heartbeat_timer();
}

#if MEMFAULT_METRICS_SESSIONS_ENABLED
//! Called on boot, this function checks if the reboot was unexpected. If so,
//! any session that was active at time of reboot is triggered to record an
//! `operational_crash=1` metric, and serialized to storage.
static void prv_session_check_for_unexpected_reboot(void) {
int rv = -1;
bool unexpected_reboot;

for (eMfltMetricsSessionIndex session_key = (eMfltMetricsSessionIndex)0;
session_key < (MEMFAULT_ARRAY_SIZE(s_memfault_metrics_operational_crashes_keys));
session_key++) {
// This table always ends with a blank entry, so we can stop one iteration
// early (or if no sessions were defined). Some compilers warn on empty
// arrays.
if (session_key == MEMFAULT_ARRAY_SIZE(s_memfault_metrics_operational_crashes_keys) - 1) {
break;
}

// Only run the check for unexpected reboot once, if it hasn't been already
// run in this function. Ideally this check would be outside the for loop,
// but since we can't conditionally compile this whole block based on if
// any sessions are defined, we have to do it this way.
if (rv != 0) {
rv = memfault_reboot_tracking_get_unexpected_reboot_occurred(&unexpected_reboot);
if ((rv != 0) || !unexpected_reboot) {
break;
}
}

// If the session was active at time of reboot, serialize a session with the
// duration_ms=0 and operational_crashes=1.
if (memfault_reboot_tracking_metrics_session_was_active(session_key)) {
// Do not start the session timer, to keep the session duration = 0ms
prv_metrics_session_start(session_key, false);

memfault_metrics_heartbeat_add(s_memfault_metrics_operational_crashes_keys[session_key], 1);
// Note: the below function clears the reboot tracking bit for this session,
// since the session is now inactive. A second crash after this won't be
// recorded as an operational_crash for the session (until the session is
// activated).
prv_metrics_session_end(session_key, false);
}
}

// Unconditionally clear the reboot tracking data for "active sessions".
memfault_reboot_tracking_clear_metrics_sessions();
}
#endif

int memfault_metrics_boot(const sMemfaultEventStorageImpl *storage_impl,
const sMemfaultMetricBootInfo *info) {
if (storage_impl == NULL || info == NULL) {
Expand Down Expand Up @@ -1262,6 +1372,10 @@ int memfault_metrics_boot(const sMemfaultEventStorageImpl *storage_impl,
return rv;
}

#if MEMFAULT_METRICS_SESSIONS_ENABLED
prv_session_check_for_unexpected_reboot();
#endif

#if MEMFAULT_PLATFORM_METRICS_CONNECTIVITY_BOOT
memfault_platform_metrics_connectivity_boot();
#endif
Expand Down
Loading

0 comments on commit 72f52c0

Please sign in to comment.