Skip to content

Commit 51d1541

Browse files
committed
rpc_wrappers: thread_stats: added
Add a wrapper for the `thread_stats` RPC, displaying stack usage. Signed-off-by: Jordan Yates <jordan@embeint.com>
1 parent 4151b5d commit 51d1541

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

src/infuse_iot/generated/rpc_definitions.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,18 @@ class rpc_struct_public_key_info_256bit(VLACompatLittleEndianStruct):
232232
_pack_ = 1
233233

234234

235+
class rpc_struct_thread_stats(VLACompatLittleEndianStruct):
236+
"""IPv6 address"""
237+
238+
_fields_ = [
239+
("stack_size", ctypes.c_uint32),
240+
("stack_used", ctypes.c_uint32),
241+
("utilization", ctypes.c_uint8),
242+
]
243+
vla_field = ("name", 0 * ctypes.c_char)
244+
_pack_ = 1
245+
246+
235247
class rpc_enum_bt_le_addr_type(enum.IntEnum):
236248
"""Bluetooth LE address type"""
237249

@@ -872,6 +884,25 @@ class response(VLACompatLittleEndianStruct):
872884
_pack_ = 1
873885

874886

887+
class thread_stats(RPCDefinitionBase):
888+
"""Query runtime thread statistics"""
889+
890+
NAME = "thread_stats"
891+
HELP = "Query runtime thread statistics"
892+
DESCRIPTION = "Query runtime thread statistics"
893+
COMMAND_ID = 26
894+
895+
class request(VLACompatLittleEndianStruct):
896+
_fields_ = []
897+
_pack_ = 1
898+
899+
class response(VLACompatLittleEndianStruct):
900+
_fields_ = [
901+
("num_threads", ctypes.c_uint16),
902+
]
903+
_pack_ = 1
904+
905+
875906
class coap_download(RPCDefinitionBase):
876907
"""Download a file from a COAP server (Infuse-IoT DTLS protected)"""
877908

@@ -1334,6 +1365,7 @@ class response(VLACompatLittleEndianStruct):
13341365
lte_state_v2.COMMAND_ID: lte_state_v2,
13351366
data_logger_state_v2.COMMAND_ID: data_logger_state_v2,
13361367
data_logger_read_chunks.COMMAND_ID: data_logger_read_chunks,
1368+
thread_stats.COMMAND_ID: thread_stats,
13371369
coap_download.COMMAND_ID: coap_download,
13381370
zperf_upload.COMMAND_ID: zperf_upload,
13391371
coap_download_v2.COMMAND_ID: coap_download_v2,
@@ -1373,6 +1405,7 @@ class response(VLACompatLittleEndianStruct):
13731405
"rpc_struct_heap_info",
13741406
"rpc_struct_data_logger_chunk",
13751407
"rpc_struct_public_key_info_256bit",
1408+
"rpc_struct_thread_stats",
13761409
"rpc_enum_bt_le_addr_type",
13771410
"rpc_enum_file_action",
13781411
"rpc_enum_infuse_bt_characteristic",
@@ -1406,6 +1439,7 @@ class response(VLACompatLittleEndianStruct):
14061439
"lte_state_v2",
14071440
"data_logger_state_v2",
14081441
"data_logger_read_chunks",
1442+
"thread_stats",
14091443
"coap_download",
14101444
"zperf_upload",
14111445
"coap_download_v2",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env python3
2+
3+
import ctypes
4+
5+
import tabulate
6+
7+
import infuse_iot.definitions.rpc as defs
8+
from infuse_iot.commands import InfuseRpcCommand
9+
from infuse_iot.zephyr.errno import errno
10+
11+
12+
class thread_stats(InfuseRpcCommand, defs.thread_stats):
13+
RPC_DATA_RECEIVE = True
14+
15+
@classmethod
16+
def add_parser(cls, parser):
17+
sort = parser.add_mutually_exclusive_group()
18+
sort.add_argument("--sort-stack", action="store_true", help="Sort threads by stack usage (%)")
19+
20+
def __init__(self, args):
21+
self.args = args
22+
self._info = []
23+
24+
def request_struct(self):
25+
return self.request()
26+
27+
def request_json(self):
28+
return {}
29+
30+
def data_recv_cb(self, offset: int, data: bytes) -> None:
31+
base_size = ctypes.sizeof(defs.rpc_struct_thread_stats)
32+
while len(data) > 0:
33+
base = defs.rpc_struct_thread_stats.from_buffer_copy(data)
34+
data = data[base_size:]
35+
name_len = data.find(b"\x00") + 1
36+
name = data[:name_len].decode()
37+
data = data[name_len:]
38+
percent = int(100 * base.stack_used / base.stack_size)
39+
self._info.append((name, base.stack_used, base.stack_size, percent, base.utilization))
40+
41+
def handle_response(self, return_code, response):
42+
if return_code != 0:
43+
print(f"Failed to query thread stats ({errno.strerror(-return_code)})")
44+
return
45+
46+
if self.args.sort_stack:
47+
# Sort by stack usage
48+
display = sorted(self._info, key=lambda x: x[3], reverse=True)
49+
else:
50+
display = self._info
51+
52+
headings = ["Thread", "Stack Used", "Stack Size", "Stack %", "CPU %"]
53+
print(tabulate.tabulate(display, headers=headings))

0 commit comments

Comments
 (0)