#!/usr/bin/env bash # Enumerates GPUs that can report utilisation, with a readable name for each. # # Panama's vitals readout needs one specific sysfs file, and the card numbering # is neither stable across machines nor meaningful to a person: this box has # card1 and card2, both amdgpu, one discrete and one integrated. Picking a # number blindly shows whichever the kernel happened to enumerate first. # # Names come from lspci where available, because the sysfs device directory # exposes only numeric vendor/device ids. set -euo pipefail first=true printf '[' for busy in /sys/class/drm/card*/device/gpu_busy_percent; do [[ -r "$busy" ]] || continue device_dir="$(dirname "$busy")" card="$(basename "$(dirname "$device_dir")")" # The device directory is a symlink into the PCI tree; its target's basename # is the PCI address lspci wants. pci="$(basename "$(readlink -f "$device_dir")" 2>/dev/null || true)" name="" if [[ -n "$pci" ]] && command -v lspci >/dev/null 2>&1; then # Strip the leading domain: lspci -s wants 00:02.0, sysfs gives 0000:00:02.0 short="${pci#*:}" name="$(lspci -s "$short" 2>/dev/null | sed -E 's/^[^ ]+ [^:]+: //' | head -1)" fi if [[ -z "$name" ]]; then driver="$(sed -n 's/^DRIVER=//p' "$device_dir/uevent" 2>/dev/null | head -1)" name="${driver:-Graphics} ($card)" fi reading="$(cat "$busy" 2>/dev/null || printf '')" [[ "$reading" =~ ^[0-9]+$ ]] || reading=-1 [[ "$first" == true ]] || printf ',' first=false printf '{"card":"%s","path":"%s","name":%s,"busy":%s}' \ "$card" "$busy" "$(printf '%s' "$name" | jq -Rs .)" "$reading" done printf ']\n'