Linux驱动性能调优小记


前几天,接到任务,要驱动性能调优。吭哧吭哧搞了两周,终于搞定。结果是圆满的,道路确是曲折的。聊以记之,不正之处,还请指正。

性能调优的目标

首先,我们确立了性能调优的目标。通过建立简化的驱动模型,得到一个IOPS数据,那么不简化下,应当接近这个数据。

性能调优的过程

性能调优——IOPS

通过top指令,查看系统的状态,发现CPU利用率过高,接近100%。这显然会影响到驱动的运行速度。再看CPU占用率过高的原因,主要是在处理软中断中。

软中断占用CPU过高,一方面可能是因为硬中断过高,一方面可能因为软中断本身处理时间过长。首先查看中断次数,通过cat /proc/interrupts,可以看到对应中断线上的中断在不断增长。看到这些中断都集中在单个CPU上,于是想把中断分配到其他CPU上,那么这个CPU的压力会小些。

于是开始设置中断亲合。通过改/proc/irq/1231(需要填对应的中断号)/smp_affinity将中断调到其他CPU上处理。当前CPU的占用率是降低了,但是IOPS却没提升。推测可能与CPU cache有关。从一个CPU上切换到另一个CPU,会存在cache命中率降低的问题。

这样就放弃了调中断亲和。还是先考虑中断次数是否正常的问题。通过vmstat,可以看到CPU接收到硬中断的频率。大概有4到5万次/sec,对比友商,这是正常的。那么就是软中断处理本身处理的异常了。

通过perf,来查看系统哪个函数占用CPU过高。TIPS:perf是通过采样来实现的,当原本系统已经负荷较大时,perf会运行的不正常。此时,应当适当降低负荷。

我调低了系统的IO并发数,此时perf运行正常。看到一个spin_lock函数,CPU占用率达30%左右。仔细思考后,这应该是锁冲突很严重!再看锁所在的函数,是其他模块的。我们在软中断中,调用了该模块的接口。把数据发给相应模块负责人,他终于承认是有这个问题。之前还一直跟我说,他们模块的性能是正常的。

换掉那个模块之后,系统的性能果然提升上来了。IOPS提升了70%。

考虑是否还有优化的空间。之前记得,在测试中断聚合和多队列后,IOPS也有一定的提升。于是开始了设置中断聚合。从最细粒度的中断,每个消息报次中断,到最粗粒度的中断,每16个消息报次中断。发现IOPS降低了。这个可以理解,每16个消息报次中断,自然增加了消息的传送速度。在系统性能允许的情况下,应当不设置中断聚合,才能获得最佳的IOPS性能。这里有个小插曲,在每16个消息报次中断后,CPU的占用率很低,让我误以为CPU不是性能瓶颈了,这里我走过弯路。

既然中断聚合不考虑,那么再看下多队列。参考友商,将芯片到驱动的消息队列从一个改为2个。此时,性能再次获得提升,IOPS基本与简化版的驱动一致了。我理解的是,使用了多队列后,芯片的并发能力获得了增加。因为我实际中检查过驱动测,增加多队列后,对驱动的锁之类的基本我影响,所以我想,是芯片的并发能力得到了发挥。

性能调优——CPU占用率

IOPS达标以后,CPU占用率与产品要求,仍存在一定的差距。再次用perf分析,发下系统运行基本正常。没有影响比较明显的热点函数,意味着我修改代码,也不能带来性能上的明显提升。

后来,得知CPU型号不同时,CPU占用率会差别较大。通过cat /proc/cpuinfo | grep name | cut -f2 -d: |uniq -c发现CPU果然与产品要求的不同。那么是我们的环境有问题了。TIPS:比较CPU,不能只比较频率,因为影响性能的还有CPU架构,所以比较时直接看型号即可。

因为暂无产品的环境,所以调优工作暂时到此。

后记

驱动性能调优初步结束,看起来很顺的样子是吧?其实,我也是走了弯路的,做了一些优化,由于它们并不是瓶颈,所以不太影响性能,还有些其他的经验。这些也是个学习的过程

优化锁

tasklet是不会在不同CPU上并发的,所以无需加锁

性能编码规范

看过一个《性能编码规范》,比如IO路径上要避免无意义的初始化,mem_set与mem_cpy要慎重使用,还有些线程调度之类的

充分的IO统计

将IO的相关数据统计出来,会很有助于分析。内核可以精细到纳秒级

单并发 and 多并发

分析性能,可以从单并发着手,然后再扩展到多并发。16并发的IOPS,应当接近单并发的16倍,如果实在相差太远,那么说明这个并行能力太弱,可能就有问题。

 

性能优化,是个复杂的过程。以上步骤,有部分略写,如果有朋友感兴趣,可以私下详细交流。本文不到之处,也欢迎大家指正!

 

你可能感兴趣的:(Linux驱动性能调优小记)