仔细阅读了http://www.cnblogs.com/cmt/p/3729386.html这篇关于xen的博文,这篇博文写的挺赞的,分析的也很细致,涉及到4年前的一个patch的故事。在讲这个故事之前,先说明下,阿里云官方的xen已经包含了博文中提到的xen的cpu idle潜在问题的修复版本(commit见:
http://xenbits.xen.org/gitweb/?p=xen.git;a=commit;h=964fae8ac2fa6732856179a2532b0914dba5e4bb),请童鞋们放心。
下面进入故事环节:先说patch的V1 版。当时是Xen Power Management开发的高峰时期,又正快到Xen3.4的代码冻结时间,代码冻结后就不会再接受新的feature patch,但bugfix patch还是可以提交进入upstream。
当时有一系列Xen cpuidle/cpufreq的patch已经进了Xen3.4 upstream-upstable,所以希望让这个feature patch先上车,然后补票(追加一个bugfix patch)。这是基于两点:一是这个patch的开发者Ke Ke同学是调bug的高手,有把握在代码冻结期间搞定这个bug;二是这个bug波及不到普通用户,所以放到patch里一般不会有什么负面影响。博主博客中提到的‘普通用户’其实就是指HVM domain,原因是在Xen3.4时期VCPUOP_set_singleshot_timer仅属于PV domain的一个hypercall(不像现在扩展到对HVM domain提供支持),所以对HVM domain没影响。但Keir同学还是没同意,所以Ke Ke同学只好苦哈哈地加班调bug去了 :)
这个bug其实比较诡异,如同博主博文中对V2 patch分析的那样,根源是V1 patch的出现导致IPI唤醒处于deep Cx的处理器失败。这里我只是补充一点问题产生的背景:Xen为什么要用IPI唤醒deep Cx处理器?V1 patch为什么导致IPI中断唤醒失败?
其实这一问题产生于某些老处理器硬件上存在的缺陷。通常中断的发生都会导致处于deep Cx的处理器被唤醒,所以理论上大可不必大费周章地由一个处理器发IPI唤醒另一个睡眠中处理器。但凡事总有例外 -- 处理器的设计一般是希望CPU进入deep Cx时,关闭尽可能多的部件以节省更多能耗 -- 但有些老处理器设计时把诸如APIC Timer部件的电源也顺手关了。这使得CPU进入deep Cx时产生不了APIC Timer中断。为了防止这种有问题的处理器进入深度睡眠时,无法产生APIC Timer中断而导致的Timer到期无法醒来的问题,Xen采用了比较保守的方法来处理,即由另一处理器在HPET Timer 发生时通过IPI来唤醒处于深度睡眠的处理器。HPET部件位于南桥,不受CPU状态的影响,工作可靠,精度开销都还可以接受,于是皆大欢喜…
但Ke Ke同学的V1 patch又踩了什么坑,导致IPI无法唤醒处于深度睡眠的处理器?原来Xen hypervisor的wakeup IPI的逻辑是,先检查对方是否有pending的softirq。如果有,则不必发IPI以节省开销,其原因是处理器进入深度睡眠之前都要检查并处理自己当前pending的softirq,所以如果对方有pending softirq则肯定没睡,那就没必要发IPI了。V1 patch正好踩了这个坑:在CPU进入睡眠前处理完pending softirq后,新增的sched_tick_suspend()会在某些情况下设置TIMER_SOFTIRQ,于是别的处理器发wakeup IPI就‘被节省’了,再后来就是博主所说的那样,处于深度睡眠的处理器悲催了…