diff options
| author | Danilo M. <danix@danix.xyz> | 2026-11-12 19:07:18 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-11-12 19:07:18 +0100 |
| commit | fda4e7847bb5dc985404269c81400eead52b0181 (patch) | |
| tree | 724fb032a3809c9cdde521775b4d4f28ce684c95 /desktop/modules/perf/gpu.sh | |
| parent | 13f04c0d3188f9f974986225486c01f91cd18701 (diff) | |
| download | quickshell-fda4e7847bb5dc985404269c81400eead52b0181.tar.gz quickshell-fda4e7847bb5dc985404269c81400eead52b0181.zip | |
xe exposes no busy percentage, but its DRM fdinfo carries per-engine
cycle counters. vram.sh becomes gpu.sh: the same scan also sums
drm-cycles-rcs/ccs per client and prints them with the GPU's cycle
counter, and Perf.js turns two scans into a percentage per engine.
The GPU card's headline is now the busier engine, with render (games)
and compute (local LLMs) as bars, then VRAM, temperature and fan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules/perf/gpu.sh')
| -rwxr-xr-x | desktop/modules/perf/gpu.sh | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/desktop/modules/perf/gpu.sh b/desktop/modules/perf/gpu.sh new file mode 100755 index 0000000..31f8a6e --- /dev/null +++ b/desktop/modules/perf/gpu.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# GPU from the fdinfo scan, every xe fd counted once per drm-client-id +# because a client holds several fds. Prints one line, "vram rcs_busy +# rcs_clock ccs_busy ccs_clock": VRAM in bytes (drm-resident-vram0), then +# per engine the busy cycles summed over clients and the GPU's cycle +# counter, which Perf.js turns into a percentage between two scans. rcs is +# render (games), ccs compute (local LLMs). Prints nothing when no xe +# client is found. With a file argument it reads that instead of scanning, +# for test_gpu.sh. +# +# Summed here rather than in JS: a process holding thousands of DRM fds +# makes the scan a few hundred KB, which is a lot of string churn to parse +# in QML every 2 s. It was moved here while chasing a GC underflow that +# turned out to be the sound OSD's createImageData (AGENTS.md), not this. +# +# Fds of a repeated client id with different values: the first one awk's +# for-in reaches counts, where Perf.js took the first in scan order. They +# share one client, so the values agree in practice. + +scan() { + if [ -n "$1" ]; then cat "$1" + else grep -sH -e '^drm-driver' -e '^drm-client-id' -e '^drm-resident-vram0' \ + -e '^drm-cycles-[rc]cs' -e '^drm-total-cycles-[rc]cs' \ + /proc/[0-9]*/fdinfo/* 2>/dev/null + fi +} + +scan "$1" | awk -F: ' + NF >= 3 && $2 ~ /^drm-/ { + v = $3 + for (i = 4; i <= NF; i++) v = v ":" $i + sub(/^[ \t]+/, "", v) + d[$1, $2] = v + fd[$1] + } + END { + for (p in fd) { + id = d[p, "drm-client-id"] + if (d[p, "drm-driver"] != "xe" || id == "" || (id in seen)) continue + if (split(d[p, "drm-resident-vram0"], n, " ") < 1 || n[1] !~ /^[0-9]+$/) continue + for (i = 1; i <= 2; i++) { + e = i == 1 ? "rcs" : "ccs" + busy[e] += d[p, "drm-cycles-" e] + c = d[p, "drm-total-cycles-" e] + 0 + if (c > clock[e]) clock[e] = c + } + seen[id] + u = n[2] == "KiB" ? 1024 : n[2] == "MiB" ? 1048576 : n[2] == "GiB" ? 1073741824 : 1 + total += n[1] * u + any = 1 + } + if (any) printf "%.0f %.0f %.0f %.0f %.0f\n", total, busy["rcs"], clock["rcs"], busy["ccs"], clock["ccs"] + }' |
