Skip to content

Commit aaafda9

Browse files
authored
chore: upload lakeprof report (#272)
This PR makes the bench suite upload the lakeprof report it collected while building cslib. The report will be accessible through the "Lakeprof report" button in radar when viewing a commit (as long as the benchmark run for the commit has completed successfully).
1 parent 02e2a23 commit aaafda9

4 files changed

Lines changed: 127 additions & 0 deletions

File tree

scripts/bench/build/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ The following metrics are collected individually for each module:
2222

2323
- `build/module/<name>//lines`
2424
- `build/module/<name>//instructions`
25+
26+
If the file `build_upload_lakeprof_report` is present in the repo root,
27+
the lakeprof report will be uploaded once the benchmark run concludes.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Lakeprof Report</title>
6+
</head>
7+
<body>
8+
<h1>Lakeprof Report</h1>
9+
<button type="button" id="btn_fetch">View build trace in Perfetto</button>
10+
<pre><code>__LAKEPROF_REPORT__</code></pre>
11+
12+
<script type="text/javascript">
13+
// https://perfetto.dev/docs/visualization/deep-linking-to-perfetto-ui
14+
// https://gist.github.com/chromy/170c11ce30d9084957d7f3aa065e89f8
15+
16+
const BASE_URL = __BASE_URL__;
17+
const ORIGIN = "https://ui.perfetto.dev";
18+
19+
const btnFetch = document.getElementById("btn_fetch");
20+
21+
async function fetchAndOpen(traceUrl) {
22+
const resp = await fetch(traceUrl);
23+
// Error checking is left as an exercise to the reader.
24+
const blob = await resp.blob();
25+
const arrayBuffer = await blob.arrayBuffer();
26+
openTrace(arrayBuffer, traceUrl);
27+
}
28+
29+
function openTrace(arrayBuffer, traceUrl) {
30+
const win = window.open(ORIGIN);
31+
if (!win) {
32+
btnFetch.style.background = "#f3ca63";
33+
btnFetch.onclick = () => openTrace(arrayBuffer);
34+
btnFetch.innerText =
35+
"Popups blocked, click here to open the trace file";
36+
return;
37+
}
38+
39+
const timer = setInterval(() => win.postMessage("PING", ORIGIN), 50);
40+
41+
const onMessageHandler = (evt) => {
42+
if (evt.data !== "PONG") return;
43+
44+
// We got a PONG, the UI is ready.
45+
window.clearInterval(timer);
46+
window.removeEventListener("message", onMessageHandler);
47+
48+
const reopenUrl = new URL(location.href);
49+
reopenUrl.hash = `#reopen=${traceUrl}`;
50+
win.postMessage(
51+
{
52+
perfetto: {
53+
buffer: arrayBuffer,
54+
title: "Lake Build Trace",
55+
url: reopenUrl.toString(),
56+
},
57+
},
58+
ORIGIN
59+
);
60+
};
61+
62+
window.addEventListener("message", onMessageHandler);
63+
}
64+
65+
// This is triggered when following the link from the Perfetto UI's sidebar.
66+
if (location.hash.startsWith("#reopen=")) {
67+
const traceUrl = location.hash.substr(8);
68+
fetchAndOpen(traceUrl);
69+
}
70+
71+
btnFetch.onclick = () => fetchAndOpen(`${BASE_URL}/lakeprof.trace_event`);
72+
</script>
73+
</body>
74+
</html>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env python3
2+
3+
import json
4+
import subprocess
5+
import sys
6+
from pathlib import Path
7+
8+
9+
def run(*args: str) -> None:
10+
subprocess.run(args, check=True)
11+
12+
13+
def run_stdout(*command: str, cwd: str | None = None) -> str:
14+
result = subprocess.run(command, capture_output=True, encoding="utf-8", cwd=cwd)
15+
if result.returncode != 0:
16+
print(result.stdout, end="", file=sys.stdout)
17+
print(result.stderr, end="", file=sys.stderr)
18+
sys.exit(result.returncode)
19+
return result.stdout
20+
21+
22+
def main() -> None:
23+
script_file = Path(__file__)
24+
template_file = script_file.parent / "lakeprof_report_template.html"
25+
26+
sha = run_stdout("git", "rev-parse", "@").strip()
27+
base_url = f"https://speed.lean-lang.org/cslib-out/{sha}"
28+
report = run_stdout("lakeprof", "report", "-prc")
29+
with open(template_file) as f:
30+
template = f.read()
31+
32+
template = template.replace("__BASE_URL__", json.dumps(base_url))
33+
template = template.replace("__LAKEPROF_REPORT__", report)
34+
35+
with open("index.html", "w") as f:
36+
f.write(template)
37+
38+
run("curl", "-T", "index.html", f"{base_url}/index.html")
39+
run("curl", "-T", "lakeprof.log", f"{base_url}/lakeprof.log")
40+
run("curl", "-T", "lakeprof.trace_event", f"{base_url}/lakeprof.trace_event")
41+
42+
43+
if __name__ == "__main__":
44+
main()

scripts/bench/build/run

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ LAKE_OVERRIDE_LEAN=true LEAN=$(realpath "$BENCH/build/fake-root/bin/lean") \
1515
# Analyze lakeprof data
1616
lakeprof report -pj | jq -c '{metric: "build/lakeprof/longest build path//wall-clock", value: .[-1][2], unit: "s"}' >> measurements.jsonl
1717
lakeprof report -rj | jq -c '{metric: "build/lakeprof/longest rebuild path//wall-clock", value: .[-1][2], unit: "s"}' >> measurements.jsonl
18+
19+
# Upload lakeprof report
20+
# Guarded to prevent accidental uploads (which wouldn't work anyways) during local runs.
21+
if [ -f build_upload_lakeprof_report ]; then
22+
python3 "$BENCH/build/lakeprof_report_upload.py"
23+
fi

0 commit comments

Comments
 (0)