Files
virtualjaguar-libretro/scripts/profile-mac.sh
Joseph MattielloandClaude Opus 4.7 28b56ce744 perf: add reusable perf_counters.h instrumentation system
Generalizes the ad-hoc BLITTER_PROFILE pattern into a reusable,
zero-overhead-when-off counter system any subsystem can use.

* src/core/perf_counters.{h,c} - PERF_COUNTER / PERF_INC / PERF_ADD
  macros backed by a constructor-registered linked list.  When
  BENCH_PROFILE is undefined every macro expands to (0) so there is
  no runtime, code-size, or symbol cost in shipped builds.

* src/tom/blitter.c - migrate the existing BLITTER_PROFILE counters
  in BlitterMidsummer2 onto the new system.  Counters are embedded in
  existing initializers via the comma operator so the file stays
  C89-clean (no statements before declarations).

* Makefile - `make BENCH_PROFILE=1` defines the macro globally.
  `make benchmark BENCH_PROFILE=1` re-invokes with TEST_EXPORTS=1 so
  test_benchmark can dlsym `perf_counters_dump` and print all
  registered counters next to the FPS report.

* test/tools/test_benchmark.c - dlsym the optional dump symbol; if
  present (BENCH_PROFILE build), call it before the BENCHMARK RESULTS
  block.  No effect on default builds.

* exports-test.list / link-test.T - add perf_counters_{dump,reset,
  register} so harnesses can reach them under TEST_EXPORTS=1.

* scripts/profile-mac.sh - one-line wrapper around `xctrace record`.
  Defaults to Time Profiler; --template "CPU Counters" for PMU
  events on Apple Silicon.  Builds the core + harness, runs the
  benchmark under instrumentation, writes a .trace bundle, and can
  auto-open it with --open.

* docs/profiling.md - new sections covering BENCH_PROFILE counters
  (when to use vs sampling profilers) and the profile-mac.sh wrapper.

Validated end-to-end with `make benchmark BENCH_PROFILE=1
BENCH_BLITTER=accurate`: counters populate
(blitter_inner=283994 over 120 frames of yarc), and default builds
remain unchanged.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-01 23:12:07 -04:00

82 lines
2.3 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# profile-mac.sh -- Run test_benchmark under Xcode Instruments on Apple Silicon
# (or any Mac with Xcode CLT).
#
# Usage:
# scripts/profile-mac.sh [--template NAME] [--frames N] [--warmup N]
# [--blitter fast|accurate] [--rom PATH] [--open]
#
# Defaults:
# template = "Time Profiler"
# frames = 600 warmup = 60 blitter = accurate
# rom = test/roms/yarc.j64
# --open = open the .trace bundle in Instruments when finished
#
# Common templates:
# "Time Profiler" -- where time is being spent (call tree / flame)
# "CPU Counters" -- Apple Silicon PMU (cycles, instr, branches, misses)
# "System Trace" -- syscalls, scheduler, VM events
#
set -euo pipefail
TEMPLATE="Time Profiler"
FRAMES=600
WARMUP=60
BLITTER=accurate
ROM="test/roms/yarc.j64"
OPEN_TRACE=0
while [ $# -gt 0 ]; do
case "$1" in
--template) TEMPLATE="$2"; shift 2 ;;
--frames) FRAMES="$2"; shift 2 ;;
--warmup) WARMUP="$2"; shift 2 ;;
--blitter) BLITTER="$2"; shift 2 ;;
--rom) ROM="$2"; shift 2 ;;
--open) OPEN_TRACE=1; shift ;;
-h|--help)
sed -n '2,20p' "$0"
exit 0 ;;
*)
echo "Unknown arg: $1" >&2
exit 2 ;;
esac
done
if ! command -v xctrace >/dev/null 2>&1; then
echo "xctrace not found. Install Xcode Command Line Tools: xcode-select --install" >&2
exit 1
fi
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
mkdir -p build
TRACE="build/profile-$(date +%Y%m%d-%H%M%S).trace"
# Make sure the core + harness are built (no BENCH_PROFILE; profiling
# instrumentation skews sampling results).
make -j"$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)" >/dev/null
cc -O2 -Wall -std=c99 -I. -I./libretro-common/include \
-o test/tools/test_benchmark test/tools/test_benchmark.c
CORE="./virtualjaguar_libretro.dylib"
HARNESS="./test/tools/test_benchmark"
echo ">>> xctrace template: $TEMPLATE"
echo ">>> trace output: $TRACE"
echo ">>> rom / blitter: $ROM / $BLITTER"
echo ">>> frames (+warmup): $FRAMES (+$WARMUP)"
xctrace record \
--template "$TEMPLATE" \
--output "$TRACE" \
--launch -- "$HARNESS" "$CORE" "$ROM" "$FRAMES" \
--warmup "$WARMUP" --blitter "$BLITTER"
echo ">>> trace written to $TRACE"
if [ "$OPEN_TRACE" = "1" ]; then
open "$TRACE"
fi