Commit a72f012f authored by one's avatar one
Browse files

[xcl-lens] Improve topo mapping report

parent a4e38ce1
......@@ -113,10 +113,30 @@ class RcclLogParser:
print(f"{field}: {values[0]}")
continue
print(f"{field}: (WARNING: Different values across ranks)")
for (host, rank), field_values in sorted(entries.items()):
joined = " | ".join(sorted(field_values))
print(f" {host} rank {rank}: {joined}")
host_values = {}
host_has_rank_conflict = set()
for (host, _rank), field_values in entries.items():
host_values.setdefault(host, set()).update(field_values)
if len(field_values) > 1:
host_has_rank_conflict.add(host)
for host, field_values in host_values.items():
if len(field_values) > 1:
host_has_rank_conflict.add(host)
warning_scope = "nodes" if len(host_values) > 1 else "ranks"
print(f"{field}: (WARNING: Different values across {warning_scope})")
for host in sorted(host_values):
if host not in host_has_rank_conflict:
joined = " | ".join(sorted(host_values[host]))
print(f" {host}: {joined}")
continue
for (entry_host, rank), field_values in sorted(entries.items()):
if entry_host != host:
continue
joined = " | ".join(sorted(field_values))
print(f" {host} rank {rank}: {joined}")
print()
def _report_net_ib_info(self):
......@@ -448,88 +468,81 @@ class RcclLogParser:
print(df.to_string(index=False))
print()
def _report_aggregated_info(
self,
title: str,
filter_func,
patterns: list,
accumulate_fields: set,
col_order: list,
):
"""
Generic method for sections where multiple log lines contribute different
fields to a single per-(host, rank) record.
Unlike _extract_and_print (one line → all fields), this aggregates
across lines: each line may fill one field of the record.
Args:
title: Section title.
filter_func: Pre-filter for log content (content -> bool).
patterns: List of (search_pattern, field, group_idx, literal).
accumulate_fields: Fields that collect values across multiple lines (stored as set).
col_order: Preferred column display order.
"""
print(f"===> {title}:\n")
def _report_topo_mapping_info(self):
print("===> Topology Mapping File Info:\n")
records: dict[tuple, dict] = {}
topo_mapping_patterns = [
(r"No topo mapping file", "status", None, "no_file"),
(r"environmental key word is (\S+)", "fingerprint", 1, None),
(r"Loading topology mapping file (\S+)", "loaded", 1, None),
(r"(?:parseing|parsing) topology mapping group[:\s]*(.*)", "parsed", 1, None),
(r"skip topology mapping group:\s*([^,]+)", "skipped", 1, None),
]
records = {}
for host, rank, content in self.log_entries:
if not filter_func(content):
if not any(
s in content.lower()
for s in ("topo mapping", "topology mapping", "environmental key word")
):
continue
for pattern, field, group_idx, literal in patterns:
for pattern, field, group_idx, literal in topo_mapping_patterns:
m = re.search(pattern, content, re.IGNORECASE)
if m:
key = (host, rank)
rec = records.setdefault(key, {"host": host, "rank": rank})
value = (literal if group_idx is None else m.group(group_idx).strip()) or "-"
if field in accumulate_fields:
rec.setdefault(field, set()).add(value)
else:
rec[field] = value
break # each line matches at most one pattern
if not m:
continue
rec = records.setdefault((host, rank), {"host": host, "rank": rank})
value = (literal if group_idx is None else m.group(group_idx).strip()) or "-"
if field in {"parsed", "skipped"}:
rec.setdefault(field, set()).add(value)
else:
rec[field] = value
break
if not records:
print(" (No data found)\n")
return
# Flatten accumulated sets → sorted string
for rec in records.values():
for field in accumulate_fields:
for field in ("parsed", "skipped"):
if field in rec:
rec[field] = " | ".join(sorted(rec[field]))
df = pd.DataFrame(list(records.values()))
df.sort_values(by=["host", "rank"], inplace=True)
ordered = [c for c in col_order if c in df.columns]
remaining = [c for c in df.columns if c not in ordered]
df = df[ordered + remaining]
print(df.fillna("-").to_string(index=False))
print()
rec[field] = sorted(rec[field])
if rec.get("status") == "no_file":
continue
if rec.get("parsed"):
rec["status"] = "parsed"
elif rec.get("skipped"):
rec["status"] = "skipped"
else:
rec["status"] = "-"
by_host = {}
for (host, rank), rec in records.items():
by_host.setdefault(host, []).append((rank, rec))
field_order = ["status", "fingerprint", "loaded", "parsed", "skipped"]
for host in sorted(by_host):
print(host)
host_records = sorted(by_host[host], key=lambda item: item[0])
normalized = [
{field: rec.get(field, "-") for field in field_order} for _, rec in host_records
]
if len({repr(item) for item in normalized}) == 1:
self._print_topo_record(normalized[0], indent=" ")
print()
continue
def _report_topo_mapping_info(self):
# (search_pattern, field_name, capture_group_index_or_None, literal_value_or_None)
# - capture_group_index: int → get regex group, None → use literal_value
# - accumulate: True → this field may come from multiple lines, append rather than overwrite
topo_mapping_patterns = [
(r"No topo mapping file", "status", None, "no_file"),
(r"environmental key word is (\S+)", "fingerprint", 1, None),
(r"Loading topology mapping file (\S+)", "loaded", 1, None),
(r"(?:parseing|parsing) topology mapping group[:\s]*(.*)", "parsed", 1, None),
(r"skip topology mapping group:\s*([^,]+)", "skipped", 1, None),
]
# Fields that should accumulate across multiple matching lines (per host/rank)
topo_mapping_accumulate_fields = {"skipped", "parsed"}
for rank, rec in host_records:
print(f" rank {rank}")
self._print_topo_record(rec, indent=" ")
print()
self._report_aggregated_info(
title="Topology Mapping File Info",
filter_func=lambda c: any(
s in c.lower()
for s in ("topo mapping", "topology mapping", "environmental key word")
),
patterns=topo_mapping_patterns,
accumulate_fields=topo_mapping_accumulate_fields,
col_order=["host", "rank", "status", "fingerprint", "loaded", "parsed", "skipped"],
)
def _print_topo_record(self, record, indent):
for field in ("status", "fingerprint", "loaded"):
if field in record:
print(f"{indent}{field}: {record[field]}")
for field in ("parsed", "skipped"):
if field not in record:
continue
print(f"{indent}{field}:")
for value in record[field]:
print(f"{indent} {value}")
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment