From 09abd8020febc77c06727bdce8aab165e005606c Mon Sep 17 00:00:00 2001 From: gartung Date: Fri, 17 Apr 2026 13:32:37 -0500 Subject: [PATCH 01/22] Try using DataTables javascript --- .../moduleAllocMonitor-circles-diff.py | 239 +++++++++++++----- 1 file changed, 178 insertions(+), 61 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 621842ca03c..5872c4c1741 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -3,6 +3,7 @@ import sys import json import os +import html threshold = 5000.0 error_threshold = 20000.0 @@ -51,24 +52,30 @@ def format_metric(value): return f"{value:.2f}" if isinstance(value, float) else str(value) -def append_triplet_cell(summary_lines, ib, pr, diff, attrs='align="right"'): - summary_lines.append( - "%s
%s
%s" - % (attrs, format_metric(ib), format_metric(pr), format_metric(diff)) - ) +def safe_text(value, default=""): + text = default if value is None else str(value) + return html.escape(text, quote=True) + + +def append_triplet_cell(summary_lines, ib, pr, diff, attrs=''): + summary_lines.extend([ + "%s" % (attrs, safe_text(format_metric(ib))), + "%s" % (attrs, safe_text(format_metric(pr))), + "%s" % (attrs, safe_text(format_metric(diff))), + ]) def added_total_color(diff_value): if not isinstance(diff_value, (int, float)): return "" if diff_value > error_threshold: - return 'bgcolor="red"' + return "red" if diff_value > threshold: - return 'bgcolor="orange"' + return "orange" if diff_value < -1.0 * error_threshold: - return 'bgcolor="green"' + return "green" if diff_value < -1.0 * threshold: - return 'bgcolor="cyan"' + return "cyan" return "" @@ -105,70 +112,158 @@ def update_added_totals(datamapres): def build_header_row(): return [ - 'added begin job', - 'added construction', - 'added begin run', - 'added begin luminosity block', - 'added event', - 'added event setup', - 'added total', - 'nAlloc begin job', - 'nAlloc construction', - 'nAlloc begin run', - 'nAlloc begin luminosity block', - 'nAlloc event', - 'nAlloc event setup', - 'nAlloc total', - 'nDealloc begin job', - 'nDealloc construction', - 'nDealloc begin run', - 'nDealloc begin luminosity block', - 'nDealloc event', - 'nDealloc event setup', - 'nDealloc total', - 'maxTemp begin job', - 'maxTemp construction', - 'maxTemp begin run', - 'maxTemp begin luminosity block', - 'maxTemp event', - 'maxTemp event setup', - 'maxTemp total', - 'max1Alloc begin job', - 'max1Alloc construction', - 'max1Alloc begin run', - 'max1Alloc begin luminosity block', - 'max1Alloc event', - 'max1Alloc event setup', - 'max1Alloc total', + 'added begin job IB', + 'added begin job PR', + 'added begin job diff', + 'added construction IB', + 'added construction PR', + 'added construction diff', + 'added begin run IB', + 'added begin run PR', + 'added begin run diff', + 'added begin luminosity block IB', + 'added begin luminosity block PR', + 'added begin luminosity block diff', + 'added event IB', + 'added event PR', + 'added event diff', + 'added event setup IB', + 'added event setup PR', + 'added event setup diff', + 'added total IB', + 'added total PR', + 'added total diff', + 'nAlloc begin job IB', + 'nAlloc begin job PR', + 'nAlloc begin job diff', + 'nAlloc construction IB', + 'nAlloc construction PR', + 'nAlloc construction diff', + 'nAlloc begin run IB', + 'nDealloc begin run PR', + 'nDealloc begin run diff', + 'nDealloc begin luminosity block IB', + 'nDealloc begin luminosity block PR', + 'nDealloc begin luminosity block diff', + 'nDealloc event IB', + 'nDealloc event PR', + 'nDealloc event diff', + 'nDealloc event setup IB', + 'nDealloc event setup PR', + 'nDealloc event setup diff', + 'nDealloc total IB', + 'nDealloc total PR', + 'nDealloc total diff', + 'nDealloc begin job IB', + 'nDealloc begin job PR', + 'nDealloc begin job diff', + 'nDealloc construction IB', + 'nDealloc construction PR', + 'nDealloc construction diff', + 'nDealloc begin run IB', + 'nDealloc begin run PR', + 'nDealloc begin run diff', + 'nDealloc begin luminosity block IB', + 'nDealloc begin luminosity block PR', + 'nDealloc begin luminosity block diff', + 'nDealloc event IB', + 'nDealloc event PR', + 'nDealloc event diff', + 'nDealloc event setup IB', + 'nDealloc event setup PR', + 'nDealloc event setup diff', + 'nDealloc total IB', + 'nDealloc total PR', + 'nDealloc total diff', + 'maxTemp begin job IB', + 'maxTemp begin job PR', + 'maxTemp begin job diff', + 'maxTemp construction IB', + 'maxTemp construction PR', + 'maxTemp construction diff', + 'maxTemp begin run IB', + 'maxTemp begin run PR', + 'maxTemp begin run diff', + 'maxTemp begin luminosity block IB', + 'maxTemp begin luminosity block PR', + 'maxTemp begin luminosity block diff', + 'maxTemp event IB', + 'maxTemp event PR', + 'maxTemp event diff', + 'maxTemp event setup IB', + 'maxTemp event setup PR', + 'maxTemp event setup diff', + 'maxTemp total IB', + 'maxTemp total PR', + 'maxTemp total diff', + 'max1Alloc begin job IB', + 'max1Alloc begin job PR', + 'max1Alloc begin job diff', + 'max1Alloc construction IB', + 'max1Alloc construction PR', + 'max1Alloc construction diff', + 'max1Alloc begin run IB', + 'max1Alloc begin run PR', + 'max1Alloc begin run diff', + 'max1Alloc begin luminosity block IB', + 'max1Alloc begin luminosity block PR', + 'max1Alloc begin luminosity block diff', + 'max1Alloc event IB', + 'max1Alloc event PR', + 'max1Alloc event diff', + 'max1Alloc event setup IB', + 'max1Alloc event setup PR', + 'max1Alloc event setup diff', + 'max1Alloc total IB', + 'max1Alloc total PR', + 'max1Alloc total diff', ] def build_summary_header(ibdata, prdata, results): summary_header = [ + "", "", - "", "", - "

ModuleAllocMonitor Resources Difference

", - '
", "", "
', + "

ModuleAllocMonitor Resources Difference

", + '", "", "
', "warn threshold %0.2f kB" % threshold, - '
', + '
', "error threshold %0.2f kB" % error_threshold, - '
', + '
', "warn threshold -%0.2f kB" % threshold, - '
', + '
', "warn threshold -%0.2f kB" % error_threshold, "
metric:
<baseline>
<pull request>
<PR - baseline>
", - "", - '', + "
Type
Label
", + '', ] summary_header += build_header_row() summary_header += [ "", + "", + "", "", - "" % (prdata["total"]["type"], prdata["total"]["label"]), + "" + % ( + safe_text(prdata["total"]["type"]), + safe_text(prdata["total"]["label"]), + safe_text(prdata["total"].get("record", "N/A")), + ), ] for metric in METRICS_KEYS: append_triplet_cell( @@ -256,24 +351,31 @@ def build_summary_header(ibdata, prdata, results): ), ) summary_header += [ - "
TypeLabelRecord
%s
%s
%s%s%s
", - '', + "
Module label
Module type
Module record
", + '', + "", + '', + '', + '', ] summary_header += build_header_row() summary_header += [ - '', + '', + '', + '', "", ] return summary_header def append_module_columns_prefix(summary_lines, moduleres, prefix): - cell_attrs = 'align="right"' + cell_style = "text-align: right;" if prefix == "added": addedtotaldiff = numeric_value(moduleres, "added total diff", float("-inf")) color = added_total_color(addedtotaldiff) if color: - cell_attrs += " " + color + cell_style += f" background-color: {color};" + cell_attrs = f'style="{cell_style}"' append_triplet_cell( summary_lines, sum_with_prefix_suffix(moduleres, BEGIN_JOB_KEYS, prefix=prefix, suffix="IB"), @@ -322,8 +424,12 @@ def append_module_columns_prefix(summary_lines, moduleres, prefix): def append_module_rows(summary_lines, moduleib, modulepr, moduleres): summary_lines += [ "", - '' - % (moduleres.get("label", ""), moduleres.get("type", ""), moduleres.get("record", "")), + '' + % ( + safe_text(moduleres.get("label", "")), + safe_text(moduleres.get("type", "")), + safe_text(moduleres.get("record", "N/A")), + ), ] for metric in METRICS_KEYS: append_module_columns_prefix(summary_lines, moduleres, metric) @@ -353,7 +459,18 @@ def build_summary_lines(ibdata, prdata, results, datamapib, datamappr, datamapre summary_lines = build_summary_header(ibdata, prdata, results) update_added_totals(datamapres) append_sorted_module_rows(summary_lines, datamapib, datamappr, datamapres) - summary_lines += [""] + summary_lines += [ + "
Module labelModule typeModule recordtransitionstransitions IBtransitions PRtransitions diff
%s
%s
%s
%s%s%s
"] + summary_lines += [ + "" + ] + summary_lines += [ + "", + ] return summary_lines From a7b36330bf829be39f76085fd1faf3fb25c86ea0 Mon Sep 17 00:00:00 2001 From: gartung Date: Fri, 17 Apr 2026 14:16:48 -0500 Subject: [PATCH 02/22] Remove DataTables javascript which make the page hang --- comparisons/moduleAllocMonitor-circles-diff.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 5872c4c1741..ffc387ec0a2 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -228,11 +228,6 @@ def build_summary_header(ibdata, prdata, results): '', "ModuleAllocMonitor Resources Difference", ] - summary_header += [ - '', - '', - '', - ] summary_header += [ "", @@ -249,7 +244,7 @@ def build_summary_header(ibdata, prdata, results): "
metric:
<baseline>
<pull request>
<PR - baseline>
", - "", + '
', '', ] summary_header += build_header_row() @@ -352,7 +347,7 @@ def build_summary_header(ibdata, prdata, results): ) summary_header += [ "
TypeLabelRecord
", - '', + '
', "", '', '', @@ -461,13 +456,6 @@ def build_summary_lines(ibdata, prdata, results, datamapib, datamappr, datamapre append_sorted_module_rows(summary_lines, datamapib, datamappr, datamapres) summary_lines += [ "
Module labelModule type
"] - summary_lines += [ - "" - ] summary_lines += [ "", ] From dba2585fc7a24e6eae73cb70458e6d0206c6f6e6 Mon Sep 17 00:00:00 2001 From: gartung Date: Fri, 17 Apr 2026 14:59:47 -0500 Subject: [PATCH 03/22] Add module_alloc_monitor_view.html cooked up by VSCode Copilot to display ModuleAllocMonitor diff json file. --- comparisons/module_alloc_monitor_viewer.html | 835 +++++++++++++++++++ 1 file changed, 835 insertions(+) create mode 100644 comparisons/module_alloc_monitor_viewer.html diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html new file mode 100644 index 00000000000..395861ca404 --- /dev/null +++ b/comparisons/module_alloc_monitor_viewer.html @@ -0,0 +1,835 @@ + + + + + + Module Allocation Monitor Viewer + + + + + + +
+
+
+

Module Allocation Monitor Viewer

+

Inspect module-level metrics from moduleAllocMonitor circles JSON files.

+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
Drag and drop a JSON file here
+
No data loaded yet.
+
+ +
+
Modules
0
+
Types
0
+
Diff Mean
0
+
Max |Diff|
0
+
+ +
+
+ + + Page 0/0 +
+ +
+ + + + + + + + + + + + + +
LabelTypeRecordIBPRdiffVisual
+
Load a JSON file to begin.
+
+
+
+
+ + + + From edcf0534457516dac642a06678ce8bee14c89fae Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 10:24:57 -0500 Subject: [PATCH 04/22] Enhance module allocation viewer: improve layout, add sortable columns, and update sorting functionality --- comparisons/module_alloc_monitor_viewer.html | 122 ++++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index 395861ca404..07ac9cf4ab7 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -39,8 +39,9 @@ } .wrap { - width: min(1280px, 96vw); - margin: 2rem auto 3rem; + width: 100%; + margin: 0; + padding: 1rem; display: grid; gap: 1rem; } @@ -219,6 +220,15 @@ z-index: 2; } + thead th.sortable { + cursor: pointer; + user-select: none; + } + + thead th.sortable:hover { + background: #ebf3f1; + } + tbody td { border-bottom: 1px solid #efe4d5; padding: 0.48rem 0.7rem; @@ -313,8 +323,7 @@ @media (max-width: 560px) { .wrap { - width: 95vw; - margin-top: 1rem; + padding: 0.75rem; } .grid, @@ -362,10 +371,18 @@

Module Allocation Monitor Viewer

@@ -400,12 +417,12 @@

Module Allocation Monitor Viewer

- - - - - - + + + + + + @@ -443,6 +460,9 @@

Module Allocation Monitor Viewer

statTypes: document.getElementById("statTypes"), statMean: document.getElementById("statMean"), statMaxAbs: document.getElementById("statMaxAbs"), + colLabel: document.getElementById("colLabel"), + colType: document.getElementById("colType"), + colRecord: document.getElementById("colRecord"), colIB: document.getElementById("colIB"), colPR: document.getElementById("colPR"), colDiff: document.getElementById("colDiff"), @@ -563,9 +583,29 @@

Module Allocation Monitor Viewer

} function updateColumnHeaders(fieldBase) { - el.colIB.textContent = `${fieldBase} IB`; - el.colPR.textContent = `${fieldBase} PR`; - el.colDiff.textContent = `${fieldBase} diff`; + const arrow = { + "label-desc": " ▼", + "label-asc": " ▲", + "type-desc": " ▼", + "type-asc": " ▲", + "record-desc": " ▼", + "record-asc": " ▲", + "ib-desc": " ▼", + "ib-asc": " ▲", + "pr-desc": " ▼", + "pr-asc": " ▲", + "metric-desc": " ▼", + "metric-asc": " ▲" + }; + const sortBy = el.sortBy.value; + + el.colLabel.textContent = `Label${arrow[sortBy] && sortBy.startsWith("label-") ? arrow[sortBy] : ""}`; + el.colType.textContent = `Type${arrow[sortBy] && sortBy.startsWith("type-") ? arrow[sortBy] : ""}`; + el.colRecord.textContent = `Record${arrow[sortBy] && sortBy.startsWith("record-") ? arrow[sortBy] : ""}`; + + el.colIB.textContent = `${fieldBase} IB${arrow[sortBy] && sortBy.startsWith("ib-") ? arrow[sortBy] : ""}`; + el.colPR.textContent = `${fieldBase} PR${arrow[sortBy] && sortBy.startsWith("pr-") ? arrow[sortBy] : ""}`; + el.colDiff.textContent = `${fieldBase} diff${arrow[sortBy] && sortBy.startsWith("metric-") ? arrow[sortBy] : ""}`; } function updateStats(rows, fieldBase) { @@ -614,21 +654,54 @@

Module Allocation Monitor Viewer

}); rows.sort((a, b) => { + const ibKey = `${fieldBase} IB`; + const prKey = `${fieldBase} PR`; const av = toNumber(a[diffKey]); const bv = toNumber(b[diffKey]); if (sortBy === "abs-desc") { return Math.abs(bv) - Math.abs(av); } + if (sortBy === "label-desc") { + return String(b.label || "").localeCompare(String(a.label || "")); + } + if (sortBy === "label-asc") { + return String(a.label || "").localeCompare(String(b.label || "")); + } + if (sortBy === "type-desc") { + return String(b.type || "").localeCompare(String(a.type || "")); + } + if (sortBy === "type-asc") { + return String(a.type || "").localeCompare(String(b.type || "")); + } + if (sortBy === "record-desc" || sortBy === "record-asc") { + const aNum = Number(a.record); + const bNum = Number(b.record); + const bothNumeric = Number.isFinite(aNum) && Number.isFinite(bNum); + if (bothNumeric) { + return sortBy === "record-desc" ? bNum - aNum : aNum - bNum; + } + const cmp = String(a.record || "").localeCompare(String(b.record || ""), undefined, { numeric: true }); + return sortBy === "record-desc" ? -cmp : cmp; + } + if (sortBy === "ib-desc") { + return toNumber(b[ibKey]) - toNumber(a[ibKey]); + } + if (sortBy === "ib-asc") { + return toNumber(a[ibKey]) - toNumber(b[ibKey]); + } + if (sortBy === "pr-desc") { + return toNumber(b[prKey]) - toNumber(a[prKey]); + } + if (sortBy === "pr-asc") { + return toNumber(a[prKey]) - toNumber(b[prKey]); + } if (sortBy === "metric-desc") { return bv - av; } if (sortBy === "metric-asc") { return av - bv; } - if (sortBy === "label-desc") { - return String(b.label || "").localeCompare(String(a.label || "")); - } return String(a.label || "").localeCompare(String(b.label || "")); }); @@ -752,6 +825,12 @@

Module Allocation Monitor Viewer

} function wireEvents() { + function toggleSort(descValue, ascValue) { + el.sortBy.value = el.sortBy.value === descValue ? ascValue : descValue; + state.page = 1; + applyFilters(); + } + el.fileInput.addEventListener("change", async (evt) => { const file = evt.target.files && evt.target.files[0]; if (!file) { @@ -777,6 +856,13 @@

Module Allocation Monitor Viewer

}); }); + el.colIB.addEventListener("click", () => toggleSort("ib-desc", "ib-asc")); + el.colPR.addEventListener("click", () => toggleSort("pr-desc", "pr-asc")); + el.colDiff.addEventListener("click", () => toggleSort("metric-desc", "metric-asc")); + el.colLabel.addEventListener("click", () => toggleSort("label-desc", "label-asc")); + el.colType.addEventListener("click", () => toggleSort("type-desc", "type-asc")); + el.colRecord.addEventListener("click", () => toggleSort("record-desc", "record-asc")); + el.prevBtn.addEventListener("click", () => { state.page = Math.max(1, state.page - 1); renderTable(); From e55a276ce19d0d2fd956913bfa4ce92f33c1b138 Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 11:03:03 -0500 Subject: [PATCH 05/22] Add HTML viewer generation for module allocation comparison results --- .../moduleAllocMonitor-circles-diff.py | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index ffc387ec0a2..05016aad57e 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -5,6 +5,28 @@ import os import html + +def build_viewer_html(template_path, embedded_data, source_label): + with open(template_path, encoding="utf-8") as template_file: + content = template_file.read() + + embedded_json = json.dumps(embedded_data).replace(" + (function () { + var embeddedData = %s; + if (typeof loadFromObject === "function") { + loadFromObject(embeddedData, %s); + } + })(); + +""" % (embedded_json, json.dumps(source_label)) + + if "" in content: + content = content.replace("", autoload_snippet + "", 1) + return content + threshold = 5000.0 error_threshold = 20000.0 @@ -570,9 +592,6 @@ def diff_from(metrics, data, dest, res): datamapres = {} for module in results["modules"]: datamapres[module_key(module)] = module - - -summaryLines = build_summary_lines(ibdata, prdata, results, datamapib, datamappr, datamapres) dumpfile = ( os.path.dirname(os.path.realpath(sys.argv[2])) + "/diff-" @@ -587,6 +606,11 @@ def diff_from(metrics, data, dest, res): + os.path.basename(os.path.realpath(sys.argv[2])) + ".html" ) -with open(summaryFile, "w") as g: - for summaryLine in summaryLines: - print(summaryLine, file=g) + +templateFile = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "module_alloc_monitor_viewer.html" +) +summaryHtml = build_viewer_html(template_path=templateFile, embedded_data=results, source_label="embedded diff data") + +with open(summaryFile, "w", encoding="utf-8") as g: + g.write(summaryHtml) From b7d785fe5c3118fc2057fa89d6d03853caf62a64 Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 11:03:25 -0500 Subject: [PATCH 06/22] Add row-break and update dropzone styles for improved layout --- comparisons/module_alloc_monitor_viewer.html | 29 ++++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index 07ac9cf4ab7..cd34e8fbe1c 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -103,6 +103,13 @@ min-width: 0; } + .row-break { + grid-column: 1 / -1; + height: 0; + padding: 0; + margin: 0; + } + label { display: block; font-size: 0.8rem; @@ -152,6 +159,14 @@ transition: 150ms ease; } + .dropzone-inline { + grid-column: 4 / -1; + min-height: 46px; + display: flex; + align-items: center; + justify-content: center; + } + .dropzone.drag { border-color: var(--accent); background: #def4ef; @@ -312,6 +327,14 @@ } @media (max-width: 980px) { + .row-break { + display: none; + } + + .dropzone-inline { + grid-column: 1 / -1; + } + .grid { grid-template-columns: repeat(2, minmax(140px, 1fr)); } @@ -355,6 +378,8 @@

Module Allocation Monitor Viewer

+
Drag and drop a JSON file here
+
@@ -394,8 +419,6 @@

Module Allocation Monitor Viewer

- -
Drag and drop a JSON file here
No data loaded yet.
@@ -640,7 +663,7 @@

Module Allocation Monitor Viewer

} if (q) { - const hay = `${m.label || ""} ${m.type || ""}`.toLowerCase(); + const hay = `${m.label || ""} ${m.type || ""} ${m.record || ""}`.toLowerCase(); if (!hay.includes(q)) { return false; } From 6ee07b4b5809839bbd9847d98cbcc9a63462eb21 Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 12:22:26 -0500 Subject: [PATCH 07/22] Update datamapres with totals after processing modules --- comparisons/moduleAllocMonitor-circles-diff.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 05016aad57e..895357014ba 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -592,6 +592,9 @@ def diff_from(metrics, data, dest, res): datamapres = {} for module in results["modules"]: datamapres[module_key(module)] = module + +update_added_totals(datamapres) + dumpfile = ( os.path.dirname(os.path.realpath(sys.argv[2])) + "/diff-" From 26dc07d95a9bd653d1e1c78d93c25dc615f2db9f Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 12:36:00 -0500 Subject: [PATCH 08/22] Enhance module allocation viewer: add expandable rows for detailed transitions and update quantity selection functionality --- comparisons/module_alloc_monitor_viewer.html | 378 +++++++++++++++---- 1 file changed, 300 insertions(+), 78 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index cd34e8fbe1c..dec224ecee7 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -254,6 +254,59 @@ background: #faf5ec; } + tbody tr.expandable { + cursor: pointer; + } + + tbody tr.expanded { + background: #f2faf8; + } + + .expand-icon { + display: inline-block; + width: 1.1em; + color: #3f5d5a; + font-size: 0.8em; + } + + .detail-row td { + background: #fff8ee; + border-bottom: 1px solid #e8d9c4; + padding: 0; + } + + .detail-wrap { + padding: 0.65rem 0.8rem 0.8rem; + } + + .detail-title { + margin: 0 0 0.45rem; + font-size: 0.78rem; + color: var(--ink-soft); + letter-spacing: 0.02em; + text-transform: uppercase; + } + + .detail-table { + width: 100%; + min-width: 0; + border-collapse: collapse; + font-size: 0.82rem; + } + + .detail-table th, + .detail-table td { + border-bottom: 1px solid #eddcc6; + padding: 0.35rem 0.45rem; + text-align: left; + } + + .detail-table th { + background: #f9efe1; + color: #374247; + position: static; + } + .mono { font-family: "IBM Plex Mono", monospace; white-space: nowrap; @@ -389,7 +442,11 @@

Module Allocation Monitor Viewer

- + + +
+
+
@@ -461,18 +518,24 @@

Module Allocation Monitor Viewer

const state = { modules: [], filtered: [], - fieldGroups: [], + fieldGroupsByQuantity: {}, + quantities: [], + expandedRows: new Set(), page: 1, maxAbsMetric: 1, fileName: "" }; + const QUANTITY_ORDER = ["added", "nAlloc", "nDealloc", "max1Alloc", "maxTemp"]; + const FIXED_SORT_FIELD_BASE = "added total"; + const el = { fileInput: document.getElementById("fileInput"), defaultFile: document.getElementById("defaultFile"), autoLoadBtn: document.getElementById("autoLoadBtn"), search: document.getElementById("search"), typeFilter: document.getElementById("typeFilter"), + quantitySelect: document.getElementById("quantitySelect"), metricSelect: document.getElementById("metricSelect"), sortBy: document.getElementById("sortBy"), minAbs: document.getElementById("minAbs"), @@ -518,6 +581,70 @@

Module Allocation Monitor Viewer

return Number.isFinite(n) ? n : 0; } + function escapeHtml(value) { + return String(value ?? "") + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); + } + + function rowKey(row) { + return `${row.label || ""}|${row.type || ""}|${row.record || ""}`; + } + + function metricDisplayValue(row, key) { + if (!Object.prototype.hasOwnProperty.call(row, key)) { + return "-"; + } + const value = Number(row[key]); + return Number.isFinite(value) ? fmtNumber(value) : "-"; + } + + function buildExpandedMetricsRows(row, quantity) { + const rows = []; + const groups = state.fieldGroupsByQuantity[quantity] || []; + const hasRecord = row.record !== undefined && row.record !== null && String(row.record).trim() !== ""; + for (const group of groups) { + const groupLower = String(group).toLowerCase(); + if (hasRecord) { + if (groupLower !== "event setup" && groupLower !== "total") { + continue; + } + } else if (groupLower === "event setup") { + continue; + } + const fieldBase = group === "(none)" ? quantity : `${quantity} ${group}`; + const ibKey = `${fieldBase} IB`; + const prKey = `${fieldBase} PR`; + const diffKey = `${fieldBase} diff`; + const hasAny = + Object.prototype.hasOwnProperty.call(row, ibKey) || + Object.prototype.hasOwnProperty.call(row, prKey) || + Object.prototype.hasOwnProperty.call(row, diffKey); + if (!hasAny) { + continue; + } + rows.push( + `
` + ); + } + if (!rows.length) { + return ''; + } + return rows.join(""); + } + + function toggleRowExpanded(key) { + if (state.expandedRows.has(key)) { + state.expandedRows.delete(key); + } else { + state.expandedRows.add(key); + } + renderTable(); + } + function extractModules(data) { if (data && Array.isArray(data.modules)) { return data.modules; @@ -532,46 +659,65 @@

Module Allocation Monitor Viewer

function collectFieldGroups(modules) { const map = new Map(); - for (const mod of modules.slice(0, 80)) { + for (const mod of modules) { Object.keys(mod).forEach((k) => { const m = k.match(/^(.*) (IB|PR|diff)$/); - if (!m || typeof mod[k] !== "number") { + if (!m) { return; } const base = m[1]; const part = m[2]; if (!map.has(base)) { - map.set(base, { IB: false, PR: false, diff: false }); + map.set(base, { IB: false, PR: false, diff: false, hasNumeric: false }); + } + const flags = map.get(base); + flags[part] = true; + if (Number.isFinite(Number(mod[k]))) { + flags.hasNumeric = true; } - map.get(base)[part] = true; }); } - const groups = []; + const grouped = {}; for (const [base, flags] of map.entries()) { - if (flags.IB && flags.PR && flags.diff) { - groups.push(base); + if (flags.IB && flags.PR && flags.diff && flags.hasNumeric) { + const idx = base.indexOf(" "); + const quantity = idx > 0 ? base.slice(0, idx) : base; + const group = idx > 0 ? base.slice(idx + 1) : "(none)"; + if (!grouped[quantity]) { + grouped[quantity] = []; + } + grouped[quantity].push(group); } } - groups.sort(); - return groups; + Object.keys(grouped).forEach((quantity) => grouped[quantity].sort()); + + const known = QUANTITY_ORDER.filter((q) => grouped[q]); + const extra = Object.keys(grouped).filter((q) => !QUANTITY_ORDER.includes(q)).sort(); + return { + byQuantity: grouped, + quantities: [...known, ...extra] + }; } - function chooseDefaultField(keys) { - const byPreference = [ - "added total", - "maxTemp total", - "nAlloc total", - "added event" - ]; + function chooseDefaultQuantity(quantities) { + for (const wanted of QUANTITY_ORDER) { + if (quantities.includes(wanted)) { + return wanted; + } + } + return quantities[0] || ""; + } + function chooseDefaultGroup(groups) { + const byPreference = ["total", "event", "construction", "begin job"]; for (const wanted of byPreference) { - if (keys.includes(wanted)) { + if (groups.includes(wanted)) { return wanted; } } - return keys[0] || ""; + return groups[0] || ""; } function setStatus(message, isError = false) { @@ -594,15 +740,38 @@

Module Allocation Monitor Viewer

} } - function populateMetricSelect(keys) { + function populateQuantitySelect(quantities) { + el.quantitySelect.innerHTML = ""; + for (const quantity of quantities) { + const opt = document.createElement("option"); + opt.value = quantity; + opt.textContent = quantity; + el.quantitySelect.appendChild(opt); + } + el.quantitySelect.value = chooseDefaultQuantity(quantities); + } + + function populateMetricSelect(groups) { el.metricSelect.innerHTML = ""; - for (const key of keys) { + for (const key of groups) { const opt = document.createElement("option"); opt.value = key; opt.textContent = key; el.metricSelect.appendChild(opt); } - el.metricSelect.value = chooseDefaultField(keys); + el.metricSelect.value = chooseDefaultGroup(groups); + } + + function getSelectedFieldBase() { + const quantity = el.quantitySelect.value; + const group = el.metricSelect.value; + if (!quantity || !group) { + return ""; + } + if (group === "(none)") { + return quantity; + } + return `${quantity} ${group}`; } function updateColumnHeaders(fieldBase) { @@ -650,10 +819,19 @@

Module Allocation Monitor Viewer

function applyFilters() { const q = el.search.value.trim().toLowerCase(); const type = el.typeFilter.value; - const fieldBase = el.metricSelect.value; + const fieldBase = getSelectedFieldBase(); + if (!fieldBase) { + state.filtered = []; + updateColumnHeaders("(field)"); + updateStats([], ""); + renderTable(); + return; + } const diffKey = `${fieldBase} diff`; + const ibKey = `${fieldBase} IB`; + const prKey = `${fieldBase} PR`; const minAbs = Math.abs(toNumber(el.minAbs.value)); - const sortBy = el.sortBy.value; + const fixedSortDiffKey = `${FIXED_SORT_FIELD_BASE} diff`; updateColumnHeaders(fieldBase || "(field)"); @@ -673,59 +851,49 @@

Module Allocation Monitor Viewer

return false; } + if ((el.sortBy.value === "record-asc" || el.sortBy.value === "record-desc") && + (!m.record || String(m.record).trim() === "")) { + return false; + } + return true; }); rows.sort((a, b) => { - const ibKey = `${fieldBase} IB`; - const prKey = `${fieldBase} PR`; - const av = toNumber(a[diffKey]); - const bv = toNumber(b[diffKey]); - - if (sortBy === "abs-desc") { - return Math.abs(bv) - Math.abs(av); - } - if (sortBy === "label-desc") { - return String(b.label || "").localeCompare(String(a.label || "")); - } - if (sortBy === "label-asc") { - return String(a.label || "").localeCompare(String(b.label || "")); - } - if (sortBy === "type-desc") { - return String(b.type || "").localeCompare(String(a.type || "")); - } - if (sortBy === "type-asc") { - return String(a.type || "").localeCompare(String(b.type || "")); - } - if (sortBy === "record-desc" || sortBy === "record-asc") { - const aNum = Number(a.record); - const bNum = Number(b.record); - const bothNumeric = Number.isFinite(aNum) && Number.isFinite(bNum); - if (bothNumeric) { - return sortBy === "record-desc" ? bNum - aNum : aNum - bNum; + switch (el.sortBy.value) { + case "label-asc": + return String(a.label || "").localeCompare(String(b.label || "")); + case "label-desc": + return String(b.label || "").localeCompare(String(a.label || "")); + case "type-asc": + return String(a.type || "").localeCompare(String(b.type || "")); + case "type-desc": + return String(b.type || "").localeCompare(String(a.type || "")); + case "record-asc": + return String(a.record || "").localeCompare(String(b.record || "")); + case "record-desc": + return String(b.record || "").localeCompare(String(a.record || "")); + case "ib-asc": + return toNumber(a[ibKey]) - toNumber(b[ibKey]); + case "ib-desc": + return toNumber(b[ibKey]) - toNumber(a[ibKey]); + case "pr-asc": + return toNumber(a[prKey]) - toNumber(b[prKey]); + case "pr-desc": + return toNumber(b[prKey]) - toNumber(a[prKey]); + case "metric-asc": + return toNumber(a[diffKey]) - toNumber(b[diffKey]); + case "metric-desc": + return toNumber(b[diffKey]) - toNumber(a[diffKey]); + case "abs-desc": + default: { + const byFixedMetric = Math.abs(toNumber(b[fixedSortDiffKey])) - Math.abs(toNumber(a[fixedSortDiffKey])); + if (byFixedMetric !== 0) { + return byFixedMetric; + } + return String(a.label || "").localeCompare(String(b.label || "")); } - const cmp = String(a.record || "").localeCompare(String(b.record || ""), undefined, { numeric: true }); - return sortBy === "record-desc" ? -cmp : cmp; - } - if (sortBy === "ib-desc") { - return toNumber(b[ibKey]) - toNumber(a[ibKey]); - } - if (sortBy === "ib-asc") { - return toNumber(a[ibKey]) - toNumber(b[ibKey]); - } - if (sortBy === "pr-desc") { - return toNumber(b[prKey]) - toNumber(a[prKey]); - } - if (sortBy === "pr-asc") { - return toNumber(a[prKey]) - toNumber(b[prKey]); } - if (sortBy === "metric-desc") { - return bv - av; - } - if (sortBy === "metric-asc") { - return av - bv; - } - return String(a.label || "").localeCompare(String(b.label || "")); }); state.filtered = rows; @@ -745,7 +913,15 @@

Module Allocation Monitor Viewer

} function renderTable() { - const fieldBase = el.metricSelect.value; + const fieldBase = getSelectedFieldBase(); + if (!fieldBase) { + el.tbody.innerHTML = ""; + el.empty.style.display = "block"; + el.pageInfo.textContent = "Page 0/0"; + el.prevBtn.disabled = true; + el.nextBtn.disabled = true; + return; + } const ibKey = `${fieldBase} IB`; const prKey = `${fieldBase} PR`; const diffKey = `${fieldBase} diff`; @@ -765,9 +941,14 @@

Module Allocation Monitor Viewer

const prValue = toNumber(row[prKey]); const diffValue = toNumber(row[diffKey]); const visual = barStyle(diffValue); + const key = rowKey(row); + const isExpanded = state.expandedRows.has(key); + + tr.className = isExpanded ? "expandable expanded" : "expandable"; + tr.setAttribute("aria-expanded", String(isExpanded)); tr.innerHTML = ` - + @@ -779,7 +960,33 @@

Module Allocation Monitor Viewer

`; + tr.addEventListener("click", () => toggleRowExpanded(key)); el.tbody.appendChild(tr); + + if (isExpanded) { + const detailTr = document.createElement("tr"); + detailTr.className = "detail-row"; + detailTr.innerHTML = ` + + `; + el.tbody.appendChild(detailTr); + } } const from = state.filtered.length ? start + 1 : 0; @@ -796,15 +1003,19 @@

Module Allocation Monitor Viewer

} state.modules = modules; - state.fieldGroups = collectFieldGroups(modules); + const groupedFields = collectFieldGroups(modules); + state.fieldGroupsByQuantity = groupedFields.byQuantity; + state.quantities = groupedFields.quantities; state.page = 1; - if (!state.fieldGroups.length) { - throw new Error("No IB/PR/diff field groups found in module records."); + if (!state.quantities.length) { + throw new Error("No IB/PR/diff transitions found in module records."); } populateTypeFilter(modules); - populateMetricSelect(state.fieldGroups); + populateQuantitySelect(state.quantities); + const selectedQuantity = el.quantitySelect.value; + populateMetricSelect(state.fieldGroupsByQuantity[selectedQuantity] || []); applyFilters(); setStatus(`Loaded ${modules.length.toLocaleString()} modules from ${sourceLabel}.`); @@ -871,6 +1082,13 @@

Module Allocation Monitor Viewer

tryAutoLoad(el.defaultFile.value); }); + el.quantitySelect.addEventListener("change", () => { + const groups = state.fieldGroupsByQuantity[el.quantitySelect.value] || []; + populateMetricSelect(groups); + state.page = 1; + applyFilters(); + }); + [el.search, el.typeFilter, el.metricSelect, el.sortBy, el.minAbs, el.rowsPerPage].forEach((node) => { const eventName = node.tagName === "INPUT" ? "input" : "change"; node.addEventListener(eventName, () => { @@ -927,6 +1145,10 @@

Module Allocation Monitor Viewer

function boot() { wireEvents(); el.typeFilter.innerHTML = ''; + el.sortBy.disabled = false; + el.sortBy.value = "abs-desc"; + el.sortBy.title = "Default sort: abs(added total diff) high to low."; + el.quantitySelect.innerHTML = ""; el.metricSelect.innerHTML = ""; renderTable(); From 853af1db81c309a26165a96e24fcb3dc5a043731 Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 12:50:17 -0500 Subject: [PATCH 09/22] Refactor module allocation comparison script: remove unused functions and variables for improved clarity --- .../moduleAllocMonitor-circles-diff.py | 400 ------------------ 1 file changed, 400 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 895357014ba..a117843e571 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -3,7 +3,6 @@ import sys import json import os -import html def build_viewer_html(template_path, embedded_data, source_label): @@ -27,9 +26,6 @@ def build_viewer_html(template_path, embedded_data, source_label): content = content.replace("", autoload_snippet + "", 1) return content -threshold = 5000.0 -error_threshold = 20000.0 - BEGIN_JOB_KEYS = ["begin job"] BEGIN_RUN_KEYS = ["global begin run", "stream begin run"] BEGIN_LUMI_KEYS = [ @@ -54,11 +50,6 @@ def module_key(module): return "%s|%s|%s" % (module.get("label", ""), module.get("type", ""), module.get("record", "")) -def numeric_value(data, key, default="N/A"): - value = data.get(key, default) - return value if isinstance(value, (int, float)) else default - - def sum_numeric_values(data, keys, default="N/A"): values = [data.get(key, default) for key in keys] return sum(values) if all(isinstance(value, (int, float)) for value in values) else default @@ -70,49 +61,10 @@ def sum_with_prefix_suffix(data, metric_keys, prefix="added", suffix="", default ) -def format_metric(value): - return f"{value:.2f}" if isinstance(value, float) else str(value) - - -def safe_text(value, default=""): - text = default if value is None else str(value) - return html.escape(text, quote=True) - - -def append_triplet_cell(summary_lines, ib, pr, diff, attrs=''): - summary_lines.extend([ - "" % (attrs, safe_text(format_metric(ib))), - "" % (attrs, safe_text(format_metric(pr))), - "" % (attrs, safe_text(format_metric(diff))), - ]) - - -def added_total_color(diff_value): - if not isinstance(diff_value, (int, float)): - return "" - if diff_value > error_threshold: - return "red" - if diff_value > threshold: - return "orange" - if diff_value < -1.0 * error_threshold: - return "green" - if diff_value < -1.0 * threshold: - return "cyan" - return "" - - def is_valid_module_key(key): return key != "None|None|None" and key != "||" -def transitions_diff_value(transitions_ib, transitions_pr): - if isinstance(transitions_ib, (int, float)) and isinstance(transitions_pr, (int, float)): - return transitions_ib - transitions_pr - if not isinstance(transitions_ib, (int, float)) and isinstance(transitions_pr, (int, float)): - return transitions_pr - 0 - if isinstance(transitions_ib, (int, float)) and not isinstance(transitions_pr, (int, float)): - return 0 - transitions_ib - return "N/A" def update_added_totals(datamapres): @@ -132,358 +84,6 @@ def update_added_totals(datamapres): ) -def build_header_row(): - return [ - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - ] - - -def build_summary_header(ibdata, prdata, results): - summary_header = [ - "", - "", - "", - '', - "ModuleAllocMonitor Resources Difference", - ] - summary_header += [ - "", - "", - "

ModuleAllocMonitor Resources Difference

", - '
LabelTypeRecordIBPRdiffLabelTypeRecordIBPRdiff Visual
${escapeHtml(quantity)}${escapeHtml(group)}${metricDisplayValue(row, ibKey)}${metricDisplayValue(row, prKey)}${metricDisplayValue(row, diffKey)}
No transition details available.
${row.label || ""}${isExpanded ? "▼" : "▶"}${row.label || ""} ${row.type || "(none)"} ${row.record || "-"} ${fmtNumber(ibValue)} +
+

Transitions for quantity: ${escapeHtml(el.quantitySelect.value)}

+ + + + + + + + + + + ${buildExpandedMetricsRows(row, el.quantitySelect.value)} +
QuantityTransitionIBPRDiff
+
+
%s%s%sadded begin job IBadded begin job PRadded begin job diffadded construction IBadded construction PRadded construction diffadded begin run IBadded begin run PRadded begin run diffadded begin luminosity block IBadded begin luminosity block PRadded begin luminosity block diffadded event IBadded event PRadded event diffadded event setup IBadded event setup PRadded event setup diffadded total IBadded total PRadded total diffnAlloc begin job IBnAlloc begin job PRnAlloc begin job diffnAlloc construction IBnAlloc construction PRnAlloc construction diffnAlloc begin run IBnDealloc begin run PRnDealloc begin run diffnDealloc begin luminosity block IBnDealloc begin luminosity block PRnDealloc begin luminosity block diffnDealloc event IBnDealloc event PRnDealloc event diffnDealloc event setup IBnDealloc event setup PRnDealloc event setup diffnDealloc total IBnDealloc total PRnDealloc total diffnDealloc begin job IBnDealloc begin job PRnDealloc begin job diffnDealloc construction IBnDealloc construction PRnDealloc construction diffnDealloc begin run IBnDealloc begin run PRnDealloc begin run diffnDealloc begin luminosity block IBnDealloc begin luminosity block PRnDealloc begin luminosity block diffnDealloc event IBnDealloc event PRnDealloc event diffnDealloc event setup IBnDealloc event setup PRnDealloc event setup diffnDealloc total IBnDealloc total PRnDealloc total diffmaxTemp begin job IBmaxTemp begin job PRmaxTemp begin job diffmaxTemp construction IBmaxTemp construction PRmaxTemp construction diffmaxTemp begin run IBmaxTemp begin run PRmaxTemp begin run diffmaxTemp begin luminosity block IBmaxTemp begin luminosity block PRmaxTemp begin luminosity block diffmaxTemp event IBmaxTemp event PRmaxTemp event diffmaxTemp event setup IBmaxTemp event setup PRmaxTemp event setup diffmaxTemp total IBmaxTemp total PRmaxTemp total diffmax1Alloc begin job IBmax1Alloc begin job PRmax1Alloc begin job diffmax1Alloc construction IBmax1Alloc construction PRmax1Alloc construction diffmax1Alloc begin run IBmax1Alloc begin run PRmax1Alloc begin run diffmax1Alloc begin luminosity block IBmax1Alloc begin luminosity block PRmax1Alloc begin luminosity block diffmax1Alloc event IBmax1Alloc event PRmax1Alloc event diffmax1Alloc event setup IBmax1Alloc event setup PRmax1Alloc event setup diffmax1Alloc total IBmax1Alloc total PRmax1Alloc total diff
", - "", - "
', - "warn threshold %0.2f kB" % threshold, - '
', - "error threshold %0.2f kB" % error_threshold, - '
', - "warn threshold -%0.2f kB" % threshold, - '
', - "warn threshold -%0.2f kB" % error_threshold, - "
metric:
<baseline>
<pull request>
<PR - baseline>
", - '', - '', - ] - summary_header += build_header_row() - summary_header += [ - "", - "", - "", - "", - "" - % ( - safe_text(prdata["total"]["type"]), - safe_text(prdata["total"]["label"]), - safe_text(prdata["total"].get("record", "N/A")), - ), - ] - for metric in METRICS_KEYS: - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in BEGIN_JOB_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in BEGIN_JOB_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in BEGIN_JOB_KEYS] - ), - ) - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in CONSTRUCTION_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in CONSTRUCTION_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in CONSTRUCTION_KEYS] - ), - ) - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in BEGIN_RUN_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in BEGIN_RUN_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in BEGIN_RUN_KEYS] - ), - ) - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in BEGIN_LUMI_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in BEGIN_LUMI_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in BEGIN_LUMI_KEYS] - ), - ) - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in EVENT_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in EVENT_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in EVENT_KEYS] - ), - ) - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in EVENT_SETUP_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in EVENT_SETUP_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in EVENT_SETUP_KEYS] - ), - ) - append_triplet_cell( - summary_header, - sum_numeric_values( - results["total"], ["%s %s IB" % (metric, key) for key in TOTAL_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s PR" % (metric, key) for key in TOTAL_KEYS] - ), - sum_numeric_values( - results["total"], ["%s %s diff" % (metric, key) for key in TOTAL_KEYS] - ), - ) - summary_header += [ - "
TypeLabelRecord
%s%s%s
", - '', - "", - '', - '', - '', - ] - summary_header += build_header_row() - summary_header += [ - '', - '', - '', - "", - ] - return summary_header - - -def append_module_columns_prefix(summary_lines, moduleres, prefix): - cell_style = "text-align: right;" - if prefix == "added": - addedtotaldiff = numeric_value(moduleres, "added total diff", float("-inf")) - color = added_total_color(addedtotaldiff) - if color: - cell_style += f" background-color: {color};" - cell_attrs = f'style="{cell_style}"' - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, BEGIN_JOB_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, BEGIN_JOB_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, BEGIN_JOB_KEYS, prefix=prefix, suffix="diff"), - ) - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, CONSTRUCTION_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, CONSTRUCTION_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, CONSTRUCTION_KEYS, prefix=prefix, suffix="diff"), - ) - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, BEGIN_RUN_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, BEGIN_RUN_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, BEGIN_RUN_KEYS, prefix=prefix, suffix="diff"), - ) - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, BEGIN_LUMI_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, BEGIN_LUMI_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, BEGIN_LUMI_KEYS, prefix=prefix, suffix="diff"), - ) - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, EVENT_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, EVENT_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, EVENT_KEYS, prefix=prefix, suffix="diff"), - ) - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, EVENT_SETUP_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, EVENT_SETUP_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, EVENT_SETUP_KEYS, prefix=prefix, suffix="diff"), - ) - append_triplet_cell( - summary_lines, - sum_with_prefix_suffix(moduleres, TOTAL_KEYS, prefix=prefix, suffix="IB"), - sum_with_prefix_suffix(moduleres, TOTAL_KEYS, prefix=prefix, suffix="PR"), - sum_with_prefix_suffix(moduleres, TOTAL_KEYS, prefix=prefix, suffix="diff"), - attrs=cell_attrs, - ) - - -def append_module_rows(summary_lines, moduleib, modulepr, moduleres): - summary_lines += [ - "", - '' - % ( - safe_text(moduleres.get("label", "")), - safe_text(moduleres.get("type", "")), - safe_text(moduleres.get("record", "N/A")), - ), - ] - for metric in METRICS_KEYS: - append_module_columns_prefix(summary_lines, moduleres, metric) - transitions_ib = numeric_value(moduleib, "transitions") - transitions_pr = numeric_value(modulepr, "transitions") - transitions_diff = transitions_diff_value(transitions_ib, transitions_pr) - append_triplet_cell(summary_lines, transitions_ib, transitions_pr, transitions_diff) - summary_lines += [""] - - -def append_sorted_module_rows(summary_lines, datamapib, datamappr, datamapres): - for item in sorted( - datamapres.items(), - key=lambda x: numeric_value(x[1], "added total diff", float("-inf")), - reverse=True, - ): - key = module_key(item[1]) - if not is_valid_module_key(key): - continue - moduleib = datamapib.get(key, {}) - modulepr = datamappr.get(key, {}) - moduleres = datamapres.get(key, {}) - append_module_rows(summary_lines, moduleib, modulepr, moduleres) - - -def build_summary_lines(ibdata, prdata, results, datamapib, datamappr, datamapres): - summary_lines = build_summary_header(ibdata, prdata, results) - update_added_totals(datamapres) - append_sorted_module_rows(summary_lines, datamapib, datamappr, datamapres) - summary_lines += [ - "
Module labelModule typeModule recordtransitions IBtransitions PRtransitions diff
%s%s%s
"] - summary_lines += [ - "", - ] - return summary_lines - - def diff_from(metrics, data, dest, res): for metric in metrics: ibkey = "%s IB" % metric From 7e5c24efff67d358c1f7a3bb7b8df39536c10119 Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 12:57:08 -0500 Subject: [PATCH 10/22] Black formatting --- .../moduleAllocMonitor-circles-diff.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index a117843e571..7e8bab3f3e4 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -6,12 +6,12 @@ def build_viewer_html(template_path, embedded_data, source_label): - with open(template_path, encoding="utf-8") as template_file: - content = template_file.read() + with open(template_path, encoding="utf-8") as template_file: + content = template_file.read() - embedded_json = json.dumps(embedded_data).replace(" (function () { var embeddedData = %s; @@ -22,9 +22,10 @@ def build_viewer_html(template_path, embedded_data, source_label): """ % (embedded_json, json.dumps(source_label)) - if "" in content: - content = content.replace("", autoload_snippet + "", 1) - return content + if "" in content: + content = content.replace("", autoload_snippet + "", 1) + return content + BEGIN_JOB_KEYS = ["begin job"] BEGIN_RUN_KEYS = ["global begin run", "stream begin run"] @@ -65,8 +66,6 @@ def is_valid_module_key(key): return key != "None|None|None" and key != "||" - - def update_added_totals(datamapres): for module in datamapres.values(): key = module_key(module) @@ -213,7 +212,9 @@ def diff_from(metrics, data, dest, res): templateFile = os.path.join( os.path.dirname(os.path.realpath(__file__)), "module_alloc_monitor_viewer.html" ) -summaryHtml = build_viewer_html(template_path=templateFile, embedded_data=results, source_label="embedded diff data") +summaryHtml = build_viewer_html( + template_path=templateFile, embedded_data=results, source_label="embedded diff data" +) with open(summaryFile, "w", encoding="utf-8") as g: g.write(summaryHtml) From 43b4b4a3b8c0221bb8bf31574e90e72bddba091f Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 15:03:07 -0500 Subject: [PATCH 11/22] Refactor module allocation viewer: adjust max-height for better layout, update rows per page input, and enhance data validation logic --- comparisons/module_alloc_monitor_viewer.html | 54 +++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index dec224ecee7..af84d90c946 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -213,7 +213,7 @@ border: 1px solid var(--line); border-radius: 12px; background: #fff; - max-height: 62vh; + max-height: 100%; } table { @@ -473,7 +473,7 @@

Module Allocation Monitor Viewer

- +
No data loaded yet.
@@ -608,8 +608,11 @@

Module Allocation Monitor Viewer

const hasRecord = row.record !== undefined && row.record !== null && String(row.record).trim() !== ""; for (const group of groups) { const groupLower = String(group).toLowerCase(); + if (groupLower === "total") { + continue; + } if (hasRecord) { - if (groupLower !== "event setup" && groupLower !== "total") { + if (groupLower !== "event setup") { continue; } } else if (groupLower === "event setup") { @@ -619,13 +622,50 @@

Module Allocation Monitor Viewer

const ibKey = `${fieldBase} IB`; const prKey = `${fieldBase} PR`; const diffKey = `${fieldBase} diff`; - const hasAny = - Object.prototype.hasOwnProperty.call(row, ibKey) || - Object.prototype.hasOwnProperty.call(row, prKey) || - Object.prototype.hasOwnProperty.call(row, diffKey); + const hasIB = Object.prototype.hasOwnProperty.call(row, ibKey); + const hasPR = Object.prototype.hasOwnProperty.call(row, prKey); + const hasDiff = Object.prototype.hasOwnProperty.call(row, diffKey); + const hasAny = hasIB || hasPR || hasDiff; if (!hasAny) { continue; } + const ibValue = Number(row[ibKey]); + const prValue = Number(row[prKey]); + const diffValue = Number(row[diffKey]); + const hasNumericIB = hasIB && Number.isFinite(ibValue); + const hasNumericPR = hasPR && Number.isFinite(prValue); + const hasNumericDiff = hasDiff && Number.isFinite(diffValue); + const missingOrNonNumericCount = + (hasNumericIB ? 0 : 1) + + (hasNumericPR ? 0 : 1) + + (hasNumericDiff ? 0 : 1); + const presentNumericValues = []; + if (hasNumericIB) { + presentNumericValues.push(ibValue); + } + if (hasNumericPR) { + presentNumericValues.push(prValue); + } + if (hasNumericDiff) { + presentNumericValues.push(diffValue); + } + const missingAndRemainingZero = + missingOrNonNumericCount > 0 && + presentNumericValues.length > 0 && + presentNumericValues.every((v) => v === 0); + if (missingAndRemainingZero) { + continue; + } + const allZero = + Number.isFinite(ibValue) && + Number.isFinite(prValue) && + Number.isFinite(diffValue) && + ibValue === 0 && + prValue === 0 && + diffValue === 0; + if (allZero) { + continue; + } rows.push( `${escapeHtml(quantity)}${escapeHtml(group)}${metricDisplayValue(row, ibKey)}${metricDisplayValue(row, prKey)}${metricDisplayValue(row, diffKey)}` ); From fbf2ca7a602255950f36cd62ea246364ebf86978 Mon Sep 17 00:00:00 2001 From: gartung Date: Mon, 20 Apr 2026 16:27:18 -0500 Subject: [PATCH 12/22] Add transition order sorting and update detail table structure for module allocation viewer --- comparisons/module_alloc_monitor_viewer.html | 34 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index af84d90c946..6decd7bc75a 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -528,6 +528,17 @@

Module Allocation Monitor Viewer

const QUANTITY_ORDER = ["added", "nAlloc", "nDealloc", "max1Alloc", "maxTemp"]; const FIXED_SORT_FIELD_BASE = "added total"; + const TRANSITION_ORDER = [ + "construction", + "begin job", + "begin stream", + "global begin run", + "stream begin run", + "global begin luminosity block", + "stream begin luminosity block", + "event", + "event setup", + ]; const el = { fileInput: document.getElementById("fileInput"), @@ -671,7 +682,7 @@

Module Allocation Monitor Viewer

); } if (!rows.length) { - return 'No transition details available.'; + return 'No transition details available.'; } return rows.join(""); } @@ -731,7 +742,17 @@

Module Allocation Monitor Viewer

} } - Object.keys(grouped).forEach((quantity) => grouped[quantity].sort()); + const transitionRank = new Map(TRANSITION_ORDER.map((name, index) => [name, index])); + Object.keys(grouped).forEach((quantity) => { + grouped[quantity].sort((a, b) => { + const aRank = transitionRank.has(a) ? transitionRank.get(a) : Number.MAX_SAFE_INTEGER; + const bRank = transitionRank.has(b) ? transitionRank.get(b) : Number.MAX_SAFE_INTEGER; + if (aRank !== bRank) { + return aRank - bRank; + } + return a.localeCompare(b); + }); + }); const known = QUANTITY_ORDER.filter((q) => grouped[q]); const extra = Object.keys(grouped).filter((q) => !QUANTITY_ORDER.includes(q)).sort(); @@ -1007,10 +1028,17 @@

Module Allocation Monitor Viewer

const detailTr = document.createElement("tr"); detailTr.className = "detail-row"; detailTr.innerHTML = ` - +

Transitions for quantity: ${escapeHtml(el.quantitySelect.value)}

+ + + + + + + From 434d6d19042519c12fa3824f8fbd7181c90c8f1e Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 10:26:05 -0500 Subject: [PATCH 13/22] Refactor module allocation viewer: swap color gradients for up/down indicators, enhance quantity handling, and update metric display logic --- comparisons/module_alloc_monitor_viewer.html | 81 +++++++++++++++----- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index 6decd7bc75a..b6641cfe91b 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -346,11 +346,11 @@ } .up { - background: linear-gradient(90deg, #41bd97, #0b8a6a); + background: linear-gradient(90deg, #e67f67, #c53d20); } .down { - background: linear-gradient(90deg, #e67f67, #c53d20); + background: linear-gradient(90deg, #41bd97, #0b8a6a); } .pager { @@ -519,6 +519,7 @@

Module Allocation Monitor Viewer

modules: [], filtered: [], fieldGroupsByQuantity: {}, + quantityUnits: {}, quantities: [], expandedRows: new Set(), page: 1, @@ -527,7 +528,6 @@

Module Allocation Monitor Viewer

}; const QUANTITY_ORDER = ["added", "nAlloc", "nDealloc", "max1Alloc", "maxTemp"]; - const FIXED_SORT_FIELD_BASE = "added total"; const TRANSITION_ORDER = [ "construction", "begin job", @@ -570,12 +570,13 @@

Module Allocation Monitor Viewer

pageInfo: document.getElementById("pageInfo") }; - function fmtNumber(value) { + function fmtNumber(value, quantity) { if (value === null || value === undefined || Number.isNaN(value)) { return "-"; } const abs = Math.abs(value); - if (abs >= 1000000) { + const useFixedPoint = !!quantity; + if (abs >= 1000000 && !useFixedPoint) { return value.toExponential(3); } if (abs >= 1000) { @@ -605,12 +606,12 @@

Module Allocation Monitor Viewer

return `${row.label || ""}|${row.type || ""}|${row.record || ""}`; } - function metricDisplayValue(row, key) { + function metricDisplayValue(row, key, quantity) { if (!Object.prototype.hasOwnProperty.call(row, key)) { return "-"; } const value = Number(row[key]); - return Number.isFinite(value) ? fmtNumber(value) : "-"; + return Number.isFinite(value) ? fmtNumber(value, quantity) : "-"; } function buildExpandedMetricsRows(row, quantity) { @@ -678,7 +679,7 @@

Module Allocation Monitor Viewer

continue; } rows.push( - `
` + `` ); } if (!rows.length) { @@ -708,6 +709,36 @@

Module Allocation Monitor Viewer

return []; } + function extractQuantityUnits(data) { + const quantityUnits = {}; + if (!data || !Array.isArray(data.resources)) { + return quantityUnits; + } + + for (const resource of data.resources) { + if (!resource || typeof resource.name !== "string") { + continue; + } + const quantity = resource.name.trim().split(/\s+/)[0]; + if (!quantity || quantityUnits[quantity]) { + continue; + } + + let unit = typeof resource.unit === "string" ? resource.unit : ""; + unit = unit.replace(/\s*(IB|PR|diff)\s*$/, "").trim(); + if (unit) { + quantityUnits[quantity] = unit; + } + } + + return quantityUnits; + } + + function quantityLabel(quantity) { + const unit = state.quantityUnits[quantity]; + return unit ? `${quantity} (${unit})` : quantity; + } + function collectFieldGroups(modules) { const map = new Map(); for (const mod of modules) { @@ -806,13 +837,14 @@

Module Allocation Monitor Viewer

for (const quantity of quantities) { const opt = document.createElement("option"); opt.value = quantity; - opt.textContent = quantity; + opt.textContent = quantityLabel(quantity); el.quantitySelect.appendChild(opt); } el.quantitySelect.value = chooseDefaultQuantity(quantities); } function populateMetricSelect(groups) { + const currentValue = el.metricSelect.value; el.metricSelect.innerHTML = ""; for (const key of groups) { const opt = document.createElement("option"); @@ -820,7 +852,11 @@

Module Allocation Monitor Viewer

opt.textContent = key; el.metricSelect.appendChild(opt); } - el.metricSelect.value = chooseDefaultGroup(groups); + if (groups.includes(currentValue)) { + el.metricSelect.value = currentValue; + } else { + el.metricSelect.value = chooseDefaultGroup(groups); + } } function getSelectedFieldBase() { @@ -851,18 +887,21 @@

Module Allocation Monitor Viewer

"metric-asc": " ▲" }; const sortBy = el.sortBy.value; + const quantity = fieldBase.split(" ")[0]; + const unit = state.quantityUnits[quantity] ? ` [${state.quantityUnits[quantity]}]` : ""; el.colLabel.textContent = `Label${arrow[sortBy] && sortBy.startsWith("label-") ? arrow[sortBy] : ""}`; el.colType.textContent = `Type${arrow[sortBy] && sortBy.startsWith("type-") ? arrow[sortBy] : ""}`; el.colRecord.textContent = `Record${arrow[sortBy] && sortBy.startsWith("record-") ? arrow[sortBy] : ""}`; - el.colIB.textContent = `${fieldBase} IB${arrow[sortBy] && sortBy.startsWith("ib-") ? arrow[sortBy] : ""}`; - el.colPR.textContent = `${fieldBase} PR${arrow[sortBy] && sortBy.startsWith("pr-") ? arrow[sortBy] : ""}`; - el.colDiff.textContent = `${fieldBase} diff${arrow[sortBy] && sortBy.startsWith("metric-") ? arrow[sortBy] : ""}`; + el.colIB.textContent = `${fieldBase} IB${unit}${arrow[sortBy] && sortBy.startsWith("ib-") ? arrow[sortBy] : ""}`; + el.colPR.textContent = `${fieldBase} PR${unit}${arrow[sortBy] && sortBy.startsWith("pr-") ? arrow[sortBy] : ""}`; + el.colDiff.textContent = `${fieldBase} diff${unit}${arrow[sortBy] && sortBy.startsWith("metric-") ? arrow[sortBy] : ""}`; } function updateStats(rows, fieldBase) { const diffKey = `${fieldBase} diff`; + const quantity = fieldBase.split(" ")[0]; const values = rows.map((r) => toNumber(r[diffKey])); const count = values.length; const mean = count ? values.reduce((a, b) => a + b, 0) / count : 0; @@ -873,8 +912,8 @@

Module Allocation Monitor Viewer

el.statModules.textContent = count.toLocaleString(); el.statTypes.textContent = types.toLocaleString(); - el.statMean.textContent = fmtNumber(mean); - el.statMaxAbs.textContent = fmtNumber(maxAbs); + el.statMean.textContent = fmtNumber(mean, quantity); + el.statMaxAbs.textContent = fmtNumber(maxAbs, quantity); } function applyFilters() { @@ -892,7 +931,6 @@

Module Allocation Monitor Viewer

const ibKey = `${fieldBase} IB`; const prKey = `${fieldBase} PR`; const minAbs = Math.abs(toNumber(el.minAbs.value)); - const fixedSortDiffKey = `${FIXED_SORT_FIELD_BASE} diff`; updateColumnHeaders(fieldBase || "(field)"); @@ -948,7 +986,7 @@

Module Allocation Monitor Viewer

return toNumber(b[diffKey]) - toNumber(a[diffKey]); case "abs-desc": default: { - const byFixedMetric = Math.abs(toNumber(b[fixedSortDiffKey])) - Math.abs(toNumber(a[fixedSortDiffKey])); + const byFixedMetric = Math.abs(toNumber(b[diffKey])) - Math.abs(toNumber(a[diffKey])); if (byFixedMetric !== 0) { return byFixedMetric; } @@ -996,6 +1034,8 @@

Module Allocation Monitor Viewer

el.tbody.innerHTML = ""; el.empty.style.display = pageRows.length ? "none" : "block"; + const quantity = fieldBase.split(" ")[0]; + for (const row of pageRows) { const tr = document.createElement("tr"); const ibValue = toNumber(row[ibKey]); @@ -1012,9 +1052,9 @@

Module Allocation Monitor Viewer

- - - + + + `; + }); + + return ` +

Event setup dictionary entries (${escapeHtml(quantity)})

+
Quantity
${escapeHtml(quantity)}${escapeHtml(group)}${metricDisplayValue(row, ibKey)}${metricDisplayValue(row, prKey)}${metricDisplayValue(row, diffKey)}
${escapeHtml(quantity)}${escapeHtml(group)}${metricDisplayValue(row, ibKey, quantity)}${metricDisplayValue(row, prKey, quantity)}${metricDisplayValue(row, diffKey, quantity)}
${isExpanded ? "▼" : "▶"}${row.label || ""} ${row.type || "(none)"} ${row.record || "-"}${fmtNumber(ibValue)}${fmtNumber(prValue)}${fmtNumber(diffValue)}${fmtNumber(ibValue, quantity)}${fmtNumber(prValue, quantity)}${fmtNumber(diffValue, quantity)}
@@ -1071,6 +1111,7 @@

Module Allocation Monitor Viewer

} state.modules = modules; + state.quantityUnits = extractQuantityUnits(data); const groupedFields = collectFieldGroups(modules); state.fieldGroupsByQuantity = groupedFields.byQuantity; state.quantities = groupedFields.quantities; From 4c48b6f1cec38fc573eaf9343b5e3bca73a7ba34 Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 13:06:58 -0500 Subject: [PATCH 14/22] Comment out the runall_vtune.sh execution in profiling script for debugging purposes --- pr_testing/run-pr-profiling.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr_testing/run-pr-profiling.sh b/pr_testing/run-pr-profiling.sh index 9512ced0cfa..7e5a84f0b97 100755 --- a/pr_testing/run-pr-profiling.sh +++ b/pr_testing/run-pr-profiling.sh @@ -60,7 +60,7 @@ EOF export RUNALLSTEPS=1 $WORKSPACE/profiling/Gen_tool/runall.sh $CMSSW_VERSION || true $WORKSPACE/profiling/Gen_tool/runall_allocmon.sh $CMSSW_VERSION || true - $WORKSPACE/profiling/Gen_tool/runall_vtune.sh $CMSSW_VERSION || true +# $WORKSPACE/profiling/Gen_tool/runall_vtune.sh $CMSSW_VERSION || true if [ ! -d $WORKSPACE/$CMSSW_VERSION/$PROFILING_WORKFLOW ] ; then mark_commit_status_all_prs "profiling wf $PROFILING_WORKFLOW" 'success' -u "${BUILD_URL}" -d "Error: failed to run profiling" echo "
$PROFILING_WORKFLOW: No such directory" >> $WORKSPACE/upload/profiling/index-$PROFILING_WORKFLOW.html From 6560f941e2b652c14e5db3973248ae55c74ed68c Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 13:16:51 -0500 Subject: [PATCH 15/22] Revert "Comment out the runall_vtune.sh execution in profiling script for debugging purposes" This reverts commit 4c48b6f1cec38fc573eaf9343b5e3bca73a7ba34. --- pr_testing/run-pr-profiling.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr_testing/run-pr-profiling.sh b/pr_testing/run-pr-profiling.sh index 7e5a84f0b97..9512ced0cfa 100755 --- a/pr_testing/run-pr-profiling.sh +++ b/pr_testing/run-pr-profiling.sh @@ -60,7 +60,7 @@ EOF export RUNALLSTEPS=1 $WORKSPACE/profiling/Gen_tool/runall.sh $CMSSW_VERSION || true $WORKSPACE/profiling/Gen_tool/runall_allocmon.sh $CMSSW_VERSION || true -# $WORKSPACE/profiling/Gen_tool/runall_vtune.sh $CMSSW_VERSION || true + $WORKSPACE/profiling/Gen_tool/runall_vtune.sh $CMSSW_VERSION || true if [ ! -d $WORKSPACE/$CMSSW_VERSION/$PROFILING_WORKFLOW ] ; then mark_commit_status_all_prs "profiling wf $PROFILING_WORKFLOW" 'success' -u "${BUILD_URL}" -d "Error: failed to run profiling" echo "
$PROFILING_WORKFLOW: No such directory" >> $WORKSPACE/upload/profiling/index-$PROFILING_WORKFLOW.html From 17a373e153e37aa32e817bc2fcd8b3f331514874 Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 15:17:15 -0500 Subject: [PATCH 16/22] Enhance module allocation viewer: add event setup metrics handling, improve data processing functions, and update HTML rendering for detailed event setup entries --- .../moduleAllocMonitor-circles-diff.py | 123 ++++++++++++++++-- comparisons/module_alloc_monitor_viewer.html | 113 ++++++++++++++-- 2 files changed, 212 insertions(+), 24 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 7e8bab3f3e4..8b3aa6c7309 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -48,12 +48,30 @@ def build_viewer_html(template_path, embedded_data, source_label): def module_key(module): - return "%s|%s|%s" % (module.get("label", ""), module.get("type", ""), module.get("record", "")) + return "%s|%s" % (module.get("label", ""), module.get("type", "")) + + +def module_record(module): + record = module.get("record", "") + return str(record).strip() + + +def is_event_setup_metric(metric): + return str(metric).strip().lower().endswith(" event setup") + + +def to_numeric_or_none(value): + if isinstance(value, (int, float)): + return value + if isinstance(value, dict): + values = [sub_value for sub_value in value.values() if isinstance(sub_value, (int, float))] + return sum(values) if values else None + return None def sum_numeric_values(data, keys, default="N/A"): - values = [data.get(key, default) for key in keys] - return sum(values) if all(isinstance(value, (int, float)) for value in values) else default + values = [to_numeric_or_none(data.get(key, default)) for key in keys] + return sum(values) if all(value is not None for value in values) else default def sum_with_prefix_suffix(data, metric_keys, prefix="added", suffix="", default="N/A"): @@ -65,6 +83,34 @@ def sum_with_prefix_suffix(data, metric_keys, prefix="added", suffix="", default def is_valid_module_key(key): return key != "None|None|None" and key != "||" +def compute_event_setup_total(event_setup): + total = 0 + if not isinstance(event_setup, dict): + return total + for key, value in event_setup.items(): + if key == "total": + continue + if isinstance(value, (int, float)): + total += value + elif isinstance(value, dict): + for nested in value.values(): + if isinstance(nested, (int, float)): + total += nested + return total + + +def ensure_event_setup_total(module): + for key in ["IB", "PR", "diff"]: + for metric in METRICS_KEYS: + event_setup = module.get("%s event setup %s" % (metric, key)) + if not isinstance(event_setup, dict): + event_setup = {"total": 0} + event_setup["total"] = compute_event_setup_total(event_setup) + module["%s event setup %s" % (metric, key)] = event_setup + + + + def update_added_totals(datamapres): for module in datamapres.values(): @@ -83,13 +129,70 @@ def update_added_totals(datamapres): ) +def merge_modules_by_key(modules, metrics): + merged = {} + for module in modules: + key = module_key(module) + if key not in merged: + merged[key] = { + "type": module.get("type"), + "label": module.get("label"), + "event setup": {"total": 0}, + } + dest = merged[key] + record = module_record(module) + if record: + dest["event setup"].setdefault(record, {}) + + for metric in metrics: + value = module.get(metric, "N/A") + if is_event_setup_metric(metric): + metric_map = dest.get(metric) + if not isinstance(metric_map, dict): + metric_map = {} + dest[metric] = metric_map + rec_key = record if record else "total" + metric_map[rec_key] = value + + if record and isinstance(value, (int, float)): + dest["event setup"][record][metric] = value + elif isinstance(value, (int, float)): + dest[metric] = dest.get(metric, 0) + value + elif metric not in dest: + dest[metric] = value + return merged + + def diff_from(metrics, data, dest, res): + def diff_dictionary_values(ib_values, pr_values): + records = sorted(set(ib_values.keys()) | set(pr_values.keys())) + diff_values = {} + for record in records: + ib_value = ib_values.get(record, "N/A") + pr_value = pr_values.get(record, "N/A") + if isinstance(ib_value, (int, float)) and isinstance(pr_value, (int, float)): + diff_values[record] = pr_value - ib_value + elif isinstance(pr_value, (int, float)): + diff_values[record] = pr_value + elif isinstance(ib_value, (int, float)): + diff_values[record] = -ib_value + else: + diff_values[record] = "N/A" + return diff_values + for metric in metrics: ibkey = "%s IB" % metric - res[ibkey] = data.get(metric, "N/A") + ibvalue = data.get(metric, "N/A") + res[ibkey] = ibvalue prkey = "%s PR" % metric - res[prkey] = dest.get(metric, "N/A") - if res[ibkey] == "N/A" or res[prkey] == "N/A": + prvalue = dest.get(metric, "N/A") + res[prkey] = prvalue + + if isinstance(ibvalue, dict) or isinstance(prvalue, dict): + ibdict = ibvalue if isinstance(ibvalue, dict) else {} + prdict = prvalue if isinstance(prvalue, dict) else {} + res[metric + " diff"] = diff_dictionary_values(ibdict, prdict) + elif res[ibkey] == "N/A" or res[prkey] == "N/A": if res[prkey] != "N/A": res[metric + " diff"] = res[prkey] - 0 elif res[ibkey] != "N/A": @@ -115,7 +218,7 @@ def diff_from(metrics, data, dest, res): for key in resource: metrics.append(key) -datamapib = {module_key(module): module for module in ibdata["modules"]} +datamapib = merge_modules_by_key(ibdata["modules"], metrics) datacumulsib = {} for module in ibdata["modules"]: @@ -137,7 +240,7 @@ def diff_from(metrics, data, dest, res): print("Error: input files describe different metrics") sys.exit(1) -datamappr = {module_key(module): module for module in prdata["modules"]} +datamappr = merge_modules_by_key(prdata["modules"], metrics) if ibdata["total"]["label"] != prdata["total"]["label"]: @@ -174,18 +277,16 @@ def diff_from(metrics, data, dest, res): if key in datamapib and key not in datamappr: result["type"] = datamapib.get(key).get("type") result["label"] = datamapib.get(key).get("label") - result["record"] = datamapib.get(key).get("record") diff_from(metrics, datamapib.get(key, {}), {}, result) elif key in datamappr and key not in datamapib: result["type"] = datamappr.get(key).get("type") result["label"] = datamappr.get(key).get("label") - result["record"] = datamappr.get(key).get("record") diff_from(metrics, {}, datamappr.get(key, {}), result) else: result["type"] = datamappr.get(key).get("type") result["label"] = datamappr.get(key).get("label") - result["record"] = datamappr.get(key).get("record") diff_from(metrics, datamapib.get(key, {}), datamappr.get(key, {}), result) + ensure_event_setup_total(result) results["modules"].append(result) datamapres = {} diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index b6641cfe91b..200d87f4303 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -588,8 +588,22 @@

Module Allocation Monitor Viewer

return value.toLocaleString(undefined, { maximumFractionDigits: 6 }); } + function metricNumber(value) { + const numeric = Number(value); + if (Number.isFinite(numeric)) { + return numeric; + } + if (value && typeof value === "object") { + const total = Number(value.total); + if (Number.isFinite(total)) { + return total; + } + } + return NaN; + } + function toNumber(val) { - const n = Number(val); + const n = metricNumber(val); return Number.isFinite(n) ? n : 0; } @@ -610,7 +624,7 @@

Module Allocation Monitor Viewer

if (!Object.prototype.hasOwnProperty.call(row, key)) { return "-"; } - const value = Number(row[key]); + const value = metricNumber(row[key]); return Number.isFinite(value) ? fmtNumber(value, quantity) : "-"; } @@ -620,6 +634,16 @@

Module Allocation Monitor Viewer

const hasRecord = row.record !== undefined && row.record !== null && String(row.record).trim() !== ""; for (const group of groups) { const groupLower = String(group).toLowerCase(); + const fieldBase = group === "(none)" ? quantity : `${quantity} ${group}`; + const ibKey = `${fieldBase} IB`; + const prKey = `${fieldBase} PR`; + const diffKey = `${fieldBase} diff`; + const hasEventSetupDictionary = + groupLower === "event setup" && + [row[ibKey], row[prKey], row[diffKey]].some((value) => { + return value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "total"); + }); + const keepEventSetupTotalRow = groupLower === "event setup" && (hasRecord || hasEventSetupDictionary); if (groupLower === "total") { continue; } @@ -627,13 +651,9 @@

Module Allocation Monitor Viewer

if (groupLower !== "event setup") { continue; } - } else if (groupLower === "event setup") { + } else if (groupLower === "event setup" && !hasEventSetupDictionary) { continue; } - const fieldBase = group === "(none)" ? quantity : `${quantity} ${group}`; - const ibKey = `${fieldBase} IB`; - const prKey = `${fieldBase} PR`; - const diffKey = `${fieldBase} diff`; const hasIB = Object.prototype.hasOwnProperty.call(row, ibKey); const hasPR = Object.prototype.hasOwnProperty.call(row, prKey); const hasDiff = Object.prototype.hasOwnProperty.call(row, diffKey); @@ -641,9 +661,9 @@

Module Allocation Monitor Viewer

if (!hasAny) { continue; } - const ibValue = Number(row[ibKey]); - const prValue = Number(row[prKey]); - const diffValue = Number(row[diffKey]); + const ibValue = metricNumber(row[ibKey]); + const prValue = metricNumber(row[prKey]); + const diffValue = metricNumber(row[diffKey]); const hasNumericIB = hasIB && Number.isFinite(ibValue); const hasNumericPR = hasPR && Number.isFinite(prValue); const hasNumericDiff = hasDiff && Number.isFinite(diffValue); @@ -665,7 +685,7 @@

Module Allocation Monitor Viewer

missingOrNonNumericCount > 0 && presentNumericValues.length > 0 && presentNumericValues.every((v) => v === 0); - if (missingAndRemainingZero) { + if (missingAndRemainingZero && !keepEventSetupTotalRow) { continue; } const allZero = @@ -675,7 +695,7 @@

Module Allocation Monitor Viewer

ibValue === 0 && prValue === 0 && diffValue === 0; - if (allZero) { + if (allZero && !keepEventSetupTotalRow) { continue; } rows.push( @@ -688,6 +708,71 @@

Module Allocation Monitor Viewer

return rows.join(""); } + function eventSetupEntries(value) { + if (!value || typeof value !== "object") { + return null; + } + const keys = Object.keys(value).filter((k) => k !== "total"); + if (!keys.length) { + return null; + } + return keys; + } + + function buildEventSetupDetailTable(row, quantity) { + const ibKey = `${quantity} event setup IB`; + const prKey = `${quantity} event setup PR`; + const diffKey = `${quantity} event setup diff`; + const ibMap = row[ibKey] && typeof row[ibKey] === "object" ? row[ibKey] : null; + const prMap = row[prKey] && typeof row[prKey] === "object" ? row[prKey] : null; + const diffMap = row[diffKey] && typeof row[diffKey] === "object" ? row[diffKey] : null; + + const keySet = new Set(); + [ibMap, prMap, diffMap].forEach((map) => { + const keys = eventSetupEntries(map); + if (!keys) { + return; + } + keys.forEach((k) => keySet.add(k)); + }); + + const keys = [...keySet].sort((a, b) => a.localeCompare(b)); + if (!keys.length) { + return ""; + } + + const rows = keys.map((k) => { + const ibValue = ibMap ? metricNumber(ibMap[k]) : NaN; + const prValue = prMap ? metricNumber(prMap[k]) : NaN; + const diffValue = diffMap ? metricNumber(diffMap[k]) : NaN; + const ibText = Number.isFinite(ibValue) ? fmtNumber(ibValue, quantity) : "-"; + const prText = Number.isFinite(prValue) ? fmtNumber(prValue, quantity) : "-"; + const diffText = Number.isFinite(diffValue) ? fmtNumber(diffValue, quantity) : "-"; + return `
${escapeHtml(k)}${ibText}${prText}${diffText}
+ + + + + + + + + + + + + + + ${rows.join("")} +
KeyIBPRDiff
+ `; + } + function toggleRowExpanded(key) { if (state.expandedRows.has(key)) { state.expandedRows.delete(key); @@ -754,7 +839,7 @@

Module Allocation Monitor Viewer

} const flags = map.get(base); flags[part] = true; - if (Number.isFinite(Number(mod[k]))) { + if (Number.isFinite(metricNumber(mod[k]))) { flags.hasNumeric = true; } }); @@ -1065,6 +1150,7 @@

Module Allocation Monitor Viewer

el.tbody.appendChild(tr); if (isExpanded) { + const eventSetupDetail = buildEventSetupDetailTable(row, el.quantitySelect.value); const detailTr = document.createElement("tr"); detailTr.className = "detail-row"; detailTr.innerHTML = ` @@ -1090,6 +1176,7 @@

Module Allocation Monitor Viewer

${buildExpandedMetricsRows(row, el.quantitySelect.value)} + ${eventSetupDetail}
`; From dd658f1a085d756d405015a916730b2f84788320 Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 15:22:49 -0500 Subject: [PATCH 17/22] Implement sortable columns for event setup metrics table: add sorting functionality and update header elements for user interaction --- comparisons/module_alloc_monitor_viewer.html | 79 +++++++++++++++++--- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index 200d87f4303..e52b8e9e625 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -522,6 +522,7 @@

Module Allocation Monitor Viewer

quantityUnits: {}, quantities: [], expandedRows: new Set(), + eventSetupSort: { column: "key", direction: "asc" }, page: 1, maxAbsMetric: 1, fileName: "" @@ -736,19 +737,56 @@

Module Allocation Monitor Viewer

keys.forEach((k) => keySet.add(k)); }); - const keys = [...keySet].sort((a, b) => a.localeCompare(b)); + const keys = [...keySet]; if (!keys.length) { return ""; } - const rows = keys.map((k) => { + const entries = keys.map((k) => { const ibValue = ibMap ? metricNumber(ibMap[k]) : NaN; const prValue = prMap ? metricNumber(prMap[k]) : NaN; const diffValue = diffMap ? metricNumber(diffMap[k]) : NaN; - const ibText = Number.isFinite(ibValue) ? fmtNumber(ibValue, quantity) : "-"; - const prText = Number.isFinite(prValue) ? fmtNumber(prValue, quantity) : "-"; - const diffText = Number.isFinite(diffValue) ? fmtNumber(diffValue, quantity) : "-"; - return `${escapeHtml(k)}${ibText}${prText}${diffText}`; + return { key: k, ibValue, prValue, diffValue }; + }); + + const sortState = state.eventSetupSort || { column: "key", direction: "asc" }; + const direction = sortState.direction === "desc" ? -1 : 1; + entries.sort((a, b) => { + const col = sortState.column; + if (col === "key") { + return direction * a.key.localeCompare(b.key); + } + const av = col === "ib" ? a.ibValue : col === "pr" ? a.prValue : a.diffValue; + const bv = col === "ib" ? b.ibValue : col === "pr" ? b.prValue : b.diffValue; + const aFinite = Number.isFinite(av); + const bFinite = Number.isFinite(bv); + if (!aFinite && !bFinite) { + return a.key.localeCompare(b.key); + } + if (!aFinite) { + return 1; + } + if (!bFinite) { + return -1; + } + if (av === bv) { + return a.key.localeCompare(b.key); + } + return direction * (av - bv); + }); + + function sortArrow(column) { + if (sortState.column !== column) { + return ""; + } + return sortState.direction === "desc" ? " ▼" : " ▲"; + } + + const rows = entries.map((entry) => { + const ibText = Number.isFinite(entry.ibValue) ? fmtNumber(entry.ibValue, quantity) : "-"; + const prText = Number.isFinite(entry.prValue) ? fmtNumber(entry.prValue, quantity) : "-"; + const diffText = Number.isFinite(entry.diffValue) ? fmtNumber(entry.diffValue, quantity) : "-"; + return `${escapeHtml(entry.key)}${ibText}${prText}${diffText}`; }); return ` @@ -762,10 +800,10 @@

Module Allocation Monitor Viewer

- Key - IB - PR - Diff + Key${sortArrow("key")} + IB${sortArrow("ib")} + PR${sortArrow("pr")} + Diff${sortArrow("diff")} ${rows.join("")} @@ -1261,6 +1299,19 @@

Module Allocation Monitor Viewer

applyFilters(); } + function toggleEventSetupSort(column) { + if (!column) { + return; + } + if (state.eventSetupSort.column === column) { + state.eventSetupSort.direction = state.eventSetupSort.direction === "desc" ? "asc" : "desc"; + } else { + state.eventSetupSort.column = column; + state.eventSetupSort.direction = column === "key" ? "asc" : "desc"; + } + renderTable(); + } + el.fileInput.addEventListener("change", async (evt) => { const file = evt.target.files && evt.target.files[0]; if (!file) { @@ -1300,6 +1351,14 @@

Module Allocation Monitor Viewer

el.colType.addEventListener("click", () => toggleSort("type-desc", "type-asc")); el.colRecord.addEventListener("click", () => toggleSort("record-desc", "record-asc")); + el.tbody.addEventListener("click", (evt) => { + const header = evt.target.closest("th.es-sortable"); + if (!header) { + return; + } + toggleEventSetupSort(header.dataset.esSort || ""); + }); + el.prevBtn.addEventListener("click", () => { state.page = Math.max(1, state.page - 1); renderTable(); From 98e6804ddffdca6c84b4c40bf26543bf19b459ec Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 15:24:08 -0500 Subject: [PATCH 18/22] Black formatting --- comparisons/moduleAllocMonitor-circles-diff.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 8b3aa6c7309..740ffdcf1c9 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -83,6 +83,7 @@ def sum_with_prefix_suffix(data, metric_keys, prefix="added", suffix="", default def is_valid_module_key(key): return key != "None|None|None" and key != "||" + def compute_event_setup_total(event_setup): total = 0 if not isinstance(event_setup, dict): @@ -108,9 +109,6 @@ def ensure_event_setup_total(module): event_setup["total"] = compute_event_setup_total(event_setup) module["%s event setup %s" % (metric, key)] = event_setup - - - def update_added_totals(datamapres): for module in datamapres.values(): From 28a6adfd96f927f113a4d2f262529cf51d138c45 Mon Sep 17 00:00:00 2001 From: gartung Date: Tue, 21 Apr 2026 19:35:11 -0500 Subject: [PATCH 19/22] Fix to_numeric_or_none function: return total value from dict if present --- comparisons/moduleAllocMonitor-circles-diff.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/comparisons/moduleAllocMonitor-circles-diff.py b/comparisons/moduleAllocMonitor-circles-diff.py index 740ffdcf1c9..1c502c99032 100755 --- a/comparisons/moduleAllocMonitor-circles-diff.py +++ b/comparisons/moduleAllocMonitor-circles-diff.py @@ -64,6 +64,9 @@ def to_numeric_or_none(value): if isinstance(value, (int, float)): return value if isinstance(value, dict): + total_value = value.get("total") + if isinstance(total_value, (int, float)): + return total_value values = [sub_value for sub_value in value.values() if isinstance(sub_value, (int, float))] return sum(values) if values else None return None From 87f1018f305b2e12bf1e045e06c2ea9496dac08a Mon Sep 17 00:00:00 2001 From: gartung Date: Wed, 22 Apr 2026 08:14:42 -0500 Subject: [PATCH 20/22] Remove condition for keeping event setup total row when all values are zero --- comparisons/module_alloc_monitor_viewer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index e52b8e9e625..9c43ae2b12a 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -696,7 +696,7 @@

Module Allocation Monitor Viewer

ibValue === 0 && prValue === 0 && diffValue === 0; - if (allZero && !keepEventSetupTotalRow) { + if (allZero) { continue; } rows.push( From 7a18f9e5c44ef0969a8923ccbd9a5befb6d5c90d Mon Sep 17 00:00:00 2001 From: gartung Date: Wed, 22 Apr 2026 11:03:09 -0500 Subject: [PATCH 21/22] Add right alignment and numeric formatting for table cells --- comparisons/module_alloc_monitor_viewer.html | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index 9c43ae2b12a..3a419d60326 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -312,6 +312,11 @@ white-space: nowrap; } + td.mono { + text-align: right; + font-variant-numeric: tabular-nums; + } + .pill { display: inline-block; border-radius: 999px; @@ -575,18 +580,9 @@

Module Allocation Monitor Viewer

if (value === null || value === undefined || Number.isNaN(value)) { return "-"; } - const abs = Math.abs(value); - const useFixedPoint = !!quantity; - if (abs >= 1000000 && !useFixedPoint) { - return value.toExponential(3); - } - if (abs >= 1000) { - return value.toLocaleString(undefined, { maximumFractionDigits: 2 }); - } - if (abs >= 1) { - return value.toLocaleString(undefined, { maximumFractionDigits: 4 }); - } - return value.toLocaleString(undefined, { maximumFractionDigits: 6 }); + return value.toLocaleString(undefined, { + maximumFractionDigits: 1 + }); } function metricNumber(value) { From a1bdede1f37470255ae1a1705e7dd21b788de220 Mon Sep 17 00:00:00 2001 From: gartung Date: Wed, 22 Apr 2026 13:58:51 -0500 Subject: [PATCH 22/22] Remove custom font families and revert to system default fonts for improved performance and consistency Co-authored-by: Copilot --- comparisons/module_alloc_monitor_viewer.html | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/comparisons/module_alloc_monitor_viewer.html b/comparisons/module_alloc_monitor_viewer.html index 3a419d60326..6f6ae38360b 100644 --- a/comparisons/module_alloc_monitor_viewer.html +++ b/comparisons/module_alloc_monitor_viewer.html @@ -4,9 +4,7 @@ Module Allocation Monitor Viewer - - - +