Skip to content

Commit 2aa5438

Browse files
committed
utop: Add initial implementation for ESP32.
Signed-off-by: Daniël van de Giessen <daniel@dvdgiessen.nl>
1 parent ffb07db commit 2aa5438

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

micropython/utop/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# utop
2+
3+
Provides a top-like live overview of the running system.
4+
5+
On the `esp32` port this depends on the `esp32.idf_task_stats()` function, which
6+
can be enabled by adding the following lines to the board `sdkconfig`:
7+
8+
```ini
9+
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
10+
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
11+
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
12+
```

micropython/utop/manifest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
metadata(
2+
version="0.1.0",
3+
description="Provides a top-like live overview of the running system.",
4+
)
5+
6+
module("utop.py")

micropython/utop/utop.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import gc
2+
import time
3+
4+
try:
5+
import esp32
6+
except ImportError:
7+
esp32 = None
8+
9+
def top(update_interval_ms=1000, timeout_ms=None):
10+
time_start = time.ticks_ms()
11+
previous_total_runtime = None
12+
previous_task_runtimes = {}
13+
previous_line_count = 0
14+
esp32_task_state_names = ('running', 'ready', 'blocked', 'suspended', 'deleted', 'invalid')
15+
16+
while timeout_ms is None or abs(time.ticks_diff(time.ticks_ms(), time_start)) < timeout_ms:
17+
if previous_line_count > 0:
18+
print('\x1B[{}A'.format(previous_line_count), end='')
19+
line_count = 0
20+
21+
if esp32 is not None:
22+
if not hasattr(esp32, 'idf_task_stats'):
23+
print('INFO: esp32.idf_task_stats() is not available, cannot list active tasks.\x1B[K')
24+
line_count += 1
25+
else:
26+
print(' CPU% CORE PRIORITY STATE STACKWATERMARK NAME\x1B[K')
27+
line_count += 1
28+
29+
total_runtime, tasks = esp32.idf_task_stats()
30+
tasks.sort(key=lambda t: t[1])
31+
for task_name, task_id, task_state, task_priority, task_runtime, task_stackhighwatermark, task_coreid in tasks:
32+
task_runtime_percentage = '-'
33+
if total_runtime > 0:
34+
if previous_total_runtime is not None and task_id in previous_task_runtimes:
35+
task_cpu_percentage = 100 * (task_runtime - previous_task_runtimes[task_id]) / (total_runtime - previous_total_runtime)
36+
else:
37+
task_cpu_percentage = 100 * task_runtime / total_runtime
38+
task_runtime_percentage = '{:.2f}%'.format(task_cpu_percentage)
39+
task_state_name = 'unknown'
40+
if task_state >= 0 and task_state < len(esp32_task_state_names):
41+
task_state_name = esp32_task_state_names[task_state]
42+
43+
print('{:>7} {:>4d} {:>8d} {:<9} {:<14d} {}\x1B[K'.format(
44+
task_runtime_percentage,
45+
task_coreid,
46+
task_priority,
47+
task_state_name,
48+
task_stackhighwatermark,
49+
task_name
50+
))
51+
line_count += 1
52+
53+
previous_task_runtimes[task_id] = task_runtime
54+
else:
55+
print('INFO: Platform does not support listing active tasks.\x1B[K')
56+
line_count += 1
57+
58+
if previous_line_count > line_count:
59+
for _ in range(previous_line_count - line_count):
60+
print('\x1B[K')
61+
print('\x1B[{}A'.format(previous_line_count - line_count), end='')
62+
63+
previous_total_runtime = total_runtime
64+
previous_line_count = line_count
65+
66+
time.sleep_ms(update_interval_ms)

0 commit comments

Comments
 (0)