Linux - 迁移和切换的区别?

11

查看/proc/<PID>/sched中的调度统计信息,您可以得到如下输出:

[horro@system ~]$ cat /proc/1/sched
systemd (1, #threads: 1)
-------------------------------------------------------------------
se.exec_start                                :    2499611106.982616
se.vruntime                                  :          7952.917943
se.sum_exec_runtime                          :         58651.279127
se.nr_migrations                             :                53355
nr_switches                                  :               169561
nr_voluntary_switches                        :               168185
nr_involuntary_switches                      :                 1376
se.load.weight                               :              1048576
se.avg.load_sum                              :               343837
se.avg.util_sum                              :               338827
se.avg.load_avg                              :                    7
se.avg.util_avg                              :                    7
se.avg.last_update_time                      :     2499611106982616
policy                                       :                    0
prio                                         :                  120
clock-delta                                  :                  180
mm->numa_scan_seq                            :                    1
numa_pages_migrated                          :                  296
numa_preferred_nid                           :                    0
total_numa_faults                            :                   34
current_node=0, numa_group_id=0
numa_faults node=0 task_private=0 task_shared=23 group_private=0 group_shared=0
numa_faults node=1 task_private=0 task_shared=0 group_private=0 group_shared=0
numa_faults node=2 task_private=0 task_shared=0 group_private=0 group_shared=0
numa_faults node=3 task_private=0 task_shared=11 group_private=0 group_shared=0
numa_faults node=4 task_private=0 task_shared=0 group_private=0 group_shared=0
numa_faults node=5 task_private=0 task_shared=0 group_private=0 group_shared=0
numa_faults node=6 task_private=0 task_shared=0 group_private=0 group_shared=0
numa_faults node=7 task_private=0 task_shared=0 group_private=0 group_shared=0

我一直在试图弄清楚迁移和切换之间的区别,这里 还有 这里 有些回答。总结这些回答:

  • nr_switches:上下文切换次数。
  • nr_voluntary_switches:自愿切换次数,即线程被阻塞,因此选择另一个线程。
  • nr_involuntary_switches:调度程序将线程踢出,因为另一个饥饿的线程已准备好运行。

那么,什么是迁移?这些概念是否相关?迁移在核心之间进行,而切换则在一个核心内进行吗?

1个回答

17

当线程在上下文切换后被调度到与之前不同的CPU上时,这就是迁移。

编辑1:

维基百科上提供有关迁移的更多信息: https://en.wikipedia.org/wiki/Process_migration

这里是内核代码增加计数器的代码: https://github.com/torvalds/linux/blob/master/kernel/sched/core.c#L1175

if (task_cpu(p) != new_cpu) {
    ...
    p->se.nr_migrations++;

编辑2:

线程可以在以下情况下迁移到另一个CPU:

  1. exec() 期间
  2. fork() 期间
  3. 在线程唤醒期间。
  4. 如果线程亲和力掩码已更改。
  5. 当当前CPU正在离线时。

有关更多信息,请查看同一源文件中的函数 set_task_cpu()move_queued_task()migrate_tasks()https://github.com/torvalds/linux/blob/master/kernel/sched/core.c

调度程序遵循的策略在 select_task_rq() 中描述,这取决于您使用的调度程序类。策略的基本版本:

if (p->nr_cpus_allowed > 1)
    cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags);
else
    cpu = cpumask_any(&p->cpus_allowed);

来源:https://github.com/torvalds/linux/blob/master/kernel/sched/core.c#L1534

为了避免迁移,使用sched_setaffinity(2)系统调用或相应的POSIX API pthread_setaffinity_np(3)设置您的线程的CPU亲和性掩码。

这里是完全公平调度器(Completely Fair Scheduler)的select_task_rq()定义: https://github.com/torvalds/linux/blob/master/kernel/sched/fair.c#L5860

逻辑相当复杂,但基本上,我们要么选择兄弟空闲的CPU,要么找到最不忙的新CPU。

希望这回答了你的问题。


2
@horro,我尝试手动控制线程核心亲和力后得出结论:这样做没有意义,策略太过复杂。需要考虑的事情太多了,而且对于每台计算机都不同。例如,在双 CPU 机器上,你可能需要考虑哪个 CPU 拥有大部分线程的数据(超载 QPI 总线毫无意义)。这本身就是一个复杂的问题;连续的内存页面可以在 CPU 之间交错,也可以不交错(这是某些机器上的 BIOS 设置)。操作系统知道这一切甚至更多。我害怕深入探究…… - bazza
@AndriyBerestovskyy,您能否简要描述一下CPU迁移可能会引起的性能问题?据我现在的理解,这似乎与某个线程从某个CPU中取消调度,然后稍后被调度到另一个CPU中相同,对吗?我的意思是亲和力如何帮助? - St.Antario
2
@St.Antario 简言之,迁移会导致更多的缓存未命中(现代 CPU 至少具备指令、数据和 TLB 缓存),更多的分支预测器未命中等问题。我相信还有其他问题,但这是我目前所想到的;) - Andriy Berestovskyy
@AndriyBerestovskyy 非常感谢您的回复!但我想再问您一个澄清。这是否意味着现代CPU不允许直接访问它们的L1缓存,而只能访问更高级别的缓存?因此,操作系统在上下文切换时无法交换L1缓存。这正确吗? - St.Antario
1
@St.Antario 通常情况下,L1缓存是“私有”的。这就是为什么L1缓存比L2快几倍的原因。虽然有缓存一致性协议,但通常数据会通过一致性点(即更高级别的缓存)。据我所知,TLB缓存和分支预测器历史记录会被丢弃。请查看我的The Spectre of Meltdowns演示文稿,了解缓存和分支预测器的基础知识。 - Andriy Berestovskyy
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接