From 6572c5cbafb6b99b3a3e7400a42b8e3e3b7d134f Mon Sep 17 00:00:00 2001 From: anti Date: Fri, 17 Apr 2026 13:20:05 -0400 Subject: [PATCH] =?UTF-8?q?added:=20scripts/profile/view.sh=20=E2=80=94=20?= =?UTF-8?q?auto-pick=20newest=20artifact=20and=20open=20viewer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dispatches by extension: .prof -> snakeviz, memray .bin -> memray flamegraph (overridable via VIEW=table|tree|stats|summary|leaks), .svg/.html -> xdg-open. Positional arg can be a file path or a type keyword (cprofile, memray, pyspy, pyinstrument). --- scripts/profile/view.sh | 67 +++++++++++++++++++++++++++++++++++++++++ tests/perf/README.md | 21 +++++++++++++ 2 files changed, 88 insertions(+) create mode 100755 scripts/profile/view.sh diff --git a/scripts/profile/view.sh b/scripts/profile/view.sh new file mode 100755 index 0000000..15d8caa --- /dev/null +++ b/scripts/profile/view.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# Open the newest profile artifact in the right viewer. +# +# Usage: +# scripts/profile/view.sh # newest file in ./profiles/ +# scripts/profile/view.sh # explicit path +# scripts/profile/view.sh cprofile # newest .prof +# scripts/profile/view.sh memray # newest memray .bin +# scripts/profile/view.sh pyspy # newest .svg +# scripts/profile/view.sh pyinstrument # newest pyinstrument .html +# +# Memray viewer override: +# VIEW=flamegraph|table|tree|stats|summary (default: flamegraph) +# VIEW=leaks (render flamegraph with --leaks filter) +set -euo pipefail + +DIR="${DIR:-profiles}" +VIEW="${VIEW:-flamegraph}" + +if [[ ! -d "${DIR}" ]]; then + echo "No ${DIR}/ directory yet — run one of the profile scripts first." >&2 + exit 1 +fi + +pick_newest() { + local pattern="$1" + find "${DIR}" -maxdepth 1 -type f -name "${pattern}" -printf '%T@ %p\n' 2>/dev/null \ + | sort -n | tail -n 1 | cut -d' ' -f2- +} + +TARGET="" +case "${1:-}" in + "") TARGET="$(pick_newest '*')" ;; + cprofile) TARGET="$(pick_newest '*.prof')" ;; + memray) TARGET="$(pick_newest 'memray-*.bin')" ;; + pyspy) TARGET="$(pick_newest 'pyspy-*.svg')" ;; + pyinstrument) TARGET="$(pick_newest '*.html')" ;; + *) TARGET="$1" ;; +esac + +if [[ -z "${TARGET}" || ! -f "${TARGET}" ]]; then + echo "No matching profile artifact found." >&2 + exit 1 +fi + +echo "Opening ${TARGET}" + +case "${TARGET}" in + *.prof) + exec snakeviz "${TARGET}" + ;; + *memray*.bin|*.bin) + case "${VIEW}" in + leaks) exec memray flamegraph --leaks -f "${TARGET}" ;; + flamegraph|table) exec memray "${VIEW}" -f "${TARGET}" ;; + tree|stats|summary) exec memray "${VIEW}" "${TARGET}" ;; + *) echo "Unknown VIEW=${VIEW}" >&2; exit 1 ;; + esac + ;; + *.svg|*.html) + exec xdg-open "${TARGET}" + ;; + *) + echo "Don't know how to view ${TARGET}" >&2 + exit 1 + ;; +esac diff --git a/tests/perf/README.md b/tests/perf/README.md index b5f7918..7a9ebf7 100644 --- a/tests/perf/README.md +++ b/tests/perf/README.md @@ -67,6 +67,27 @@ Hunt leaks and allocation hot spots in the API / workers. memray flamegraph profiles/memray.bin ``` +## Viewing artifacts + +All profiling outputs land under `./profiles/`. Use the viewer wrapper to +auto-pick the newest file and launch the right tool: + +```bash +./scripts/profile/view.sh # newest artifact of any kind +./scripts/profile/view.sh cprofile # newest .prof -> snakeviz +./scripts/profile/view.sh memray # newest memray .bin -> flamegraph +./scripts/profile/view.sh pyinstrument # newest .html -> browser +./scripts/profile/view.sh path/to/file # explicit file + +# Memray view modes: +VIEW=flamegraph ./scripts/profile/view.sh memray # default +VIEW=table ./scripts/profile/view.sh memray +VIEW=tree ./scripts/profile/view.sh memray # terminal +VIEW=stats ./scripts/profile/view.sh memray # terminal summary +VIEW=summary ./scripts/profile/view.sh memray # top allocators +VIEW=leaks ./scripts/profile/view.sh memray # leak-filtered flamegraph +``` + ## Load generation Pair any of the in-process lenses (2, 5) with Locust for realistic traffic: