Objective
Learn the fundamentals of processes management on Linux
Operating System and Software Versions
- Operating System: – All Linux distributions
Requirements
- Some programs mentioned in this tutorial require root access
Difficulty
EASY
Conventions
- # – requires given linux commands to be executed with root privileges either
directly as a root user or by use ofsudo
command - $ – requires given linux commands to be executed as a regular non-privileged user
Introduction
One of the core activities of a system administrator is that of monitoring and interacting with the processes running on a machine. In this tutorial you will be introduced to the use of some fundamental tools that will help you accomplish that vital task.
The ps command
Ps is one of the fundamental programs used in process monitoring: it basically gives you a snapshot
of the processes running on a machine at the moment you invoke the command. Let’s see it in action: first we will try to run it without any options:
$ ps PID TTY TIME CMD 24424 pts/0 00:00:00 bash 24468 pts/0 00:00:00 ps
As you can see from the output above, only two processes are shown: bash
with a PID
(process id) 24424
and ps
itself with the pid 24468
. This is because when invoked without any option, the ps
command shows processes associated with the UID
of the user who launched the command, and the terminal from which it is invoked.
How to overcome this limitation? Using the -a
option we can make ps
to show us all processes, with the exception of the session leaders
and the processes not associated with a terminal.
A session leader is a process which has a PID that is the same of the SID
(Session Id) of the session of which it is (the first) member. When a process is created it is made part of the same session of its parent process: since by convention the session id is the same of the PID
of its first member, we call this process a session leader
. Let’s try to run ps
with the -a
option and check its output:
$ ps -a PID TTY TIME CMD 12466 tty1 00:00:00 gnome-session-b 12480 tty1 00:00:17 gnome-shell 12879 tty1 00:00:00 Xwayland 12954 tty1 00:00:00 gsd-sound 12955 tty1 00:00:00 gsd-wacom 12957 tty1 00:00:00 gsd-xsettings 12961 tty1 00:00:00 gsd-a11y-keyboa 12962 tty1 00:00:00 gsd-a11y-settin 12965 tty1 00:00:00 gsd-clipboard 12966 tty1 00:00:03 gsd-color 12967 tty1 00:00:00 gsd-datetime 12970 tty1 00:00:00 gsd-housekeepin 12971 tty1 00:00:00 gsd-keyboard 12972 tty1 00:00:00 gsd-media-keys 12973 tty1 00:00:00 gsd-mouse 12976 tty1 00:00:00 gsd-orientation [...]
The output of the program has been truncated, but you can easily see that it now includes processes which belong to different terminals and users. The output shows us information about PID
in the first column, TTY
in the second, TIME
which is the cumulative time the CPU spent on the process, and CMD
which is the command that started the process.
To have an even richer output we can add the -u
and -x
options: the former tells ps
to do a selection by user id
, while the latter instructs the program to include also processes not associated with a terminal, such as daemons:
$ ps -aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.2 223932 8708 ? Ss Jul20 0:04 /usr/lib/systemd/systemd --switched-root --system --deserialize 25 root 2 0.0 0.0 0 0 ? S Jul20 0:00 [kthreadd] root 4 0.0 0.0 0 0 ? S< Jul20 0:00 [kworker/0:0H] root 6 0.0 0.0 0 0 ? S< Jul20 0:00 [mm_percpu_wq] root 7 0.0 0.0 0 0 ? S Jul20 0:00 [ksoftirqd/0] root 8 0.0 0.0 0 0 ? S Jul20 0:07 [rcu_sched] root 9 0.0 0.0 0 0 ? S Jul20 0:00 [rcu_bh] root 10 0.0 0.0 0 0 ? S Jul20 0:04 [rcuos/0] root 11 0.0 0.0 0 0 ? S Jul20 0:00 [rcuob/0] root 12 0.0 0.0 0 0 ? S Jul20 0:00 [migration/0] root 13 0.0 0.0 0 0 ? S Jul20 0:00 [watchdog/0] root 14 0.0 0.0 0 0 ? S Jul20 0:00 [cpuhp/0] root 15 0.0 0.0 0 0 ? S Jul20 0:00 [cpuhp/1] root 16 0.0 0.0 0 0 ? S Jul20 0:00 [watchdog/1] root 17 0.0 0.0 0 0 ? S Jul20 0:00 [migration/1] root 18 0.0 0.0 0 0 ? S Jul20 0:00 [ksoftirqd/1] root 20 0.0 0.0 0 0 ? S< Jul20 0:00 [kworker/1:0H] root 21 0.0 0.0 0 0 ? S Jul20 0:02 [rcuos/1] root 22 0.0 0.0 0 0 ? S Jul20 0:00 [rcuob/1] root 23 0.0 0.0 0 0 ? S Jul20 0:00 [cpuhp/2] root 24 0.0 0.0 0 0 ? S Jul20 0:00 [watchdog/2] root 25 0.0 0.0 0 0 ? S Jul20 0:00 [migration/2] root 26 0.0 0.0 0 0 ? S Jul20 0:00 [ksoftirqd/2] root 28 0.0 0.0 0 0 ? S< Jul20 0:00 [kworker/2:0H] [...] egdoc 13128 0.0 0.1 74736 5388 ? Ss Jul20 0:00 /usr/lib/systemd/systemd --user egdoc 13133 0.0 0.0 106184 420 ? S Jul20 0:00 (sd-pam) egdoc 13143 0.0 0.1 218328 3612 ? Sl Jul20 0:00 /usr/bin/gnome-keyring-daemon --daemonize --login [...]
You can see that quite a lot of new information has been added. The first new column of the output is %CPU
: this shows the cpu utilization of the process, expressed as a percentage. A percentage is also used for the next column, %MEM
, which shows the physical memory on the machine used by the process. VSZ
is the virtual memory size of the process expressed in KiB.
The STAT
column uses a code to express the process state. We are not going to describe all possible states here, but just explain the ones appearing in the output above (you can have a complete overview by consulting the ps manpage).
Let’s examine the first process in the output: it is has PID 1
, therefore is the first process launched by the kernel. This makes sense, we can see that it is systemd
, the relatively new Linux init system, now adopted by almost all distributions. First of all we have an S
which indicates that the process is in the state of interruptible sleep
which means that it is idle, and will wake up as soon as it receives an input. The s
, instead, tells us that the process is a session leader
.
Another symbol, not appearing in the first raw, but in some of the other processes descriptions is <
which indicates that the process has high priority, and therefore a low nice
value (we will see what a nice value is in the relevant section of this tutorial). An l
in the STAT
column, indicates that the process is multi-threaded, and a +
sign, that it is in the foreground process group.
Finally, in the last column, we have the START
column, showing the time the command started.
Another nice option we can pass to the ps
command, is -o
, which is the short version of --format
. This option let’s you modify the output by the use of placeholders, specifying what columns to show. For example, running:
$ ps -ax -o %U%p%n%c
Will give us the USER
column first (%U), followed by the PID
of the process (%p), by the NI
column (%n), which indicates the nice
level, and finally by the COMMAND
column (%c):
USER PID NI COMMAND root 1 0 systemd root 2 0 kthreadd root 4 -20 kworker/0:0H root 6 -20 mm_percpu_wq root 7 0 ksoftirqd/0 root 8 0 rcu_sched root 9 0 rcu_bh root 10 0 rcuos/0 root 11 0 rcuob/0 root 12 - migration/0 root 13 - watchdog/0 root 14 0 cpuhp/0 root 15 0 cpuhp/1 root 16 - watchdog/1 root 17 - migration/1 root 18 0 ksoftirqd/1 root 20 -20 kworker/1:0H root 21 0 rcuos/1 root 22 0 rcuob/1 root 23 0 cpuhp/2 root 24 - watchdog/2 root 25 - migration/2 root 26 0 ksoftirqd/2
Using ‘top’ to dynamically interact with processes
While ps
gives us a static snapshot of processes and their information at the time you run it, top
gives us a dynamic view of the processes, updated at a specified time interval that we can specify both when launching the program and interactively (default is 3 seconds).
Top doesn’t just show us a dynamic representation of the running processes: we can interact with them and with the program itself, by the use of some keys. For example, pressing B
lets us toggle the use of bold characters, d
lets us enter a value to change the delay time, k
lets us send a signal to a process by prompting for its PID
and for the signal
code, with SIGTERM
being the default.
Change priority of processes with nice and renice
As we have seen before, each process have a priority
assigned to it, which indicates how much the process have to wait for other processes to free resources before it can access them. This priority can be specified with a value which is in a range that goes from -20
to 19
. The less the value, the highest the priority of the process. This can seem counter-intuitive at first, but see it this way: the nicer the process is to other processes, the more they will surpass it in accessing the resources.
But how can we set the priority of a process? We can use the nice
program to accomplish the task. Say you want to run a script with the lowest possible priority value: you would preface it this way:
$ nice -n 19 ./script.sh
You can also change the priority of a program that is already running by the use of renice
knowing its PID
:
# renice -n 15 PID
Where PID is the process id of the program. Just remember that the renice
command must be run with root permissions.
Send signals to processes with the kill and killall commands
We can use the kill command to send a signal
to a process which belong to us, or to every process if we have root permissions. The various signals we can send are identified by a number: we can easily see these correspondences by running the kill command with the -l
option:
$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
If no option is passed to the kill
command, by default it will send a SIGTERM
signal to the specified process, to which the latter could react in various ways: it may stop immediately, try to do some cleanup before stopping, or just ignore the signal.
To specify the signal to be sent using kill, we run the command followed by a dash and the number of the signal to be sent. For example to run a SIGKILL
signal we should run:
kill -9 PID
The SIGKILL
signal, unlike SIGTERM
cannot be caught by the process, which cannot react: it will just be terminated immediately.
Another signal you will often see is SIGINT
which is the signal that is sent on keyboard interrupt (CTRL-c). It also tries to terminate the process in a graceful way, and can be ignored by the process. SIGSTOP
and SIGCONT
will respectively suspend and resume the execution of a process: the former, like SIGKILL
cannot be caught or ignored. For a complete list and description of signals you can consult the manual for signal(7)
running:
man 7 signal
The killall
program has the same purpose of kill
, and like kill, sends a SIGTERM
signal when no other is specified, (this time with the --signal
option), but instead of referencing a process by its PID
, it will do it by command name, effectively killing all processes running under the same one.