Skip to content
This repository was archived by the owner on Sep 22, 2023. It is now read-only.

Commit c637d80

Browse files
authored
feat: Improve output of "backend.ai admin agent" command with live-stat (#149)
* When cpu_util is not available yet because the agent has just started, show "(calculating...)"
1 parent 5dff011 commit c637d80

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

changes/145.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve the output `backend.ai admin agent <AgentID>` command with live statistics

src/ai/backend/client/cli/admin/agents.py

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import json
12
import sys
23

34
import click
5+
import humanize
46
from tabulate import tabulate
57

68
from . import admin
@@ -14,9 +16,63 @@
1416
from ...exceptions import NoItems
1517

1618

19+
def format_stats(raw_stats):
20+
21+
value_formatters = {
22+
'bytes': lambda m: "{} / {}".format(
23+
humanize.filesize.naturalsize(int(m['current'])),
24+
humanize.filesize.naturalsize(int(m['capacity'])),
25+
),
26+
'Celsius': lambda m: "{:,} C".format(
27+
float(m['current']),
28+
),
29+
'bps': lambda m: "{}/s".format(
30+
humanize.naturalsize(float(m['current'])),
31+
),
32+
'pct': lambda m: "{} %".format(
33+
m['pct'],
34+
),
35+
}
36+
37+
def format_value(metric):
38+
formatter = value_formatters.get(
39+
metric['unit_hint'],
40+
lambda m: "{} / {} {}".format(
41+
m['current'],
42+
m['capacity'],
43+
m['unit_hint'],
44+
),
45+
)
46+
return formatter(metric)
47+
48+
bufs = []
49+
node_metric_bufs = []
50+
for stat_key, metric in raw_stats['node'].items():
51+
if stat_key == 'cpu_util':
52+
num_cores = len(raw_stats['devices']['cpu_util'])
53+
if metric['pct'] is None:
54+
node_metric_bufs.append(f"{stat_key}: (calculating...) % ({num_cores} cores)")
55+
else:
56+
node_metric_bufs.append(f"{stat_key}: {metric['pct']} % ({num_cores} cores)")
57+
else:
58+
node_metric_bufs.append(f"{stat_key}: {format_value(metric)}")
59+
bufs.append(", ".join(node_metric_bufs))
60+
dev_metric_bufs = []
61+
for stat_key, per_dev_metric in raw_stats['devices'].items():
62+
dev_metric_bufs.append(f"+ {stat_key}")
63+
if stat_key == 'cpu_util' and len(per_dev_metric) > 8:
64+
dev_metric_bufs.append(" - (per-core stats hidden for large CPUs with more than 8 cores)")
65+
else:
66+
for dev_id, metric in per_dev_metric.items():
67+
dev_metric_bufs.append(
68+
f" - {dev_id}: {format_value(metric)}"
69+
)
70+
bufs.append("\n".join(dev_metric_bufs))
71+
return '\n'.join(bufs)
72+
73+
1774
@admin.command()
18-
@click.option('-i', '--id', 'agent_id', required=True,
19-
help='The agent Id to inspect.')
75+
@click.argument('agent_id')
2076
def agent(agent_id):
2177
'''
2278
Show the information about the given agent.
@@ -27,9 +83,9 @@ def agent(agent_id):
2783
('Region', 'region'),
2884
('First Contact', 'first_contact'),
2985
('CPU Usage (%)', 'cpu_cur_pct'),
30-
('Used Memory (MiB)', 'mem_cur_bytes'),
3186
('Total slots', 'available_slots'),
3287
('Occupied slots', 'occupied_slots'),
88+
('Live Stat', 'live_stat'),
3389
]
3490
if is_legacy_server():
3591
del fields[9]
@@ -46,7 +102,10 @@ def agent(agent_id):
46102
if key == 'mem_cur_bytes' and resp[key] is not None:
47103
resp[key] = round(resp[key] / 2 ** 20, 1)
48104
if key in resp:
49-
rows.append((name, resp[key]))
105+
if key == 'live_stat' and resp[key] is not None:
106+
rows.append((name, format_stats(json.loads(resp[key]))))
107+
else:
108+
rows.append((name, resp[key]))
50109
print(tabulate(rows, headers=('Field', 'Value')))
51110

52111

0 commit comments

Comments
 (0)