Skip to content

Commit 99ce370

Browse files
committed
utop: Add initial implementation for ESP32.
Signed-off-by: Daniël van de Giessen <[email protected]>
1 parent 5b496e9 commit 99ce370

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

Diff for: micropython/utop/README.md

+12
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+
```

Diff for: micropython/utop/manifest.py

+6
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")

Diff for: micropython/utop/utop.py

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

0 commit comments

Comments
 (0)