#!/usr/bin/env bash # # Runs ./build/nufi_poisson under `perf record`, then converts the # result into a flamegraph. Run this from the project root ("."). # # All profiling artifacts are written to ./results/perf/ set -euo pipefail # ---- config ----------------------------------------------------------- BINARY="./build/nufi_poisson" FLAMEGRAPH_DIR="${HOME}/.local/bin/FlameGraph" OUT_DIR="./results/perf" PERF_FREQ=99 # ---- checks ------------------------------------------------------------- if [[ ! -x "${BINARY}" ]]; then echo "error: ${BINARY} not found or not executable. Build the project first." >&2 exit 1 fi if [[ ! -x "${FLAMEGRAPH_DIR}/stackcollapse-perf.pl" ]] || [[ ! -x "${FLAMEGRAPH_DIR}/flamegraph.pl" ]]; then echo "error: FlameGraph scripts not found under ${FLAMEGRAPH_DIR}" >&2 exit 1 fi if ! command -v perf >/dev/null 2>&1; then echo "error: 'perf' not found on PATH." >&2 exit 1 fi PARANOID_PATH="/proc/sys/kernel/perf_event_paranoid" DESIRED_PARANOID="${PERF_EVENT_PARANOID:--1}" if [[ -r "${PARANOID_PATH}" ]]; then CURRENT_PARANOID="$(cat "${PARANOID_PATH}")" if [[ "${CURRENT_PARANOID}" -gt "${DESIRED_PARANOID}" ]]; then echo "==> kernel.perf_event_paranoid is ${CURRENT_PARANOID}, lowering to ${DESIRED_PARANOID} (needs sudo) ..." if ! sudo sysctl -w "kernel.perf_event_paranoid=${DESIRED_PARANOID}" >/dev/null; then echo "warning: could not lower kernel.perf_event_paranoid -- kernel symbols/call graphs may be incomplete." >&2 echo " you can set it manually with: sudo sysctl -w kernel.perf_event_paranoid=${DESIRED_PARANOID}" >&2 fi fi fi mkdir -p "${OUT_DIR}" PERF_DATA="${OUT_DIR}/perf.data" PERF_SCRIPT_OUT="${OUT_DIR}/out.perf" FOLDED_OUT="${OUT_DIR}/out.folded" FLAMEGRAPH_OUT="${OUT_DIR}/flamegraph.svg" # ---- run ---------------------------------------------------------------- echo "==> Recording with perf (-F ${PERF_FREQ}) ..." echo " (Ctrl+C stops the binary early and still runs the rest of the pipeline)" set +e trap '' SIGINT perf record -F "${PERF_FREQ}" -g -o "${PERF_DATA}" -- "${BINARY}" PERF_EXIT=$? trap - SIGINT set -e if [[ ${PERF_EXIT} -ne 0 ]]; then echo " (perf record exited with code ${PERF_EXIT}, likely from an interrupt -- continuing anyway)" fi if [[ ! -s "${PERF_DATA}" ]]; then echo "error: ${PERF_DATA} is missing or empty, nothing to process." >&2 exit 1 fi echo "==> Generating perf script output ..." perf script -i "${PERF_DATA}" > "${PERF_SCRIPT_OUT}" echo "==> Collapsing stacks ..." "${FLAMEGRAPH_DIR}/stackcollapse-perf.pl" "${PERF_SCRIPT_OUT}" > "${FOLDED_OUT}" echo "==> Building flamegraph ..." "${FLAMEGRAPH_DIR}/flamegraph.pl" "${FOLDED_OUT}" > "${FLAMEGRAPH_OUT}" echo "==> Done." echo " perf.data : ${PERF_DATA}" echo " out.perf : ${PERF_SCRIPT_OUT}" echo " out.folded : ${FOLDED_OUT}" echo " flamegraph : ${FLAMEGRAPH_OUT}"