5
11
2020
14

Linux 的进程优先级与 nice 值

本文来自依云's Blog,转载请注明。

2024年04月20日更新:autogroup 仅对位于根 cgroup 中的进程有效。而在现在使用 systemd 的系统中,默认会使用 cgroup v2,没有进程位于根 cgroup,autogroup 也就不起效了。如果没有开启 cgroup 的 cpu 控制器的话,进程的 nice 值将起效。


假设有一个程序叫 use-cpu,它运行的时候会一直消耗一个 CPU 核心。试问,如果我开两个终端窗口,分别执行以下两个进程,其 CPU 会如何分配?

$ taskset 2 ./use-cpu
$ taskset 2 nice -n 10 ./use-cpu

两个进程都在1号CPU上运行,意味着它们必定争抢时间片。第二个进程使用 nice 命令设置其 nice 为 10,那么,是不是第二个进程会占用比较少的 CPU 呢?

很合情合理的推理,然而答案是否定的。

呃,也不一定。cat /proc/sys/kernel/sched_autogroup_enabled 看一下,这个开了的话,CPU 调度会多一个层级。默认是开的,所以这两个进程会均分 CPU 时间。

首先说好了呀,这里只讨论普通进程(SCHED_OTHER)的调度。实时进程啥的不考虑。当然啦,CPU 分配只发生在 R(Runnable)状态的进程之间,暂时用不到 CPU 的进程不管。

最上面的层级是 cgroups 了。按照 cgroup 层级,每一层的子组或者进程间按权重分配。对于 cgroups v1,权重文件是 cpu.shares;cgroups v2 则是 cpu.weight。不管用哪个版本的 cgroups,systemd 默认都没有做特别的设置的。对于 v1,大家全在根组里;对于 v2,CPU 控制器都没有启用。如果你去设置 systemd 单元的 CPUWeight 属性(或者旧的 CPUShares 属性),那么 systemd 就会开始用 cgroups 来分配 CPU 了。一个意外的状况是,使用 cgroups v2 时,systemd-run 不会自动启用上层组的 CPU 控制器,以至于如果上层未手动启用的话,设置不起作用。在使用 cgroups v1 时,用 systemd 设置 CPUWeight 或者 CPUShares 也不太好用,因为它并不会自动把进程挪到相应的层级里去……

其次就是这个默认会开的 autogroup。这个特性是为了提升交互式的桌面系统的性能而引入的,会把同一 session 的进程放一个组里。每个 autogroup 作为一个整体进行调度,每个 autogroup 也有个 nice 值,在 /proc/PID/autogroup 里可以看到,也可以 echo 一个想要的 nice 值进去。至于这个 session,不是 systemd 的那个 session,而是传统 UNIX 的那个 session,也是 setsid(2) 的那个 session。我一直以为它没多大作用,没想到在这里用上了。基本上,同一群进程会在同一个 session 里(比如一群火狐进程,或者一群 make 进程),同一个终端里跑的进程也都在一个 session 里(除非你 setsid 了)。

最后才是轮到进程。其实准确地讲是线程。同一个 autogroup 里的时间片如何分配,就看里边这些线程的 nice 值的大小了。所以其实,我系统里的那些高 nice 值的进程,由于 autogroup 的存在而它们又没有去设置 autogroup 的 nice 值,其实调度起来没什么差别的。

参考资料

  • man 7 sched
  • man 7 cgroups
Category: Linux | Tags: linux systemd cgroups | Read Count: 161265
拿铁 说:
May 11, 2020 07:29:49 PM

嗯,不明觉厉
nice~

山水之间 说:
May 14, 2020 02:41:56 PM

跟着依云学Linux.

疾风之狼 说:
Jul 16, 2020 08:53:02 AM

很有道理,终于明白为什么nice现在没用了。

druggo 说:
Feb 19, 2021 11:31:08 AM

随手试了下
$ cat /proc/sys/kernel/sched_autogroup_enabled
1
$ taskset 2 yes > /dev/null &
[1] 212920
$ taskset 2 nice -n 20 yes > /dev/null &
[2] 212921

