注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

FY

Johnson 's Blog

 
 
 

日志

 
 

SMP亲和性和Linux下合适的中断处理  

2017-02-01 13:29:29|  分类: Linux内核 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

简介

硬件中断通常都很昂贵。不知道什么原因,这些软件小片段消耗了如此多的CPU资源,接着软件工程师和硬件工程师都在尝试改变这种状态。虽然已经做了一些意义深远的改进,然而硬件中断依然消耗了大量的CPU资源。

你在桌面系统上很少看见中断的影响。打开你的/proc/interrupts文件看看。这个文件列举了所有你的硬件设备和每个设备收到了多少个中断,以及在每个CPU上有多少。如果你在一个一般的桌面系统上,你会发现你的电脑处理的中断数相当少。即便每秒处理上百万数据包的强大服务器每秒处理的中断也才只有一万多个。然而这些中断消耗了CPU资源,适当的处理他们无疑会对提升系统的性能有帮助。

但事实上,我们能对中断做什么?

有很多事可以做。一些Linux发行版带有改动过的内核,深远的改变了这种处境。各种技术,比如NAPI,如此引人注目的减少了中断数和中断处理开销,否则流行的服务器很可能都无法处理1Gbps的以太链接。NAPI作为内核的一部分已经很久了。其他的包括中断合并。

这篇文章我将着重于介绍强大技术中的一个来优化中断处理。

SMP亲和性

SMP亲和性或者处理器亲和性术语有非常宽广的含义,需要一些解释。亲和性这个词代表在多处理器系统上一个确定的任务和一个确定的处理器之前的亲近程度。比如,当处理器X运行进程Y,他们相互之间就很亲近。这个处理器有进程的部分内存在缓存里,因此当调度的时候经常移动进程到不同的处理器很可能使调度低效。

只要涉及中断,SMP亲和性就牵扯到哪个处理器处理哪个确定的中断。和进程不一样,绑定中断到一个CPU很有可能导致性能下降,这儿有说明为什么。中断处理程序通常很小。中断的内存足迹相应的也很小,因此保持中断在一个CPU上不会增加缓存命中。相反,太多的中断反而让其中一个核超载而其他的相应很闲。调度器对于这种情况没有办法。它假设我们的中断处理核和其他其他任意核一样,都很忙。结果你将面对性能瓶颈,因为一个进程或者线程偶尔在一个只有10%资源的CPU上运行(这里估计是作者笔误,原文是90%)。

事情可能更糟,通常核0默认处理所有的中断。在繁忙的系统上所有的中断可能消耗核0的大约30%的资源。因为我们假设所有的核有一样多的资源,我们可能发现我们的软件系统只能有效使用所有CPU资源的70%。

谁的责任

APIC或者高级可编程中断控制器已经成为所有基于x86系统的组件很久了--SP和MP。这个元件负责传递中断。他也决定那个中断去哪儿,哪个核。

默认APIC传递所有中断到核0。这就是为什么/proc/interrupts在各种不同的主流Linux系统上看起来像这样:

         CPU0     CPU1     CPU2     CPU3
  0:   123357        0        0        0   IO-APIC-edge  timer
  8:        0        0        0        0   IO-APIC-edge  rtc
 11:        0        0        0        0  IO-APIC-level  acpi
169:        0        0        0        0  IO-APIC-level  uhci_hcd:usb1
177:        0        0        0        0  IO-APIC-level  qla2xxx
185:        0        0        0        0  IO-APIC-level  qla2xxx
193:    12252        0        0        0  IO-APIC-level  ioc0
209:        0        0        0        0  IO-APIC-level  uhci_hcd:usb2
217:      468        0        0        0  IO-APIC-level  eth0
225:      285        0        0        0  IO-APIC-level  eth1
NMI:      120       66       76       45
LOC:   123239   123220   123187   123065
ERR:        0
MIS:        0

看到可疑的事了吗?CPU0处理了所有的硬中断。这是你在一个中断SMP亲和性没配置好的系统上看见的情况。

问题的简单解决办法

这个问题因为有APIC已经完美解决了。他拥有一些中断传递和目标模式,物理上和逻辑上,固定和低优先级,等等。重要的一个事实是它有能力传递中断到任意一个核甚至在他们间做负载均衡。

它的配置受限于前八个核。如果你有多于八个核,不要期待任何高于7的核收到中断。

默认情况它工作在物理/固定模式。这意味着它会传递一个确定的中断到一个确定的核。你已经知道了默认情况下是核0.你可以轻松的改变接受主要中断的核。

对于/proc/interrupts文件第一列的每个IRQ号,/proc/irq/下都有一个对应的子目录。这个目录包含了一个文件smp_affinity。使用这个文件你可以改变哪个核可以处理哪个中断。读取这个文件产生一个16进制掩码,每个位代表一个核。当一个位被设置,APIC将传递中断到与其相应的核。

让我们来看个例子。。。

#   
# cat /proc/interrupts
         CPU0     CPU1     CPU2     CPU3
  0: 19599546        0        0        0   IO-APIC-edge  timer
  8:        0        0        0        0   IO-APIC-edge  rtc 
 11:        0        0        0        0  IO-APIC-level  acpi
