Insert Title

Jul 22, 2018

Running applications only when you are idle

The problem: Bad responsiveness caused by high I/O load

On a typical desktop PC, there are several long-running tasks with a high I/O load which usually need to be executed regularly — like backups, indexing files for search, checking the backups, etc. Tasks with high I/O load however can cause bad responsiveness of the system under Linux, which results in applications being frozen, the mouse cursor not moving, etc.

With the most systems this can usually be fixed by selecting the CFQ scheduler in the kernel. If you are running particular new hardware however, this might not work since e.g. the kernel does not support setting an I/O scheduler for those new fancy m.2 SSDs. Running an application like recollindex or borgbackup on one of those disks can completely fubar the desktop until they are done.

The solution

To work around this problem, I've created the following script:

#!/bin/bash
# execute-idle.sh
# Copyright (C) 2018 Philipp Ludwig, <idle (at) philippludwig.net>
# License: GPLv3
export DISPLAY=:0.0
set -e

if [ "$1" == "" ]; then
    echo "Error: No command given"
    exit 1
fi

$@ &

PID=$!

if [ "$PID" == "" ]; then
    echo "Could not determine PID of $1!"
    exit 1
fi

kill -SIGSTOP $PID
for p in $(ps --ppid $PID -ho '%p'); do kill -SIGSTOP $p; done

while kill -0 $PID &> /dev/null; do
    sleep 5
    if [ "$(xprintidle)" -gt 30000 ]; then # 30 seconds
        signal="-SIGCONT"
    else
        signal="-SIGSTOP"
    fi

    kill $signal $PID
    for p in $(ps --ppid $PID -ho '%p'); do kill $signal $p; done
done

It is called execute-idle.sh and designed to run these tasks only while you are not using the computer (e.g. when you are in the kitchen for 10 minutes, waiting on the cup of coffee).

Dependencies: xprintidle, bash

How it works

execute-idle.sh first starts the task specified as an argument, then pauses it immediately by sending a SIGSTOP. Then it calls xprintidle every 5 seconds to check if you are still using the computer — if not, it sends a SIGCONT signal to the process and all of its children, letting the job continue. As soon as you return and type on your keyboard or move your mouse, execute-idle.sh again sends SIGSTOP to the process and its children, pausing the task until you are idle again.

How to use it

Just put it in your crontab like this:

0 12 * * * ~/tools/execute-idle.sh ~/my-backup-script.sh

Remarks

You might think that this causes some jobs to never finish, but after using this script for several weeks I didn't encounter any problems like this. Due to the rather short 5 second interval, execute-idle.sh can utilize even small breaks of e.g. 30 seconds.

Try running your backup with it — your regular backup check job should tell you if something went wrong.