top看明显nice的进程得不到多少cpu啊

进程号 USER PR NI VIRT RES SHR %CPU %MEM TIME+ COMMAND
212920 druggo 20 0 13692 708 632 R 98.7 0.0 0:28.04 yes
212921 druggo 39 19 13692 704 632 R 1.7 0.0 0:00.37 yes

系统是5.11-gentoo,gnome 3.38

Avatar_small
依云 说:
Feb 19, 2021 01:17:52 PM

同一个 UNIX 会话里,nice 值高的进程是会比较 nice 啊。所以我说的是开两个终端窗口。autogroup 是按 UNIX 会话分的。

libing195205 说:
Apr 18, 2024 12:17:13 AM

h1是一个算sha的程序

root用户运行:
root@vm:~$ taskset 2 nice -n 20 /home/marvin/yourvm/capture/h1 1 1000
Started: thread_count=1, duration(second)=1000
top显示:cpu 98.7%

marvin用户运行:
marvin@vm:~$ taskset 2 /home/marvin/yourvm/capture/h1 1 1000
Started: thread_count=1, duration(second)=1000
top显示:cpu 1.3%

root@vm:~# cat /proc/sys/kernel/sched_autogroup_enabled
1
marvin@vm:~$ uname -a
Linux vm 6.5.0-27-generic #28~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 15 10:51:06 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
marvin@vm:~$

“呃,也不一定。cat /proc/sys/kernel/sched_autogroup_enabled 看一下,这个开了的话,CPU 调度会多一个层级。默认是开的,所以这两个进程会均分 CPU 时间。”
============================
文章中的结论,和实践验证完全对应不起来。

Avatar_small
依云 说:
Apr 18, 2024 12:20:05 PM

噗,你这 nice 的效果相反了?还是,你去掉 nice 试试?
另外我完全不知道你的 cgroup / unix session 的结构。

libing195205 说:
Apr 18, 2024 12:39:27 PM

sorry,效果写反了。

h1都是运行在机器B上。

1. 在机器A上,以root用户 ssh 到B,在B上运行h1。

2. marvin用户,直接在机器B上 开个terminal运行h1。

3. 在机器B上,开个terminal 运行top命令看效果。

https://zhuanlan.zhihu.com/p/687433100
我觉得这个文章可能是对的,ubuntu使用了systemd,所以,我的每一个进程其实都在 user.slice 这个cgroup下,所以,autogroup根本就不起作用啦。

libing195205 说:
Apr 18, 2024 12:45:10 PM

谢谢您的回复哦:)

另外,同样是上面的测试方式,我昨天也试过,去掉nice值,两者是可以50%平分cpu的。

Avatar_small
依云 说:
Apr 18, 2024 02:36:33 PM

你这样的话,显然程序会在不同的 cgroup 里。不过这效果也不对啊……如果 cgroup 开了 cpu 控制器,那么应当按 cpu.weight 来分配,否则应该还是看 autogroup 的。——还是说,Ubuntu 改了 nice 的实现?

你看看 cat /proc/self/cgroup,然后去看看 /sys/fs/cgroup 下对应 cgroup 里的 cpu.weight 呢?

libing195205 说:
Apr 20, 2024 05:17:26 PM

记录下了测试过程

https://blog.csdn.net/iceman1952/article/details/138001536

Avatar_small
依云 说:
Apr 20, 2024 09:38:55 PM

原来需要在 root cgroup 里啊。这样一来,在使用 systemd 的系统上,这 autogroup 就彻底废啦。

Avatar_small
依云 说:
Apr 20, 2024 09:46:06 PM

我想了一下,应该是当年的 systemd 还在用 cgroup v1,并且它默认只用其来管理进程关系,并没有把进程往子 cpu cgroup 里放,所以我测到了 autogroup 的效果。现在 systemd 都默认 cgroup v2 啦,不再按资源分不同的 cgroup 树了。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com