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.jsclinic doctor -- node server.js writes 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.

Publish a profile →

Related