Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/zenmonitor
/zenmonitor-cli
*.o
58 changes: 55 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,60 @@ Alternatively, you can set capabilities to zenmonitor executable: `sudo setcap c

``--coreid`` - Display core_id instead of core index

``--interval MS`` - Initial refresh interval in milliseconds (50-60000, default 1000). The interval is also adjustable while running via the "Update interval" button in the header bar; changing it resets the rolling averages.

``--average WINDOWS`` - Show additional rolling-average columns for the given comma-separated time windows, e.g. ``--average 30s,1m,5m`` (suffixes: ``s`` seconds, ``m`` minutes, ``h`` hours; a bare number is seconds). Omit to show no average columns.

``--average-only SUBSTRINGS`` - Only average sensors whose label contains one of these comma-separated substrings (case-insensitive), e.g. ``--average-only power,temp``. Non-matching rows still show Value/Min/Max but leave the average cells blank. Omit to average every sensor.

## Command line interface (zenmonitor-cli)
A headless build is available for terminals and panels:
```
make build-cli
sudo make install-cli
```
It reuses the same sensor backends and supports ``--delay SECONDS`` (poll
interval), ``--coreid``, ``--refresh-in-place`` (redraw in place), ``--output-once``,
and ``--file FILE`` (stream readings to a CSV file, one row per refresh). The CSV
is appended and flushed as it goes, so memory use stays constant, ``tail -f``
works on it, and the log survives up to the last row if the machine crashes -
which makes it suitable for long high-frequency captures.

``--sensors SUBSTRINGS`` limits output to sensors whose label contains one of the
given comma-separated substrings (case-insensitive), e.g.
``--sensors "temperature,package power"``. Besides trimming the output and the
per-sensor average buffers, if a whole backend has no matching sensors its
per-tick read is skipped entirely (handy to avoid the MSR reads when you only
want temperatures).

### Rolling averages in a panel (daemon mode)
A rolling average needs a process that has been sampling for the whole window,
so short-lived panel commands can't compute one on their own. Run zenmonitor-cli
as a small resident daemon instead:
```
zenmonitor-cli --daemon --delay 1 --average 1m,5m
```
It samples every ``--delay`` seconds and rewrites a snapshot file (default
``$XDG_RUNTIME_DIR/zenmonitor.snapshot``, override with ``--snapshot FILE``)
containing each sensor's current value and the configured rolling averages.
The window→sample conversion follows ``--delay``, so ``5m`` is five minutes at
any poll rate.

``data/zenmonitor-cli.service`` is an example systemd *user* unit that keeps the
daemon running. ``data/zenmonitor-genmon.sh`` reads the snapshot for the
[xfce4-genmon-plugin](https://docs.xfce.org/panel-plugins/xfce4-genmon-plugin);
point a genmon item at, for example:
```
zenmonitor-genmon.sh "CPU Temperature (tCtl)" "Avg 1m"
```

Note: temperature/SVI2 sensors (via the zenpower driver) work as a normal user,
but RAPL package/core power needs MSR privileges. To include power in the daemon
snapshot, grant capabilities to the binary:
```
sudo setcap cap_sys_rawio,cap_dac_read_search+ep /usr/local/bin/zenmonitor-cli
```

## Installing
By default, Zenmonitor will be installed to /usr/local.
```
Expand All @@ -57,11 +111,9 @@ sudo modprobe msr
sudo bash -c 'echo "msr" > /etc/modules-load.d/msr.conf'
sudo apt install build-essential libgtk-3-dev git
cd ~
git clone https://github.com/ocerman/zenmonitor
git clone https://github.com/HonsW/zenmonitor
cd zenmonitor
make
sudo make install
sudo make install-polkit
```
## Setup on Arch
You may use the AUR package [zenmonitor-git](https://aur.archlinux.org/packages/zenmonitor-git/) to install via [traditional method](https://wiki.archlinux.org/index.php/Arch_User_Repository) or using an AUR helper (like yay)
18 changes: 18 additions & 0 deletions data/zenmonitor-cli.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Example systemd *user* service for the zenmonitor-cli snapshot daemon.
# Install: cp data/zenmonitor-cli.service ~/.config/systemd/user/
# systemctl --user enable --now zenmonitor-cli.service
#
# Note: SVI2/temperature sensors (zenpower) work as a normal user, but RAPL
# package/core power comes from the MSR device and needs privileges. Grant them
# to the binary if you want power in the snapshot:
# sudo setcap cap_sys_rawio,cap_dac_read_search+ep /usr/local/bin/zenmonitor-cli

[Unit]
Description=Zenmonitor CLI snapshot daemon (rolling averages for panels)

[Service]
ExecStart=/usr/local/bin/zenmonitor-cli --daemon --delay 1 --average 1m,5m
Restart=on-failure

[Install]
WantedBy=default.target
49 changes: 49 additions & 0 deletions data/zenmonitor-genmon.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/sh
# xfce4-genmon-plugin consumer for the zenmonitor-cli daemon snapshot.
#
# Usage in a genmon panel item (Command field):
# zenmonitor-genmon.sh "CPU Temperature (tCtl)" "Avg 1m"
#
# Arg 1: exact sensor label as written in the snapshot (default: first sensor)
# Arg 2: column to display - "value" or one of the configured average
# windows, e.g. "Avg 1m" (default: value)
#
# The snapshot is produced by: zenmonitor-cli --daemon --average 1m,5m
# Path resolution: $ZENMONITOR_SNAPSHOT, else $XDG_RUNTIME_DIR/zenmonitor.snapshot,
# else /tmp/zenmonitor.snapshot.

snapshot="${ZENMONITOR_SNAPSHOT:-${XDG_RUNTIME_DIR:-/tmp}/zenmonitor.snapshot}"
sensor="$1"
column="${2:-value}"

if [ ! -r "$snapshot" ]; then
echo "<txt>n/a</txt>"
echo "<tool>zenmonitor daemon not running ($snapshot)</tool>"
exit 0
fi

awk -F'\t' -v sensor="$sensor" -v col="$column" '
NR == 2 {
sub(/^# /, "", $0)
n = split($0, h, "\t")
for (i = 1; i <= n; i++)
if (h[i] == col) ci = i
if (sensor == "") skip_sensor = 1
next
}
NR > 2 && (skip_sensor || $1 == sensor) {
if (ci == "") { print "<txt>?col</txt>"; exit }
v = $ci
if (v == "") { print "<txt>--</txt>"; exit }
printf "<txt>%.1f</txt>\n", v
printf "<tool>%s — %s: %.2f</tool>\n", $1, col, v
found = 1
exit
}
END {
if (!found) {
print "<txt>n/a</txt>"
print "<tool>sensor not found: " sensor "</tool>"
}
}
' "$snapshot"
40 changes: 35 additions & 5 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
CC := cc

ifeq ($(PREFIX),)
PREFIX := /usr/local
endif

BUILD_FILES_COMMON := \
src/ss/*.c \
src/sysfs.c \
src/zenmonitor-lib.c

BUILD_FILES_GUI := \
$(BUILD_FILES_COMMON) \
src/gui.c \
src/zenmonitor.c

BUILD_FILES_CLI := \
$(BUILD_FILES_COMMON) \
src/zenmonitor-cli.c

.PHONY: build build-cli all install install-cli install-polkit uninstall uninstall-cli clean

build:
cc -Isrc/include `pkg-config --cflags gtk+-3.0` src/*.c src/ss/*.c -o zenmonitor `pkg-config --libs gtk+-3.0` -lm -no-pie -Wall
$(CC) -Isrc/include `pkg-config --cflags gtk+-3.0` $(BUILD_FILES_GUI) -o zenmonitor `pkg-config --libs gtk+-3.0` -lm -no-pie -O2 -Wall $(CFLAGS)

build-cli:
$(CC) -Isrc/include `pkg-config --cflags glib-2.0` $(BUILD_FILES_CLI) -o zenmonitor-cli `pkg-config --libs glib-2.0` -lm -lncurses -no-pie -O2 -Wall $(CFLAGS)

all: build build-cli

install:
mkdir -p $(DESTDIR)$(PREFIX)/bin
install -m 755 zenmonitor $(DESTDIR)$(PREFIX)/bin

mkdir -p $(DESTDIR)$(PREFIX)/share/applications
sed -e "s|@APP_EXEC@|${DESTDIR}${PREFIX}/bin/zenmonitor|" \
sed -e "s|@APP_EXEC@|${PREFIX}/bin/zenmonitor|" \
data/zenmonitor.desktop.in > \
$(DESTDIR)$(PREFIX)/share/applications/zenmonitor.desktop

install-cli:
mkdir -p $(DESTDIR)$(PREFIX)/bin
install -m 755 zenmonitor-cli $(DESTDIR)$(PREFIX)/bin

install-polkit:
sed -e "s|@APP_EXEC@|${DESTDIR}${PREFIX}/bin/zenmonitor|" \
sed -e "s|@APP_EXEC@|${PREFIX}/bin/zenmonitor|" \
data/zenmonitor-root.desktop.in > \
$(DESTDIR)$(PREFIX)/share/applications/zenmonitor-root.desktop

sed -e "s|@APP_EXEC@|${DESTDIR}${PREFIX}/bin/zenmonitor|" \
sed -e "s|@APP_EXEC@|${PREFIX}/bin/zenmonitor|" \
data/org.pkexec.zenmonitor.policy.in > \
$(DESTDIR)/usr/share/polkit-1/actions/org.pkexec.zenmonitor.policy

Expand All @@ -29,5 +56,8 @@ uninstall:
rm -f $(DESTDIR)$(PREFIX)/share/applications/zenmonitor-root.desktop
rm -f $(DESTDIR)/usr/share/polkit-1/actions/org.pkexec.zenmonitor.policy

uninstall-cli:
rm -f $(DESTDIR)$(PREFIX)/bin/zenmonitor-cli

clean:
rm -f zenmonitor
rm -f zenmonitor zenmonitor-cli *.o
Loading