Share a profiling report
Profilers produce the most persuasive artifact in performance work and the
least shareable one. pyinstrument gives you a call tree with the wall-clock
cost of every frame. clinic.js gives you the event-loop picture. A flame
graph shows you, in one image, exactly which stack ate the request.
Then the sharing step flattens all of it into a sentence — "serialization is about 40% of it" — and the team makes a decision about a claim instead of about evidence.
Publish it
pyinstrument --renderer html -o profile.html -m pytest tests/test_slow.py
import os, requests
r = requests.post(
"https://commareports.com/api/v1/reports",
headers={"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
json={
"title": "Checkout endpoint — 1.8s p95",
"description": "40% in JSON serialization, all of it in the nested cart items.",
"html": open("profile.html").read(),
},
)
print(r.json()["url"])
One self-contained file, one URL. The call tree stays interactive inside the
sandboxed iframe (allow-scripts, no allow-same-origin) — collapsing
frames, hiding library code, reading the timing bars.
Other profilers, same motion:
- clinic.js —
clinic doctor -- node server.jswrites a self-contained HTML report; publish the file. - flamegraph.pl — the output is SVG. Wrap it in a minimal HTML page with the paragraph explaining what was under load, and publish that. The paragraph is what makes it a report rather than an image.
cProfile+ snakeviz — snakeviz is a local server, not an artifact. Render with pyinstrument or export the stats and publish a rendered view.
The description does the work
A profile with no context is a wall of frames. The two sentences at the top —
what you were running, what load, what you think it means — are what turn it
into something a reviewer can engage with. Write them into the report
description and the first heading; they are what someone reads before
deciding whether to open the tree.
Then let people disagree
The best outcome of a shared profile is someone who knows the code better saying so, on the frame:
- "That's the N+1 — the serializer lazy-loads each cart item."
- "This was profiled with the cache cold. Rerun it warm before we act."
- "Fixed in #4412. Reprofile and we should see this frame vanish."
Threads anchor to the rendered content and survive the next profile PATCHed to the same report id — so the before and after live at one URL with a diff between them. See commenting on HTML.
Limits
- HTML body: 5 MB. A deep profile of a long run can exceed it — profile a narrower slice, or raise the interval so the tree is smaller and, usually, more readable.
- Scripts run, sandboxed: no same-origin fetches.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.