-
Notifications
You must be signed in to change notification settings - Fork 1
/
how_busy_linux.py
executable file
·136 lines (108 loc) · 4.16 KB
/
how_busy_linux.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/python3
# how_busy functions for linux only
# Kib vs KB
# iostat uses KiB: https://man7.org/linux/man-pages/man1/iostat.1.html
# sar uses KiB: https://man7.org/linux/man-pages/man1/sar.1.html
# All numbers are converted to base units of bytes for simplicity
import shutil
from sd.columns import auto_cols
from sd.common import avg, sorted_array, flatten, quickrun, DotDict
# See what commands are available
AVAIL = DotDict()
for cmd, msg in dict(mpstat='CPU monitoring will not function.',
sar='Network monitor will not function.',
iostat='Disk usage monitor will not function.',
).items():
if not shutil.which(cmd):
print('Warning!', cmd, 'is not available.', msg)
AVAIL[cmd] = False
else:
AVAIL[cmd] = True
def get_cpu_usage(interval=1, samples=4):
if not AVAIL.mpstat:
return 0
out = quickrun(['mpstat', interval, samples])
idle = out[-1].split()[-1]
return 100 - float(idle)
def get_network_usage(interval=1, samples=4, verbose=0):
'''Return total network usage in Bytes / second, adds up rxkB/s and txkB/s columns from sar
Requires: sudo apt install sysstat'''
if not AVAIL.sar:
return 0
out = quickrun('sar', '-n', 'DEV', interval, samples, verbose=verbose)
if verbose:
auto_cols(map(str.split, out[-3:]))
out = [line for line in out if line.startswith('Average:')]
out = flatten([line.split()[4:6] for line in out[1:]])
return int(sum(map(float, out)) * 1024)
def all_disk_usage(interval=2, reps=4, verbose=0, ignore_links=True):
'''Return total i/o for all devices in Bytes / second
ignore_links will ignore loop and dm-? devs for total'''
if not AVAIL.iostat:
return 0
ready = False
total = 0
table = dict()
rep = -1
for line in quickrun('nice', 'iostat', '-d', interval, reps + 1, verbose=verbose):
if verbose >= 2:
print(rep, line)
if not line:
continue
if line.startswith('Device'):
ready = True
rep += 1
continue
if ready and rep > 0:
# Skip the first rep because it contains bad data
line = line.split()
dev = line[0]
usage = sum(map(float, line[2:4]))
table.setdefault(dev, []).append(usage)
if ignore_links and (dev.startswith('dm-') or dev.startswith('loop')):
continue
total += usage
if verbose:
out = [['Device'] + ['Rep ' + str(rep + 1) for rep in range(reps)] + ['', 'Average MB/s']]
for dev in sorted(table.keys()):
out.append([dev] + list(map(int, table[dev])))
out[-1] += ['=', int(avg(table[dev]))]
out = [out[0]] + list(sorted_array(out[1:], reverse=True))
auto_cols(out, manual={-3: 2, -2: 2})
return int(total / reps * 1024)
'''
def get_device_usage(dev, wait=2, reps=4, verbose=0):
"Check how busy the device is"
if reps < 2:
reps = 2
usage = []
get_ready = False #next line contains the percentage
for line in quickrun('nice', 'iostat', '-d', '-x', dev, wait, reps + 1, verbose=verbose):
val = re.split(' +', line)[-1]
if get_ready:
usage.append(float(val))
get_ready = bool(val == '%util')
# print(dev+':', usage[1:], '=', percent(avg(usage[1:])))
return int(avg(usage[1:]) * 1024)
def wait_until_not_busy(folder, threshold=11, wait=2, reps=8, delta=2, sleep=2):
"Threshold in % points
Loop waiting until device isn't busy.
every loop the threshold grows higher by delta"
dev = find_device(folder)
print("Probing", dev)
for x in itertools.count():
usage = get_device_usage(dev, wait, reps)
if usage * 100 < threshold:
break
else:
print(percent(usage), '>', int(threshold))
threshold += ((x + 1) * delta)
time.sleep(x * sleep)
'''
def test():
print('Utilities available:', AVAIL)
print("Disk Usage (MB/S):", all_disk_usage() / 1e6)
print("Cpu Usage:", get_cpu_usage())
print("Network Usage:", get_network_usage())
if __name__ == "__main__":
test()