98 lines
2.5 KiB
Bash
Executable File
98 lines
2.5 KiB
Bash
Executable File
#!/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}"
|