#!/bin/sh # perf.sh PID [SECONDS]: a process's cpu %, the cpu % of the commands it ran and waited for # (children), its gpu busy % per engine (drm fdinfo, xe and i915) and its resident memory # over SECONDS (default 10). cpu 100 % is one core pid=${1:?pid}; secs=${2:-10} sample() { # utime + stime in clock ticks, then engine cycles summed over every drm fd as "engine used total" awk '{print "cpu", $14 + $15, $16 + $17}' /proc/$pid/stat cat /proc/$pid/fdinfo/* 2>/dev/null | awk ' /^drm-cycles-/ {e=substr($1, 12); sub(":", "", e); used[e]+=$2} /^drm-total-cycles-/ {e=substr($1, 18); sub(":", "", e); total[e]=$2} /^drm-engine-[a-z]+:/ && $3 == "ns" {e=substr($1, 12); sub(":", "", e); ns[e]+=$2} END {for (e in used) print "cyc", e, used[e], total[e]; for (e in ns) print "ns", e, ns[e]}' } a=$(sample); start=$(date +%s%N); sleep "$secs"; b=$(sample); end=$(date +%s%N) printf '%s\n--\n%s\n' "$a" "$b" | awk -v tck="$(getconf CLK_TCK)" -v wall="$(( (end - start) / 1000 ))" ' $1 == "--" {second=1; next} $1 == "cpu" {if (second) {cpu1=$2; kid1=$3} else {cpu0=$2; kid0=$3}} $1 == "cyc" {if (second) {u1[$2]=$3; t1[$2]=$4} else {u0[$2]=$3; t0[$2]=$4}} $1 == "ns" {if (second) n1[$2]=$3; else n0[$2]=$3} END { printf "cpu %.1f %% children %.1f %%", (cpu1 - cpu0) / tck * 1e6 / wall * 100, (kid1 - kid0) / tck * 1e6 / wall * 100 for (e in u1) if (t1[e] > t0[e]) printf " %s %.2f %%", e, (u1[e] - u0[e]) / (t1[e] - t0[e]) * 100 for (e in n1) printf " %s %.2f %%", e, (n1[e] - n0[e]) / (wall * 1000) * 100 }' printf ' rss %s MiB\n' "$(awk '/^VmRSS/ {printf "%.0f", $2 / 1024}' /proc/$pid/status)"