change sacct delimiter for safer parsing

This commit is contained in:
2026-07-08 15:23:04 +02:00
parent e8d094cc33
commit 2bdda23d6a
+10 -4
View File
@@ -63,6 +63,8 @@ VERSION=0.3
# Default GB per CPUs for the cluster
default_mempercpu_gb = 2.2
SACCT_DELIM = "\x1f" # ASCII Unit Separator
SACCT_FIELDS = [
"JobIDRaw",
"JobID",
@@ -667,11 +669,13 @@ def pct(numerator: float | None, denominator: float | None) -> float | None:
return None
return 100.0 * numerator / denominator
#TODO: Put the parsing on safer ground. The delimiter based parsing may
# fail in exotic cases. Better to use json (but slower)
def run_sacct(args: argparse.Namespace) -> list[dict[str, str]]:
cmd = [
"sacct",
"-P",
f"--delimiter={SACCT_DELIM}",
"-n",
"--units=K",
"--format=" + ",".join(SACCT_FIELDS),
@@ -686,6 +690,8 @@ def run_sacct(args: argparse.Namespace) -> list[dict[str, str]]:
if args.state:
cmd += ["--state", args.state]
# print(f"DEBUG: sacct cmd: {cmd}")
# Include job steps because MaxRSS often lives on batch/extern/step rows.
# We later collapse rows back to the base job ID.
try:
@@ -701,7 +707,7 @@ def run_sacct(args: argparse.Namespace) -> list[dict[str, str]]:
def parse_pipe_rows(lines: Iterable[str]) -> list[dict[str, str]]:
rows: list[dict[str, str]] = []
reader = csv.reader(lines, delimiter="|")
reader = csv.reader(lines, delimiter=SACCT_DELIM)
for parts in reader:
if not parts:
continue
@@ -719,7 +725,7 @@ def write_cache_raw(path: str, rows: list[dict[str, str]]) -> None:
sys.exit(1)
with open(path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=SACCT_FIELDS, delimiter="|", lineterminator="\n")
writer = csv.DictWriter(f, fieldnames=SACCT_FIELDS, delimiter=SACCT_DELIM, lineterminator="\n")
writer.writeheader()
writer.writerows(rows)
@@ -727,7 +733,7 @@ def write_cache_raw(path: str, rows: list[dict[str, str]]) -> None:
def read_cache_raw(path: str) -> list[dict[str, str]]:
"""Read a raw sacct output file."""
with open(path, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f, delimiter="|")
reader = csv.DictReader(f, delimiter=SACCT_DELIM)
missing = [x for x in SACCT_FIELDS if x not in (reader.fieldnames or [])]
# Older cache files from versions before CPUTimeRAW can still be read.
# CPU efficiency will be NA for those rows unless CPUTimeRAW is present.