Skip to content

Commit 06d8c08

Browse files
DvdGiessendpgeorge
authored andcommitted
esp32/modesp32: Implement esp32.idf_task_info().
This adds a new function, `esp32.idf_task_info()`, that can be used to retrieve task statistics which is useful for diagnosing issues where some tasks are using up a lot of CPU time. It's best used in conjunction with the `utop` module from micropython-lib. Signed-off-by: Daniël van de Giessen <[email protected]>
1 parent 10f6c06 commit 06d8c08

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

docs/library/esp32.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,29 @@ Functions
8080
The result of :func:`gc.mem_free()` is the total of the current "free"
8181
and "max new split" values printed by :func:`micropython.mem_info()`.
8282

83+
.. function:: idf_task_info()
84+
85+
Returns information about running ESP-IDF/FreeRTOS tasks, which include
86+
MicroPython threads. This data is useful to gain insight into how much time
87+
tasks spend running or if they are blocked for significant parts of time,
88+
and to determine if allocated stacks are fully utilized or might be reduced.
89+
90+
``CONFIG_FREERTOS_USE_TRACE_FACILITY=y`` must be set in the board
91+
configuration to make this method available. Additionally configuring
92+
``CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y`` and
93+
``CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y`` is recommended to be able to
94+
retrieve the total and per-task runtime and the core ID respectively.
95+
96+
The return value is a 2-tuple where the first value is the total runtime,
97+
and the second a list of tasks. Each task is a 7-tuple containing: the task
98+
ID, name, current state, priority, runtime, stack high water mark, and the
99+
ID of the core it is running on. Runtime and core ID will be None when the
100+
respective FreeRTOS configuration option is not enabled.
101+
102+
.. note:: For an easier to use output based on this function you can use the
103+
`utop library <https://github.com/micropython/micropython-lib/tree/master/micropython/utop>`_,
104+
which implements a live overview similar to the Unix ``top`` command.
105+
83106

84107
Flash partitions
85108
----------------

ports/esp32/modesp32.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,49 @@ static mp_obj_t esp32_idf_heap_info(const mp_obj_t cap_in) {
212212
}
213213
static MP_DEFINE_CONST_FUN_OBJ_1(esp32_idf_heap_info_obj, esp32_idf_heap_info);
214214

215+
#if CONFIG_FREERTOS_USE_TRACE_FACILITY
216+
static mp_obj_t esp32_idf_task_info(void) {
217+
const size_t task_count_max = uxTaskGetNumberOfTasks();
218+
TaskStatus_t *task_array = m_new(TaskStatus_t, task_count_max);
219+
uint32_t total_time;
220+
const size_t task_count = uxTaskGetSystemState(task_array, task_count_max, &total_time);
221+
222+
mp_obj_list_t *task_list = MP_OBJ_TO_PTR(mp_obj_new_list(task_count, NULL));
223+
for (size_t i = 0; i < task_count; i++) {
224+
mp_obj_t task_data[] = {
225+
mp_obj_new_int_from_uint((mp_uint_t)task_array[i].xHandle),
226+
mp_obj_new_str(task_array[i].pcTaskName, strlen(task_array[i].pcTaskName)),
227+
MP_OBJ_NEW_SMALL_INT(task_array[i].eCurrentState),
228+
MP_OBJ_NEW_SMALL_INT(task_array[i].uxCurrentPriority),
229+
#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
230+
mp_obj_new_int_from_uint(task_array[i].ulRunTimeCounter),
231+
#else
232+
mp_const_none,
233+
#endif
234+
mp_obj_new_int_from_uint(task_array[i].usStackHighWaterMark),
235+
#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
236+
MP_OBJ_NEW_SMALL_INT(task_array[i].xCoreID),
237+
#else
238+
mp_const_none,
239+
#endif
240+
};
241+
task_list->items[i] = mp_obj_new_tuple(7, task_data);
242+
}
243+
244+
m_del(TaskStatus_t, task_array, task_count_max);
245+
mp_obj_t task_stats[] = {
246+
#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
247+
MP_OBJ_NEW_SMALL_INT(total_time),
248+
#else
249+
mp_const_none,
250+
#endif
251+
task_list
252+
};
253+
return mp_obj_new_tuple(2, task_stats);
254+
}
255+
static MP_DEFINE_CONST_FUN_OBJ_0(esp32_idf_task_info_obj, esp32_idf_task_info);
256+
#endif
257+
215258
static const mp_rom_map_elem_t esp32_module_globals_table[] = {
216259
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) },
217260

@@ -228,6 +271,9 @@ static const mp_rom_map_elem_t esp32_module_globals_table[] = {
228271
{ MP_ROM_QSTR(MP_QSTR_mcu_temperature), MP_ROM_PTR(&esp32_mcu_temperature_obj) },
229272
#endif
230273
{ MP_ROM_QSTR(MP_QSTR_idf_heap_info), MP_ROM_PTR(&esp32_idf_heap_info_obj) },
274+
#if CONFIG_FREERTOS_USE_TRACE_FACILITY
275+
{ MP_ROM_QSTR(MP_QSTR_idf_task_info), MP_ROM_PTR(&esp32_idf_task_info_obj) },
276+
#endif
231277

232278
{ MP_ROM_QSTR(MP_QSTR_NVS), MP_ROM_PTR(&esp32_nvs_type) },
233279
{ MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) },

0 commit comments

Comments
 (0)