@@ -80,6 +80,68 @@ Functions
80
80
The result of :func: `gc.mem_free() ` is the total of the current "free"
81
81
and "max new split" values printed by :func: `micropython.mem_info() `.
82
82
83
+ .. function :: idf_task_stats()
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 setting
92
+ ``CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y `` and
93
+ ``CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y `` is recommended to be able to
94
+ retrieve the core id and runtime 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
+ name, ID, current state, priority, runtime, stack high water mark, and the
99
+ ID of the core it is running on.
100
+
101
+ Example displaying a constantly updating task list::
102
+
103
+ import esp32
104
+ import time
105
+ def print_task_stats(timeout_seconds=None):
106
+ if not hasattr(esp32, 'idf_task_stats'):
107
+ raise RuntimeError('esp32.idf_task_stats() is not supported!')
108
+ time_start = time.ticks_ms()
109
+ previous_total_runtime = None
110
+ previous_task_runtimes = {}
111
+ previous_line_count = 0
112
+ task_state_names = ['running', 'ready', 'blocked', 'suspended', 'deleted', 'invalid']
113
+ print('')
114
+ while timeout_seconds is None or abs(time.ticks_diff(time.ticks_ms(), time_start)) < 1000 * timeout_seconds:
115
+ total_runtime, tasks = esp32.idf_task_stats()
116
+ tasks.sort(key=lambda t: t[1])
117
+ print('\x1B[{}A'.format(previous_line_count), end='')
118
+ print(' CPU% CORE PRIORITY STATE STACKWATERMARK NAME\x1B[K')
119
+ previous_line_count = 1
120
+ for task_name, task_id, task_state, task_priority, task_runtime, task_stackhighwatermark, task_coreid in tasks:
121
+ task_runtime_percentage = '-'
122
+ if total_runtime > 0:
123
+ if previous_total_runtime is not None and task_id in previous_task_runtimes:
124
+ task_cpu_percentage = 100 * (task_runtime - previous_task_runtimes[task_id]) / (total_runtime - previous_total_runtime)
125
+ else:
126
+ task_cpu_percentage = 100 * task_runtime / total_runtime
127
+ task_runtime_percentage = '{:.2f}%'.format(task_cpu_percentage)
128
+ task_state_name = 'unknown'
129
+ if task_state >= 0 and task_state < len(task_state_names):
130
+ task_state_name = task_state_names[task_state]
131
+ print('{:>7} {:>4d} {:>8d} {:<9} {:<14d} {}\x1B[K'.format(
132
+ task_runtime_percentage,
133
+ task_coreid,
134
+ task_priority,
135
+ task_state_name,
136
+ task_stackhighwatermark,
137
+ task_name
138
+ ))
139
+ previous_task_runtimes[task_id] = task_runtime
140
+ previous_line_count += 1
141
+ print('\x1B[K')
142
+ previous_line_count += 1
143
+ previous_total_runtime = total_runtime
144
+ time.sleep_ms(1000)
83
145
84
146
Flash partitions
85
147
----------------
0 commit comments