Skip to content

Commit a639dd0

Browse files
committed
cubestat: metric reg
1 parent 0ad963c commit a639dd0

File tree

14 files changed

+122
-38
lines changed

14 files changed

+122
-38
lines changed

cubestat/cubestat.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from cubestat.platforms.factory import get_platform
1616

17-
from cubestat.metrics.registry import get_metrics, metrics_configure_argparse
17+
from cubestat.metrics_registry import get_metrics, metrics_configure_argparse
1818

1919

2020
class ViewMode(DisplayMode):
@@ -134,9 +134,20 @@ def start(stdscr, platform, args):
134134
def main():
135135
logging.basicConfig(filename='/tmp/cubestat.log', level=logging.INFO)
136136
parser = argparse.ArgumentParser("cubestat")
137-
parser.add_argument('--refresh_ms', '-i', type=int, default=1000, help='Update frequency, milliseconds')
138-
parser.add_argument('--buffer_size', type=int, default=500, help='How many datapoints to store. Having it larger than screen width is a good idea as terminal window can be resized')
139-
parser.add_argument('--view', type=ViewMode, default=ViewMode.one, choices=list(ViewMode), help='legend/values/time mode. Can be toggled by pressing v.')
137+
parser.add_argument(
138+
'--refresh_ms', '-i', type=int, default=1000,
139+
help='Update frequency (milliseconds)'
140+
)
141+
142+
parser.add_argument(
143+
'--buffer_size', type=int, default=500,
144+
help='Number of datapoints to store. Consider setting it larger than the screen width to accommodate window resizing.'
145+
)
146+
147+
parser.add_argument(
148+
'--view', type=ViewMode, default=ViewMode.one, choices=list(ViewMode),
149+
help='Display mode (legend, values, time). Hotkey: "v".'
150+
)
140151

141152
metrics_configure_argparse(parser)
142153
args = parser.parse_args()

cubestat/data.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
44

55
class DataManager:
66
def __init__(self, buffer_size):
7-
init_series = lambda: collections.deque(maxlen=buffer_size)
8-
init_group = lambda: collections.defaultdict(init_series)
7+
8+
def init_series():
9+
return collections.deque(maxlen=buffer_size)
10+
11+
def init_group():
12+
return collections.defaultdict(init_series)
13+
914
self.data = collections.defaultdict(init_group)
1015

1116
def get_slice(self, series, indent, h_shift, cols, spacing):

cubestat/input.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,7 @@ def __init__(self, horizon):
66
self.horizon = horizon
77
self.hotkeys = [(m.hotkey(), m) for m in self.horizon.metrics.values() if m.hotkey()]
88

9-
def handle_input(self):
10-
key = self.horizon.screen.stdscr.getch()
11-
if key == ord('q') or key == ord('Q'):
12-
exit(0)
13-
for k, metric in self.hotkeys:
14-
if key == ord(k):
15-
with self.horizon.lock:
16-
metric.mode = metric.mode.next()
17-
self.horizon.settings_changed = True
18-
if key == ord(k.upper()):
19-
with self.horizon.lock:
20-
metric.mode = metric.mode.prev()
21-
self.horizon.settings_changed = True
9+
def handle_shifts(self, key):
2210
if key == curses.KEY_UP:
2311
with self.horizon.lock:
2412
if self.horizon.v_shift > 0:
@@ -38,6 +26,8 @@ def handle_input(self):
3826
if self.horizon.h_shift > 0:
3927
self.horizon.h_shift -= 1
4028
self.horizon.settings_changed = True
29+
30+
def handle_reset(self, key):
4131
if key == ord('0'):
4232
with self.horizon.lock:
4333
if self.horizon.v_shift > 0:
@@ -46,6 +36,20 @@ def handle_input(self):
4636
if self.horizon.h_shift > 0:
4737
self.horizon.h_shift = 0
4838
self.horizon.settings_changed = True
39+
40+
def handle_input(self):
41+
key = self.horizon.screen.stdscr.getch()
42+
if key == ord('q') or key == ord('Q'):
43+
exit(0)
44+
for k, metric in self.hotkeys:
45+
if key == ord(k):
46+
with self.horizon.lock:
47+
metric.mode = metric.mode.next()
48+
self.horizon.settings_changed = True
49+
if key == ord(k.upper()):
50+
with self.horizon.lock:
51+
metric.mode = metric.mode.prev()
52+
self.horizon.settings_changed = True
4953
if key == ord('v'):
5054
with self.horizon.lock:
5155
self.horizon.view = self.horizon.view.next()
@@ -62,3 +66,5 @@ def handle_input(self):
6266
with self.horizon.lock:
6367
self.horizon.theme = self.horizon.theme.prev()
6468
self.horizon.settings_changed = True
69+
self.handle_shifts(key)
70+
self.handle_reset(key)

