Skip to content

Commit 0d60de6

Browse files
committed
utop: Add initial implementation for ESP32.
Signed-off-by: Daniël van de Giessen <[email protected]>
1 parent 68e0dfc commit 0d60de6

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-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_info()` 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: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import time
2+
3+
try:
4+
import esp32
5+
import _thread
6+
except ImportError:
7+
esp32 = None
8+
9+
10+
def top(update_interval_ms=1000, timeout_ms=None, thread_names={}):
11+
time_start = time.ticks_ms()
12+
previous_total_runtime = None
13+
previous_task_runtimes = {}
14+
previous_line_count = 0
15+
esp32_task_state_names = dict(
16+
enumerate(("running", "ready", "blocked", "suspended", "deleted", "invalid"))
17+
)
18+
19+
while timeout_ms is None or abs(time.ticks_diff(time.ticks_ms(), time_start)) < timeout_ms:
20+
if previous_line_count > 0:
21+
print("\x1b[{}A".format(previous_line_count), end="")
22+
line_count = 0
23+
24+
if esp32 is not None:
25+
if not hasattr(esp32, "idf_task_info"):
26+
print(
27+
"INFO: esp32.idf_task_info() is not available, cannot list active tasks.\x1b[K"
28+
)
29+
line_count += 1
30+
else:
31+
print(" CPU% CORE PRIORITY STATE STACKWATERMARK NAME\x1b[K")
32+
line_count += 1
33+
34+
total_runtime, tasks = esp32.idf_task_info()
35+
current_thread_id = _thread.get_ident()
36+
tasks.sort(key=lambda t: t[0])
37+
for (
38+
task_id,
39+
task_name,
40+
task_state,
41+
task_priority,
42+
task_runtime,
43+
task_stackhighwatermark,
44+
task_coreid,
45+
) in tasks:
46+
task_runtime_percentage = "-"
47+
if (
48+
total_runtime != previous_total_runtime
49+
and task_id in previous_task_runtimes
50+
):
51+
task_runtime_percentage = "{:.2f}%".format(
52+
100
53+
* ((task_runtime - previous_task_runtimes[task_id]) & (2**32 - 1))
54+
/ ((total_runtime - previous_total_runtime) & (2**32 - 1))
55+
)
56+
print(
57+
"{:>7} {:>4} {:>8d} {:<9} {:<14d} {}{}\x1b[K".format(
58+
task_runtime_percentage,
59+
"-" if task_coreid is None else task_coreid,
60+
task_priority,
61+
esp32_task_state_names.get(task_state, "unknown"),
62+
task_stackhighwatermark,
63+
thread_names.get(task_id, task_name),
64+
" (*)" if task_id == current_thread_id else "",
65+
)
66+
)
67+
line_count += 1
68+
69+
previous_task_runtimes[task_id] = task_runtime
70+
previous_total_runtime = total_runtime
71+
else:
72+
print("INFO: Platform does not support listing active tasks.\x1b[K")
73+
line_count += 1
74+
75+
if previous_line_count > line_count:
76+
for _ in range(previous_line_count - line_count):
77+
print("\x1b[K")
78+
print("\x1b[{}A".format(previous_line_count - line_count), end="")
79+
80+
previous_line_count = line_count
81+
82+
try:
83+
time.sleep_ms(update_interval_ms)
84+
except KeyboardInterrupt:
85+
break

0 commit comments

Comments
 (0)