diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 34 | ||||
-rwxr-xr-x | firestart.redux | 57 | ||||
-rwxr-xr-x | src/firefox-io-slayer-redux | 95 | ||||
-rwxr-xr-x | src/firefox@.service.in | 19 | ||||
-rwxr-xr-x | src/generate-firefox-unit | 51 | ||||
-rw-r--r-- | src/ioslay@.service | 5 | ||||
-rwxr-xr-x | src/sliceweasel.lib.sh | 3 |
8 files changed, 256 insertions, 9 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..704aefd --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1 @@ | |||
/firefox\@.service | |||
@@ -1,14 +1,32 @@ | |||
1 | BINDIR = /usr/local/bin | 1 | BINDIR = /usr/local/bin |
2 | BINARIES = firestart firestartx $(addprefix src/,sliceweasel.lib.sh firefox-io-slayer ioslay-firefox) | 2 | BINARIES = firestart firestartx $(addprefix src/,sliceweasel.lib.sh firefox-io-slayer-redux ioslay-firefox) |
3 | SUDO != [ "$$(id -u)" = 0 ] || echo sudo | ||
4 | 3 | ||
5 | .PHONY: install install-bin | 4 | ifeq ($(shell id -u),0) |
5 | # Prevent running as root | ||
6 | .PHONY: install-bin | ||
7 | all: | ||
8 | install-bin: | ||
9 | install $(BINARIES) -t $(BINDIR) | ||
10 | else | ||
11 | |||
12 | .PHONY: install install-bin start stop restart | ||
13 | |||
14 | firefox@.service: src/firefox@.service.in src/generate-firefox-unit | ||
15 | ./src/generate-firefox-unit $< $@ | ||
16 | |||
17 | install: install-bin firefox@.service | ||
18 | systemctl --user link ./firefox@.service | ||
19 | systemctl --user link ./src/ioslay@.service | ||
20 | systemctl --user daemon-reload | ||
21 | |||
22 | start: install | ||
23 | systemctl --user start "firefox@$$DISPLAY" | ||
6 | 24 | ||
7 | install: install-bin | 25 | stop: |
8 | systemctl --user restart ioslay | 26 | systemctl --user stop firefox@$$DISPLAY ioslay@$$DISPLAY |
9 | 27 | ||
10 | uninstall-units: | 28 | restart: stop start |
11 | systemctl --user disable ioslay | ||
12 | 29 | ||
13 | install-bin: | 30 | install-bin: |
14 | $(SUDO) install $(BINARIES) -t $(BINDIR) | 31 | sudo $(MAKE) -$(MAKEFLAGS) $@ |
32 | 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 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | die() { printf "%s: Error: %s\n" "$0" "$*" >&2; exit 1; } | ||
4 | |||
5 | # Test DEVICE WRITE OPS BY WRITEOPS | ||
6 | test_write_ops() | ||
7 | { | ||
8 | if ! [ -e "$1" ] | ||
9 | then | ||
10 | mkdir -p "$(dirname "$1")" | ||
11 | sync | ||
12 | begin=$(date +%s%N) | ||
13 | dd if=/dev/urandom of="$DIR"/urandom.out bs=1M count=300 | ||
14 | sync | ||
15 | end=$(date +%s%N) | ||
16 | ops=$(( (end - begin) / 1000000000 )) | ||
17 | rm "$DIR"/urandom.out | ||
18 | echo "$ops" > "$1" | ||
19 | fi | ||
20 | cat "$1" | ||
21 | } | ||
22 | |||
23 | CMD=firefox | ||
24 | UNIT=$CMD | ||
25 | DIR=~/.mozilla | ||
26 | READ_OPS=1G | ||
27 | WRITE_OPS=$READ_OPS | ||
28 | CONFDIR=$HOME/.config/firestart | ||
29 | |||
30 | if [ -e "$CONFDIR"/conf ] | ||
31 | then | ||
32 | . "$CONFDIR"/conf | ||
33 | fi | ||
34 | |||
35 | WRITE_OPS=$(test_write_ops "$CONFDIR"/diskspeed.dat) | ||
36 | WRITE_OPS=${WRITE_OPS%.*} | ||
37 | READ_OPS=$WRITE_OPS | ||
38 | |||
39 | [ -e "$DIR" ] || die "does not exist: $DIR" | ||
40 | [ -d "$DIR" ] || die "not a directory: $DIR" | ||
41 | |||
42 | DEV=$(echo $(findmnt --target "$DIR" -o MAJ:MIN -n)) | ||
43 | [ "$DEV" ] || die "could not determine backing device for $DIR" | ||
44 | |||
45 | IOReadIOPSMax="$DEV $READ_OPS" | ||
46 | IOWriteIOPSMax="$DEV $WRITE_OPS" | ||
47 | |||
48 | sed -e "s/^IOReadIOPSMax *=.*/IOReadIOPSMax = $IOReadIOPSMax/" \ | ||
49 | -e "s/^IOWriteIOPSMax *=.*/IOWriteIOPSMax = $IOWriteIOPSMax/" \ | ||
50 | < firefox@.service.in > firefox@.service | ||
51 | |||
52 | set -x | ||
53 | |||
54 | systemctl --user link "$PWD"/firefox@.service | ||
55 | systemctl --user link "$PWD"/ioslay@.service | ||
56 | systemctl --user daemon-reload | ||
57 | 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 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | DISPLAY=$1 | ||
4 | |||
5 | if [ -e /usr/lib/bash/sleep ] | ||
6 | then | ||
7 | enable -f /usr/lib/bash/sleep sleep | ||
8 | fi | ||
9 | |||
10 | export NOTICE=y | ||
11 | noticeLOG() { [ "$NOTICE" ] || return; echo "Notice: $*" >&2; } | ||
12 | debugLOG() { [ "$DBG" ] || return; echo "Debug: $*" >&2; } | ||
13 | |||
14 | . sliceweasel.lib.sh | ||
15 | |||
16 | vkill() | ||
17 | { | ||
18 | if [ $# = 0 ] | ||
19 | then | ||
20 | return | ||
21 | fi | ||
22 | ( | ||
23 | if [ "$(id -u)" = 0 ] | ||
24 | then sudo= | ||
25 | else sudo=sudo | ||
26 | fi | ||
27 | set -x | ||
28 | ps u "$@" | ||
29 | $sudo kill "$@" | ||
30 | ) | ||
31 | } | ||
32 | |||
33 | slay_slayer() | ||
34 | { | ||
35 | if [ "$ioslay" ] | ||
36 | then | ||
37 | children=$(for pid in $ioslay; do pgrep -P $ioslay; done) | ||
38 | grandchildren=$(for pid in $children; do pgrep -P $pid; done) | ||
39 | vkill $ioslay $children $grandchildren | ||
40 | fi | ||
41 | } | ||
42 | |||
43 | group_procs=$(get_firefox_cgroup_procs) | ||
44 | |||
45 | ioslay= | ||
46 | lastprocs= | ||
47 | SIGNALLED= | ||
48 | trap 'SIGNALLED=y' SIGINT SIGTERM SIGHUP | ||
49 | while [ ! "$SIGNALLED" ] | ||
50 | do | ||
51 | if ! [ -e "$group_procs" ] | ||
52 | then | ||
53 | [ "$warned" ] || echo "Warning: firefox not running or cgroup not found" >&2 | ||
54 | warned=y | ||
55 | else | ||
56 | if [ "$warned" ] | ||
57 | then | ||
58 | echo "Found firefox cgroup: $group_procs" >&2 | ||
59 | warned= | ||
60 | fi | ||
61 | read -N 1000100 procs < "$group_procs" | ||
62 | if [ "$procs" ] | ||
63 | then | ||
64 | set -- | ||
65 | for pid in $procs | ||
66 | do | ||
67 | read comm < /proc/$pid/comm | ||
68 | case "$comm" in | ||
69 | 'Isolated Web Content' | 'Web Content' | 'Isolated Web Co') | ||
70 | set -- "$@" "$pid" | ||
71 | debugLOG "accept /proc/$pid/comm $comm" | ||
72 | ;; | ||
73 | *) | ||
74 | debugLOG "reject /proc/$pid/comm $comm" | ||
75 | esac | ||
76 | done | ||
77 | |||
78 | # echo "pids: ($*|$(echo $procs))" >&2 | ||
79 | if [ "$lastargs" != "$*" ] | ||
80 | then | ||
81 | slay_slayer | ||
82 | wait $ioslay | ||
83 | if [ $# -gt 0 ] | ||
84 | then | ||
85 | ioslay-firefox "$@" & | ||
86 | ioslay=$! | ||
87 | noticeLOG "Launched ioslay-firefox[$ioslay] $*" | ||
88 | fi | ||
89 | fi | ||
90 | lastargs=$* | ||
91 | fi | ||
92 | fi | ||
93 | sleep 1 | ||
94 | done | ||
95 | 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 @@ | |||
1 | [Unit] | ||
2 | Description = Firefox | ||
3 | # Requires=ioslay@%I | ||
4 | # Requires=pulseaudio.socket # require X11 somehow | ||
5 | ConditionUser = !root # seems reasonable | ||
6 | ConditionEnvironment = DISPLAY | ||
7 | |||
8 | [Service] | ||
9 | ExecStartPre = /usr/bin/systemctl --user start ioslay@%I | ||
10 | ExecStart = /usr/local/bin/firefox | ||
11 | Restart = on-failure | ||
12 | PassEnvironment = DISPLAY XAUTHORITY | ||
13 | MemoryMax = 50% | ||
14 | IOReadIOPSMax = | ||
15 | IOWriteIOPSMax = | ||
16 | |||
17 | [Install] | ||
18 | Also=ioslay@.service | ||
19 | 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 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | INPUT_FILE=$1 | ||
4 | OUTPUT_FILE=$2 | ||
5 | |||
6 | die() { printf "%s: Error: %s\n" "$0" "$*" >&2; exit 1; } | ||
7 | |||
8 | # Test DEVICE WRITE OPS BY WRITEOPS | ||
9 | test_write_ops() | ||
10 | { | ||
11 | if ! [ -e "$1" ] | ||
12 | then | ||
13 | mkdir -p "$(dirname "$1")" | ||
14 | sync | ||
15 | begin=$(date +%s%N) | ||
16 | dd if=/dev/urandom of="$DIR"/urandom.out bs=1M count=300 | ||
17 | sync | ||
18 | end=$(date +%s%N) | ||
19 | ops=$(( (end - begin) / 1000000000 )) | ||
20 | rm "$DIR"/urandom.out | ||
21 | echo "$ops" > "$1" | ||
22 | fi | ||
23 | cat "$1" | ||
24 | } | ||
25 | |||
26 | DIR=~/.mozilla | ||
27 | READ_OPS=1G | ||
28 | WRITE_OPS=$READ_OPS | ||
29 | CONFDIR=$HOME/.config/firestart | ||
30 | |||
31 | if [ -e "$CONFDIR"/conf ] | ||
32 | then | ||
33 | . "$CONFDIR"/conf | ||
34 | fi | ||
35 | |||
36 | WRITE_OPS=$(test_write_ops "$CONFDIR"/diskspeed.dat) | ||
37 | WRITE_OPS=${WRITE_OPS%.*} | ||
38 | READ_OPS=$WRITE_OPS | ||
39 | |||
40 | [ -e "$DIR" ] || die "does not exist: $DIR" | ||
41 | [ -d "$DIR" ] || die "not a directory: $DIR" | ||
42 | |||
43 | DEV=$(echo $(findmnt --target "$DIR" -o MAJ:MIN -n)) | ||
44 | [ "$DEV" ] || die "could not determine backing device for $DIR" | ||
45 | |||
46 | IOReadIOPSMax="$DEV $READ_OPS" | ||
47 | IOWriteIOPSMax="$DEV $WRITE_OPS" | ||
48 | |||
49 | sed -e "s/^IOReadIOPSMax *=.*/IOReadIOPSMax = $IOReadIOPSMax/" \ | ||
50 | -e "s/^IOWriteIOPSMax *=.*/IOWriteIOPSMax = $IOWriteIOPSMax/" \ | ||
51 | < "$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 @@ | |||
1 | [Unit] | ||
2 | Description = Kill firefox when it spins the disk | ||
3 | |||
4 | [Service] | ||
5 | 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() | |||
112 | { | 112 | { |
113 | uid=$(get_uid) | 113 | uid=$(get_uid) |
114 | [ "$uid" ] || return | 114 | [ "$uid" ] || return |
115 | echo /sys/fs/cgroup/user.slice/user-$uid.slice/user@$uid.service/app.slice/firefox.service/cgroup.procs | 115 | [ "$DISPLAY" ] || return |
116 | echo /sys/fs/cgroup/user.slice/user-$uid.slice/user@$uid.service/app.slice/app-firefox.slice/firefox@$DISPLAY.service/cgroup.procs | ||
116 | } | 117 | } |
117 | 118 | ||
118 | get_current_group() | 119 | get_current_group() |