Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/infuse_iot/rpc_wrappers/thread_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class thread_stats(InfuseRpcCommand, defs.thread_stats):
@classmethod
def add_parser(cls, parser):
sort = parser.add_mutually_exclusive_group()
sort.add_argument("--sort-stack", action="store_true", help="Sort threads by stack usage (%)")
sort.add_argument("--sort-percentage", action="store_true", help="Sort threads by stack usage (%)")
sort.add_argument("--sort-bytes", action="store_true", help="Sort threads by bytes bytes")

def __init__(self, args):
self.args = args
Expand All @@ -36,18 +37,22 @@ def data_recv_cb(self, offset: int, data: bytes) -> None:
name = data[:name_len].decode()
data = data[name_len:]
percent = int(100 * base.stack_used / base.stack_size)
self._info.append((name, base.stack_used, base.stack_size, percent, base.utilization))
unused = base.stack_size - base.stack_used
self._info.append((name, base.stack_used, unused, base.stack_size, percent, base.utilization))

def handle_response(self, return_code, response):
if return_code != 0:
print(f"Failed to query thread stats ({errno.strerror(-return_code)})")
return

if self.args.sort_stack:
# Sort by stack usage
display = sorted(self._info, key=lambda x: x[3], reverse=True)
if self.args.sort_percentage:
# Sort by stack usage percent
display = sorted(self._info, key=lambda x: x[4], reverse=True)
elif self.args.sort_bytes:
# Sort by stack bytes free
display = sorted(self._info, key=lambda x: x[2], reverse=True)
else:
display = self._info

headings = ["Thread", "Stack Used", "Stack Size", "Stack %", "CPU %"]
headings = ["Thread", "Stack Used", "Stack Free", "Stack Size", "Stack %", "CPU %"]
print(tabulate.tabulate(display, headers=headings))
49 changes: 37 additions & 12 deletions src/infuse_iot/tools/csv_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,56 @@ class SubCommand(InfuseCommand):

@classmethod
def add_parser(cls, parser):
parser.add_argument("--file", "-f", required=True, type=ValidFile)
parser.add_argument(
"--files",
"-f",
required=True,
type=ValidFile,
nargs="+",
)
parser.add_argument("--start", type=str, default="2024-01-01", help="Display data after")
parser.add_argument("--field", type=str, help="Single column to plot")
parser.add_argument("--group", action="store_true", help="Group all lines onto a single plot")

def __init__(self, args):
self.file = args.file
self.files = args.files
self.field = args.field
self.start = args.start
self.group = args.group

def run(self):
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from dash import Dash, dcc, html

df = pd.read_csv(self.file)
fig: None | go.Figure = None
figures: list[dcc.Graph] = []
if self.group:
fig = go.Figure()

mask = df["time"] >= self.start
filtered_df = df.loc[mask]
for file in self.files:
df = pd.read_csv(file)

fig = px.line(
filtered_df,
x="time",
y=filtered_df.columns.values[1:],
title=str(self.file),
)
mask = df["time"] >= self.start
filtered_df = df.loc[mask]

y_data = filtered_df[self.field] if self.field else filtered_df.columns.values[1:]
if self.group:
assert fig is not None
fig.add_trace(go.Scatter(x=filtered_df["time"], y=y_data, name=str(file.name), mode="lines"))
else:
fig = px.line(
filtered_df,
x="time",
y=y_data,
title=str(file),
)
figures.append(dcc.Graph(figure=fig))

app = Dash()
app.layout = html.Div([dcc.Graph(figure=fig)])
if self.group:
figures = [dcc.Graph(figure=fig, style={"height": "90vh"})]
app.layout = html.Div(figures)

app.run(debug=True)