内核SLES10SP3的老版本内核2.6.16.60-0.54.5也是使用了很长时间了,虽然之前也有一些bug,不过都是组内单个patch自己编译内核搞定问题的,虽然内核用的是SLES,但补丁却不是同步的,没办法,业务模式不同,卖出去的服务器又不能像windows一样,开个后门远程打补丁,只能慢慢积攒影响一般的补丁,最后搞一次大的,把内核版本升级上来,到2.6.16.60-0.83.2,从版本号上看,步子迈得小了不会扯着蛋,但仍然会出现很多神奇的问题。

Linux内核升级上来之后与产品进行联合调试,当时产品便转来一个当时看比较奇葩的问题:内核升级后,产品的进程CPU占用率从200升到了400.接手问题一看,产品是基于java开发的,自己对于JVM一窍不通呀,java程序的CPU升高请产品先分析一下JVM吧,排查自己代码问题。最后确是产品的哥们用小学学到的对比法证明了是内核的问题:JVM及上层代码保持不变,只更新内核vmlinuz等相关文件,问题复现。

对于类似的问题陷入盲目,看不懂产品的代码(java都忘光了),更不了解JVM的具体实现,为什么一个单独的java进程CPU会升高这么多?最终还是东少给了建议:忽略上层,先看内核函数CPU分布热点。

于是便引进了oprofile工具,用来分析CPU占用率。最终发现系统使用的30%的CPU属于mark_offset_pmtmr函数占用,对比前后代码看,函数内容并没有变化,mark_offset_pmtmr属于定时器的内容,被pmtmr定时器唯一引用

代码未动便是系统对定时器的选择做了变动,查看系统启动日志boot.msg发现系统更换TSC定时器

发现新内核在unsynchronized_tsc函数下做了CPU的判别定义

内核根据CPU model值判定TSC不稳定,返回给init_tsc使其初始化失败,然后使用pmtmr定时器。
查看CPU model

确实在CPU型号在问题范围内。于是便咨询李义SUSE这个改动的原因为何,同时看了一下kernel最新代码是否有这个问题,令人意外的是新代码中unsynchronized_tsc函数删除了对CPU modle的判定,后来得到答复:补丁人员代码从高版本改动后,push到低版本时忘了,忘了.....

平台版本赶着过线,SUSE出正式补丁估计要一段时间了,只好自己写了,unsynchronized_tsc函数耦合还是比较强的,改了4个文件才基本OK,同时编译替换产品的内核,CPU升高的问题解决。

SP4的正式补丁参考:

http://kernel.opensuse.org/cgit/kernel-source/commit/?id=1a06c258106e7b293f3e9784d3907c5048f7574f


内核bug导致Java进程CPU升高来自于OenHan

链接为:http://oenhan.com/kernel-bug-double-java-cpu

发表评论