最近刚发现了DELL R410的BIOS缺陷导致的一个严重性能问题。通过更改BIOS设置,我为某项目节省掉了一半的机器。

现象

我们组有一套流处理系统,它接收事件,处理,再转给下一个。这是一个计算密集型的程序,瓶颈在CPU上。当它发现它的处理速度跟不上的时候,它就开始丢事件。于是我们就增加了机器数量,以期望解决问题。实际结果却是变得更糟了,事件丢失比例大幅增加。原因是publisher的事件分发采用的是roundrobin的策略,新加的这几台机器的性能明显弱于其它机器,于是它们就拼命丢事件。但是,所有这些机器的CPU都是一样的啊。最主要的区别是,旧机器是HP,新机器是DELL的。

cpu_busy_ratio

上面的线是DELL的机器,下面的是HP的。峰值的CPU使用率,DELL的比HP的几乎高一倍。空闲时大约高50%左右。

于是我开始调查为什么DELL的机器会比HP的慢。然后在DELL的机器的启动时的dmesg中找到了这样一句话:

“p4-clockmod: Warning: EST-capable CPU detected. The acpi-cpufreq module offers voltage scaling in addition to frequency scaling. You should use that instead of p4-clockmod, if possible.”

并且,DELL机器的/proc/cpuinfo和HP的相比,cpu flags中少了est这个flag。还有一个区别是:根据/proc/cpuinfo中的信息,DELL的机器的CPU始终是满频(2.4G Hz)运行。而HP的机器则是时高时低,空闲的CPU都运行在1.6GHz。DELL机器的cpuinfo我列在了下面:

processor	15
vendor_id	GenuineIntel
cpu family	6
model	44
model name	Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
stepping	2
cpu MHz	2394.035
cache size	12288 KB
physical id	0
siblings	8
core id	10
cpu cores	4
apicid	21
initial apicid	21
fpu	yes
fpu_exception	yes
cpuid level	11
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 pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 popcnt aes lahf_lm ida arat dts tpr_shadow vnmi flexpriority ept vpid (est is missing!!!)
bogomips	4787.84
clflush size	64
cache_alignment	64
address sizes	40 bits physical, 48 bits virtual

上面显示的2394MHz是假的!是谎报!我在网上找了一个工具i7z测试了一下,发现这些CPU在DELL的机器上并非是按照2.4G的频率运行。实际上大部分时间都是1.6G。最终我发现这是BIOS设置的问题。

原因解释

DELL的BIOS中有这样三条重要的设置:

  1. C-states. 是否允许CPU进去节能状态。默认打开。
  2. C1E. CPU的C1E节能状态,即 speedstep。它是一种特殊的C-states,开启它会导致CPU的频率和电压动态降低。 默认打开。
  3. Power Management. 谁来控制CPU运行在什么样的C-States下? 操作系统还是 BIOS ? 默认: BIOS.

C-states是CPU的一系列特殊状态,用于在空闲状态下节省能源消耗。其中C0是CPU的基础状态。C1是轻度睡眠,CPU在不断的执行hlt指令。C1E-C6则是让CPU进入更深度的睡眠状态,并且频率和电压会降低。我们打开了CPU的自动变频(为了省电),并且让BIOS来控制CPU的频率和电压。而操作系统因为拿不到电源管理的控制权,它误以为CPU始终是在最高频率运行的。所以,解决办法是:要么禁用C-states,要么让操作系统来控制power。

如果禁用C-states:

  1. CPU将会更耗电。不环保。
  2. 系统的稳定性会有显著提升。稳定性是因为,在不同的C-states中间切换是很复杂的一件事情,CPU以及BIOS的实现可能都有问题,存在种种缺陷。这些缺陷会在升级到高版本的操作系统(如RHEL6/7)时暴露出来。老的操作系统反而没事,是因为它们不支持这些新的C-states。
  3. 系统的响应速度会有显著提升。这是针对延迟敏感的应用来说的。拿E5620这款CPU为例,它从最深度的睡眠状态唤醒到C0,需要0.2ms。这0.2ms会很明显的反应到网络延迟的监控数据上。

解决

为了柴静的孩子,领导决定还是使用C-states。于是我们首先把BIOS刷新到1.11.0,因为默认的BIOS和RHEL6配合有严重问题,每天会死好几次。然后进入BIOS把Power Management改成OS。这中间有个细节,BIOS中大部分设置要修改的时候都是按回车然后选用哪个。但是这个设置不是,这个设置是用方向键选择的。所以我们的系统工程师找了好久才找到。