我已经在多个地方读过Linux的默认调度程序在多核计算机上超线程识别,这意味着如果你有一台拥有2个真实核心的计算机(4 HT) ),它不会将两个忙线程安排到逻辑核心上,使它们在相同的物理内核上运行(在许多情况下会导致2倍的性能成本)。
但是当我在我的Intel i5-2520M上运行stress -c 2
(产生两个线程以在100%CPU上运行)时,它经常安排(并保持)这两个线程到HT核心1和2,映射到相同的物理核心。即使系统处于空闲状态,也是如此。
这也适用于真正的程序(我在这里使用stress
,因为它可以很容易地重现),当发生这种情况时,我的程序可以理解地需要两倍的时间来运行。使用taskset
手动设置关联性可以修复我的程序,但我希望HT感知调度程序能够自行正确地执行此操作。
您可以使用egrep "processor|physical id|core id" /proc/cpuinfo | sed 's/^processor/\nprocessor/g'
找到 HT->物理核心分配。
所以我的问题是:为什么调度程序会将我的线程放在同一个物理内核上?
注意:
stress -c
检查自己),并想知道原因。taskset
工具或sched_setaffinity
功能。这不是我想要的,我希望调度程序能够自己知道将两个忙线程映射到一个物理内核并将一个物理内核完全清空是个不错的主意。stress
可以在单独的物理核心上运行。答案 0 :(得分:7)
我认为现在是时候从评论中总结一些知识了。
Linux调度程序感知超级线程 - 有关它的信息应该从BIOS / UEFI提供的ACPI SRAT / SLIT表中读取 - 而不是从Linux构建scheduler domains 。
域具有层次结构 - 即在2 CPU服务器上,您将获得三层域: all-cpus,per-cpu-package 和 per-cpu-core 域名。您可以从/proc/schedstat
:
$ awk '/^domain/ { print $1, $2; } /^cpu/ { print $1; }' /proc/schedstat
cpu0
domain0 0000,00001001 <-- all cpus from core 0
domain1 0000,00555555 <-- all cpus from package 0
domain2 0000,00ffffff <-- all cpus in the system
CFS调度程序的一部分是负载均衡器 - 应该将任务从忙碌核心窃取到另一个核心的野兽。以下是内核文档中的描述:
在执行此操作时,它会检查当前域是否已耗尽 重新平衡间隔。如果是,则在该域上运行
load_balance()
。然后检查 parent sched_domain(如果存在),以及父级的父级等 类推。最初,
load_balance()
找到当前sched域中最繁忙的组。 如果成功,它会查找所有CPU的最繁忙的运行队列&#39;运行中的 那个小组。如果它设法找到这样的runqueue,它会锁定我们的初始值 CPU的runqueue和新发现的最繁忙的runqueue并开始从中移动任务 到我们的runqueue。确切的任务数量之前相当于不平衡 迭代这个sched域的组时计算。
来自:https://www.kernel.org/doc/Documentation/scheduler/sched-domains.txt
您可以通过比较/proc/schedstat
中的数字来监控负载均衡器的活动。我为此写了一个脚本:schedstat.py
计数器alb_pushed
显示负载均衡器已成功移出任务:
Sun Apr 12 14:15:52 2015 cpu0 cpu1 ... cpu6 cpu7 cpu8 cpu9 cpu10 ...
.domain1.alb_count ... 1 1 1
.domain1.alb_pushed ... 1 1 1
.domain2.alb_count 1 ...
.domain2.alb_pushed 1 ...
但是,负载均衡器的逻辑很复杂,因此很难确定哪些原因可以阻止它正常工作以及它们与schedstat计数器的关系。我和@thatotherguy都不能重现你的问题。
我看到了这种行为的两种可能性:
mpstat
和schedstat
数据)答案 1 :(得分:4)
我无法在3.13.0-48上使用我的英特尔(R)Xeon(R)CPU E5-1650 0 @ 3.20GHz重现这一点。
我有6个超线程核心,逻辑核心N映射到物理核心N mod 6.
以下是两列top
stress -c 4
的典型输出,因此每一行都是一个物理核心(由于我的系统不空闲,我遗漏了几个核心):
%Cpu0 :100.0 us, %Cpu6 : 0.0 us,
%Cpu1 :100.0 us, %Cpu7 : 0.0 us,
%Cpu2 : 5.9 us, %Cpu8 : 2.0 us,
%Cpu3 :100.0 us, %Cpu9 : 5.7 us,
%Cpu4 : 3.9 us, %Cpu10 : 3.8 us,
%Cpu5 : 0.0 us, %Cpu11 :100.0 us,
这是在杀死并重新启动stress
之后:
%Cpu0 :100.0 us, %Cpu6 : 2.6 us,
%Cpu1 :100.0 us, %Cpu7 : 0.0 us,
%Cpu2 : 0.0 us, %Cpu8 : 0.0 us,
%Cpu3 : 2.6 us, %Cpu9 : 0.0 us,
%Cpu4 : 0.0 us, %Cpu10 :100.0 us,
%Cpu5 : 2.6 us, %Cpu11 :100.0 us,
我这样做了几次,并没有看到任何实例,其中12个逻辑核心上的4个线程将在同一物理核心上进行调度。
使用-c 6
我倾向于得到这样的结果,其中Linux似乎有助于在自己的物理内核上安排其他进程。即便如此,它们的分布方式也好于偶然:
%Cpu0 : 18.2 us, %Cpu6 : 4.5 us,
%Cpu1 : 0.0 us, %Cpu7 :100.0 us,
%Cpu2 :100.0 us, %Cpu8 :100.0 us,
%Cpu3 :100.0 us, %Cpu9 : 0.0 us,
%Cpu4 :100.0 us, %Cpu10 : 0.0 us,
%Cpu5 :100.0 us, %Cpu11 : 0.0 us,
答案 2 :(得分:-2)
使用两个似乎正常工作的额外处理器,i7-2600和Xeon E5-1620,引用您的体验;这可能是一个长镜头,但CPU微码更新怎么样?如果它的内部CPU行为可能包括解决问题的东西。
Intel CPU Microcode下载:http://intel.ly/1aku6ak