cubestat/metrics/__init__.py

Whitespace-only changes.

cubestat/metrics/accel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import subprocess
22
from cubestat.metrics.base_metric import base_metric
3-
from cubestat.metrics.registry import cubestat_metric
3+
from cubestat.metrics_registry import cubestat_metric
44

55

66
@cubestat_metric('darwin')

cubestat/metrics/cpu.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import psutil
33

44
from cubestat.metrics.base_metric import base_metric
5-
from cubestat.metrics.registry import cubestat_metric
5+
from cubestat.metrics_registry import cubestat_metric
66
from cubestat.common import DisplayMode
77

88

@@ -43,7 +43,13 @@ def hotkey(self):
4343

4444
@classmethod
4545
def configure_argparse(cls, parser):
46-
parser.add_argument('--cpu', type=CPUMode, default=auto_cpu_mode(), choices=list(CPUMode), help='CPU mode - showing all cores, only cumulative by cluster or both. Can be toggled by pressing c.')
46+
parser.add_argument(
47+
'--cpu',
48+
type=CPUMode,
49+
default=auto_cpu_mode(),
50+
choices=list(CPUMode),
51+
help='Select CPU mode: all cores, cumulative by cluster, or both. Hotkey: "c".'
52+
)
4753

4854

4955
@cubestat_metric('linux')

cubestat/metrics/disk.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from cubestat.common import SimpleMode, RateReader, label_bytes_per_sec
44
from cubestat.metrics.base_metric import base_metric
5-
from cubestat.metrics.registry import cubestat_metric
5+
from cubestat.metrics_registry import cubestat_metric
66

77

88
class disk_metric(base_metric):
@@ -23,7 +23,13 @@ def hotkey(self):
2323

2424
@classmethod
2525
def configure_argparse(cls, parser):
26-
parser.add_argument('--disk', type=SimpleMode, default=SimpleMode.show, choices=list(SimpleMode), help="Show disk read/write. Can be toggled by pressing d.")
26+
parser.add_argument(
27+
'--disk',
28+
type=SimpleMode,
29+
default=SimpleMode.show,
30+
choices=list(SimpleMode),
31+
help='Show disk read/write rate. Hotkey: "d"'
32+
)
2733

2834
def configure(self, conf):
2935
self.mode = conf.disk

cubestat/metrics/gpu.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from cubestat.common import DisplayMode
55
from cubestat.metrics.base_metric import base_metric
6-
from cubestat.metrics.registry import cubestat_metric
6+
from cubestat.metrics_registry import cubestat_metric
77

88

99
class GPUMode(DisplayMode):
@@ -38,7 +38,13 @@ def hotkey(self):
3838

3939
@classmethod
4040
def configure_argparse(cls, parser):
41-
parser.add_argument('--gpu', type=GPUMode, default=GPUMode.load_only, choices=list(GPUMode), help='GPU mode - hidden, showing all GPUs load, or showing load and vram usage. Can be toggled by pressing g.')
41+
parser.add_argument(
42+
'--gpu',
43+
type=GPUMode,
44+
default=GPUMode.load_only,
45+
choices=list(GPUMode),
46+
help='GPU mode - hidden, load, or load and vram usage. Hotkey: "g"'
47+
)
4248

4349

4450
@cubestat_metric('linux')

cubestat/metrics/memory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import psutil
22

33
from cubestat.metrics.base_metric import base_metric
4-
from cubestat.metrics.registry import cubestat_metric
4+
from cubestat.metrics_registry import cubestat_metric
55
from cubestat.common import label_bytes
66
from cubestat.common import DisplayMode
77

cubestat/metrics/network.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from cubestat.common import SimpleMode, RateReader, label_bytes_per_sec
44
from cubestat.metrics.base_metric import base_metric
5-
from cubestat.metrics.registry import cubestat_metric
5+
from cubestat.metrics_registry import cubestat_metric
66

77

88
class network_metric(base_metric):
@@ -28,7 +28,13 @@ def configure(self, conf):
2828

2929
@classmethod
3030
def configure_argparse(cls, parser):
31-
parser.add_argument('--network', type=SimpleMode, default=SimpleMode.show, choices=list(SimpleMode), help="Show network io. Can be toggled by pressing n.")
31+
parser.add_argument(
32+
'--network',
33+
type=SimpleMode,
34+
default=SimpleMode.show,
35+
choices=list(SimpleMode),
36+
help='Show network io. Hotkey: "n"'
37+
)
3238

3339

3440
@cubestat_metric('darwin')

cubestat/metrics/power.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from cubestat.common import DisplayMode, label10
22
from cubestat.metrics.base_metric import base_metric
3-
from cubestat.metrics.registry import cubestat_metric
3+
from cubestat.metrics_registry import cubestat_metric
44

55

66
class PowerMode(DisplayMode):
@@ -44,4 +44,10 @@ def hotkey(self):
4444

4545
@classmethod
4646
def configure_argparse(cls, parser):
47-
parser.add_argument('--power', type=PowerMode, default=PowerMode.combined, choices=list(PowerMode), help='Power mode - off, showing breakdown CPU/GPU/ANE load, or showing combined usage. Can be toggled by pressing p.')
47+
parser.add_argument(
48+
'--power',
49+
type=PowerMode,
50+
default=PowerMode.combined,
51+
choices=list(PowerMode),
52+
help='Power: hidden, CPU/GPU/ANE breakdown, or combined usage. Hotkey: "p"'
53+
)

cubestat/metrics/swap.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import subprocess
44

55
from cubestat.metrics.base_metric import base_metric
6-
from cubestat.metrics.registry import cubestat_metric
6+
from cubestat.metrics_registry import cubestat_metric
77
from cubestat.common import SimpleMode, label_bytes
88

99

@@ -22,7 +22,13 @@ def key(cls):
2222

2323
@classmethod
2424
def configure_argparse(cls, parser):
25-
parser.add_argument('--swap', type=SimpleMode, default=SimpleMode.show, choices=list(SimpleMode), help="Show swap . Can be toggled by pressing s.")
25+
parser.add_argument(
26+
'--swap',
27+
type=SimpleMode,
28+
default=SimpleMode.show,
29+
choices=list(SimpleMode),
30+
help='swap show/hide. Hotkey: "s"'
31+
)
2632

2733
def configure(self, conf):
2834
self.mode = conf.swap
@@ -54,10 +60,18 @@ def read(self, _context):
5460
res = {}
5561
try:
5662
swap_stats = subprocess.run(["sysctl", "vm.swapusage"], capture_output=True, text=True)
63+
swap_stats.check_returncode() # Raise CalledProcessError if exit status is non-zero
5764
tokens = swap_stats.stdout.strip().split(' ')
65+
if len(tokens) < 8:
66+
raise IndexError("Invalid sysctl output")
5867
res['swap used'] = self._parse_memstr(tokens[7])
59-
except:
60-
logging.error("unable to get swap stats.")
68+
except subprocess.CalledProcessError as e:
69+
logging.error(f"sysctl command failed: {e}")
70+
except IndexError as e:
71+
logging.error(f"Invalid sysctl output: {e}")
72+
except Exception as e:
73+
logging.error(f"Unexpected error: {e}")
74+
6175
return res
6276

6377

cubestat/metrics/registry.py renamed to cubestat/metrics_registry.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import importlib
2+
import pkgutil
13
import sys
24

35
_metrics = []
@@ -24,5 +26,15 @@ def get_metrics(args):
2426
}
2527

2628

27-
# to run the annotations and register metrics
28-
from cubestat.metrics import cpu, gpu, memory, accel, swap, network, disk, power
29+
# Dynamically discover and import metrics
30+
def import_submodules(package_name):
31+
package = importlib.import_module(package_name)
32+
for _, module_name, is_pkg in pkgutil.iter_modules(package.__path__):
33+
full_module_name = f"{package_name}.{module_name}"
34+
importlib.import_module(full_module_name)
35+
if is_pkg:
36+
import_submodules(full_module_name)
37+
38+
39+
# Import all submodules of cubestat.metrics
40+
import_submodules("cubestat.metrics")

cubestat/platforms/macos.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
class MacOSPlatform:
66
def __init__(self, interval_ms) -> None:
7-
cmd = ['sudo', 'powermetrics', '-f', 'plist', '-i', str(interval_ms), '-s', 'cpu_power,gpu_power,ane_power,network,disk']
7+
cmd = [
8+
'sudo',
9+
'powermetrics',
10+
'-f', 'plist',
11+
'-i', str(interval_ms),
12+
'-s', 'cpu_power,gpu_power,ane_power,network,disk'
13+
]
814
self.powermetrics = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
915
# getting first line here to allow user to enter sudo credentials before
1016
# curses initialization.

0 commit comments

Comments
 (0)