2222
2323LOG_MODULE_REGISTER (main , LOG_LEVEL_INF );
2424
25- #if CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_MEMORY_METRICS
25+ #if CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_METRICS
2626 //! Size of memory to allocate on main stack
2727 //! This requires a larger allocation due to the method used to measure stack usage
2828 #define STACK_ALLOCATION_SIZE (CONFIG_MAIN_STACK_SIZE >> 2)
@@ -36,7 +36,7 @@ static void *heap_ptrs[4] = { NULL };
3636
3737//! Keep a reference to the main thread for stack info
3838static struct k_thread * s_main_thread = NULL ;
39- #endif // CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_MEMORY_METRICS
39+ #endif // CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_METRICS
4040
4141// Blink code taken from the zephyr/samples/basic/blinky example.
4242static void blink_forever (void ) {
@@ -122,7 +122,7 @@ static void prv_init_test_thread_timer(void) {
122122static void prv_init_test_thread_timer (void ) { }
123123#endif // CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_THREAD_TOGGLE
124124
125- #if CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_MEMORY_METRICS
125+ #if CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_METRICS
126126
127127//! Helper function to collect metric value on main thread stack usage.
128128static void prv_collect_main_thread_stack_free (void ) {
@@ -142,6 +142,35 @@ static void prv_collect_main_thread_stack_free(void) {
142142 }
143143}
144144
145+ static void prv_collect_main_thread_run_stats (void ) {
146+ static uint64_t s_prev_main_thread_cycles = 0 ;
147+ static uint64_t s_prev_cpu_all_cycles = 0 ;
148+
149+ if (s_main_thread == NULL ) {
150+ return ;
151+ }
152+
153+ k_thread_runtime_stats_t rt_stats_main = { 0 };
154+ k_thread_runtime_stats_t rt_stats_all = { 0 };
155+
156+ k_thread_runtime_stats_get (s_main_thread , & rt_stats_main );
157+ k_thread_runtime_stats_all_get (& rt_stats_all );
158+
159+ // Calculate difference since last heartbeat
160+ uint64_t current_main_thread_cycles = rt_stats_main .execution_cycles - s_prev_main_thread_cycles ;
161+ // Note: execution_cycles = idle + non-idle, total_cycles = non-idle
162+ uint64_t current_cpu_total_cycles = rt_stats_all .execution_cycles - s_prev_cpu_all_cycles ;
163+
164+ // Calculate permille of main thread execution vs total CPU time
165+ // Multiply permille factor first to avoid truncating lower bits after integer division
166+ uint32_t main_thread_cpu_time = (current_main_thread_cycles * 1000 ) / current_cpu_total_cycles ;
167+ MEMFAULT_METRIC_SET_UNSIGNED (main_thread_cpu_time_permille , main_thread_cpu_time );
168+
169+ // Update previous values
170+ s_prev_main_thread_cycles = current_main_thread_cycles ;
171+ s_prev_cpu_all_cycles = current_cpu_total_cycles ;
172+ }
173+
145174//! Shell function to exercise example memory metrics
146175//!
147176//! This function demonstrates the change in stack and heap memory metrics
@@ -185,6 +214,7 @@ SHELL_CMD_REGISTER(memory_metrics, NULL, "Collects runtime memory metrics from a
185214// and print current metric values
186215void memfault_metrics_heartbeat_collect_data (void ) {
187216 prv_collect_main_thread_stack_free ();
217+ prv_collect_main_thread_run_stats ();
188218 memfault_metrics_heartbeat_debug_print ();
189219}
190220
@@ -193,7 +223,7 @@ static void prv_run_stack_metrics_example(void) {
193223 volatile uint8_t stack_array [STACK_ALLOCATION_SIZE ];
194224 memset ((uint8_t * )stack_array , 0 , STACK_ALLOCATION_SIZE );
195225}
196- #endif // CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_MEMORY_METRICS
226+ #endif // CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_METRICS
197227
198228#if defined(CONFIG_MEMFAULT_FAULT_HANDLER_RETURN )
199229 #include MEMFAULT_ZEPHYR_INCLUDE (fatal .h )
@@ -213,7 +243,7 @@ int main(void) {
213243 memfault_zephyr_collect_reset_info ();
214244#endif
215245
216- #if CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_MEMORY_METRICS
246+ #if CONFIG_ZEPHYR_MEMFAULT_EXAMPLE_METRICS
217247 s_main_thread = k_current_get ();
218248
219249 // @warning This code uses `memfault_metrics_heartbeat_debug_trigger` which is not intended
0 commit comments