Auto-select the gaming GPU + cross-vendor CPU-power tooling
MangoHud logs one GPU. On a hybrid box (discrete NVIDIA/AMD beside an AMD/Intel iGPU) its default often latches onto the idle iGPU, so every gpu_* column reads ~0 while the discrete card does the rendering. Detect the actual gaming GPU — any vendor, single- or multi-GPU — and pin it via gpu_list. Selection: single GPU -> that one; discrete NVIDIA preferred; otherwise the card with the most VRAM. Override with MANGOHUD_LOGGER_GPU. Verified against MangoHud's own enumeration (gpu_list=0 -> renderD128, RTX 5060 Ti) and 7 synthetic layouts incl. NVIDIA as the second node. Also make CPU telemetry work across AMD and Intel. cpu_power was logging 0 because the RAPL energy counters are root-only since CVE-2020-8694 (same intel-rapl powercap path on both vendors). Add: - doctor: read-only GPU/CPU telemetry readiness report - fix-cpu-power: install a udev rule making RAPL counters user-readable - enable-time warnings pointing at the fix CPU temp already works via hwmon (k10temp/zenpower/coretemp). Default no-arg behavior (toggle on/off) is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
aeb84a3d68
commit
551471f0b3
2 changed files with 388 additions and 12 deletions
83
README.md
83
README.md
|
|
@ -21,8 +21,9 @@ won't trample anything you wrote by hand):
|
||||||
|
|
||||||
1. **`~/.config/MangoHud/MangoHud.conf`** — appends a marker-bracketed block
|
1. **`~/.config/MangoHud/MangoHud.conf`** — appends a marker-bracketed block
|
||||||
with `output_folder`, `autostart_log=1`, `log_duration=0` (= until you
|
with `output_folder`, `autostart_log=1`, `log_duration=0` (= until you
|
||||||
quit), `log_interval=100`, `toggle_logging=Shift_L+F2`, and a
|
quit), `log_interval=100`, `toggle_logging=Shift_L+F2`, a `no_display=0`
|
||||||
`no_display=0` override. (Also serves as the on/off state marker.)
|
override, and a `gpu_list=<index>` pin (see [GPU selection](#gpu-selection)).
|
||||||
|
(Also serves as the on/off state marker.)
|
||||||
|
|
||||||
2. **`~/.config/environment.d/95-mangohud-logger.conf`** — contains:
|
2. **`~/.config/environment.d/95-mangohud-logger.conf`** — contains:
|
||||||
- `MANGOHUD=1` so the Vulkan loader auto-injects MangoHud into every game.
|
- `MANGOHUD=1` so the Vulkan loader auto-injects MangoHud into every game.
|
||||||
|
|
@ -39,6 +40,40 @@ won't trample anything you wrote by hand):
|
||||||
|
|
||||||
When you toggle it off, the script removes everything it wrote.
|
When you toggle it off, the script removes everything it wrote.
|
||||||
|
|
||||||
|
## GPU selection
|
||||||
|
|
||||||
|
MangoHud logs stats for **one** GPU. On a hybrid machine — a discrete
|
||||||
|
NVIDIA/AMD card alongside an AMD/Intel iGPU (common on modern AMD desktops,
|
||||||
|
laptops, and handhelds) — MangoHud's default frequently latches onto the *idle*
|
||||||
|
iGPU, so every `gpu_*` column in the CSV reads ~0 (0 % load, idle clocks, idle
|
||||||
|
power) even while the discrete card does all the rendering.
|
||||||
|
|
||||||
|
On enable, the script auto-detects the GPU that's actually rendering games and
|
||||||
|
pins MangoHud to it with `gpu_list=<index>`. It's **vendor-agnostic**:
|
||||||
|
|
||||||
|
- **Single GPU** (any vendor) → that GPU.
|
||||||
|
- **Discrete NVIDIA** present → the NVIDIA card.
|
||||||
|
- **Two AMD/Intel GPUs** → the one with the most VRAM (the discrete card;
|
||||||
|
iGPUs report little or none).
|
||||||
|
|
||||||
|
It works by mapping DRM render nodes (`renderD128`, `renderD129`, …) to
|
||||||
|
MangoHud's `gpu_list` index order. The chosen GPU is printed on enable:
|
||||||
|
|
||||||
|
```
|
||||||
|
:: gpu logged: gpu_list=0 → renderD128 (NVIDIA), 2 GPU(s) detected
|
||||||
|
```
|
||||||
|
|
||||||
|
If the guess is wrong, override it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
MANGOHUD_LOGGER_GPU=amd ./mangohud-logger.sh # or: nvidia | intel
|
||||||
|
MANGOHUD_LOGGER_GPU=1 ./mangohud-logger.sh # or an explicit gpu_list index
|
||||||
|
```
|
||||||
|
|
||||||
|
> **NVIDIA note:** MangoHud reads NVIDIA load/power/clocks via NVML. If NVML
|
||||||
|
> (`libnvidia-ml`, shipped with `nvidia-utils`) is missing, the script warns you
|
||||||
|
> — without it the NVIDIA `gpu_*` columns stay at 0.
|
||||||
|
|
||||||
## Session-flavor detection
|
## Session-flavor detection
|
||||||
|
|
||||||
Game Mode is launched differently on different distros, and the fix differs
|
Game Mode is launched differently on different distros, and the fix differs
|
||||||
|
|
@ -140,13 +175,30 @@ mangohud-logger
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./mangohud-logger.sh
|
./mangohud-logger.sh # toggle logging on/off (default)
|
||||||
|
./mangohud-logger.sh doctor # report GPU/CPU telemetry readiness (no changes)
|
||||||
|
./mangohud-logger.sh fix-cpu-power # make RAPL CPU-power counters readable (sudo)
|
||||||
|
./mangohud-logger.sh help # usage
|
||||||
```
|
```
|
||||||
|
|
||||||
No flags, no subcommands. First run enables; second run disables. After the
|
Run with no argument to toggle: first run enables, second disables. After the
|
||||||
first enable, **log out and back in** (Game Mode users: fully restart into Game
|
first enable, **log out and back in** (Game Mode users: fully restart into Game
|
||||||
Mode) so the env vars become effective. You only need to do that once.
|
Mode) so the env vars become effective. You only need to do that once.
|
||||||
|
|
||||||
|
Before your first benchmark, run `doctor` — it tells you exactly which columns
|
||||||
|
will hold real data and what (if anything) needs fixing:
|
||||||
|
|
||||||
|
```
|
||||||
|
:: GPUs (DRM render nodes):
|
||||||
|
renderD128 (NVIDIA)
|
||||||
|
renderD129 (AMD)
|
||||||
|
✓ will log: gpu_list=0 → renderD128 (NVIDIA), 2 GPU(s) detected
|
||||||
|
✓ NVML present → NVIDIA load/power/clocks will log
|
||||||
|
:: CPU: AMD
|
||||||
|
✓ temp source: hwmon 'k10temp' → cpu_temp will log
|
||||||
|
! power (RAPL): root-only → cpu_power = 0. Fix: mangohud-logger.sh fix-cpu-power
|
||||||
|
```
|
||||||
|
|
||||||
In-game keys (set by the script's MangoHud block):
|
In-game keys (set by the script's MangoHud block):
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|
|
@ -157,6 +209,29 @@ In-game keys (set by the script's MangoHud block):
|
||||||
CSV files appear in `~/Downloads/mango-logs/`. Drop them into
|
CSV files appear in `~/Downloads/mango-logs/`. Drop them into
|
||||||
<https://flightlessmango.com/> for graphs, or open in a spreadsheet.
|
<https://flightlessmango.com/> for graphs, or open in a spreadsheet.
|
||||||
|
|
||||||
|
## CPU power (`cpu_power` column reads 0?)
|
||||||
|
|
||||||
|
MangoHud reads CPU package power from the RAPL powercap energy counters. Since
|
||||||
|
CVE-2020-8694 those counters are **root-only** (mode `0400`), so user-mode
|
||||||
|
MangoHud can't read them and `cpu_power` logs as `0`. This is the same on **AMD
|
||||||
|
and Intel** — the powercap interface is named `intel-rapl` on both (it's the
|
||||||
|
framework name; on AMD `intel_rapl_msr` feeds it from the Zen RAPL MSRs).
|
||||||
|
|
||||||
|
`fix-cpu-power` installs a udev rule
|
||||||
|
(`/etc/udev/rules.d/60-mangohud-logger-rapl.rules`) that makes `energy_uj`
|
||||||
|
user-readable, and applies it immediately:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./mangohud-logger.sh fix-cpu-power
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Security note:** this re-exposes the low-severity PLATYPUS power
|
||||||
|
> side-channel. Fine for a personal gaming/benchmark box; skip it on shared or
|
||||||
|
> multi-user machines. Remove the rule file to revert.
|
||||||
|
|
||||||
|
CPU **temperature** needs no fix — it comes from hwmon (`k10temp`/`zenpower` on
|
||||||
|
AMD, `coretemp` on Intel) and works out of the box.
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
- **SteamOS Game Mode** (`/usr/lib/steamos/gamescope-session`) — logs via
|
- **SteamOS Game Mode** (`/usr/lib/steamos/gamescope-session`) — logs via
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,20 @@
|
||||||
# → appends a marker block with output_folder, autostart_log, etc.
|
# → appends a marker block with output_folder, autostart_log, etc.
|
||||||
# → keeps your existing keys; overrides `no_display` while logging
|
# → keeps your existing keys; overrides `no_display` while logging
|
||||||
# (autostart_log rides on the render hook that no_display disables).
|
# (autostart_log rides on the render hook that no_display disables).
|
||||||
|
# → pins gpu_list to the GPU actually rendering games (see below), so the
|
||||||
|
# gpu_* columns log real data instead of an idle second GPU.
|
||||||
# 2. ~/.config/environment.d/95-mangohud-logger.conf
|
# 2. ~/.config/environment.d/95-mangohud-logger.conf
|
||||||
# → contains MANGOHUD=1 so the Vulkan layer auto-loads into every
|
# → contains MANGOHUD=1 so the Vulkan layer auto-loads into every
|
||||||
# game (gamescope sessions, Steam, native Vulkan apps).
|
# game (gamescope sessions, Steam, native Vulkan apps).
|
||||||
# Picked up by systemd-user at next session login.
|
# Picked up by systemd-user at next session login.
|
||||||
#
|
#
|
||||||
|
# GPU selection (vendor-agnostic):
|
||||||
|
# MangoHud logs stats for ONE GPU. On a hybrid box (an AMD/Intel iGPU beside a
|
||||||
|
# discrete NVIDIA/AMD card) its default often picks the idle iGPU, so every
|
||||||
|
# gpu_* column reads ~0. We auto-detect the render node that's the actual
|
||||||
|
# gaming GPU — any vendor — and pin `gpu_list` to its index. Override with
|
||||||
|
# MANGOHUD_LOGGER_GPU=<index> or =nvidia|amd|intel if the guess is wrong.
|
||||||
|
#
|
||||||
# Logs land in the user's Downloads folder under "mango-logs"
|
# Logs land in the user's Downloads folder under "mango-logs"
|
||||||
# (honours XDG_DOWNLOAD_DIR from ~/.config/user-dirs.dirs, else ~/Downloads).
|
# (honours XDG_DOWNLOAD_DIR from ~/.config/user-dirs.dirs, else ~/Downloads).
|
||||||
|
|
||||||
|
|
@ -75,15 +84,269 @@ info() { printf '\033[36m::\033[0m %s\n' "$*"; }
|
||||||
ok() { printf '\033[32m✓\033[0m %s\n' "$*"; }
|
ok() { printf '\033[32m✓\033[0m %s\n' "$*"; }
|
||||||
warn() { printf '\033[33m!\033[0m %s\n' "$*"; }
|
warn() { printf '\033[33m!\033[0m %s\n' "$*"; }
|
||||||
|
|
||||||
if ! command -v mangohud >/dev/null 2>&1; then
|
# PCI vendor IDs (as reported by /sys/class/drm/*/device/vendor).
|
||||||
err "mangohud is not installed — install it first (e.g. 'sudo pacman -S mangohud lib32-mangohud')."
|
readonly VENDOR_NVIDIA=0x10de
|
||||||
exit 1
|
readonly VENDOR_AMD=0x1002
|
||||||
fi
|
readonly VENDOR_INTEL=0x8086
|
||||||
|
|
||||||
mkdir -p "$CONFIG_DIR"
|
# select_gpu — figure out which GPU MangoHud should log, vendor-agnostically.
|
||||||
[[ -f "$CONFIG_FILE" ]] || : > "$CONFIG_FILE"
|
#
|
||||||
|
# MangoHud enumerates DRM render nodes (renderD128, renderD129, …) in ascending
|
||||||
|
# order and `gpu_list=<n>` selects the n-th of them (verified: gpu_list=0 maps to
|
||||||
|
# renderD128). We pick the node that's the real gaming GPU and return its index.
|
||||||
|
#
|
||||||
|
# Selection order:
|
||||||
|
# 1. MANGOHUD_LOGGER_GPU override — a numeric index, or nvidia|amd|intel.
|
||||||
|
# 2. Single GPU → index 0 (covers every single-card machine, any vendor).
|
||||||
|
# 3. Multi-GPU → prefer a discrete NVIDIA; else the card with the most VRAM
|
||||||
|
# (discrete AMD/Intel report mem_info_vram_total; iGPUs report far less/none).
|
||||||
|
#
|
||||||
|
# Sets globals: GPU_INDEX (may be ""), GPU_VENDOR, GPU_DESC.
|
||||||
|
select_gpu() {
|
||||||
|
GPU_INDEX=""; GPU_VENDOR=""; GPU_DESC=""
|
||||||
|
|
||||||
if grep -qF "$MARKER_BEGIN" "$CONFIG_FILE"; then
|
local nodes=()
|
||||||
|
mapfile -t nodes < <(
|
||||||
|
for n in /sys/class/drm/renderD*; do
|
||||||
|
[[ -e "$n/device/vendor" ]] && basename "$n"
|
||||||
|
done | sort # ascending == MangoHud's gpu_list index order
|
||||||
|
)
|
||||||
|
|
||||||
|
local count=${#nodes[@]}
|
||||||
|
if (( count == 0 )); then
|
||||||
|
GPU_DESC="no DRM render node found (software renderer?) — gpu_list left unset"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Index-aligned vendor + VRAM for each node.
|
||||||
|
local vendors=() vrams=() i
|
||||||
|
for i in "${!nodes[@]}"; do
|
||||||
|
vendors[i]=$(cat "/sys/class/drm/${nodes[i]}/device/vendor" 2>/dev/null || echo unknown)
|
||||||
|
vrams[i]=$(cat "/sys/class/drm/${nodes[i]}/device/mem_info_vram_total" 2>/dev/null || echo 0)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "${MANGOHUD_LOGGER_GPU:-}" ]]; then
|
||||||
|
local ov="${MANGOHUD_LOGGER_GPU,,}"
|
||||||
|
if [[ "$ov" =~ ^[0-9]+$ ]]; then
|
||||||
|
GPU_INDEX="$ov"
|
||||||
|
else
|
||||||
|
local want=""
|
||||||
|
case "$ov" in
|
||||||
|
nvidia) want=$VENDOR_NVIDIA ;;
|
||||||
|
amd) want=$VENDOR_AMD ;;
|
||||||
|
intel) want=$VENDOR_INTEL ;;
|
||||||
|
esac
|
||||||
|
for i in "${!nodes[@]}"; do
|
||||||
|
[[ "${vendors[i]}" == "$want" ]] && { GPU_INDEX="$i"; break; }
|
||||||
|
done
|
||||||
|
[[ -z "$GPU_INDEX" ]] && GPU_INDEX=0 # requested vendor absent → first GPU
|
||||||
|
fi
|
||||||
|
elif (( count == 1 )); then
|
||||||
|
GPU_INDEX=0
|
||||||
|
else
|
||||||
|
# Prefer discrete NVIDIA (NVIDIA never populates mem_info_vram_total via DRM
|
||||||
|
# sysfs, so the VRAM check below can't see it — hence this explicit pass).
|
||||||
|
for i in "${!nodes[@]}"; do
|
||||||
|
[[ "${vendors[i]}" == "$VENDOR_NVIDIA" ]] && { GPU_INDEX="$i"; break; }
|
||||||
|
done
|
||||||
|
if [[ -z "$GPU_INDEX" ]]; then
|
||||||
|
local best=0 bestvram=-1
|
||||||
|
for i in "${!nodes[@]}"; do
|
||||||
|
if (( ${vrams[i]:-0} > bestvram )); then bestvram=${vrams[i]:-0}; best=$i; fi
|
||||||
|
done
|
||||||
|
GPU_INDEX="$best"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Describe the choice (guard against an out-of-range manual override).
|
||||||
|
local node="${nodes[$GPU_INDEX]:-?}" vsel="${vendors[$GPU_INDEX]:-unknown}" name
|
||||||
|
case "$vsel" in
|
||||||
|
"$VENDOR_NVIDIA") name=NVIDIA ;;
|
||||||
|
"$VENDOR_AMD") name=AMD ;;
|
||||||
|
"$VENDOR_INTEL") name=Intel ;;
|
||||||
|
*) name="vendor $vsel" ;;
|
||||||
|
esac
|
||||||
|
GPU_VENDOR="$vsel"
|
||||||
|
GPU_DESC="gpu_list=$GPU_INDEX → $node ($name), $count GPU(s) detected"
|
||||||
|
}
|
||||||
|
|
||||||
|
# libnvidia-ml (NVML) is what lets MangoHud read NVIDIA load/power/clocks.
|
||||||
|
have_nvml() {
|
||||||
|
ldconfig -p 2>/dev/null | grep -q 'libnvidia-ml' \
|
||||||
|
|| [[ -e /usr/lib/libnvidia-ml.so.1 || -e /usr/lib64/libnvidia-ml.so.1 ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── CPU telemetry (vendor-neutral: works on AMD *and* Intel) ────────────────
|
||||||
|
#
|
||||||
|
# MangoHud reads CPU temperature from hwmon and CPU package power from the RAPL
|
||||||
|
# powercap energy counters. Both paths are the same regardless of CPU vendor:
|
||||||
|
# • temp → hwmon driver: k10temp/zenpower (AMD), coretemp (Intel)
|
||||||
|
# • power → /sys/class/powercap/intel-rapl:* — despite the "intel" name this is
|
||||||
|
# the powercap *framework*; on AMD it's fed by intel_rapl_msr from the Zen
|
||||||
|
# RAPL MSRs. Since CVE-2020-8694 the energy_uj files are root-only (0400),
|
||||||
|
# so user-mode MangoHud can't read them and cpu_power logs as 0.
|
||||||
|
|
||||||
|
readonly RAPL_UDEV_FILE=/etc/udev/rules.d/60-mangohud-logger-rapl.rules
|
||||||
|
|
||||||
|
# cpu_vendor → AMD | Intel | <raw string>
|
||||||
|
cpu_vendor() {
|
||||||
|
local v; v=$(awk -F': ' '/^vendor_id/{print $2; exit}' /proc/cpuinfo 2>/dev/null)
|
||||||
|
case "$v" in
|
||||||
|
AuthenticAMD) echo AMD ;;
|
||||||
|
GenuineIntel) echo Intel ;;
|
||||||
|
*) echo "${v:-unknown}" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# First RAPL package energy counter (enough to gate on), else empty.
|
||||||
|
rapl_energy_file() { compgen -G '/sys/class/powercap/*rapl*/energy_uj' 2>/dev/null | head -1; }
|
||||||
|
|
||||||
|
# rapl_state → readable | denied | absent
|
||||||
|
rapl_state() {
|
||||||
|
local f; f=$(rapl_energy_file)
|
||||||
|
[[ -z "$f" ]] && { echo absent; return; }
|
||||||
|
if cat "$f" >/dev/null 2>&1; then echo readable; else echo denied; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# cpu_temp_source → hwmon 'name' providing CPU temp (any vendor), else empty.
|
||||||
|
cpu_temp_source() {
|
||||||
|
local h n
|
||||||
|
for h in /sys/class/hwmon/hwmon*; do
|
||||||
|
n=$(cat "$h/name" 2>/dev/null) || continue
|
||||||
|
case "$n" in
|
||||||
|
k10temp|zenpower|zenpower3|coretemp|k8temp) echo "$n"; return ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# do_fix_cpu_power — install a udev rule making RAPL energy counters readable so
|
||||||
|
# MangoHud can log cpu_power. Vendor-neutral (same RAPL path on AMD and Intel).
|
||||||
|
do_fix_cpu_power() {
|
||||||
|
local vend; vend=$(cpu_vendor)
|
||||||
|
info "CPU power ($vend) comes from RAPL energy counters, root-only since CVE-2020-8694."
|
||||||
|
info "This installs a udev rule so they're user-readable and MangoHud can log cpu_power."
|
||||||
|
warn "Security note: re-exposes the low-severity PLATYPUS power side-channel."
|
||||||
|
warn "Fine for a personal gaming/benchmark box; skip on shared/multi-user machines."
|
||||||
|
echo
|
||||||
|
|
||||||
|
case "$(rapl_state)" in
|
||||||
|
absent)
|
||||||
|
err "no RAPL powercap interface found."
|
||||||
|
info "try: sudo modprobe intel_rapl_msr (then re-run)"
|
||||||
|
return 1 ;;
|
||||||
|
readable)
|
||||||
|
ok "RAPL energy counters are already user-readable — nothing to do."
|
||||||
|
return 0 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
local chmod_bin; chmod_bin=$(command -v chmod || echo /usr/bin/chmod)
|
||||||
|
# KERNEL match covers the package (intel-rapl:0) and its subzones (intel-rapl:0:0).
|
||||||
|
# %S%p resolves to the node's /sys path; we chmod its energy_uj attribute.
|
||||||
|
local rule="SUBSYSTEM==\"powercap\", KERNEL==\"intel-rapl:*\", RUN+=\"$chmod_bin 0444 %S%p/energy_uj\""
|
||||||
|
|
||||||
|
info "writing $RAPL_UDEV_FILE (sudo)…"
|
||||||
|
if ! printf '%s\n' \
|
||||||
|
"# Installed by mangohud-logger: make RAPL energy_uj user-readable for CPU-power logging." \
|
||||||
|
"# Remove this file to revert. See: mangohud-logger help" \
|
||||||
|
"$rule" | sudo tee "$RAPL_UDEV_FILE" >/dev/null; then
|
||||||
|
err "failed to write $RAPL_UDEV_FILE"; return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo udevadm control --reload-rules 2>/dev/null || true
|
||||||
|
sudo udevadm trigger --subsystem-match=powercap 2>/dev/null || true
|
||||||
|
# Apply to already-present nodes now (udev 'add' won't re-fire for existing ones).
|
||||||
|
sudo "$chmod_bin" -f 0444 /sys/class/powercap/*rapl*/energy_uj 2>/dev/null || true
|
||||||
|
|
||||||
|
if [[ "$(rapl_state)" == readable ]]; then
|
||||||
|
ok "done — cpu_power will now be logged (persists across reboots)."
|
||||||
|
else
|
||||||
|
warn "rule installed but counters still not readable; a reboot should apply it."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# do_doctor — report cross-vendor telemetry readiness; makes no changes.
|
||||||
|
do_doctor() {
|
||||||
|
info "mangohud-logger doctor — telemetry readiness (read-only)"
|
||||||
|
echo
|
||||||
|
if command -v mangohud >/dev/null 2>&1; then
|
||||||
|
ok "mangohud: $(mangohud --version 2>/dev/null | head -1)"
|
||||||
|
else
|
||||||
|
err "mangohud: NOT installed"
|
||||||
|
fi
|
||||||
|
info "session flavor: $GS_FLAVOR"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# GPUs — list every render node, then the one that will be logged.
|
||||||
|
info "GPUs (DRM render nodes):"
|
||||||
|
local n vend name
|
||||||
|
for n in $(compgen -G '/sys/class/drm/renderD*' 2>/dev/null | sort); do
|
||||||
|
[[ -e "$n/device/vendor" ]] || continue
|
||||||
|
vend=$(cat "$n/device/vendor" 2>/dev/null)
|
||||||
|
case "$vend" in
|
||||||
|
"$VENDOR_NVIDIA") name=NVIDIA ;; "$VENDOR_AMD") name=AMD ;;
|
||||||
|
"$VENDOR_INTEL") name=Intel ;; *) name="vendor $vend" ;;
|
||||||
|
esac
|
||||||
|
printf ' %s (%s)\n' "$(basename "$n")" "$name"
|
||||||
|
done
|
||||||
|
select_gpu
|
||||||
|
if [[ -n "$GPU_INDEX" ]]; then ok "will log: $GPU_DESC"
|
||||||
|
else warn "will log: $GPU_DESC"; fi
|
||||||
|
if [[ "$GPU_VENDOR" == "$VENDOR_NVIDIA" ]]; then
|
||||||
|
if have_nvml; then ok " NVML present → NVIDIA load/power/clocks will log"
|
||||||
|
else err " NVML missing → NVIDIA gpu_* columns will be 0 (install nvidia-utils)"; fi
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# CPU — temp + power, vendor-neutral.
|
||||||
|
info "CPU: $(cpu_vendor)"
|
||||||
|
local ts; ts=$(cpu_temp_source)
|
||||||
|
if [[ -n "$ts" ]]; then ok " temp source: hwmon '$ts' → cpu_temp will log"
|
||||||
|
else warn " temp: no known sensor (k10temp/zenpower/coretemp) → cpu_temp may be 0"; fi
|
||||||
|
case "$(rapl_state)" in
|
||||||
|
readable) ok " power (RAPL): readable → cpu_power will log" ;;
|
||||||
|
denied) warn " power (RAPL): root-only → cpu_power = 0. Fix: $(basename "$0") fix-cpu-power" ;;
|
||||||
|
absent) warn " power (RAPL): no powercap interface → cpu_power = 0 (modprobe intel_rapl_msr)" ;;
|
||||||
|
esac
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [[ -f "$CONFIG_FILE" ]] && grep -qF "$MARKER_BEGIN" "$CONFIG_FILE"; then
|
||||||
|
ok "logging is currently ENABLED (log folder: $LOG_DIR)"
|
||||||
|
else
|
||||||
|
info "logging is currently disabled — run '$(basename "$0")' to enable"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
mangohud-logger — toggle MangoHud CSV logging, with cross-vendor telemetry setup
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
$(basename "$0") Toggle logging on/off (default action)
|
||||||
|
$(basename "$0") doctor Report GPU/CPU telemetry readiness (no changes)
|
||||||
|
$(basename "$0") fix-cpu-power Make RAPL CPU-power counters user-readable (sudo)
|
||||||
|
$(basename "$0") help Show this help
|
||||||
|
|
||||||
|
ENVIRONMENT:
|
||||||
|
MANGOHUD_LOGGER_GPU=<index|nvidia|amd|intel>
|
||||||
|
Force which GPU MangoHud logs (default: auto —
|
||||||
|
prefers the discrete gaming GPU, any vendor)
|
||||||
|
|
||||||
|
Works across AMD/Intel CPUs and NVIDIA/AMD/Intel GPUs, single- or multi-GPU.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# do_toggle — the original enable/disable behavior (default action).
|
||||||
|
do_toggle() {
|
||||||
|
if ! command -v mangohud >/dev/null 2>&1; then
|
||||||
|
err "mangohud is not installed — install it first (e.g. 'sudo pacman -S mangohud lib32-mangohud')."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$CONFIG_DIR"
|
||||||
|
[[ -f "$CONFIG_FILE" ]] || : > "$CONFIG_FILE"
|
||||||
|
|
||||||
|
if grep -qF "$MARKER_BEGIN" "$CONFIG_FILE"; then
|
||||||
# Currently enabled → strip the block and remove the env file.
|
# Currently enabled → strip the block and remove the env file.
|
||||||
tmp=$(mktemp)
|
tmp=$(mktemp)
|
||||||
awk -v b="$MARKER_BEGIN" -v e="$MARKER_END" '
|
awk -v b="$MARKER_BEGIN" -v e="$MARKER_END" '
|
||||||
|
|
@ -121,10 +384,13 @@ else
|
||||||
# Currently disabled → append the config block + write the env file.
|
# Currently disabled → append the config block + write the env file.
|
||||||
# Check for pre-existing manual log keys *before* we write, so the warning is accurate.
|
# Check for pre-existing manual log keys *before* we write, so the warning is accurate.
|
||||||
manual_log_keys=0
|
manual_log_keys=0
|
||||||
if grep -qE '^\s*(output_folder|autostart_log|log_duration|log_interval|toggle_logging)\s*=' "$CONFIG_FILE"; then
|
if grep -qE '^\s*(output_folder|autostart_log|log_duration|log_interval|toggle_logging|gpu_list)\s*=' "$CONFIG_FILE"; then
|
||||||
manual_log_keys=1
|
manual_log_keys=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Work out which GPU to log (any vendor, single- or multi-GPU) before writing.
|
||||||
|
select_gpu
|
||||||
|
|
||||||
mkdir -p "$LOG_DIR"
|
mkdir -p "$LOG_DIR"
|
||||||
{
|
{
|
||||||
[[ -s "$CONFIG_FILE" ]] && printf '\n'
|
[[ -s "$CONFIG_FILE" ]] && printf '\n'
|
||||||
|
|
@ -138,6 +404,9 @@ else
|
||||||
# Override any earlier `no_display` — MangoHud's autostart_log rides on the
|
# Override any earlier `no_display` — MangoHud's autostart_log rides on the
|
||||||
# render hook, which `no_display` disables. Without this, logs never start.
|
# render hook, which `no_display` disables. Without this, logs never start.
|
||||||
printf 'no_display=0\n'
|
printf 'no_display=0\n'
|
||||||
|
# Pin the GPU MangoHud logs to the actual gaming GPU (see select_gpu). Omitted
|
||||||
|
# only when no render node was found, so MangoHud keeps its own default.
|
||||||
|
[[ -n "$GPU_INDEX" ]] && printf 'gpu_list=%s\n' "$GPU_INDEX"
|
||||||
printf '%s\n' "$MARKER_END"
|
printf '%s\n' "$MARKER_END"
|
||||||
} >> "$CONFIG_FILE"
|
} >> "$CONFIG_FILE"
|
||||||
|
|
||||||
|
|
@ -147,6 +416,7 @@ else
|
||||||
# but it never sets MANGOHUD_CONFIG, so ours (from environment.d) wins for every game.
|
# but it never sets MANGOHUD_CONFIG, so ours (from environment.d) wins for every game.
|
||||||
# NOTE: relies on output_folder having no commas/spaces (true for the default path).
|
# NOTE: relies on output_folder having no commas/spaces (true for the default path).
|
||||||
MH_INLINE="output_folder=$LOG_DIR,autostart_log=1,log_duration=0,log_interval=100,toggle_logging=Shift_L+F2,no_display=0"
|
MH_INLINE="output_folder=$LOG_DIR,autostart_log=1,log_duration=0,log_interval=100,toggle_logging=Shift_L+F2,no_display=0"
|
||||||
|
[[ -n "$GPU_INDEX" ]] && MH_INLINE+=",gpu_list=$GPU_INDEX"
|
||||||
|
|
||||||
mkdir -p "$ENV_DIR"
|
mkdir -p "$ENV_DIR"
|
||||||
cat > "$ENV_FILE" <<EOF
|
cat > "$ENV_FILE" <<EOF
|
||||||
|
|
@ -208,11 +478,32 @@ EOF
|
||||||
warn "pre-existing log-related keys found in config — they may override ours."
|
warn "pre-existing log-related keys found in config — they may override ours."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# NVIDIA GPU stats come from NVML; without it every gpu_* column logs as 0.
|
||||||
|
if [[ "$GPU_VENDOR" == "$VENDOR_NVIDIA" ]] && ! have_nvml; then
|
||||||
|
warn "selected an NVIDIA GPU but libnvidia-ml (NVML) not found — GPU load/power"
|
||||||
|
warn "won't be logged. Install the NVIDIA userspace (e.g. 'nvidia-utils')."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# CPU power/temp readiness (same checks on AMD and Intel).
|
||||||
|
rapl=$(rapl_state)
|
||||||
|
if [[ "$rapl" == denied ]]; then
|
||||||
|
warn "cpu_power won't log — RAPL counters are root-only. Enable it with:"
|
||||||
|
warn " $(basename "$0") fix-cpu-power"
|
||||||
|
elif [[ "$rapl" == absent ]]; then
|
||||||
|
warn "cpu_power won't log — no RAPL powercap interface (try: sudo modprobe intel_rapl_msr)."
|
||||||
|
fi
|
||||||
|
[[ -z "$(cpu_temp_source)" ]] && warn "no known CPU temp sensor found — cpu_temp may read 0."
|
||||||
|
|
||||||
ok "MangoHud logging enabled"
|
ok "MangoHud logging enabled"
|
||||||
info "log folder: $LOG_DIR"
|
info "log folder: $LOG_DIR"
|
||||||
info "toggle key: Shift+F2 (during a game)"
|
info "toggle key: Shift+F2 (during a game)"
|
||||||
info "config file: $CONFIG_FILE"
|
info "config file: $CONFIG_FILE"
|
||||||
info "env file: $ENV_FILE (MANGOHUD=1)"
|
info "env file: $ENV_FILE (MANGOHUD=1)"
|
||||||
|
info "gpu logged: ${GPU_DESC:-MangoHud default}"
|
||||||
|
if [[ -n "$GPU_INDEX" ]]; then
|
||||||
|
info " (override with MANGOHUD_LOGGER_GPU=<index|nvidia|amd|intel>)"
|
||||||
|
fi
|
||||||
|
info "cpu ($( cpu_vendor )): temp=$( [[ -n "$(cpu_temp_source)" ]] && echo ok || echo none ) power(RAPL)=$rapl"
|
||||||
info "session type: $GS_FLAVOR (gamescope override: $gs_action)"
|
info "session type: $GS_FLAVOR (gamescope override: $gs_action)"
|
||||||
info "note: while logging is on, the HUD becomes visible during games"
|
info "note: while logging is on, the HUD becomes visible during games"
|
||||||
info " (autostart_log needs the render hook that no_display disables)"
|
info " (autostart_log needs the render hook that no_display disables)"
|
||||||
|
|
@ -231,3 +522,13 @@ EOF
|
||||||
warn "log out and back in (or restart your gamescope session) so the env var takes effect."
|
warn "log out and back in (or restart your gamescope session) so the env var takes effect."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Command dispatch ────────────────────────────────────────────────────────
|
||||||
|
case "${1:-toggle}" in
|
||||||
|
toggle|"") do_toggle ;;
|
||||||
|
doctor|check|--check|-c) do_doctor ;;
|
||||||
|
fix-cpu-power|fix|--fix-cpu-power) do_fix_cpu_power ;;
|
||||||
|
-h|--help|help) usage ;;
|
||||||
|
*) err "unknown command: $1"; echo; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue