Skip to content

Priority and Nice

The nice value tells the Linux scheduler how to share CPU time between competing processes; ionice does the same for disk I/O and chrt switches a process to a real-time policy. These controls matter when a backup, build or report job must not slow down a production service on the same host.

Track: Core · Interview weight: Med


Must-Know Facts

Fact Value Verify with
Nice range -20 (highest priority) to 19 (lowest); default 0 nice
Start with a nice value nice -n 10 cmd; the default increment is 10 nice -n 10 nice
Change a running process renice -n 5 -p <pid>; also -u user, -g pgrp ps -o ni -p <pid>
Unprivileged users May only raise the nice value (lower priority) of their own processes renice -n 2 after 5 fails
Negative nice Needs root, CAP_SYS_NICE, or a nice limit in limits.conf ulimit -e
Weight Each nice step changes CPU share by about 10% (weight ratio 1.25) two CPU hogs on one core
PR in top 20 + nice for normal tasks; rt or negative for real-time top
I/O class ionice -c 1 realtime, -c 2 -n 0..7 best-effort, -c 3 idle ionice -p <pid>
I/O priority effect Honored by the BFQ scheduler; mq-deadline and none mostly ignore it cat /sys/block/<dev>/queue/scheduler
Real-time policies SCHED_FIFO and SCHED_RR, priority 1 to 99, root only chrt -p <pid>
Scheduler CFS up to Linux 6.5; EEVDF from 6.6 (RHEL 10 ships 6.12) uname -r
Autogroup When enabled, the scheduler groups tasks by session, so nice works only within a session cat /proc/sys/kernel/sched_autogroup_enabled
systemd Nice=, CPUWeight=, IOSchedulingClass=, IOWeight= in a unit systemctl show -p Nice <unit>

nice and renice

nice; nice -n 10 nice; nice -n 25 nice
nice -n -5 true
sleep 300 >/dev/null 2>&1 &
renice -n 5 -p 2815; renice -n 2 -p 2815
sudo renice -n -5 -p 2815
ps -o pid,ni,pri,cls,rtprio,comm -p 2815

Output:

0
10
19
nice: cannot set niceness: Permission denied
2815 (process ID) old priority 0, new priority 5
renice: failed to set priority for 2815 (process ID): Permission denied
2815 (process ID) old priority 5, new priority -5
    PID  NI PRI CLS RTPRIO COMMAND
   2815  -5  24  TS      - sleep

Values above 19 are clamped to 19. A user could raise the nice value from 0 to 5 but not lower it back to 2; only root can lower it.

Children inherit the nice value of their parent:

ps -o pid,ni,comm -p 2905; nice -n 5 bash -c 'ps -o pid,ni,comm -p $$'

Output:

    PID  NI COMMAND
   2905   0 sleep
    PID  NI COMMAND
   2929   5 ps

bash -c with a single command execs ps directly, so $$ is the PID of ps, which carries nice 5.

renice changes one thread by default on Linux

Nice is a per-thread attribute. renice -p <pid> changes the main thread, and threads created afterwards inherit it; for an existing multithreaded service, renice each TID from /proc/<pid>/task/, or set Nice= in the unit and restart it.


Nice Under CPU Contention

Nice only matters when tasks compete for the same CPU. Two CPU hogs pinned to CPU 0, one at nice 0 and one at nice 10, share it roughly 90/10:

taskset -c 0 stress-ng --cpu 1 --timeout 25 >/dev/null 2>&1 &
taskset -c 0 nice -n 10 stress-ng --cpu 1 --timeout 25 >/dev/null 2>&1 &
sleep 10
ps -o pid,ni,psr,%cpu,comm -C stress-ng-cpu

Output:

    PID  NI PSR %CPU COMMAND
   2714   0   0 90.1 stress-ng-cpu
   2715  10   0  9.7 stress-ng-cpu

The weight of nice 0 is 1024 and of nice 10 is 110, so the expected split is 1024/1134 = 90%. On an idle multi-CPU host both would get 100%, and nice would change nothing.

Autogroup can make nice look ineffective

With kernel.sched_autogroup_enabled=1 (the default on this kernel), the scheduler first divides CPU between sessions, then applies nice inside each session. A nice 19 job in one SSH session still gets half the CPU against a busy process in another session; systemd services are grouped by cgroup, where CPUWeight= is the effective control.


I/O Priority

ionice sets the I/O scheduling class; it has an effect only with an I/O scheduler that supports priorities (BFQ).

ionice -p 2905; ionice -c 3 -p 2905; ionice -p 2905
cat /sys/block/vda/queue/scheduler

Output:

none: prio 0
idle
[mq-deadline] kyber bfq none
Class Option Use
Realtime -c 1 -n 0..7 Root only; can starve everything else
Best-effort -c 2 -n 0..7 Default; none means best-effort derived from nice
Idle -c 3 Gets disk time only when no one else needs it

