Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions .github/scripts/perf_comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,29 @@ def is_significant(m):
return abs(m["delta_pct"]) >= THRESHOLDS.get(m["method"], 0.1)


# Stage rows (frontend/backend) shown as base%/head% shares of their group.
# Stage rows (frontend/backend) shown as base%/head% shares with pp delta.
def breakdown(children):
base_total = sum(c["base"] for c in children)
head_total = sum(c["head"] for c in children)
if head_total <= 0:
return []
return ["| ↳ {} | {} | {} | {} |".format(
c["label"],
fmt_share(c["base"], base_total),
fmt_share(c["head"], head_total),
fmt_delta(c["delta_pct"]),
) for c in children]
rows = []
for c in children:
base_pct = c["base"] / base_total * 100 if base_total > 0 else 0
head_pct = c["head"] / head_total * 100 if head_total > 0 else 0
pp = head_pct - base_pct
if abs(pp) < 0.5:
delta_str = "~0pp"
else:
sign = "+" if pp > 0 else ""
delta_str = f"{sign}{pp:.0f}pp"
rows.append("| ↳ {} | {} | {} | {} |".format(
c["label"],
fmt_share(c["base"], base_total),
fmt_share(c["head"], head_total),
delta_str,
))
return rows


def render(results):
Expand Down
8 changes: 8 additions & 0 deletions tools/perfrunner/source/metrics.d
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ immutable MetricDef[] initials = [
MetricDef("phobos_max_rss", "peak RSS (compile Phobos)", "kb", "time -v"),
MetricDef("phobos_stage_frontend", "frontend (parse+sema)", "us", "time-trace", "compile_phobos_instr"),
MetricDef("phobos_stage_backend", "backend (inline+codegen)", "us", "time-trace", "compile_phobos_instr"),
MetricDef("phobos_stage_parse", "parse", "us", "time-trace", "phobos_stage_frontend"),
MetricDef("phobos_stage_sema", "semantic analysis", "us", "time-trace", "phobos_stage_frontend"),
MetricDef("phobos_stage_inline", "inlining", "us", "time-trace", "phobos_stage_backend"),
MetricDef("phobos_stage_codegen", "code generation", "us", "time-trace", "phobos_stage_backend"),
];

// Measure every metric for one dmd binary. `tag` ("base"/"head")
Expand All @@ -53,6 +57,10 @@ long[string] measure(string dmd, string workload, string phobos, string tmp, str
auto st = stages(dmd, phobosFlags, stdPackage, tmp, tag ~ "-phobos");
m["phobos_stage_frontend"] = st.get("stage_frontend_us", 0);
m["phobos_stage_backend"] = st.get("stage_backend_us", 0);
m["phobos_stage_parse"] = st.get("stage_parse_us", 0);
m["phobos_stage_sema"] = st.get("stage_sema_us", 0);
m["phobos_stage_inline"] = st.get("stage_inline_us", 0);
m["phobos_stage_codegen"] = st.get("stage_codegen_us", 0);
return m;
}

Expand Down
33 changes: 23 additions & 10 deletions tools/perfrunner/source/timetrace.d
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module timetrace;

import std.algorithm : canFind;

import std.file : readText;
import std.json : parseJSON;
import std.path : buildPath;
Expand All @@ -9,24 +9,33 @@ import std.process : execute;
// The top-level -ftime-trace spans grouped into frontend/backend. These names
// match main.d's generic phase spans; they don't overlap, so summing them
// partitions the compile without double-counting the nested per-symbol events.
private immutable string[] frontendSpans = ["Parsing", "Semantic analysis"];
private immutable string[] backendSpans = ["Inlining", "Code generation"];

// Sum the duration (microseconds) of the top-level spans in each bucket.
// Returns both coarse (frontend/backend) and fine (parse/sema/inline/codegen).
long[string] parseStages(string trace)
{
long frontend, backend;
long parse, sema, inline, codegen;
foreach (e; parseJSON(trace)["traceEvents"].array)
{
if (e["ph"].str != "X")
continue;
auto name = e["name"].str;
if (frontendSpans.canFind(name))
frontend += e["dur"].integer;
else if (backendSpans.canFind(name))
backend += e["dur"].integer;
if (name == "Parsing")
parse += e["dur"].integer;
else if (name == "Semantic analysis")
sema += e["dur"].integer;
else if (name == "Inlining")
inline += e["dur"].integer;
else if (name == "Code generation")
codegen += e["dur"].integer;
}
return ["stage_frontend_us": frontend, "stage_backend_us": backend];
return [
"stage_frontend_us": parse + sema,
"stage_backend_us": inline + codegen,
"stage_parse_us": parse,
"stage_sema_us": sema,
"stage_inline_us": inline,
"stage_codegen_us": codegen,
];
}

// Compile the workload with -ftime-trace and read the per-stage durations.
Expand Down Expand Up @@ -57,4 +66,8 @@ unittest
auto s = parseStages(sample);
assert(s["stage_frontend_us"] == 400);
assert(s["stage_backend_us"] == 100);
assert(s["stage_parse_us"] == 100);
assert(s["stage_sema_us"] == 300);
assert(s["stage_inline_us"] == 20);
assert(s["stage_codegen_us"] == 80);
}
Loading