169:        0        0        0        0  IO-APIC-level  uhci_hcd:usb1
177:        0        0        0        0  IO-APIC-level  qla2xxx
185:        0        0        0        0  IO-APIC-level  qla2xxx
193:    95337        0        0        0  IO-APIC-level  ioc0
209:        0        0        0        0  IO-APIC-level  uhci_hcd:usb2
217:   100778        0        0        0  IO-APIC-level  eth0
225:    56651        0        0        0  IO-APIC-level  eth1
NMI:      466      393      422      372 
LOC: 19600453 19600434 19600401 19600279
ERR:        0   
MIS:        0   
#   
#   
# echo "2" > /proc/irq/217/smp_affinity
# cat /proc/interrupts
         CPU0     CPU1     CPU2     CPU3
  0: 19606722        0        0        0   IO-APIC-edge  timer
  8:        0        0        0        0   IO-APIC-edge  rtc 
 11:        0        0        0        0  IO-APIC-level  acpi
169:        0        0        0        0  IO-APIC-level  uhci_hcd:usb1
177:        0        0        0        0  IO-APIC-level  qla2xxx
185:        0        0        0        0  IO-APIC-level  qla2xxx
193:    95349        0        0        0  IO-APIC-level  ioc0
209:        0        0        0        0  IO-APIC-level  uhci_hcd:usb2
217:   101027       49        0        0  IO-APIC-level  eth0
225:    56655        0        0        0  IO-APIC-level  eth1
NMI:      466      393      422      372 
LOC: 19607629 19607610 19607577 19607455
ERR:        0   
MIS:        0   
#

就如我们所见,一旦我们输入了“魔法”命令,CPU1开始从eth0上接收中断,而不是CPU0接收。de >echode>命令引人注目的改变了亲和性状态。我们写到文件中的是2,写入4将导致CPU2处理eth0的中断,而不是CPU1。

写入3会怎么样?理论上这会导致APIC传递中断到CPU0和CPU1。不幸的是,事情比较复杂,这完全取决于APIC是否工作于 物理 目标模式 和 低优先级 传递模式 。如果是那样,你将很可能不会再看见CPU0处理了所有中断。这是因为当内核配置APIC的工作模式在 物理/低优先级 模式,它将自动的告诉APIC去在前八个核之间负载均衡。

所以如果你的系统默认CPU0处理了所有的中断,这很可能意味着APIC没有配置清楚。

终极解决办法

首先,不幸的是这儿除了替换内核没有办法。配置APIC的软件是内核的一部分,如果我们想要改变一些事情我们除了在内核上修复没有办法。和APIC相关的事都没法配置,所以我们绝对没有选择。剩下的问题就是,把内核换成什么?

我在OpenSuSE 10.2内核版本2.6.18上测试过。安装2.6.34.3(现在最新的。译注:文章是08年的,现在的内核需要自己验证下)内核和OpenSuSE的默认内核配置文件修复了这个问题。有了这个内核看起来这样,从开始就是对的:

# cat /proc/interrupts
         CPU0     CPU1     CPU2     CPU3
  0:   728895   728796   728624   728895  IO-APIC-edge     timer
  8:        0        0        0        0  IO-APIC-edge     rtc 
 11:        0        0        0        0  IO-APIC-fasteoi  acpi
 16:        0        0        0        0  IO-APIC-fasteoi  uhci_hcd:usb1
 19:        0        0        0        0  IO-APIC-fasteoi  uhci_hcd:usb2
 24:    14090    14090    14327    14056  IO-APIC-fasteoi  ioc0
 49:        7        9        7        8  IO-APIC-fasteoi  qla2xxx
 50:        8       12       11       10  IO-APIC-fasteoi  qla2xxx
 77:     2849     2759     2841     2827  IO-APIC-fasteoi  eth0
 78:    25072    25138    24996    24980  IO-APIC-fasteoi  eth1
NMI:        0        0        0        0   
LOC:  2915270  2915256  2915228  2915092
ERR:        0  

看起来很好,不是吗?所有的核都在处理中断,因此最有效率的工作。现在如果在其他版本内核上工作怎样?这只需要测试下就行了。

有一个内核选项和我们做的差不多,一旦取消了它,你将在高于2.6.10的内核上得到相似的结果。这个选项是CONFIG_HOTPLUG_CPU。它添加了对热插拔CPU的支持。看起来把这个选项关闭,就会让内核适当的配置APIC了。

事实上这很好理解。你看,APIC被告知哪个处理器应该接收中断。你需要额外的小片段代码告诉APIC怎样处理处理器内拔掉---处理器被拔掉是CONFIG_HOTPLUG_CPU允许你做的事中的一件。我以前认为这个功能在早些的内核版本中不存在,然后在2.6.34.3中加入。

总结

我们看见了我们能够通过修改内核配置来得到真正完美的结果。在一个非常繁忙的系统,做这个小的改动能够巨大的提升系统的性能。

我希望你会发现这个信息非常有用并且使用我在这篇文章介绍的技术。

  评论这张
 
阅读(5)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017