#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: profile-daily-loop.sh --pid PID [--seconds N] [--output-dir DIR] [--flamegraph-dir DIR] Attaches perf to an existing FIDC runner process. It never starts, stops, or restarts a service. The allocation report is a CPU-sample proxy for allocator pressure; it is not an allocation count or byte-accurate heap profile. EOF } pid="" seconds=15 output_dir="" flamegraph_dir="" while [[ $# -gt 0 ]]; do case "$1" in --pid) pid="${2:-}" shift 2 ;; --seconds) seconds="${2:-}" shift 2 ;; --output-dir) output_dir="${2:-}" shift 2 ;; --flamegraph-dir) flamegraph_dir="${2:-}" shift 2 ;; -h|--help) usage exit 0 ;; *) echo "unknown argument: $1" >&2 usage >&2 exit 2 ;; esac done if [[ "${EUID}" -ne 0 ]]; then echo "run as root so perf can attach to the runner" >&2 exit 2 fi if [[ ! "${pid}" =~ ^[1-9][0-9]*$ ]]; then echo "--pid must be a positive process id" >&2 exit 2 fi if [[ ! "${seconds}" =~ ^[1-9][0-9]*$ ]]; then echo "--seconds must be a positive integer" >&2 exit 2 fi if ! kill -0 "${pid}" 2>/dev/null; then echo "process is not running: ${pid}" >&2 exit 1 fi if ! command -v perf >/dev/null 2>&1; then echo "perf is required" >&2 exit 2 fi if [[ -z "${output_dir}" ]]; then output_dir="$(pwd)/profile-$(date +%Y%m%d-%H%M%S)-${pid}" fi mkdir -p "${output_dir}" perf record --quiet --call-graph dwarf -g -e cycles:P -p "${pid}" \ -o "${output_dir}/perf.data" -- sleep "${seconds}" perf report --stdio --no-children --sort symbol --percent-limit 0.5 \ -i "${output_dir}/perf.data" > "${output_dir}/perf-report.txt" grep -E 'malloc|calloc|realloc|free|cfree|drop_glue' "${output_dir}/perf-report.txt" \ > "${output_dir}/allocation-samples.txt" || true if [[ -n "${flamegraph_dir}" ]]; then if [[ ! -x "${flamegraph_dir}/stackcollapse-perf.pl" || ! -x "${flamegraph_dir}/flamegraph.pl" ]]; then echo "flamegraph tools not found under ${flamegraph_dir}" >&2 exit 2 fi perf script -i "${output_dir}/perf.data" > "${output_dir}/perf.script" "${flamegraph_dir}/stackcollapse-perf.pl" "${output_dir}/perf.script" \ > "${output_dir}/daily-loop.folded" "${flamegraph_dir}/flamegraph.pl" \ --title="FIDC engine daily loop CPU samples" \ "${output_dir}/daily-loop.folded" > "${output_dir}/daily-loop-flamegraph.svg" fi printf '%s\n' "profile complete: ${output_dir}"