nice, renice, and ionice: Controlling Process Priority on Linux

nice, renice, and ionice: Controlling Process Priority on Linux

You start a backup and your music skips. You extract a large archive and the desktop becomes unresponsive. The instinctive fix is to give the offending process less CPU priority, and it usually does not help, because the CPU was never the problem.

Linux gives you two separate priority controls, and knowing which one applies is most of the battle.

CPU priority: nice

The nice value runs from -20, most favourable, to 19, least. Default is 0. A higher value means the process yields the CPU more readily when something else wants it.

nice -n 19 ./long-running-job.sh          # start it politely
nice -n 10 tar -czf backup.tar.gz /data

Note the inversion, which trips everyone up at least once: higher nice value means lower priority.

For processes already running:

renice -n 15 -p 1234        # by PID
renice -n 10 -u backupuser  # every process owned by a user
renice -n 5 -g 4321         # by process group

Check what a process is currently at:

ps -eo pid,ni,comm --sort=-ni | head
top -o NI

Why root is needed to go up

Any user can raise their own process’s nice value, making it less demanding. Lowering it below the current value requires root.

The reason is obvious once stated: if unprivileged users could set -20, every program would, and the mechanism would be worthless.

Disk priority: ionice

This is the one most people actually need. A backup, a dd, or an rsync uses very little CPU and saturates the disk queue. The system feels frozen while top shows an idle processor.

ionice -c 3 rsync -a /data /backup            # idle class
ionice -c 2 -n 7 tar -czf big.tar.gz /data    # best-effort, lowest priority
ionice -p 1234                                # what class is this process in
ionice -c 3 -p 1234                           # change a running process

The classes:

  • Class 1, real-time. Gets disk access ahead of everything. Requires root and can starve the rest of the system. Avoid.
  • Class 2, best-effort. The default, with priority levels 0 to 7 where lower is more favourable.
  • Class 3, idle. Only gets disk access when nothing else wants it.

Class 3 is what you want for background bulk work. A backup running in the idle class finishes slower and stops making the machine feel broken, which is almost always the right trade.

The caveat

ionice depends on the I/O scheduler. With BFQ it works well. With mq-deadline or none, common defaults on NVMe drives, the effect ranges from limited to nonexistent.

cat /sys/block/nvme0n1/queue/scheduler
cat /sys/block/sda/queue/scheduler

The bracketed entry is active. If it says [none], ionice will not do much, and the honest answer is that fast NVMe storage rarely needs it anyway.

Combining them

For a genuinely background job, lower both:

nice -n 19 ionice -c 3 rsync -a --info=progress2 /data /backup

This is a good default for anything you want to finish eventually without noticing it, and it is worth putting into your backup scripts.

The better answer for services

Wrapping a command works for one-off jobs. For anything running as a systemd unit, set it in the unit file so it applies every time:

[Service]
Nice=15
IOSchedulingClass=idle
CPUWeight=20
IOWeight=20

CPUWeight and IOWeight are cgroup controls rather than classic priority, and they are proportional: a service at weight 20 competing with one at the default 100 gets roughly a fifth of the contested resource. That is a more predictable model than nice values, and it is what modern systems should use.

Our systemd unit builder generates the file, and the systemd timer builder covers scheduled jobs, which is where this matters most.

When priority is not the answer

If a process is consuming enormous CPU, the question is why, not how to deprioritise it. Priority tuning around a runaway process is treating the symptom.

If the machine is swapping, no priority setting will save it, because the bottleneck is memory. Check with vmstat 1 and look at the si and so columns.

If a single process is starving everything, a hard limit is more appropriate than a hint. systemd-run can apply one on the fly:

systemd-run --scope -p CPUQuota=50% -p IOWeight=10 ./heavy-job.sh

That caps the job at half a core’s worth of CPU regardless of what else is happening, which is a guarantee rather than a preference.

Frequently Asked Questions

What does the nice value actually mean?

It is a CPU scheduling hint from -20 to 19, where lower means higher priority. The name comes from how nice the process is being to others: a high nice value means it readily yields the CPU. Default is 0.

Why does nice not fix my stuttering system?

Because the bottleneck is usually disk, not CPU. A backup or a large copy saturates I/O while using very little processor time, and no CPU priority change helps. ionice is the tool for that case.

Do I need root to change priority?

Only to raise it. Any user can lower the priority of their own processes by increasing the nice value. Decreasing it, meaning asking for more CPU than default, requires root, otherwise every program would simply claim top priority.

What is the difference between nice and renice?

nice sets the priority of a command as you launch it. renice changes the priority of a process that is already running, by PID, user, or process group. They are the before and after versions of the same control.

Does ionice work on every filesystem and scheduler?

It depends on the I/O scheduler in use. The idle and best-effort classes work with schedulers that support priorities, such as BFQ. With the none or mq-deadline schedulers common on NVMe drives, ionice may have little or no effect.

Is systemd a better way to do this for services?

Yes, for anything running as a unit. Nice, IOSchedulingClass, CPUWeight, and IOWeight in the unit file apply every time the service starts, rather than depending on someone remembering to wrap the command.