introduce a waste_total metric that normalizes CPU and Mem waste

This commit is contained in:
2026-06-30 15:54:14 +02:00
parent f028aea536
commit ed11319d85
+30 -4
View File
@@ -84,6 +84,7 @@ ALL_COLUMNS = [
"Walltime",
"Walltime_max",
"Time_Eff",
"waste_total",
"jobname",
]
@@ -157,6 +158,21 @@ PRESET_COLUMNS = {
"Mem_Eff",
"waste_Mem",
"jobname",],
"waste": [
"username",
"JobID",
"state",
"Count",
"NTasks",
"CPUs",
"Nodes",
"CPU_Eff",
"Mem_Eff",
"Time_Eff",
"waste_CPU",
"waste_Mem",
"waste_total",
"jobname",],
}
# One-character aliases for sorting and output format specifications.
@@ -176,6 +192,7 @@ ALIASES = {
"j": "jobname",
"X": "waste_CPU",
"Y": "waste_Mem",
"T": "waste_total",
}
NUMERIC_COLUMNS = {
@@ -195,6 +212,7 @@ NUMERIC_COLUMNS = {
"Walltime_max",
"waste_CPU",
"waste_Mem",
"waste_total",
}
state_mappings = {
@@ -419,6 +437,7 @@ class OutputRow:
walltime_max: float | None # in h
waste_CPU: float | None # CPU h
waste_Mem: float | None
waste_total: float | None
_cpu_eff_values: list[float] = field(default_factory=list, repr=False)
_mem_eff_values: list[float] = field(default_factory=list, repr=False)
_time_eff_values: list[float] = field(default_factory=list, repr=False)
@@ -446,6 +465,7 @@ class OutputRow:
"jobname": self.jobname,
"waste_CPU": self.waste_CPU,
"waste_Mem": self.waste_Mem,
"waste_total": self.waste_total
}
if sdev:
for col, vals in [
@@ -893,12 +913,12 @@ def make_single_row(rec: JobRecord, dflt_mpcpu: float) -> OutputRow:
"""Returns an OutputRow based on a single slurm job record."""
walltime = rec.elapsed_sec / 3600
waste_mem = None
waste_mem = 0
if rec.mem_eff is not None and rec.reqmem_gb is not None:
waste_mem = max(0,walltime * (100-rec.mem_eff)/100 \
* (rec.reqmem_gb - rec.cpus * dflt_mpcpu))
waste_cpu = None
waste_cpu = 0
if rec.cpu_eff is not None:
# We count failed jobs as wasted CPU!
if rec.state != state_mappings['COMPLETED']:
@@ -906,6 +926,8 @@ def make_single_row(rec: JobRecord, dflt_mpcpu: float) -> OutputRow:
else:
waste_cpu = walltime * (100-rec.cpu_eff)/100 * rec.cpus
waste_total = waste_cpu + waste_mem/dflt_mpcpu
jobid = rec.jobidraw
if jobid == "":
jobid = rec.jobid
@@ -932,6 +954,7 @@ def make_single_row(rec: JobRecord, dflt_mpcpu: float) -> OutputRow:
walltime_max= walltime,
waste_Mem=waste_mem,
waste_CPU=waste_cpu,
waste_total=waste_total,
_cpu_eff_values=[rec.cpu_eff] if rec.cpu_eff is not None else [],
_mem_eff_values=[rec.mem_eff] if rec.mem_eff is not None else [],
_time_eff_values=[rec.time_eff] if rec.time_eff is not None else [],
@@ -960,7 +983,7 @@ def make_aggregate_row(records: list[JobRecord], username: str,
memory_efficiency=mean_or_none(mem_eff_vals)
count=len(records)
waste_mem = None
waste_mem = 0
if (memory_efficiency is not None) and (walltime is not None) \
and first.reqmem_gb is not None:
waste_mem = max(0,count * walltime * (100-memory_efficiency)/100 \
@@ -968,7 +991,7 @@ def make_aggregate_row(records: list[JobRecord], username: str,
cpu_efficiency = mean_or_none(cpu_eff_vals)
waste_cpu=None
waste_cpu=0
if cpu_efficiency is not None and walltime is not None:
# We count failed jobs as wasted CPU!
if first.state != state_mappings['COMPLETED']:
@@ -976,6 +999,8 @@ def make_aggregate_row(records: list[JobRecord], username: str,
else:
waste_cpu = count * walltime * (100-cpu_efficiency)/100 * first.cpus
waste_total = waste_cpu + waste_mem/dflt_mpcpu
return OutputRow(
username=username,
JobID="",
@@ -998,6 +1023,7 @@ def make_aggregate_row(records: list[JobRecord], username: str,
walltime_max=max([r.elapsed_sec for r in records if r.elapsed_sec is not None]) / 3600,
waste_Mem=waste_mem,
waste_CPU=waste_cpu,
waste_total=waste_total,
_cpu_eff_values=cpu_eff_vals,
_mem_eff_values=mem_eff_vals,
_time_eff_values=time_eff_vals,