nodeocc 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
view/slurm_list.py ADDED
@@ -0,0 +1,148 @@
1
+ from datetime import datetime
2
+
3
+ from view.styles import _format_to, cmdstyle
4
+ from view.utils import is_cvcs_viz, is_student_viz, is_dev, is_prod
5
+
6
+ midlane = "─────────── ▲ DEV ──────────────────────────────── ▼ PROD ────────────"
7
+
8
+
9
+ def format_date(str_date):
10
+ return datetime.strftime(datetime.strptime(str_date, '%Y-%m-%dT%H:%M:%S'), '%m/%d-%H:%M')
11
+
12
+
13
+ def _joblet_format(instance, job, width=74, jobid_type='agg'):
14
+ joblet_reprs = []
15
+ for i, joblet in enumerate(job.joblets):
16
+ jid = str(job.jobid if jobid_type == 'agg' else job.true_jobid)
17
+ joblet_repr = ''
18
+ joblet_repr += _format_to(jid.replace('[', '').replace(']', '').split('%')[0], 14)
19
+ joblet_repr += ' '
20
+ loffset = 0
21
+ if instance.show_prio:
22
+ joblet_repr += '(' + _format_to(job.priority, len(str(job.priority))) + ')'
23
+ joblet_repr += ' '
24
+ loffset += 9
25
+ if instance.show_account:
26
+ joblet_repr += _format_to(job.account, 9)
27
+ joblet_repr += ' '
28
+ loffset += 10
29
+ if instance.show_starttime:
30
+ joblet_repr += _format_to(format_date(job.starttime), 12) if not isinstance(job.starttime, float) else _format_to('¯\\_(ツ)_/¯', 11)
31
+ joblet_repr += ' '
32
+ loffset += 13
33
+ joblet_repr += _format_to(job.name if i == 0 else '"', width - 65 - loffset, 'right')
34
+ joblet_repr += ' '
35
+ joblet_repr += _format_to(job.user if i == 0 else '"', 13, 'right')
36
+ joblet_repr += ' '
37
+ joblet_repr += _format_to(job.state if i == 0 else '"', 2, 'right')
38
+ joblet_repr += ' '
39
+ joblet_repr += _format_to(job.runtime if i == 0 else '"', 8, 'right')
40
+ joblet_repr += ' '
41
+ if isinstance(joblet.mem, str):
42
+ mem = '0'
43
+ else:
44
+ mem = round(joblet.mem / 1024)
45
+ joblet_repr += _format_to(f'{mem}G', 4, 'right')
46
+ joblet_repr += ' '
47
+ if instance.view_mode in ('gpu', 'ram'):
48
+ joblet_repr += _format_to((f'{joblet.n_gpus}gp' if joblet.n_gpus > 0 else " - "), 3, 'left')
49
+ elif instance.view_mode == 'cpu':
50
+ joblet_repr += _format_to((f'{joblet.cpus}cp' if joblet.cpus > 0 else "-"), 3, 'left')
51
+ joblet_repr += ' '
52
+ joblet_repr += _format_to(joblet.node if joblet.node is not None else job.reason, 11)
53
+ joblet_reprs.append(joblet_repr)
54
+ job_repr = '\n'.join(joblet_reprs)
55
+ return job_repr
56
+
57
+
58
+ STYLE_MAPPING = {'R': None, 'S': 'MAGENTA', 'PD': 'YELLOW', 'CG': 'MAGENTA'}
59
+
60
+
61
+ def dev_sort_key(x):
62
+ return (x.user,
63
+ x.jobid.split('_')[0],
64
+ int(x.jobid.split('_')[1]) if '_' in x.jobid and '[' not in x.jobid else (999 if '[' in x.jobid else 0))
65
+
66
+
67
+ def prod_sort_key(x, instance):
68
+ return ((x.user if not instance.sort_by_prio else -x.priority,
69
+ x.jobid.split('_')[0],
70
+ int(x.jobid.split('_')[1]) if '_' in x.jobid and '[' not in x.jobid else (999 if '[' in x.jobid else 0)))
71
+
72
+
73
+ def view_list(instance, jobs, filter=None, work=True, stylefn=cmdstyle, current_user=None, width=74, jit='agg'):
74
+ # this is for hot reload
75
+ if not work:
76
+ return "UPDATE IN PROGRESS - PLZ W8 M8 B8"
77
+
78
+ # who is the current user?
79
+ if current_user is None:
80
+ import os
81
+ current_user = os.path.basename(os.environ['HOME'])
82
+
83
+ # what will this function print?
84
+ printable = set()
85
+ if filter is None:
86
+ printable.add('me')
87
+ printable.add('prod')
88
+ printable.add('stud')
89
+ printable.add('cvcs')
90
+ elif filter == 'me':
91
+ printable.add('me')
92
+ elif filter == 'prod':
93
+ printable.add('prod')
94
+ elif filter == 'stud':
95
+ printable.add('stud')
96
+ elif filter == 'cvcs':
97
+ printable.add('cvcs')
98
+
99
+ jobs_to_print = []
100
+ for j in jobs:
101
+ if j.user == current_user and 'me' in printable:
102
+ jobs_to_print.append(j)
103
+ elif 'stud' in printable and is_student_viz(j):
104
+ jobs_to_print.append(j)
105
+ elif 'prod' in printable and not is_student_viz(j):
106
+ jobs_to_print.append(j)
107
+ elif 'cvcs' in printable and is_cvcs_viz(j):
108
+ jobs_to_print.append(j)
109
+
110
+ class RetScope:
111
+ return_string = ''
112
+
113
+ def cust_print(thing, style=None):
114
+ RetScope.return_string += (thing if style is None else stylefn(style, thing)) + '\n'
115
+
116
+ devjobs = sorted([x for x in jobs_to_print if is_dev(x)], key=lambda x: dev_sort_key(x))
117
+
118
+ for state in STYLE_MAPPING:
119
+ for x in devjobs:
120
+ if x.state == state:
121
+ cust_print(_joblet_format(instance, x, width=width, jobid_type=jit), style=STYLE_MAPPING[x.state])
122
+
123
+ cust_print('─' * ((width - 72) // 2) + midlane + '─' * (width - 72 - ((width - 72) // 2)))
124
+
125
+ prodjobs = sorted([x for x in jobs_to_print if not is_dev(x)], key=lambda x: prod_sort_key(x, instance))
126
+
127
+ for state in STYLE_MAPPING:
128
+ for x in prodjobs:
129
+ if x.state == state:
130
+ cust_print(_joblet_format(instance, x, width=width, jobid_type=jit), style=STYLE_MAPPING[x.state])
131
+
132
+ return RetScope.return_string
133
+
134
+
135
+ if __name__ == '__main__':
136
+ import sys
137
+
138
+ from curses_multiwindow import Singleton
139
+
140
+ from readers.slurmreader import read_jobs
141
+ instance = Singleton.getInstance()
142
+ jobs, _ = read_jobs()
143
+ if len(sys.argv) > 1 and sys.argv[1] == 'work':
144
+ print(view_list(instance, jobs, work=True, filter='me'))
145
+ elif len(sys.argv) > 1:
146
+ print(view_list(instance, jobs, filter=sys.argv[1]))
147
+ else:
148
+ print(view_list(instance, jobs))
view/slurm_viz.py ADDED
@@ -0,0 +1,494 @@
1
+ import random
2
+
3
+ import pandas as pd
4
+
5
+ from view.styles import _format_to, cmdstyle
6
+ from view.utils import is_cvcs_viz, is_student_viz, maintenance_status, to_font
7
+
8
+ ogre = '''⢀⡴⠑⡄⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀
9
+ ⠸⡇⠀⠿⡀⠀⠀⠀⣀⡴⢿⣿⣿⣿⣿⣿⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
10
+ ⠀⠀⠀⠀⠑⢄⣠⠾⠁⣀⣄⡈⠙⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀
11
+ ⠀⠀⠀⠀⢀⡀⠁⠀⠀⠈⠙⠛⠂⠈⣿⣿⣿⣿⣿⠿⡿⢿⣆⠀⠀⠀⠀⠀⠀⠀
12
+ ⠀⠀⠀⢀⡾⣁⣀⠀⠴⠂⠙⣗⡀⠀⢻⣿⣿⠭⢤⣴⣦⣤⣹⠀⠀⠀⢀⢴⣶⣆
13
+ ⠀⠀⢀⣾⣿⣿⣿⣷⣮⣽⣾⣿⣥⣴⣿⣿⡿⢂⠔⢚⡿⢿⣿⣦⣴⣾⠸⣼⡿
14
+ ⠀⢀⡞⠁⠙⠻⠿⠟⠉⠀⠛⢹⣿⣿⣿⣿⣿⣌⢤⣼⣿⣾⣿⡟⠉⠀⠀⠀⠀
15
+ ⠀⣾⣷⣶⠇⠀⠀⣤⣄⣀⡀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀
16
+ ⠀⠉⠈⠉⠀⠀⢦⡈⢻⣿⣿⣿⣶⣶⣶⣶⣤⣽⡹⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀
17
+ ⠀⠀⠀⠀⠀⠀⠀⠉⠲⣽⡻⢿⣿⣿⣿⣿⣿⣿⣷⣜⣿⣿⣿⡇⠀⠀⠀⠀⠀
18
+ ⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣷⣶⣮⣭⣽⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀
19
+ ⠀⠀⠀⠀⠀⠀⣀⣀⣈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀
20
+ ⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀
21
+ ⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀
22
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠛⠉
23
+ '''
24
+ flip = ''' ⣰⣾⣿⣿⣿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣆
25
+ ⣿⣿⣿⡿⠋⠄⡀⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠋⣉⣉⣉⡉⠙⠻⣿⣿
26
+ ⣿⣿⣿⣇⠔⠈⣿⣿⣿⣿⣿⡿⠛⢉⣤⣶⣾⣿⣿⣿⣿⣿⣿⣦⡀⠹
27
+ ⣿⣿⠃⠄⢠⣾⣿⣿⣿⠟⢁⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄
28
+ ⣿⣿⣿⣿⣿⣿⣿⠟⢁⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷
29
+ ⣿⣿⣿⣿⣿⡟⠁⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
30
+ ⣿⣿⣿⣿⠋⢠⣾⣿⣿⣿⣿⣿⣿⡿⠿⠿⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿
31
+ ⣿⣿⡿⠁⣰⣿⣿⣿⣿⣿⣿⣿⣿⠗⠄⠄⠄⠄⣿⣿⣿⣿⣿⣿⣿⡟
32
+ ⣿⡿⠁⣼⣿⣿⣿⣿⣿⣿⡿⠋⠄⠄⠄⣠⣄⢰⣿⣿⣿⣿⣿⣿⣿⠃
33
+ ⡿⠁⣼⣿⣿⣿⣿⣿⣿⣿⡇⠄⢀⡴⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⡏⢠
34
+ ⠃⢰⣿⣿⣿⣿⣿⣿⡿⣿⣿⠴⠋⠄⠄⢸⣿⣿⣿⣿⣿⣿⣿⡟⢀⣾
35
+ ⢀⣿⣿⣿⣿⣿⣿⣿⠃⠈⠁⠄⠄⢀⣴⣿⣿⣿⣿⣿⣿⣿⡟⢀⣾⣿
36
+ ⢸⣿⣿⣿⣿⣿⣿⣿⠄⠄⠄⠄⢶⣿⣿⣿⣿⣿⣿⣿⣿⠏⢀⣾⣿⣿
37
+ ⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣶⣿⣿⣿⣿⣿⣿⣿⠋⣠⣿⣿⣿⣿
38
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢁⣼⣿⣿⣿⣿⣿
39
+ ⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢁⣴⣿⣿⣿⣿⣿⣿⣿
40
+ ⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⢁⣴⣿⣿⣿⣿⠗⠄⠄⣿⣿
41
+ ⣆⠈⠻⢿⣿⣿⣿⣿⣿⣿⠿⠛⣉⣤⣾⣿⣿⣿⣿⣿⣇⠠⠺⣷⣿⣿
42
+ ⣿⣿⣦⣄⣈⣉⣉⣉⣡⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⠉⠁⣀⣼⣿⣿⣿
43
+ ⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣾⣿⣿⡿⠟
44
+ '''
45
+ chunga = '''⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣧⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
46
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣧⠀⠀⠀⢰⡿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
47
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡟⡆⠀⠀⣿⡇⢻⠀⠀⠀⠀⠀⠀⠀⠀⠀
48
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⣿⠀⢰⣿⡇⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀
49
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡄⢸⠀⢸⣿⡇⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀
50
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡇⢸⡄⠸⣿⡇⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀
51
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⢸⡅⠀⣿⢠⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀
52
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣥⣾⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
53
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀
54
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡿⡿⣿⣿⡿⡅⠀⠀⠀⠀⠀⠀⠀
55
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠉⠀⠉⡙⢔⠛⣟⢋⠦⢵⠀⠀⠀⠀⠀⠀
56
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣄⠀⠀⠁⣿⣯⡥⠃⠀⢳⠀⠀⠀⠀⠀⠀
57
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡇⠀⠀⠀⠐⠠⠊⢀⠀⢸⠀⠀⠀⠀⠀⠀
58
+ ⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⡿⠀⠀⠀⠀⠀⠈⠁⠀⠀⠘⣿⣄⠀⠀⠀⠀
59
+ ⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣷⡀⠀⠀
60
+ ⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣧⠀
61
+ ⠀⠀⠀⡜⣭⠤⢍⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢛⢭⣗
62
+ ⠀⠀⠀⠁⠈⠀⠀⣀⠝⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠠⠀⠀⠰⡅
63
+ ⠀⠀⠀⢀⠀⠀⡀⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠔⠠⡕
64
+ ⠀⠀⠀⠀⣿⣷⣶⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀
65
+ ⠀⠀⠀⠀⠘⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠀⠀⠀⠀
66
+ ⠀⠀⠀⠀⠀⠈⢿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠊⠉⢆⠀⠀⠀
67
+ ⠀⢀⠤⠀⠀⢤⣤⣽⣿⣿⣦⣀⢀⡠⢤⡤⠄⠀⠒⠀⠁⠀⠀⠀⢘⠔⠀
68
+ ⠀⠀⠀⡐⠈⠁⠈⠛⣛⠿⠟⠑⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
69
+ ⠀⠀⠉⠑⠒⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
70
+ '''
71
+
72
+ gpu_avail = '□'
73
+ gpu_occ = '■'
74
+ gpu_drain = '△'
75
+ gpu_pendr = '⧖'
76
+ gpu_down = '⨯'
77
+ gpu_paused = '◆'
78
+ gpu_name_chars = 12
79
+ gpu_box_chars = 16
80
+
81
+ mem_size = 16
82
+ mem_unit = 'ᴳ'
83
+ ram_occ = '█' # '▄'#
84
+ ram_occ_alt = '▀'
85
+ ram_avail = '░'
86
+ ram_drain = '△'
87
+ ram_pendr = '⧖'
88
+ ram_paused = '▚'
89
+ ram_down = '⨯'
90
+
91
+ cpu_size = 4
92
+ cpu_unit = 'ᶜᵖᵘ'
93
+ cpu_occ = '█' # '▄'#
94
+ cpu_occ_alt = '▀'
95
+ cpu_avail = '░'
96
+ cpu_half = '▌'
97
+ cpu_drain = '△'
98
+ cpu_pendr = '⧖'
99
+ cpu_paused = '▚'
100
+ cpu_down = '⨯'
101
+
102
+
103
+ def get_ram_block(megs):
104
+ return int(round(megs / 1024 / mem_size))
105
+
106
+
107
+ def get_cpu_block(cpus):
108
+ return cpus // cpu_size
109
+
110
+
111
+ def view_viz(infrastructure, jobs, work=True, stylefn=cmdstyle, current_user=None, mode='gpu'):
112
+ if mode == 'gpu':
113
+ return view_viz_gpu(infrastructure, jobs, work, stylefn, current_user)
114
+ elif mode == 'ram':
115
+ return view_viz_ram(infrastructure, jobs, work, stylefn, current_user)
116
+ elif mode == 'cpu':
117
+ return view_viz_cpu(infrastructure, jobs, work, stylefn, current_user)
118
+
119
+
120
+ def view_viz_ram(infrastructure, jobs, work=True, stylefn=cmdstyle, current_user=None):
121
+ # this is for hot reload
122
+ if not work:
123
+ return "UPDATE IN PROGRESS - PLZ W8 M8 B8"
124
+
125
+ # who is the current user?
126
+ if current_user is None:
127
+ import os
128
+ current_user = os.path.basename(os.environ['HOME'])
129
+
130
+ nodes = infrastructure.get_sorted_nodes()
131
+ infrast_down = all([x.status == 'down' for x in nodes])
132
+
133
+ class RetScope:
134
+ return_string = ''
135
+
136
+ def cust_print(thing, style=None):
137
+ RetScope.return_string += (thing if style is None else stylefn(style, thing)) + '\n'
138
+
139
+ if not infrast_down:
140
+ highlighted_users = [current_user]
141
+ highlighted_users += pd.DataFrame([(j.user, sum([get_ram_block(x.mem) for x in j.joblets])) for j in jobs if j.user !=
142
+ current_user and j.state in ('R', 'S')]).groupby(0).sum()[1].sort_values(ascending=False).iloc[:3].index.to_list()
143
+
144
+ user_styles = dict(zip(highlighted_users, ['RED', 'YELLOW', 'GREEN', 'MAGENTA', 'BLUE']))
145
+ students = [j.user for j in jobs if is_student_viz(j)]
146
+ for s in students:
147
+ user_styles[s] = 'CYAN'
148
+
149
+ cvcs_students = [j.user for j in jobs if is_cvcs_viz(j)]
150
+ for s in cvcs_students:
151
+ user_styles[s] = 'BLUE'
152
+
153
+ stalled_jobs = sum([j.state == 'S' for j in jobs])
154
+ total_jobs_prod = 0
155
+ total_jobs_stud = 0
156
+
157
+ # print jobs
158
+ for n in nodes:
159
+ joblet_icons = []
160
+ occs = 0
161
+ for j in sorted(jobs, key=lambda x: (x.partition, x.user)):
162
+ for jj in j.joblets:
163
+ if n.name == jj.node:
164
+ if j.is_student() and 'all_usr_prod' in j.partition:
165
+ total_jobs_stud += int(round((jj.mem) / 1024))
166
+ elif 'all_usr_prod' in j.partition:
167
+ total_jobs_prod += int(round((jj.mem) / 1024))
168
+ occs += jj.mem
169
+ icon = ram_paused if j.state == 'S' else ram_occ
170
+ st = icon * get_ram_block(jj.mem)
171
+ joblet_icons.append((st, user_styles[j.user] if j.user in user_styles else None))
172
+ joblet_icons += [(ram_drain if n.status == 'drain' else (ram_down if n.status == 'down' else (ram_pendr if n.reserved == 'pending' else ram_avail)), None)] * get_ram_block(n.mem - occs)
173
+
174
+ jobsplit = [""]
175
+ count = 0
176
+ for ic, c in joblet_icons:
177
+ for i in ic:
178
+ if count == gpu_box_chars - 3:
179
+ jobsplit.append("")
180
+ count = 0
181
+ bb = ram_occ_alt if len(jobsplit) > 1 and i == ram_occ else i
182
+ jobsplit[-1] += stylefn(c, bb) if c is not None else bb
183
+ count += 1
184
+ # if count < gpu_box_chars:
185
+ jobsplit[-1] += f'{to_font(int((n.mem-occs) / 1024))}'
186
+
187
+ for i, l in enumerate(jobsplit):
188
+ RetScope.return_string += f'{_format_to(n.name if i == 0 else "", gpu_name_chars, "right")}{"(" if n.reserved == "yes" and i == 0 else " "}{l}{")" if n.reserved == "yes" and i == (len(jobsplit) - 1) else ""}\n'
189
+
190
+ # verify maintenance status
191
+ onmain, waitString = maintenance_status(infrastructure)
192
+
193
+ # print banner
194
+ if onmain:
195
+ cust_print(' ◀ ONGOING MAINTENANCE ▶ ', 'BG_MAGENTA')
196
+ elif len(infrastructure.maintenances):
197
+ cust_print(' ◀ MAINTENANCE in %4s ▶ ' % waitString, 'BG_MAGENTA')
198
+ elif len(jobs) == 0:
199
+ cust_print(' ◀ NO JOBS ▶ ', 'BG_GREEN')
200
+ elif stalled_jobs / len(jobs) > 0.5:
201
+ cust_print(' ◀ JOBS ON HOLD ▶ ', 'BG_YELLOW')
202
+ else:
203
+ cust_print('')
204
+
205
+ cust_print(''.join(['[' + ram_occ + f'{mem_size}{mem_unit}', ram_paused + 'hld', ram_drain + 'drn', ram_pendr + 'pnd', ram_down + 'dwn', '()res]']))
206
+ gpuc = 'GREEN'
207
+
208
+ cust_print(' '.join([" ram:", stylefn(gpuc, (f"{int(round(infrastructure.ram_limit_pu / 1024)):4d}{mem_unit}")
209
+ if not pd.isna(infrastructure.ram_limit_pu) else " ∞"),
210
+ " grp:", stylefn(gpuc, f"{total_jobs_prod:4d}{mem_unit}/{int(round(infrastructure.ram_limit_grp / 1024))}{mem_unit}"
211
+ if not pd.isna(infrastructure.ram_limit_grp) else " ∞")]))
212
+ cust_print(' '.join([" Sram:", stylefn('CYAN', (f"{int(round(infrastructure.ram_limit_stu / 1024)):4d}{mem_unit}")
213
+ if not pd.isna(infrastructure.ram_limit_stu) else " ∞"),
214
+ "Sgrp:", stylefn('CYAN', f"{total_jobs_stud:4d}{mem_unit}/{int(round(infrastructure.ram_limit_stugrp / 1024))}{mem_unit}"
215
+ if not pd.isna(infrastructure.ram_limit_stugrp) else " ∞")]))
216
+
217
+ # print user list
218
+ for u, c in user_styles.items():
219
+ if c in ('CYAN', 'BLUE'):
220
+ continue
221
+ cust_print(
222
+ f" {stylefn(c, gpu_occ)} {stylefn('CYAN', u) if any(['stu' in j.partition for j in jobs if j.user == u]) else u} ({int(round(sum([sum([jj.mem / 1024 for jj in j.joblets if jj.node is not None]) for j in jobs if j.user == u])))}{mem_unit})")
223
+ cust_print(f" {stylefn('CYAN', gpu_occ)} {stylefn('CYAN', 'students')}")
224
+ cust_print(f" {stylefn('BLUE', gpu_occ)} {stylefn('BLUE', 'cvcs/ai4a')}")
225
+
226
+ else: # if infrastrcture_down
227
+ # print emergency screen
228
+ cust_print(' ◀ INFRASTRUCTURE IS DOWN ▶ ', 'BG_RED')
229
+ cust_print(random.choice([flip, chunga, ogre]), 'GREEN')
230
+
231
+ return RetScope.return_string
232
+
233
+
234
+ def view_viz_gpu(infrastructure, jobs, work=True, stylefn=cmdstyle, current_user=None):
235
+ # this is for hot reload
236
+ if not work:
237
+ return "UPDATE IN PROGRESS - PLZ W8 M8 B8"
238
+
239
+ # who is the current user?
240
+ if current_user is None:
241
+ import os
242
+ current_user = os.path.basename(os.environ['HOME'])
243
+
244
+ nodes = infrastructure.get_sorted_nodes()
245
+ infrast_down = all([x.status == 'down' for x in nodes])
246
+
247
+ class RetScope:
248
+ return_string = ''
249
+
250
+ def cust_print(thing, style=None):
251
+ RetScope.return_string += (thing if style is None else stylefn(style, thing)) + '\n'
252
+
253
+ if not infrast_down:
254
+ highlighted_users = [current_user]
255
+ highlighted_users += pd.DataFrame([(j.user, sum([x.n_gpus for x in j.joblets])) for j in jobs if j.user != current_user and j.state in ('R', 'S')]
256
+ ).groupby(0).sum()[1].sort_values(ascending=False).iloc[:3].index.to_list()
257
+
258
+ user_styles = dict(zip(highlighted_users, ['RED', 'YELLOW', 'GREEN', 'MAGENTA', 'BLUE']))
259
+ students = [j.user for j in jobs if is_student_viz(j)]
260
+ for s in students:
261
+ user_styles[s] = 'CYAN'
262
+
263
+ cvcs_students = [j.user for j in jobs if is_cvcs_viz(j)]
264
+ for s in cvcs_students:
265
+ user_styles[s] = 'BLUE'
266
+
267
+ stalled_jobs = sum([j.state == 'S' for j in jobs])
268
+ total_jobs_prod = 0
269
+ total_jobs_stud = 0
270
+
271
+ # print jobs
272
+ for n in nodes:
273
+ joblet_icons = []
274
+ occs = 0
275
+ for j in jobs:
276
+ for jj in j.joblets:
277
+ if jj.n_gpus == 0:
278
+ continue
279
+ if n.name == jj.node:
280
+ if j.is_student() and 'all_usr_prod' in j.partition:
281
+ total_jobs_stud += jj.n_gpus
282
+ elif 'all_usr_prod' in j.partition:
283
+ total_jobs_prod += jj.n_gpus
284
+ occs += jj.n_gpus
285
+ icon = gpu_paused if j.state == 'S' else gpu_occ
286
+ st = icon + (('+' if len(j.joblets) > 1 else '-') + icon) * (jj.n_gpus - 1)
287
+ joblet_icons.append((st, user_styles[j.user] if j.user in user_styles else None))
288
+ joblet_icons += [(gpu_drain if n.status == 'drain' else (gpu_down if n.status == 'down' else (gpu_pendr if n.reserved == 'pending' else gpu_avail)), None)] * (n.n_gpus - occs)
289
+
290
+ joblet_icons = [(ji[0] + (' ' if i != len(joblet_icons) - 1 else ''), ji[1]) for i, ji in enumerate(joblet_icons)]
291
+
292
+ jobsplit = [""]
293
+ count = 0
294
+ for ic, c in joblet_icons:
295
+ for i in ic:
296
+ if count == gpu_box_chars:
297
+ jobsplit.append("")
298
+ count = 0
299
+ jobsplit[-1] += stylefn(c, i) if c is not None else i
300
+ count += 1
301
+
302
+ for i, l in enumerate(jobsplit):
303
+ RetScope.return_string += f'{_format_to(n.name if i == 0 else "", gpu_name_chars, "right")}{"(" if n.reserved == "yes" and i == 0 else " "}{l}{")" if n.reserved == "yes" and i == (len(jobsplit) - 1) else ""}\n'
304
+
305
+ # verify maintenance status
306
+ onmain, waitString = maintenance_status(infrastructure)
307
+
308
+ # print banner
309
+ if onmain:
310
+ cust_print(' ◀ ONGOING MAINTENANCE ▶ ', 'BG_MAGENTA')
311
+ elif len(infrastructure.maintenances):
312
+ cust_print(' ◀ MAINTENANCE in %4s ▶ ' % waitString, 'BG_MAGENTA')
313
+ elif len(jobs) == 0:
314
+ cust_print(' ◀ NO JOBS ▶ ', 'BG_GREEN')
315
+ elif stalled_jobs / len(jobs) > 0.5:
316
+ cust_print(' ◀ JOBS ON HOLD ▶ ', 'BG_YELLOW')
317
+ else:
318
+ cust_print('')
319
+
320
+ # print summary
321
+ cust_print(''.join([' [' + gpu_occ + 'run', gpu_paused + 'hld', gpu_drain + 'drn', gpu_pendr + 'pnd', gpu_down + 'dwn', '()res]']))
322
+ gpuc = 'RED'
323
+ if infrastructure.gpu_limit_pu > 3:
324
+ gpuc = 'YELLOW'
325
+ if infrastructure.gpu_limit_pu > 6:
326
+ gpuc = 'GREEN'
327
+ cust_print(' '.join([" gpu:", stylefn(gpuc, ("%2d" % infrastructure.gpu_limit_pu) if not pd.isna(infrastructure.gpu_limit_pu) else " ∞"), " grp:",
328
+ stylefn(gpuc, "%2d/%s") % (total_jobs_prod, ("%2d" % infrastructure.gpu_limit_grp) if not pd.isna(infrastructure.gpu_limit_grp) else " ∞")]))
329
+ cust_print(' '.join([" Sgpu:", stylefn('CYAN', ("%2d" % infrastructure.gpu_limit_stu) if not pd.isna(infrastructure.gpu_limit_stu) else " ∞"), "Sgrp:",
330
+ stylefn('CYAN', "%2d/%s") % (total_jobs_stud, ("%2d" % infrastructure.gpu_limit_stugrp) if not pd.isna(infrastructure.gpu_limit_stugrp) else " ∞")]))
331
+
332
+ # print user list
333
+ for u, c in user_styles.items():
334
+ if c in ('CYAN', 'BLUE'):
335
+ continue
336
+ cust_print(
337
+ f" {stylefn(c, gpu_occ)} {stylefn('CYAN', u) if any(['stu' in j.partition for j in jobs if j.user == u]) else u} ({sum([sum([jj.n_gpus for jj in j.joblets if jj.node is not None]) for j in jobs if j.user == u])})")
338
+ cust_print(f" {stylefn('CYAN', gpu_occ)} {stylefn('CYAN', 'students')} ({sum([sum([jj.n_gpus for jj in j.joblets if jj.node is not None]) for j in jobs if is_student_viz(j)])})")
339
+ cust_print(f" {stylefn('BLUE', gpu_occ)} {stylefn('BLUE', 'cvcs/ai4a')} ({sum([sum([jj.n_gpus for jj in j.joblets if jj.node is not None]) for j in jobs if is_cvcs_viz(j)])})")
340
+
341
+ else: # if infrastrcture_down
342
+ # print emergency screen
343
+ cust_print(' ◀ INFRASTRUCTURE IS DOWN ▶ ', 'BG_RED')
344
+ cust_print(random.choice([flip, chunga, ogre]), 'GREEN')
345
+
346
+ return RetScope.return_string
347
+
348
+
349
+ def get_cpu_icon(stat):
350
+ return {
351
+ 'drain': cpu_drain,
352
+ 'down': cpu_down,
353
+ 'pending': cpu_pendr,
354
+ }.get(stat, cpu_avail)
355
+
356
+
357
+ def view_viz_cpu(infrastructure, jobs, work=True, stylefn=cmdstyle, current_user=None):
358
+ # this is for hot reload
359
+ if not work:
360
+ return "UPDATE IN PROGRESS - PLZ W8 M8 B8"
361
+
362
+ # who is the current user?
363
+ if current_user is None:
364
+ import os
365
+ current_user = os.path.basename(os.environ['HOME'])
366
+
367
+ nodes = infrastructure.get_sorted_nodes()
368
+ infrast_down = all([x.status == 'down' for x in nodes])
369
+
370
+ class RetScope:
371
+ return_string = ''
372
+
373
+ def cust_print(thing, style=None):
374
+ RetScope.return_string += (thing if style is None else stylefn(style, thing)) + '\n'
375
+
376
+ if not infrast_down:
377
+ highlighted_users = [current_user]
378
+ highlighted_users += pd.DataFrame([(j.user, sum([x.cpus for x in j.joblets])) for j in jobs if j.user != current_user and j.state in ('R', 'S')]
379
+ ).groupby(0).sum()[1].sort_values(ascending=False).iloc[:3].index.to_list()
380
+
381
+ user_styles = dict(zip(highlighted_users, ['RED', 'YELLOW', 'GREEN', 'MAGENTA', 'BLUE']))
382
+ students = [j.user for j in jobs if is_student_viz(j)]
383
+ for s in students:
384
+ user_styles[s] = 'CYAN'
385
+
386
+ cvcs_students = [j.user for j in jobs if is_cvcs_viz(j)]
387
+ for s in cvcs_students:
388
+ user_styles[s] = 'BLUE'
389
+
390
+ stalled_jobs = sum([j.state == 'S' for j in jobs])
391
+ total_jobs_prod = 0
392
+ total_jobs_stud = 0
393
+
394
+ # print jobs
395
+ for n in nodes:
396
+ joblet_icons = []
397
+ occs = 0
398
+ none_st = 0
399
+ for j in sorted(jobs, key=lambda x: (x.partition, x.user)):
400
+ for jj in j.joblets:
401
+ if n.name == jj.node:
402
+ if j.is_student() and 'all_usr_prod' in j.partition:
403
+ total_jobs_stud += jj.cpus
404
+ elif 'all_usr_prod' in j.partition:
405
+ total_jobs_prod += jj.cpus
406
+ occs += jj.cpus
407
+ icon = cpu_paused if j.state == 'S' else cpu_occ
408
+ st = icon * get_cpu_block(jj.cpus)
409
+ if st == '':
410
+ none_st += jj.cpus
411
+ joblet_icons.append((st, user_styles[j.user] if j.user in user_styles else None))
412
+ if none_st > 0:
413
+ joblet_icons += [(cpu_occ, None)] * get_cpu_block(none_st)
414
+ if none_st % cpu_size != 0:
415
+ joblet_icons.append((cpu_occ_alt, None))
416
+ joblet_icons += [(get_cpu_icon(n.status), None)] * get_cpu_block(n.cpus - occs)
417
+
418
+ jobsplit = [""]
419
+ count = 0
420
+ for ic, c in joblet_icons:
421
+ for i in ic:
422
+ if count == gpu_box_chars - 3:
423
+ jobsplit.append("")
424
+ count = 0
425
+ bb = cpu_occ_alt if len(jobsplit) > 1 and i == cpu_occ else i
426
+ jobsplit[-1] += stylefn(c, bb) if c is not None else bb
427
+ count += 1
428
+ # if count < gpu_box_chars:
429
+ jobsplit[-1] += f'{to_font(n.cpus-occs)}/{to_font(n.cpus)}'
430
+
431
+ for i, l in enumerate(jobsplit):
432
+ RetScope.return_string += f'{_format_to(n.name if i == 0 else "", gpu_name_chars, "right")}{"(" if n.reserved == "yes" and i == 0 else " "}{l}{")" if n.reserved == "yes" and i == (len(jobsplit) - 1) else ""}\n'
433
+
434
+ # verify maintenance status
435
+ onmain, waitString = maintenance_status(infrastructure)
436
+
437
+ # print banner
438
+ if onmain:
439
+ cust_print(' ◀ ONGOING MAINTENANCE ▶ ', 'BG_MAGENTA')
440
+ elif len(infrastructure.maintenances):
441
+ cust_print(' ◀ MAINTENANCE in %4s ▶ ' % waitString, 'BG_MAGENTA')
442
+ elif len(jobs) == 0:
443
+ cust_print(' ◀ NO JOBS ▶ ', 'BG_GREEN')
444
+ elif stalled_jobs / len(jobs) > 0.5:
445
+ cust_print(' ◀ JOBS ON HOLD ▶ ', 'BG_YELLOW')
446
+ else:
447
+ cust_print('')
448
+
449
+ # print summary
450
+ # cust_print(''.join([' ['+ ram_occ + 'run', paused + 'hld', drain + 'drn', down + 'dwn', '()res]']))
451
+ cust_print(''.join(['[' + ram_occ + f'{cpu_size}{cpu_unit}', cpu_paused + 'hld', cpu_drain + 'drn', cpu_pendr + 'pnd', cpu_down + 'dwn', '()res]']))
452
+ gpuc = 'GREEN'
453
+ # if infrastructure.gpu_limit_pu > 3:
454
+ # gpuc = 'YELLOW'
455
+ # if infrastructure.gpu_limit_pu > 6:
456
+ # gpuc = 'GREEN'
457
+ cust_print(' '.join([" cpu:", stylefn(gpuc, (f"{int(round(infrastructure.cpu_limit_pu)):4d}{cpu_size}")
458
+ if not pd.isna(infrastructure.cpu_limit_pu) else " ∞"),
459
+ " grp:", stylefn(gpuc, f"{total_jobs_prod:4d}{cpu_size}/{int(round(infrastructure.cpu_limit_grp))}{cpu_size}"
460
+ if not pd.isna(infrastructure.cpu_limit_grp) else " ∞ ")]))
461
+ cust_print(' '.join([" Scpu:", stylefn('CYAN', (f"{int(round(infrastructure.cpu_limit_stu)):4d}{cpu_size}")
462
+ if not pd.isna(infrastructure.cpu_limit_stu) else " ∞"),
463
+ "Sgrp:", stylefn('CYAN', f"{total_jobs_stud:4d}{cpu_size}/{int(round(infrastructure.cpu_limit_stugrp))}{cpu_size}"
464
+ if not pd.isna(infrastructure.cpu_limit_stugrp) else " ∞ ")]))
465
+
466
+ # print user list
467
+ for u, c in user_styles.items():
468
+ if c in ('CYAN', 'BLUE'):
469
+ continue
470
+ cust_print(
471
+ f" {stylefn(c, gpu_occ)} {stylefn('CYAN', u) if any(['stu' in j.partition for j in jobs if j.user == u]) else u} ({sum([sum([jj.cpus for jj in j.joblets if jj.node is not None]) for j in jobs if j.user == u])}{cpu_unit})")
472
+ cust_print(f" {stylefn('CYAN', gpu_occ)} {stylefn('CYAN', 'students')}")
473
+ cust_print(f" {stylefn('BLUE', gpu_occ)} {stylefn('BLUE', 'cvcs/ai4a')}")
474
+
475
+ else: # if infrastrcture_down
476
+ # print emergency screen
477
+ cust_print(' ◀ INFRASTRUCTURE IS DOWN ▶ ', 'BG_RED')
478
+ cust_print(random.choice([flip, chunga, ogre]), 'GREEN')
479
+
480
+ return RetScope.return_string
481
+
482
+
483
+ if __name__ == '__main__':
484
+ import sys
485
+
486
+ from readers.slurmreader import read_infrastructure, read_jobs
487
+ infr = read_infrastructure()
488
+ jobs, _ = read_jobs()
489
+ if len(sys.argv) > 1 and sys.argv[1] == 'work':
490
+ print(view_viz_gpu(infr, jobs, work=True))
491
+ print(view_viz_ram(infr, jobs, work=True))
492
+ else:
493
+ print(view_viz_gpu(infr, jobs))
494
+ print(view_viz_ram(infr, jobs))