超越单CUP:超线程加快了Linux的速度
发表于:2007-07-04来源:作者:点击数:
标签:
简介 Intel 的超线程技术通过复制、分区和共享 Intel NetBurst 微体系结构管道中的资源,使得一个物理处理器能包含两个逻辑处理器。 被复制的资源为两个线程创建了资源副本: 每个 CPU 的所有体系结构状态 指令指针,重命名逻辑 一些较小的资源(例如返回堆
简介 Intel 的超线程技术通过复制、分区和共享 Intel NetBurst 微体系结构管道中的资源,使得一个物理处理器能包含两个逻辑处理器。
被复制的资源为两个线程创建了资源副本:
每个 CPU 的所有体系结构状态
指令指针,重命名逻辑
一些较小的资源(例如返回堆栈预测器、ITLB 等)
已分区的资源划分执行线程之间的资源:
几个缓冲区(Re-Order 缓冲区、Load/Store 缓冲区、队列等)
共享的资源按需在两个正在执行的线程之间使用资源:
乱序执行引擎
高速缓存
通常,每个物理处理器在一个处理器核心上都有一个体系结构状态,来为线程提供服务。使用了 HT,每个物理处理器在单个核心上就有两个体系结构状态,这使得物理处理器看起来象有两个逻辑处理器在为线程提供服务。系统 BIOS 列举出物理处理器中的每个体系结构状态。由于支持超线程的操作系统利用了逻辑处理器,因此这些操作系统就有两倍的资源可用于为线程提供服务。
Xeon 处理器中的超线程支持 在通用处理器中 Xeon 处理器最先实现同步多线程(SMT)(请参阅参考资料以获取有关 Xeon 处理器系列的更多信息)。为达到在单一物理处理器上执行两个线程的目标,该处理器同时维持多个线程的上下文,这允许调度程序并发分派两个可能无关的线程。
操作系统(OS)将多个线程代码调度和分派给每个逻辑处理器,就如同在 SMP 系统中。没有分派线程时,相关的逻辑处理器保持空闲。
当将一个线程调度和分派给逻辑处理器 LP0 时,超线程技术利用必需的处理器资源来执行该线程。
当将第二个线程调度和分派给第二个逻辑处理器 LP1 时,就要按需为执行该线程而复制、划分或共享资源。每个处理器都在管道各点上进行选择,以控制和处理这些线程。当每个线程完成时,操作系统将未用的处理器置为空闲,释放资源让正在运行的处理器使用。
OS 将线程调度和分派给每个逻辑处理器,就好像是在双处理器或多处理器系统中进行的那样。当系统调度线程并将之引入到管道中时,按需利用资源以处理这两个线程。
Linux 内核 2.4 中的超线程支持 Linux 内核将带有两个虚拟处理器的超线程处理器看成是一对真正的物理处理器。其结果是,处理 SMP 的调度程序也应该能处理超线程。Linux 内核 2.4.x 中的超线程支持始于 2.4.17,它包括了以下增强技术:
128 字节锁对齐
螺旋等待循环优化
基于非执行的延迟循环
检测支持超线程的处理器,并启动逻辑处理器,如同该机器是 SMP
MTRR 和微码更新(Microcode Update)驱动程序中的串行化,因为它们影响共享状态
在逻辑处理器上的调度发生之前,当系统空闲时对物理处理器上的调度进行优先级排序时,对调度程序进行优化
偏移用户堆栈以避免 64K 混叠
内核
性能测量
为评定超线程对 Linux 内核性能的影响,我们在包括 Intel Xeon 处理器(具有 HT 功能)的系统上测量了内核基准测试程序的性能。硬件是:支持 SMT 的单 CPU、1.6 GHz Xeon MP 处理器、2.5 GB RAM 和两个 9.2 GB SCSI 硬盘驱动器。测量的内核是配置和构建了支持 SMP 的现有内核 V2.4.19。内核超线程支持通过引导选项 acpismp=force 来指定使用超线程,并通过引导选项 noht 来指定不使用超线程。查看是否支持超线程可以通过使用命令 cat /proc/cpuinfo,来显示处理器 0 和处理器 1 这两个处理器是否存在。请注意清单 1 中用于 CPU 0 和 1 的 ht 标志。在不支持超线程的情况下,将只显示处理器 0 的数据。
清单 1. cat /proc/cpuinfo 的输出,显示超线程支持 processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 1
model name : Intel(R) Genuine CPU 1.60GHz
stepping : 1
cpu MHz : 1600.382
cache size : 256 KB
. . .
fpu : yes
fpu_exception: yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr
pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht
tm
bogomips : 3191.60
processor : 1
vendor_id : GenuineIntel
cpu family : 15
model : 1
model name : Intel(R) Genuine CPU 1.60GHz
stepping : 1
cpu MHz : 1600.382
cache size : 256 KB
. . .
fpu : yes
fpu_exception: yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr
pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht
tm
bogomips : 3198.15
Linux 内核基准测试程序 为测量 Linux 内核性能,使用了 5 个基准测试程序:LMbench、AIM Benchmark Suite IX(AIM9)、chat、dbench 和 tbench。LMbench 基准测试程序对各种 Linux 应用程序编程接口(API)(例如,基本系统调用、上下文切换延迟和内存带宽)进行计时。AIM9 基准测试程序提供对用户应用程序工作负载的测量。chat 基准测试程序是模仿聊天室的客户机/
服务器工作负载。dbench 基准测试程序是文件服务器工作负载,tbench 是 TCP 工作负载。chat、dbench 和 tbench 是多线程基准测试程序,而其它的则是单线程基准测试程序。
超线程对 Linux API 的影响
超线程对 Linux API 的影响通过 LMbench 来测量,LMbench 是包含一套带宽和延迟测量方法的微基准测试程序。这些影响中涉及了高速缓存文件读取、内存复制(bcopy)、内存读/写(和延迟)、管道、上下文切换、联网、文件系统的创建和删除、进程的创建、信号处理以及处理器时钟延迟。LMbench 着重测量以下内核组件:调度程序、进程管理、通信、联网、内存映射和文件系统。低级内核原语提供一个很好的、底层硬件能力和性能的指示器。
为研究超线程的效果,我们着重于延迟的测量,它测量消息控制的时间(换句话说,系统执行某个操作能有多快)。延迟的数量用“微秒/操作”进行记录。
表 1 显示了用 LMbench 进行测试的部分内核功能列表。每个数据点是三次运行的平均值,而且该数据已经作过收敛测试,以保证在相同的
测试环境条件下它们是可再现的。通常,对于那些作为单线程运行的功能来说,有超线程和无超线程之间没有什么性能差别。然而,对于那些需要运行两个线程的测试(例如,管道延迟测试和三个进程延迟测试)来说,超线程似乎延长了它们的延迟时间。已配置的现有的 SMP 内核被标为 2419s。如果配置的内核不支持超线程,则将其标为 2419s-noht。若有超线程支持,则该内核被列为 2419s-ht。
表 1. 超线程对 Linux API 的影响 javascript:window.open(this.src);" style="CURSOR: pointer" onload="return imgzoom(this,550)"> 管道延迟的测试使用了两个通过" UNIX 管道进行通信的进程来测量经由套接字的进程间通信延迟。基准测试程序在这两个进程之间来回传送标记。性能下降幅度为 1%,小得可以忽略不计。
这三个进程测试包括了在 Linux 中进行的进程创建和执行。目的是测量创建基本控制线程所花去的时间。对于进程 fork+exit 测试来说,该数据表示将一个进程分成两个(几乎)相同的副本并退出其中一个所花的延迟时间。新进程就是这么创建的 - 但这不是非常有用,因为两个进程执行相同的操作。在这个测试中,超线程造成的性能下降幅度为 4%。
在进程 fork+execve 中,数据表示创建新进程并让该新进程运行新程序所花的时间。这是所有 shell(命令解释器)的内循环。由于超线程,可以看到这个测试性能下降幅度为 6%。
在进程 fork+/bin/sh -c 测试中,数据表示创建新进程并使该新进程运行新程序(通过让系统 shell 查找该程序并运行它)所要花去的时间。C 库接口就是这样实现对系统的调用。这个调用最常见,也最费时。在使用超线程的情况下,相对不用超线程而言,运行本测试慢了 2%。
超线程对 Linux 单用户应用程序工作负载的影响
AIM9 基准测试程序是单用户工作负载,旨在测量硬件和操作系统的性能。结果如表 2 所示。该基准测试程序中的大多数测试在使用超线程和不用超线程情况下执行性能都相同,只是同步文件操作和整数过滤(Integer Sieve)有所不同。同步随机磁盘写操作(Sync Random Disk Writes)、同步顺序磁盘写操作(Sync Sequential Disk Writes)和同步磁盘复制(Sync Disk Copies)这三个操作在使用超线程的情况下都慢了将近 35%。相反,在整数过滤的情况下使用超线程比不使用超线程速度提高了 60%。
表 2. 超线程对 AIM9 工作负载的影响 超线程对" Linux 多线程应用程序工作负载的影响
为测量超线程对 Linux 多线程应用程序的影响,我们使用模仿聊天室的 chat 基准测试程序。该基准测试程序包括了客户机和服务器。该基准测试程序的客户机端将报告每秒钟所发送的消息数;聊天室和消息的数量将控制工作负载。该工作负载创建许多线程和 TCP/IP 连接,并发送和接收许多消息。它使用了以下缺省参数:
聊天室个数 = 10
消息数 = 100
消息大小 = 100 字节
用户数 = 20
缺省情况下,每个聊天室有 20 位用户。10 个聊天室一共有 20x10 = 200 位用户。客户机将为聊天室里的每位用户创建至服务器的连接。由于我们有 200 位用户,所以我们将有 200 个到服务器的连接。现在,为聊天室中的每个用户(或连接)都创建了一个“发送”线程和一个“接收”线程。因此,“10 个聊天室”方案将创建 10x20x2 = 400 个客户机线程和 400 个服务器线程,一共是 800 个线程。但事实上不止这些。
每个客户机“发送”线程将把指定数量的消息发送给服务器。对于 10 个聊天室和 100 条消息而言,客户机将发送 10x20x100 = 20,000 条消息。服务器“接收”线程将接收相应数量的消息。聊天室服务器将把每条消息传回给聊天室中的其他用户。因而,对于 10 个聊天室和 100 条消息而言,服务器“发送”线程将发送 10x20x100x19 = 380,000 条消息。客户机“接收”线程将接收相应数量的消息。
通过命令行会话启动聊天服务器,以另一个命令行会话启动客户机,来开始测试。客户机模拟工作负载,并且其结果表示由该客户机所发送的消息数。当客户机结束其测试时,服务器循环并接受来自该客户机的其它启动消息。在我们的测量中,我们用 20、30、40 和 50 个聊天室来运行该基准测试程序。相应的连接和线程数如表 3 所示。
表 3. 所测试的聊天室和线程的数量 表" 4 显示了超线程对聊天工作负载性能的影响。每个数据点表示五次运行的几何平均数。数据集清楚地说明超线程根据聊天室的数量能将工作负载吞吐量提高 22% 到 28%。大体说来,基于 4 个聊天室样本的几何平均数,超线程将把聊天性能提高 24%。
表 4. 超线程对聊天吞吐量的影响 图" 1. 超线程对聊天工作负载的影响
超线程对" Linux 多线程文件服务器工作负载的影响
用 dbench 及其“同伴”测试 tbench 来测量超线程对文件服务器的影响。dbench 类似于 Ziff-Davis Media 基准程序中著名的 NetBench 基准测试程序,它让您在文件服务器处理来自客户机的
网络文件请求时,测量其性能。但是,NetBench 要求精心设置实际的物理客户机,而 dbench 则模拟 90,000 个操作以产生相同的工作负载,这些操作通常由 NetBench 客户机通过嗅探称为 client.txt 的 4 MB 文件来运行。这个文件的内容是文件操作伪指令,例如 SMBopenx、SMBclose、SMBwritebraw 和 SMBgetatr 等。这些 I/O 调用符合服务器消息块(Server Message Block,SMB)协议,SAMBA 中的 SMBD 服务器在 netbench 运行中将产生该协议。SMB 协议被 Microsoft
Windows 3.11、NT 和 95/98 用于共享磁盘和打印机。
在我们的测试中,一共使用了 18 种不同类型的 I/O 调用,包括打开文件、读、写、锁定、解锁、获取文件属性、设置文件属性、关闭、获取磁盘可用空间、获取文件时间、设置文件时间、“查找”打开、“查找”下一个、“查找”关闭、重命名文件、删除文件、创建新文件和清空文件缓冲区。
dbench 可以模拟任何数量的客户机,而不必进行物理设置。dbench 只产生文件系统负载,它没有联网调用。运行期间,每个客户机记录所移动的数据字节数并将该数除以移动该数据所需的时间量。然后累加所有的客户机吞吐量数以确定该服务器的总吞吐量。总的 I/O 吞吐量分数表示测试期间每秒钟所传送的兆字节数。这个测量说明该服务器对来自客户机的文件请求的处理
质量。
dbench 非常适合于对超线程的测试,因为它对 CPU 和 I/O 调度程序创建了大量负载和活动。dbench 可以严格测试超线程支持多线程文件服务的能力,因为客户机同时创建和访问许多文件。每个客户机必须创建相当于大约 21 兆字节的测试数据文件。对于要运行 20 个客户机的测试,预计要大约 420 兆字节的数据。对于测量 Linux 文件系统所用的电梯算法性能,dbench 被认为是非常不错的
测试方法。dbench 用于测试该算法的工作正确性,并测试电梯的反应是否足够快速。它还是很有趣的页面替换测试。
表 5 显示了 HT 对 dbench 工作负载的影响。每个数据点表示五次运行的几何平均数。数据说明了超线程将 dbench 的性能最少提高了 9%,最多提高了 29%。基于这五个
测试方案的几何平均数,总体的提高幅度是 18%。
表 5. 超线程对 dbench 吞吐量的影响 图" 2. 超线程对 dbench 工作负载的影响
tbench
tbench" 是类似于 dbench 的另一个文件服务器工作负载。但是,tbench 只产生 TCP 和进程负载。tbench 进行套接字调用,和 SMBD 在 netbench 负载下进行的调用相同,但是 tbench 不进行文件系统调用。tbench 背后的思想是将 SMBD 从 netbench 测试中消除掉,尽管可以使 SMBD 代码快速运行。tbench 的吞吐量结果告诉我们,如果我们消除所有文件系统 I/O 和 SMB 信息包处理,netbench 可以运行得有多快。tbench 被构建成 dbench 包的一部分。
表 6 描述了超线程对 tbench 工作负载的影响。和前面一样,每个数据点代表五次运行的几何平均数。超线程的确会提高 tbench 的吞吐量,提高幅度从 22% 到 31%。基于这五个测试方案的几何平均数,整体提高幅度为 27%。
表 6. 超线程对 tbench 吞吐量的影响 图" 3. 超线程对 tbench 工作负载的影响 Linux" 内核 2.5.x 中的超线程支持
Linux 内核 2.4.x 自 2.4.17 发行版起就支持 HT。内核 2.4.17 了解逻辑处理器,并将超线程处理器当作两个物理处理器。但是,仍然认为现有的内核 2.4.x 中所使用的调度程序还不成熟,因为它不能区别是两个逻辑处理器在争用资源,还是两个单独的物理处理器在争用资源。
Ingo Molnar 已经指出了当前调度程序出现错误的一些情况(请参阅参考资料以获取链接)。请研究一下带有两个物理 CPU 的系统,每个 CPU 提供两个虚拟处理器。如果两个任务正在运行,当前调度程序会让它们同时在单个物理处理器上运行,即使将其中一个进程迁移到另一个物理 CPU 会得到好得多的性能。该调度程序还不明白:将进程从一个虚拟处理器迁移到另一个虚拟处理器(同一物理 CPU 上的逻辑 CPU)要比将进程在物理处理器之间进行迁移来得更省力(由于高速缓存装入)。
解决方案是更改运行队列的工作方式。2.5 调度程序在每个处理器中维持一个运行队列,并设法避免在队列之间移动任务。这种更改是让每个物理处理器拥有一个运行队列,它能将任务提供给所有的虚拟处理器。这样就比较清晰地说明,是什么产生了空闲 CPU(所有的虚拟处理器必须为空闲),产生的代码就会“神奇地实现”在超线程系统进行调度的需要。
除了 2.5 调度程序中运行队列的更改之外,还要进行其它必要的更改,以使 Linux 内核能够利用 HT 达到最佳性能。Molnar 讨论过的那些更改(请再次参阅参考资料以获取有关此内容的更多信息)如下所示。
支持 HT 的被动的负载均衡: 用 IRQ 驱动的均衡操作必须针对各个物理 CPU,而不是各个逻辑 CPU。否则,可能会发生:一个物理 CPU 运行两个任务,而另一个物理 CPU 不运行任务;现有的调度程序不会将这种情形认为是“失衡的”。在调度程序看来,似乎是第一个物理处理器上的两个 CPU 运行 1-1 任务,而第二个物理处理器上的两个 CPU 运行 0-0 任务。现有的调度程序没有意识到这两个逻辑 CPU 属于同一个物理 CPU。
“主动的”负载均衡: 当一个逻辑 CPU 变成空闲,从而造成一个物理 CPU 失衡时,会出现这种情况。只有在现有的 1:1 调度程序中才不会出现这个机制。由空闲 CPU 引起的失衡可以通过常见的负载均衡器来解决。在使用 HT 的情况下,这种情形很特殊,因为源物理 CPU 可能只有两个任务在运行,而两个都可以运行。现有的负载均衡器不能处理这种情形,因为正在运行的任务难以迁移。而这个迁移是必需的 - 否则一个物理 CPU 费力地运行两个任务,而另一个物理 CPU 却保持空闲。
支持 HT 的任务挑选: 当调度程序挑选了一个新任务时,它在尝试从其它 CPU 接收任务之前,应该优先挑选所有共享同一物理 CPU 的任务。现有的调度程序只挑选那些被调度到特定逻辑 CPU 的任务。
支持 HT 的亲缘性: 这些任务应当设法“盯牢”物理 CPU,而不是逻辑 CPU。
支持 HT 的唤醒: 现有的调度程序只知道“当前”CPU,不知道其任何“伙伴”CPU。在 HT 上,如果一个逻辑 CPU 正在执行任务,其上的一个线程被唤醒了,而且其“伙伴”CPU 是空闲的,那么该“伙伴”CPU 必须被唤醒以立即执行刚唤醒的任务。
在撰写本文时,Molnar 已经提供了现有的内核 2.5.32 补丁程序,它通过引入共享运行队列(多个 CPU 可以共享同一个运行队列)的概念来实现上述所有更改。共享的、针对每个物理 CPU 的运行队列实现了上面所列的所有 HT 调度操作的需要。显然,这使调度和负载均衡变得复杂了,而且这对 SMP 和单处理器调度程序的影响仍然是未知的。
Linux 内核 2.5.32 中的更改旨在对带有两个以上 CPU 的 Xeon 系统产生影响,尤其是在负载均衡和线程亲缘性这些区域方面。由于硬件资源限制,我们只能测量其在我们单 CPU 测试环境中的影响。使用 2.4.19 中所使用的相同测试进程,我们在 2.5.32 上运行了三个工作负载:chat、dbench 和 tbench。对于 chat 而言,在有 40 个聊天室的情况下,HT 可以将速度提高 60%。整体提高幅度大约为 45%。对于 dbench 而言,27% 是最高的提高幅度,整体提高幅度大约为 12%。对于 tbench 而言,整体提高幅度大约为 35%。
表 7. 超线程对 Linux 内核 2.5.32 的影响 结束语 Intel" Xeon 超线程对 Linux 内核和多线程应用程序肯定有积极作用。超线程产生的性能改进在现有的内核 2.4.19 中可高达 30%,在内核 2.5.32 中由于调度程序中运行队列支持和超线程支持的大量更改,其速度可提高 51%。
原文转自:http://www.ltesting.net