Skip to content
Snippets Groups Projects
Verified Commit 68694509 authored by Renato Alves's avatar Renato Alves :seedling:
Browse files

ENH qs - Distinguish allocation from usage

Allows providing accurate availability based on system allocation
parent e5b65c65
No related branches found
No related tags found
No related merge requests found
...@@ -52,12 +52,14 @@ def collect(funcargs): ...@@ -52,12 +52,14 @@ def collect(funcargs):
parsetypes = { parsetypes = {
"num_proc": float, "num_proc": float,
"cpu": float, "cpu": float,
"slots": int,
"slots_used": int,
"mem_total": mem_parser, "mem_total": mem_parser,
"h_vmem": mem_parser, "h_vmem": mem_parser,
} }
cmd = ["ssh", "-oBatchMode=yes", target, cmd = ["ssh", "-oBatchMode=yes", target,
"qhost -F num_proc,cpu,mem_total,h_vmem -xml"] "qhost -q -F num_proc,cpu,mem_total,h_vmem -xml"]
p = Popen(cmd, stdout=PIPE, stderr=PIPE) p = Popen(cmd, stdout=PIPE, stderr=PIPE)
try: try:
out, err = p.communicate(timeout=args.timeout) out, err = p.communicate(timeout=args.timeout)
...@@ -84,11 +86,20 @@ def collect(funcargs): ...@@ -84,11 +86,20 @@ def collect(funcargs):
cluster[nodename] = OrderedDict() cluster[nodename] = OrderedDict()
# Host level values
for attr in node.getElementsByTagName("resourcevalue"): for attr in node.getElementsByTagName("resourcevalue"):
attrname = attr.attributes["name"].value attrname = attr.attributes["name"].value
value = parsetypes[attrname](attr.firstChild.nodeValue) value = parsetypes[attrname](attr.firstChild.nodeValue)
cluster[nodename][attrname] = value cluster[nodename][attrname] = value
# Host's queue level values (mostly info about slots)
for queue in node.getElementsByTagName("queue"):
for attr in queue.getElementsByTagName("queuevalue"):
attrname = attr.attributes["name"].value
if attrname in parsetypes:
value = parsetypes[attrname](attr.firstChild.nodeValue)
cluster[nodename][attrname] = value
for node in cluster: for node in cluster:
# Ignore nodes without information # Ignore nodes without information
if not cluster[node]: if not cluster[node]:
...@@ -137,7 +148,8 @@ def format_table(data, full_output=False, best_target=False): ...@@ -137,7 +148,8 @@ def format_table(data, full_output=False, best_target=False):
global_totals = { global_totals = {
"cpu": 0, "cpu": 0,
"cpu_free": 0, "slots": 0,
"slots_free": 0,
"mem": 0, "mem": 0,
"mem_free": 0, "mem_free": 0,
"usage": -1, "usage": -1,
...@@ -146,12 +158,13 @@ def format_table(data, full_output=False, best_target=False): ...@@ -146,12 +158,13 @@ def format_table(data, full_output=False, best_target=False):
cluster_totals = {} cluster_totals = {}
header = ("Host", "CPU", "CPU-Free", "MEM", "MEM-Free", "Usage %", "Avail %", "Rank") header = ("Host", "CPU (real)", "CPU-Free", "MEM", "MEM-Free", "Usage %", "Avail %", "Rank")
for i, cluster in enumerate(data): for i, cluster in enumerate(data):
totals = { totals = {
"cpu": 0, "cpu": 0,
"cpu_free": 0, "slots": 0,
"slots_free": 0,
"mem": 0, "mem": 0,
"mem_free": 0, "mem_free": 0,
"usage": -1, "usage": -1,
...@@ -160,7 +173,7 @@ def format_table(data, full_output=False, best_target=False): ...@@ -160,7 +173,7 @@ def format_table(data, full_output=False, best_target=False):
} }
if full_output: if full_output:
table.append((cluster.center(15, "="),) + ("=" * 8,) * 7) table.append((cluster.center(15, "="),) + ("=" * 12,) + ("=" * 9,) * 6)
table.append(header) table.append(header)
elif i == 0: elif i == 0:
table.append(header) table.append(header)
...@@ -172,7 +185,10 @@ def format_table(data, full_output=False, best_target=False): ...@@ -172,7 +185,10 @@ def format_table(data, full_output=False, best_target=False):
try: try:
cpu = int(round(values["num_proc"])) cpu = int(round(values["num_proc"]))
# cpu_free is used only to calculate system use vs allocation
cpu_free = int(round(cpu - (cpu * values["cpu"] / 100))) cpu_free = int(round(cpu - (cpu * values["cpu"] / 100)))
slots = int(round(values["slots"]))
slots_free = slots - int(round(values["slots_used"]))
mem = int(round(values["mem_total"])) mem = int(round(values["mem_total"]))
mem_free = int(round(values["h_vmem"])) mem_free = int(round(values["h_vmem"]))
except KeyError as e: except KeyError as e:
...@@ -182,8 +198,8 @@ def format_table(data, full_output=False, best_target=False): ...@@ -182,8 +198,8 @@ def format_table(data, full_output=False, best_target=False):
usable_hosts += 1 usable_hosts += 1
usage = ((1 - (cpu_free / cpu)) + (1 - (mem_free / mem))) / 0.02 usage = ((1 - (cpu_free / cpu)) + (1 - (mem_free / mem))) / 0.02
avail = min(cpu_free / cpu, mem_free / mem) * 100 avail = min(slots_free / slots, mem_free / mem) * 100
rank = rank_score(cpu_free, mem_free, avail / 100) rank = rank_score(slots_free, mem_free, avail / 100)
usage = limit(usage, 0, 100) usage = limit(usage, 0, 100)
avail = limit(avail, 0, 100) avail = limit(avail, 0, 100)
...@@ -192,14 +208,17 @@ def format_table(data, full_output=False, best_target=False): ...@@ -192,14 +208,17 @@ def format_table(data, full_output=False, best_target=False):
host = host.rsplit('.', 1)[0] host = host.rsplit('.', 1)[0]
if full_output: if full_output:
table.append((host, cpu, cpu_free, table.append((host,
"{} ({})".format(slots, cpu),
slots_free,
human_readable(mem), human_readable(mem_free), human_readable(mem), human_readable(mem_free),
"{:.2f}".format(usage), "{:.2f}".format(usage),
"{:.2f}".format(avail), "{:.2f}".format(avail),
"{:.2f}".format(rank))) "{:.2f}".format(rank)))
totals["cpu"] += cpu totals["cpu"] += cpu
totals["cpu_free"] += cpu_free totals["slots"] += slots
totals["slots_free"] += slots_free
totals["mem"] += mem totals["mem"] += mem
totals["mem_free"] += mem_free totals["mem_free"] += mem_free
totals["rank"] += rank totals["rank"] += rank
...@@ -221,14 +240,17 @@ def format_table(data, full_output=False, best_target=False): ...@@ -221,14 +240,17 @@ def format_table(data, full_output=False, best_target=False):
else: else:
total_title = cluster total_title = cluster
table.append((total_title, totals["cpu"], totals["cpu_free"], table.append((total_title,
"{} ({})".format(totals["slots"], totals["cpu"]),
totals["slots_free"],
human_readable(totals["mem"]), human_readable(totals["mem_free"]), human_readable(totals["mem"]), human_readable(totals["mem_free"]),
"{:.2f}".format(totals["usage"]), "{:.2f}".format(totals["usage"]),
"{:.2f}".format(totals["avail"]), "{:.2f}".format(totals["avail"]),
"{:.2f}".format(totals["rank"]))) "{:.2f}".format(totals["rank"])))
global_totals["cpu"] += totals["cpu"] global_totals["cpu"] += totals["cpu"]
global_totals["cpu_free"] += totals["cpu_free"] global_totals["slots"] += totals["slots"]
global_totals["slots_free"] += totals["slots_free"]
global_totals["mem"] += totals["mem"] global_totals["mem"] += totals["mem"]
global_totals["mem_free"] += totals["mem_free"] global_totals["mem_free"] += totals["mem_free"]
...@@ -242,9 +264,10 @@ def format_table(data, full_output=False, best_target=False): ...@@ -242,9 +264,10 @@ def format_table(data, full_output=False, best_target=False):
cluster_totals[cluster] = totals cluster_totals[cluster] = totals
table.append(("-" * 15,) + ("-" * 8,) * 7) table.append(("-" * 15,) + ("-" * 12,) + ("-" * 9,) * 6)
table.append(("GLOBAL", table.append(("GLOBAL",
global_totals["cpu"], global_totals["cpu_free"], "{} ({})".format(global_totals["slots"], global_totals["cpu"]),
global_totals["slots_free"],
human_readable(global_totals["mem"]), human_readable(global_totals["mem"]),
human_readable(global_totals["mem_free"]), human_readable(global_totals["mem_free"]),
"{:.2f}".format(global_totals["usage"]), "{:.2f}".format(global_totals["usage"]),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment