37

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?

7 Answers 7

34
+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
2
  • 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, 2016 at 12:34
  • I tried renice on a thread ID, and it reports 24995 (process ID) old priority 0, new priority -10. 24995 does not appear in ps, so it's not a process. Maybe renice-ing threads actually works? Sep 28, 2019 at 13:29
16

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)

Side notes

Nice value or CPU shares ?

Please note that nowadays, nice values may not be so relevant "system-wide", because of automatic task grouping, especially when using systemd. Please see this answer for more details.

Difference between threads and processes

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).

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


1 See this answer for more information about PID (ProcessID) and TID difference (ThreadID).

9

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;}'
4
  • 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. Feb 6, 2019 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, 2019 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. Feb 14, 2019 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, 2019 at 20:08
9

According to man renice (emphasis mine):

renice alters the scheduling priority of one or more running processes. The first argument is the priority value to be used. The other arguments are interpreted as process IDs (by default), process group IDs, user IDs, or user names. (...)

And indeed, man pgrep demonstrates, as an example:

Example 4: Make all chrome processes run nicer:

$ renice +4 $(pgrep chrome)

According to these, you can combine renice with pgrep's -w | --lightweight switch to renice all threads at once, like so:

renice <priority> $(pgrep -w <process_name>)

And to renice all child processes:

renice <priority> $(pgrep -P $(pgrep <process_name>))

Notice you can also use the -f switch with pgrep to query not only the process name, but the entire command line (needn't be a full match).

1
  • 2
    It seems to me that this solution doesn't renice children processes of children processes of the main process (not fully recursive, only 2 levels). I found the --lightweight option of pgrep interesting though.
    – Totor
    Dec 23, 2019 at 19:26
3

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>
1
  • marcz's answer already mentions this.
    – Totor
    Jan 4, 2019 at 13:48
0

Here is a script of mine:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>
3
  • 3
    This launches renice on every processes except the one you name. I personnaly consider this command as dangerous and inadequate.
    – Totor
    Aug 29, 2018 at 12:20
  • 2
    I wonder if he had meant -w not -v
    – Diablo-D3
    Jun 1, 2019 at 10:09
  • @Totor While I agree your comment in general, it is dangerous only for users not knowing what are they doing. If you need to work quickly and you know that <PROCESS_NAME> is the only process on your system, that is ok.
    – peterh
    Jun 22, 2020 at 14:03
0

After reading a lot of posts in these connected forums I think I have the solution:

root-Linuxes:

renice 10 -p $(ps -A -o pid)

Ubuntu-kind:

sudo renice 10 -p $(sudo ps -e -o pid)

This way all threads can be tamed to renice.

If a guru tells me how to use renice for priority and time-slice in the above command, I think we can make a standard Linux (or any system) to "near" preemptive (without the need to move to a preemptive-kernel-version).

Hope it helps someone, I get a very nice and soft feeling after running that in Ubuntu/Min for my Vboxes.

What is still needed is a way to run it every 3 seconds or a way to implement it to watch all processes and tame them.

Even on Windows I get these results, but only with "Process Lasso"!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .