From b00a5efe39bf1195ef0c8037093df2604afa911d Mon Sep 17 00:00:00 2001 From: Debian Live user Date: Fri, 28 Apr 2023 21:47:08 -0400 Subject: Got some new firefox launch code working. Now it uses a template file parameterized on $DISPLAY. Unfortunately, this file needs to be generated dynamically on install in order to set the IO parameters. (Might use systemd edit system for this, actually.) The ioslayer is also parameterized and started by the firefox unit file. Needs a little cleanup / removal of old code. --- .gitignore | 1 + Makefile | 34 ++++++++++++---- firestart.redux | 57 +++++++++++++++++++++++++++ src/firefox-io-slayer-redux | 95 +++++++++++++++++++++++++++++++++++++++++++++ src/firefox@.service.in | 19 +++++++++ src/generate-firefox-unit | 51 ++++++++++++++++++++++++ src/ioslay@.service | 5 +++ src/sliceweasel.lib.sh | 3 +- 8 files changed, 256 insertions(+), 9 deletions(-) create mode 100644 .gitignore create mode 100755 firestart.redux create mode 100755 src/firefox-io-slayer-redux create mode 100755 src/firefox@.service.in create mode 100755 src/generate-firefox-unit create mode 100644 src/ioslay@.service diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..704aefd --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/firefox\@.service diff --git a/Makefile b/Makefile index bcc1005..50adaed 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,32 @@ BINDIR = /usr/local/bin -BINARIES = firestart firestartx $(addprefix src/,sliceweasel.lib.sh firefox-io-slayer ioslay-firefox) -SUDO != [ "$$(id -u)" = 0 ] || echo sudo +BINARIES = firestart firestartx $(addprefix src/,sliceweasel.lib.sh firefox-io-slayer-redux ioslay-firefox) -.PHONY: install install-bin +ifeq ($(shell id -u),0) +# Prevent running as root +.PHONY: install-bin +all: +install-bin: + install $(BINARIES) -t $(BINDIR) +else + +.PHONY: install install-bin start stop restart + +firefox@.service: src/firefox@.service.in src/generate-firefox-unit + ./src/generate-firefox-unit $< $@ + +install: install-bin firefox@.service + systemctl --user link ./firefox@.service + systemctl --user link ./src/ioslay@.service + systemctl --user daemon-reload + +start: install + systemctl --user start "firefox@$$DISPLAY" -install: install-bin - systemctl --user restart ioslay +stop: + systemctl --user stop firefox@$$DISPLAY ioslay@$$DISPLAY -uninstall-units: - systemctl --user disable ioslay +restart: stop start install-bin: - $(SUDO) install $(BINARIES) -t $(BINDIR) + sudo $(MAKE) -$(MAKEFLAGS) $@ +endif diff --git a/firestart.redux b/firestart.redux new file mode 100755 index 0000000..59d8f8a --- /dev/null +++ b/firestart.redux @@ -0,0 +1,57 @@ +#!/bin/bash + +die() { printf "%s: Error: %s\n" "$0" "$*" >&2; exit 1; } + +# Test DEVICE WRITE OPS BY WRITEOPS +test_write_ops() +{ + if ! [ -e "$1" ] + then + mkdir -p "$(dirname "$1")" + sync + begin=$(date +%s%N) + dd if=/dev/urandom of="$DIR"/urandom.out bs=1M count=300 + sync + end=$(date +%s%N) + ops=$(( (end - begin) / 1000000000 )) + rm "$DIR"/urandom.out + echo "$ops" > "$1" + fi + cat "$1" +} + +CMD=firefox +UNIT=$CMD +DIR=~/.mozilla +READ_OPS=1G +WRITE_OPS=$READ_OPS +CONFDIR=$HOME/.config/firestart + +if [ -e "$CONFDIR"/conf ] +then + . "$CONFDIR"/conf +fi + +WRITE_OPS=$(test_write_ops "$CONFDIR"/diskspeed.dat) +WRITE_OPS=${WRITE_OPS%.*} +READ_OPS=$WRITE_OPS + +[ -e "$DIR" ] || die "does not exist: $DIR" +[ -d "$DIR" ] || die "not a directory: $DIR" + +DEV=$(echo $(findmnt --target "$DIR" -o MAJ:MIN -n)) +[ "$DEV" ] || die "could not determine backing device for $DIR" + +IOReadIOPSMax="$DEV $READ_OPS" +IOWriteIOPSMax="$DEV $WRITE_OPS" + +sed -e "s/^IOReadIOPSMax *=.*/IOReadIOPSMax = $IOReadIOPSMax/" \ + -e "s/^IOWriteIOPSMax *=.*/IOWriteIOPSMax = $IOWriteIOPSMax/" \ + < firefox@.service.in > firefox@.service + +set -x + +systemctl --user link "$PWD"/firefox@.service +systemctl --user link "$PWD"/ioslay@.service +systemctl --user daemon-reload +systemctl --user start "firefox@$DISPLAY" diff --git a/src/firefox-io-slayer-redux b/src/firefox-io-slayer-redux new file mode 100755 index 0000000..fe54e37 --- /dev/null +++ b/src/firefox-io-slayer-redux @@ -0,0 +1,95 @@ +#!/bin/bash + +DISPLAY=$1 + +if [ -e /usr/lib/bash/sleep ] +then + enable -f /usr/lib/bash/sleep sleep +fi + +export NOTICE=y +noticeLOG() { [ "$NOTICE" ] || return; echo "Notice: $*" >&2; } +debugLOG() { [ "$DBG" ] || return; echo "Debug: $*" >&2; } + +. sliceweasel.lib.sh + +vkill() +{ + if [ $# = 0 ] + then + return + fi + ( + if [ "$(id -u)" = 0 ] + then sudo= + else sudo=sudo + fi + set -x + ps u "$@" + $sudo kill "$@" + ) +} + +slay_slayer() +{ + if [ "$ioslay" ] + then + children=$(for pid in $ioslay; do pgrep -P $ioslay; done) + grandchildren=$(for pid in $children; do pgrep -P $pid; done) + vkill $ioslay $children $grandchildren + fi +} + +group_procs=$(get_firefox_cgroup_procs) + +ioslay= +lastprocs= +SIGNALLED= +trap 'SIGNALLED=y' SIGINT SIGTERM SIGHUP +while [ ! "$SIGNALLED" ] +do + if ! [ -e "$group_procs" ] + then + [ "$warned" ] || echo "Warning: firefox not running or cgroup not found" >&2 + warned=y + else + if [ "$warned" ] + then + echo "Found firefox cgroup: $group_procs" >&2 + warned= + fi + read -N 1000100 procs < "$group_procs" + if [ "$procs" ] + then + set -- + for pid in $procs + do + read comm < /proc/$pid/comm + case "$comm" in + 'Isolated Web Content' | 'Web Content' | 'Isolated Web Co') + set -- "$@" "$pid" + debugLOG "accept /proc/$pid/comm $comm" + ;; + *) + debugLOG "reject /proc/$pid/comm $comm" + esac + done + + # echo "pids: ($*|$(echo $procs))" >&2 + if [ "$lastargs" != "$*" ] + then + slay_slayer + wait $ioslay + if [ $# -gt 0 ] + then + ioslay-firefox "$@" & + ioslay=$! + noticeLOG "Launched ioslay-firefox[$ioslay] $*" + fi + fi + lastargs=$* + fi + fi + sleep 1 +done +slay_slayer diff --git a/src/firefox@.service.in b/src/firefox@.service.in new file mode 100755 index 0000000..e3c0329 --- /dev/null +++ b/src/firefox@.service.in @@ -0,0 +1,19 @@ +[Unit] +Description = Firefox +# Requires=ioslay@%I +# Requires=pulseaudio.socket # require X11 somehow +ConditionUser = !root # seems reasonable +ConditionEnvironment = DISPLAY + +[Service] +ExecStartPre = /usr/bin/systemctl --user start ioslay@%I +ExecStart = /usr/local/bin/firefox +Restart = on-failure +PassEnvironment = DISPLAY XAUTHORITY +MemoryMax = 50% +IOReadIOPSMax = +IOWriteIOPSMax = + +[Install] +Also=ioslay@.service +WantedBy = default.target # make an X11 user target? diff --git a/src/generate-firefox-unit b/src/generate-firefox-unit new file mode 100755 index 0000000..c285ffc --- /dev/null +++ b/src/generate-firefox-unit @@ -0,0 +1,51 @@ +#!/bin/bash + +INPUT_FILE=$1 +OUTPUT_FILE=$2 + +die() { printf "%s: Error: %s\n" "$0" "$*" >&2; exit 1; } + +# Test DEVICE WRITE OPS BY WRITEOPS +test_write_ops() +{ + if ! [ -e "$1" ] + then + mkdir -p "$(dirname "$1")" + sync + begin=$(date +%s%N) + dd if=/dev/urandom of="$DIR"/urandom.out bs=1M count=300 + sync + end=$(date +%s%N) + ops=$(( (end - begin) / 1000000000 )) + rm "$DIR"/urandom.out + echo "$ops" > "$1" + fi + cat "$1" +} + +DIR=~/.mozilla +READ_OPS=1G +WRITE_OPS=$READ_OPS +CONFDIR=$HOME/.config/firestart + +if [ -e "$CONFDIR"/conf ] +then + . "$CONFDIR"/conf +fi + +WRITE_OPS=$(test_write_ops "$CONFDIR"/diskspeed.dat) +WRITE_OPS=${WRITE_OPS%.*} +READ_OPS=$WRITE_OPS + +[ -e "$DIR" ] || die "does not exist: $DIR" +[ -d "$DIR" ] || die "not a directory: $DIR" + +DEV=$(echo $(findmnt --target "$DIR" -o MAJ:MIN -n)) +[ "$DEV" ] || die "could not determine backing device for $DIR" + +IOReadIOPSMax="$DEV $READ_OPS" +IOWriteIOPSMax="$DEV $WRITE_OPS" + +sed -e "s/^IOReadIOPSMax *=.*/IOReadIOPSMax = $IOReadIOPSMax/" \ + -e "s/^IOWriteIOPSMax *=.*/IOWriteIOPSMax = $IOWriteIOPSMax/" \ + < "$INPUT_FILE" > "$OUTPUT_FILE" diff --git a/src/ioslay@.service b/src/ioslay@.service new file mode 100644 index 0000000..1a00bd4 --- /dev/null +++ b/src/ioslay@.service @@ -0,0 +1,5 @@ +[Unit] +Description = Kill firefox when it spins the disk + +[Service] +ExecStart = /usr/local/bin/firefox-io-slayer-redux %I diff --git a/src/sliceweasel.lib.sh b/src/sliceweasel.lib.sh index 3b42a61..7f70e08 100755 --- a/src/sliceweasel.lib.sh +++ b/src/sliceweasel.lib.sh @@ -112,7 +112,8 @@ get_firefox_cgroup_procs() { uid=$(get_uid) [ "$uid" ] || return - echo /sys/fs/cgroup/user.slice/user-$uid.slice/user@$uid.service/app.slice/firefox.service/cgroup.procs + [ "$DISPLAY" ] || return + echo /sys/fs/cgroup/user.slice/user-$uid.slice/user@$uid.service/app.slice/app-firefox.slice/firefox@$DISPLAY.service/cgroup.procs } get_current_group() -- cgit v1.2.3