diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py
index d4d2199ed0c560..ae042fdd14c570 100644
--- a/src/coreclr/scripts/superpmi.py
+++ b/src/coreclr/scripts/superpmi.py
@@ -1439,6 +1439,15 @@ def replay(self):
def html_color(color, text):
return "{}".format(color, text)
+def calculate_improvements_regressions(base_diff_sizes):
+ num_improvements = sum(1 for (base_size, diff_size) in base_diff_sizes if diff_size < base_size)
+ num_regressions = sum(1 for (base_size, diff_size) in base_diff_sizes if diff_size > base_size)
+
+ byte_improvements = sum(max(0, base_size - diff_size) for (base_size, diff_size) in base_diff_sizes)
+ byte_regressions = sum(max(0, diff_size - base_size) for (base_size, diff_size) in base_diff_sizes)
+
+ return (num_improvements, num_regressions, byte_improvements, byte_regressions)
+
class SuperPMIReplayAsmDiffs:
""" SuperPMI Replay AsmDiffs class
@@ -1646,9 +1655,7 @@ def replay_with_asm_diffs(self):
diffs = read_csv_diffs(diffs_info)
- # This file had asm diffs; keep track of that.
- has_diffs = len(diffs) > 0
- if has_diffs:
+ if any(diffs):
files_with_asm_diffs.append(mch_file)
# There were diffs. Go through each method that created diffs and
@@ -1656,7 +1663,7 @@ def replay_with_asm_diffs(self):
# it. In addition, create a standalone .mc for easy iteration.
jit_analyze_summary_file = None
- if has_diffs and not self.coreclr_args.diff_with_release:
+ if any(diffs) and not self.coreclr_args.diff_with_release:
# AsmDiffs. Save the contents of the fail.mcl file to dig into failures.
if return_code == 0:
@@ -1817,9 +1824,24 @@ async def create_one_artifact(jit_path: str, location: str, flags) -> str:
# If we are not specifying custom metrics then print a summary here, otherwise leave the summarization up to jit-analyze.
if self.coreclr_args.metrics is None:
- num_improvements = sum(1 for r in diffs if int(r["Diff size"]) < int(r["Base size"]))
- num_regressions = sum(1 for r in diffs if int(r["Diff size"]) > int(r["Base size"]))
- logging.info("{} contexts with differences found ({} improvements, {} regressions)".format(len(diffs), num_improvements, num_regressions))
+ base_diff_sizes = [(int(r["Base size"]), int(r["Diff size"])) for r in diffs]
+
+ (num_improvements, num_regressions, byte_improvements, byte_regressions) = calculate_improvements_regressions(base_diff_sizes)
+
+ logging.info("{:,d} contexts with diffs ({:,d} improvements, {:,d} regressions)".format(
+ len(diffs),
+ num_improvements,
+ num_regressions,
+ byte_improvements,
+ byte_regressions))
+
+ if byte_improvements > 0 and byte_regressions > 0:
+ logging.info(" -{:,d}/+{:,d} bytes".format(byte_improvements, byte_regressions))
+ elif byte_improvements > 0:
+ logging.info(" -{:,d} bytes".format(byte_improvements))
+ elif byte_regressions > 0:
+ logging.info(" +{:,d} bytes".format(byte_regressions))
+
logging.info("")
logging.info("")
@@ -1845,10 +1867,10 @@ async def create_one_artifact(jit_path: str, location: str, flags) -> str:
logging.warning("Warning: SuperPMI encountered missing data during the diff. The diff summary printed above may be misleading.")
logging.warning("Missing with base JIT: {}. Missing with diff JIT: {}. Total contexts: {}.".format(missing_base, missing_diff, total_contexts))
- ################################################################################################ end of processing asm diffs (if has_diffs...
+ ################################################################################################ end of processing asm diffs (if any(diffs)...
mch_file_basename = os.path.basename(mch_file)
- asm_diffs.append((mch_file_basename, base_metrics, diff_metrics, has_diffs, jit_analyze_summary_file))
+ asm_diffs.append((mch_file_basename, base_metrics, diff_metrics, diffs, jit_analyze_summary_file))
if not self.coreclr_args.skip_cleanup:
if os.path.isfile(fail_mcl_file):
@@ -1871,7 +1893,7 @@ async def create_one_artifact(jit_path: str, location: str, flags) -> str:
# Construct an overall Markdown summary file.
- if len(asm_diffs) > 0 and not self.coreclr_args.diff_with_release:
+ if any(asm_diffs) and not self.coreclr_args.diff_with_release:
overall_md_summary_file = create_unique_file_name(self.coreclr_args.spmi_location, "diff_summary", "md")
if not os.path.isdir(self.coreclr_args.spmi_location):
os.makedirs(self.coreclr_args.spmi_location)
@@ -1919,8 +1941,9 @@ def sum_diff(row, col):
def has_diffs(row):
return int(row["Contexts with diffs"]) > 0
+ any_diffs = any(has_diffs(diff_metrics["Overall"]) for (_, _, diff_metrics, _, _) in asm_diffs)
# Exclude entire diffs section?
- if any(has_diffs(diff_metrics["Overall"]) for (_, _, diff_metrics, _, _) in asm_diffs):
+ if any_diffs:
def write_pivot_section(row):
# Exclude this particular Overall/MinOpts/FullOpts table?
if not any(has_diffs(diff_metrics[row]) for (_, _, diff_metrics, _, _) in asm_diffs):
@@ -1957,19 +1980,60 @@ def write_pivot_section(row):
write_fh.write("\n\n")
write_fh.write("Details
\n\n")
- write_fh.write("|Collection|Diffed contexts|MinOpts|FullOpts|Contexts with diffs|Missed, base|Missed, diff|\n")
- write_fh.write("|---|--:|--:|--:|--:|--:|--:|\n")
- for (mch_file, base_metrics, diff_metrics, has_diffs, jit_analyze_summary_file) in asm_diffs:
- write_fh.write("|{}|{:,d}|{:,d}|{:,d}|{:,d}|{:,d}|{:,d}|\n".format(
- mch_file,
- int(diff_metrics["Overall"]["Successful compiles"]),
- int(diff_metrics["MinOpts"]["Successful compiles"]),
- int(diff_metrics["FullOpts"]["Successful compiles"]),
- int(diff_metrics["Overall"]["Contexts with diffs"]),
- int(base_metrics["Overall"]["Missing compiles"]),
- int(diff_metrics["Overall"]["Missing compiles"])))
-
- write_fh.write("\n")
+ if any_diffs:
+ write_fh.write("#### Improvements/regressions per collection\n\n")
+ write_fh.write("|Collection|Contexts with diffs|Improvements|Regressions|Improvements (bytes)|Regressions (bytes)|\n")
+ write_fh.write("|---|--:|--:|--:|--:|--:|\n")
+
+ def write_row(name, diffs):
+ base_diff_sizes = [(int(r["Base size"]), int(r["Diff size"])) for r in diffs]
+ (num_improvements, num_regressions, byte_improvements, byte_regressions) = calculate_improvements_regressions(base_diff_sizes)
+ write_fh.write("|{}|{:,d}|{}|{}|{}|{}|\n".format(
+ name,
+ len(diffs),
+ html_color("green", "{:,d}".format(num_improvements)),
+ html_color("red", "{:,d}".format(num_regressions)),
+ html_color("green", "-{:,d}".format(byte_improvements)),
+ html_color("red", "+{:,d}".format(byte_regressions))))
+
+ for (mch_file, _, _, diffs, _) in asm_diffs:
+ write_row(mch_file, diffs)
+
+ if len(asm_diffs) > 1:
+ write_row("", [r for (_, _, _, diffs, _) in asm_diffs for r in diffs])
+
+ write_fh.write("\n---\n\n")
+
+ write_fh.write("#### Context information\n\n")
+ write_fh.write("|Collection|Diffed contexts|MinOpts|FullOpts|Missed, base|Missed, diff|\n")
+ write_fh.write("|---|--:|--:|--:|--:|--:|\n")
+
+ rows = [(mch_file,
+ int(diff_metrics["Overall"]["Successful compiles"]),
+ int(diff_metrics["MinOpts"]["Successful compiles"]),
+ int(diff_metrics["FullOpts"]["Successful compiles"]),
+ int(base_metrics["Overall"]["Missing compiles"]),
+ int(diff_metrics["Overall"]["Missing compiles"])) for (mch_file, base_metrics, diff_metrics, _, _) in asm_diffs]
+
+ def write_row(name, num_contexts, num_minopts, num_fullopts, num_missed_base, num_missed_diff):
+ write_fh.write("|{}|{:,d}|{:,d}|{:,d}|{:,d}|{:,d}|\n".format(
+ name,
+ num_contexts,
+ num_minopts,
+ num_fullopts,
+ num_missed_base,
+ num_missed_diff))
+
+ for t in rows:
+ write_row(*t)
+
+ if len(rows) > 1:
+ def sum_row(index):
+ return sum(r[index] for r in rows)
+
+ write_row("", sum_row(1), sum_row(2), sum_row(3), sum_row(4), sum_row(5))
+
+ write_fh.write("\n\n")
if any(has_diff for (_, _, _, has_diff, _) in asm_diffs):
write_fh.write("---\n\n")