This virtual disk uses mq-deadline (in brackets), so the idle class is recorded but not enforced. For backups on such hosts, limit I/O with the unit's IOReadBandwidthMax= or with rsync --bwlimit.


Real-Time Policies

SCHED_FIFO runs a task until it blocks or a higher real-time priority arrives, and SCHED_RR adds a time slice between tasks of equal priority. Both preempt every normal task, so only root can set them.

chrt -p 2905; chrt -m | head -3
chrt -f 10 true
sudo chrt -f 10 sleep 1 & sleep 0.3; ps -eo pid,cls,rtprio,ni,pri,comm | awk 'NR==1 || $2 == "FF"'

Output:

pid 2905's current scheduling policy: SCHED_OTHER
pid 2905's current scheduling priority: 0
SCHED_OTHER min/max priority    : 0/0
SCHED_FIFO min/max priority : 1/99
SCHED_RR min/max priority   : 1/99
chrt: failed to set pid 0's policy: Operation not permitted
    PID CLS RTPRIO  NI PRI COMMAND
     16  FF     99   - 139 migration/0
     20  FF     99   - 139 migration/1
     25  FF     99   - 139 migration/2
     30  FF     99   - 139 migration/3
     52  FF     50   -  90 watchdogd
    100  FF     50   -  90 irq/24-ACPI:Ged
    103  FF     50   -  90 irq/25-ACPI:Ged
   2917  FF     10   -  50 sleep
CLS Policy
TS SCHED_OTHER, the normal time-sharing policy
B SCHED_BATCH, CPU-bound work with fewer preemptions
IDL SCHED_IDLE, runs only when nothing else wants the CPU
FF SCHED_FIFO
RR SCHED_RR

A busy SCHED_FIFO task can lock up a CPU

The kernel reserves 5% of each second for normal tasks (kernel.sched_rt_runtime_us = 950000 of sched_rt_period_us = 1000000). Setting it to -1 removes the safety margin.


Priorities in systemd Units

A service's priority is set in its unit, which applies to every process it starts and survives restarts.

systemctl show -p Nice -p CPUWeight -p IOWeight crond

Output:

CPUWeight=[not set]
IOWeight=[not set]
Nice=0
[Service]
Nice=10
IOSchedulingClass=idle
CPUWeight=20

CPUWeight= (1 to 10000, default 100) divides CPU between cgroups and works regardless of autogroup; it requires the cpu cgroup controller to be enabled for the unit's slice.


Common Errors

nice: cannot set niceness: Permission denied

Cause: an unprivileged user asked for a negative nice value.

Fix: run it with sudo, grant a limit in /etc/security/limits.d/ (@devs - nice -5), or set Nice= in a unit.

renice: failed to set priority for 2815 (process ID): Permission denied

Cause: a user tried to lower the nice value of a process, or to renice another user's process.

Fix: use sudo renice.

chrt: failed to set pid 0's policy: Operation not permitted

Cause: real-time policies need CAP_SYS_NICE or an RLIMIT_RTPRIO limit.

Fix: sudo chrt, or CPUSchedulingPolicy=fifo in a unit.


Interview Checkpoints

L1: What does the nice value do, and what is its range?

Say first: it weights a process's share of CPU time when CPUs are contended, from -20 (most favored) to 19 (least), default 0.

Proof: two pinned CPU hogs at nice 0 and 10 get about 90% and 10%.

Follow-up: Why does nice change nothing on an idle machine?

L1: Why can a normal user increase but not decrease a nice value?

Say first: lowering nice takes CPU from other users' work, so it needs CAP_SYS_NICE or an explicit limit.

Proof: renice -n 2 after renice -n 5 fails with Permission denied.

Follow-up: Where do you grant a group permission to use negative nice values?

L2: Run a nightly compression job at the lowest CPU and I/O priority.

Say first: combine nice and ionice.

Proof: nice -n 19 ionice -c 3 tar -czf /backup/app.tgz /srv/app

Follow-up: When does ionice -c 3 have no effect?

L2: Lower the priority of every process of user reports.

Say first: renice by user.

Proof: sudo renice -n 10 -u reports

Follow-up: Does this affect processes the user starts later? (No; use a limit or a slice.)

L2: Show the scheduling policy and real-time priority of all real-time tasks.

Say first: print the class and rtprio columns and filter.

Proof: ps -eo pid,cls,rtprio,comm | awk '$2 != "TS"'

Follow-up: Why do migration/N threads run at FF 99?

L3: A batch job was started with nice 19, but the web service on the same host is still slow.

Say first: nice only shares CPU, and may be undone by autogroup; check whether the contention is CPU at all.

Proof: top for us and wa, iostat -x 1 for disk latency, cat /proc/sys/kernel/sched_autogroup_enabled, then CPUWeight= or IOWeight= through systemd-run --scope -p for the job.

Follow-up: Which cgroup settings cap the job instead of only weighting it? (CPUQuota=, IOReadBandwidthMax=.)


Captured on Rocky Linux 10.2 (iximiuz Labs microVM, kernel 6.1.167), 2026-09.