21

Linux does not (yet) follow the POSIX.1 standard which says that a renice on a process affects "all system scope threads in the process", because according to the pthreads(7) doc "threads do not share a common nice value".

However, sometimes, it can be convenient to renice "everything" related to a given process (one example would be Apache child processes and all their threads). So,

  • how can I renice all threads belonging to a given process ?
  • how can I renice all child processes belonging to a given process ?

I am looking for a fairly easy solution.

I know that process groups can sometimes be helpful, however, they do not always match what I want to do: they can include a broader or different set of processes.

Using a cgroup managed by systemd might also be helpful, but even if I am interested to hear about it, I mostly looking for a "standard" solution.

EDIT: also, man (7) pthreads says "all of the threads in a process are placed in the same thread group; all members of a thread group share the same PID". So, is it even possible to renice something which doesn't have it's own PID?

18
+50

You can use /proc/$PID/task to find all threads of a given process, therefore you can use

$ ls /proc/$PID/task | xargs renice $PRIO

to renice all threads belonging to a given process.

Same way /proc/$PID/task/$PID/children can be used to find all child processes (or /proc/$PID/task/*/children if you want all child processes of all threads of a given process).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO
  • man (7) pthreads says about the current (NPTL) implementation: "all of the threads in a process are placed in the same thread group; all members of a thread group share the same PID" and "Threads do not share a common nice value". Then, how can you renice a thread which doesn't have it's own PID, when renice uses a PID to do so? – Totor Oct 19 '16 at 12:34
7

Difference between threads and processes

Important question on Linux, because documentation perpetuates doubts (about threads not having their own PID for example).

Note: this answer explains Linux threads precisely.

In short: the kernel only handles "runnable entities", that is, something which can be run and scheduled. Kernel wise, these entities are called processes. A thread, is just a kind of process that shares (at least) memory space and signal handlers with another one.

Every such process has a system-wide unique identifier: the PID (Process ID). For so-called threads, it is sometimes called TID (Thread ID), but from the sysadmin (and kernel!) point of view, TID and PID are the same thing (they share the same namespace).

As a result, you can renice each "thread" individually because they have their own PID1.

Finding all PIDs to renice recursively

We need to get the PIDs of all processes ("normal" or "thread") which are descendant (children or in the thread group) of the to-be-niced process. This ought to be recursive (considering children's children).

Anton Leontiev answer's gives the hint to do so: all folder names in /proc/$PID/task/ are threads' PID containing a children file listing potential children processes.

However, it lacks recursivity, so here is a quick & dirty shell script to find them:

#!/bin/sh
[ "$#" -eq 1 -a -d "/proc/$1/task" ] || exit 1

PID_LIST=
findpids() {
        for pid in /proc/$1/task/* ; do
                pid="$(basename "$pid")"
                PID_LIST="$PID_LIST$pid "
                for cpid in $(cat /proc/$1/task/$pid/children) ; do
                        findpids $cpid
                done
        done
}

findpids $1
echo $PID_LIST

If process PID 1234 is the one you want to recursively nice, now you can do:

renice -n 15 -p $(/path/to/findchildren.sh 1234)

1 Note that, for POSIX compliance, calling getpid(2) within a thread will not give you the system-wide unique ID (PID) of this runnable entity, but rather the PID of the main process within the "thread group". You would need to call gettid(2) instead. See this answer for more information.

6

We should not confuse the process PID and the thread id sometime written TID or in the ps command LPW. The scommand has options to display threads, and under top or htop you switch between threads and process by the H letter. As previously told by @Totor, with NPTL, which is the current implementation with kernel > 2.6, all threads have the same pid, but they have a distinct tid. You show all the threads of a process by:

$ ps -Ljf <pid>

These tid are the names of the directories under /proc/<pid>/task, and even if renice(1) say that its default argument is a pid when applied to a pid it renice only the main thread (this is a bug in linux implementation as written in setpriority(2)), it can also be applied to a tid and it renices the thread. Thats why the answer of @Anton is valid.

But most often there is an easier way to achieve the desired result, all these threads share the same pgid which is the pid of the group leader; you can renice by pgid by issuing:

$ renice -g <pgid>

If you don't want to renice some other process that depends of the same group leader, you have to use the @Anton's recipe:

$ renice <priority> $(ls -1 /proc/<pid>/task)

or:

$renice <priority> $(ps --no-header -Lo tid <pid>)

You may also want to know what are the other processes of the same group than the process you want to renice, that is the processes which share has the same pgid. You can use ps(1), ps does not allow to select processes by group leader, but you can grep a ps to do it. The processes with pgid 1908 will be given by the command:

$ ps --no-header axo pid,pgid |sed -n '/^ *[0-9][0-9]*  *1908/s/[0-9][0-9]* *$//p'

or if you prefer awk to sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'
  • This doesn't seem to work correctly on 4.19.4 (Debian Stretch as of now): $ renice -n 18 -g 8524 renice: failed to get priority for 8524 (process group ID): No such process $ ps --no-header axo pid,pgid|awk '{if ($2=="8524") print $1;}' Whereas Totor's method does/still works: $ /bin/ls /proc/8524/task | /usr/bin/xargs renice 19 2739 (process ID) old priority 19, new priority 19 2740 (process ID) old priority 19, new priority 19 ... I've confirmed with /proc, htop, pstree, etc. that I do have the correct top-level PID. Maybe something has changed in the past year. – Bill McGonigle Feb 6 at 15:15
  • I don't know how you made your test @bill-mcgonigle, I just tried with three kernels 4.9.0 on Debian Stretch; 4.18.0 and 4.19.0 on Debian testing; And it works as I told above. – marcz Feb 12 at 18:20
  • Like I said, Debian Stretch on 4.19.4 with the commands and output shown ; the difference seems to be 4.19.0 vs 4.19.4 but I am surprised there would be much change between such minor versions. – Bill McGonigle Feb 14 at 21:12
  • I guess your process 8524 is the PID of all threaded process TID or LPW, but not the process group, so of course you find all the threads in /proc/8524/task but renice -g fail. When you look at a process tree one branch is in the same process group, not only one threaded process. Try again checking result of ps -Ljf. – marcz Feb 17 at 20:08
0

I'd like to recommend using the -g (process groups) argument instead of the -p (process id's) while using renice. It does the same thing without the bash-foo.

i.e.

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>
  • marcz's answer already mentions this. – Totor Jan 4 at 13:48
-1

Here is a script of mine:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>
  • 1
    This launches renice on every processes except the one you name. I personnaly consider this command as dangerous and inadequate. – Totor Aug 29 '18 at 12:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.