干掉性能大BUG 后台函数级问题定位介绍

发表于2015-04-29
评论0 2.5k浏览

 

              valgrind是运行在linux上一套基于仿真技巧的程序调试和辨析工具。灵便轻便而又壮大,能直穿程序过失的中心,可谓是程序员的瑞士军刀。

              首先,本文列举两种典型问题的定位思路,一种是cpu使用率过高问题,另一种是内存泄漏问题。

              然后做下简单抽象,总结函数级性能问题定位的一般方法。

1.                 pve战斗zonesvrcpu使用率异常过高

Ø         bug描述:

              卡牌游戏MLPVE战斗中,zonesvrcpu使用异常高,成为后台性能的瓶颈点。              后定位发现,原来是zonesvr里面的loadTeamCardInitPlayerCard模块导致cpu使              用率过高,而这两个模块在gamesvr同样存在,即同一处理过程,在两个不同的进程              走了两遍

Ø         优化措施:

              去掉zonesvr里面重复的代码片段,loadTeamCardInitPlayerCard模块。以上两个模              块放在gamesvr里。

Ø         优化效果:

              优化后,PVE战斗的tpstrans per second,服务器每秒处理的事务数)从1000/s提升              2000/s。优化效果明显。

              那么这个bug是如何定位出来的呢?首先,我们来看下PVE战斗时序图。

根据时序图,zonesvr只是做转发请求的操作。真正的计算环节是在gamesvr,但在实际性能测试中,发现zonesvr首先到了瓶颈,并且此时的gamesvrcpu资源使用率很低,只有30%PVE战斗的tps也很低,只有1000/s

于是,感觉zonesvr应该是出了问题,拉起神器valgrind来定位cpu热点函数

具体如何拉起,如何down下数据,km上面有其他文章,这里不再多言。

拿到valgrindcpu数据,使用kcachegrind可视化查看结果,如图:

InclSelf的区别是:

Incl表示inclusive,包含其调用的函数的消耗cost

Self表示exclusive,具有排他性,只表示自身的消耗cost

根据图中的数据(Incl主力,Self辅助)从顶部到底部的函数依次排查,发现红框内的函数消耗cost超出了预期。于是点击查看对应的调用关系图:

原来是这里出了问题。

              把这个问题反馈给开发,原来这里这些步骤(红圈内)都是可以不用的。

              因为在gamesvr中,也有同样的处理逻辑了。同一流程步骤,gamesvrzonesvr都做              了一般,重复了。原来gamesvr是从zonesvr里剥离出来的,所以有一些代码还没优化

至此,函数级问题定位完成。

大体思路是:理清测试场景的时序图,找到重点关注的svr进程,使用valgrind工具收集svr进程的函数热点数据,从顶到下,依次对每个函数进行数据分析,分析方法是基于inclself的消耗情况。最后,得出结论。


2.                 login登录场景,infosvr内存泄漏

Ø         bug描述:

                            infosvr底层使用了TC组件。在外面有一个ProcessSync是后来新增的,这里调用了                            DBGet函数,DBGet里面申请了内存,但使用完内存后,ProcessSync忘了free                                          导致出现leak

Ø         优化措施:

                            在使用完DBGet内存后,做free操作。

                            If (NULL=pszVal){free(pszVal);pszVal==NULL;}

Ø         优化效果:

                            优化后,无内存泄漏发生。

              那么这个问题是如何发现的呢?

              登录时序

              Infosvr的作用:存储玩家数据information。底层使用tcTokyo Cabinet)的实现,infosvr只是在原来的基础上,加了一层壳而已。

              压测过程中,发现Infosvr的资源使用情况有异常,内存使用如下:

              观察到infosvr的常驻内存一直增涨,so,怀疑发生leak。启用神器valgrind收集leak数据。

这里简单说下几种内存泄漏的分类:

              1) definitely lost: 明确地已经发生泄漏了,你需要修复这里。

              2) indirectly lost: 说明内存泄漏发生在基于指针(pointer-based)的数据结构里。如              果修复了definitely lost,那么indirectly lost也应该会消失。

              3) 可能内存泄漏,这是由于C/C++语言指针处理的特点造成的,这部分可能不太              准确。

              4) still reachable: 表示该内存在程序运行完的时候,仍旧有指针指向它。

              5) suppressed,表明这个leak error已经被取消了,你可以忽略掉它。

所以,我们需要重点关注definitely lost

              在项目中,或多或少会用到公司内外的一些库,对于这些库,valgrind也会采集到信息。但是在分析过程中,我们就可以把它们忽略掉了。

              最后,经过一番排查,发现如下问题:

              这里是说,有155,218个块,共11,019,820 bytes发生definitely lost。接下来,就可以根据函数栈的信息,进行问题定位了。

              首先找到栈顶对应的DBGet代码

              可以看到,ppvValBuff申请了内存(malloc),但在该函数中并没有释放掉,所以外层的函数应该有释放才行。

              又调出processSync函数代码:

              ProcessSync函数调用DBGet申请了一块内存,但使用后,没有把对应内存free掉,从而导致memory leak

              return前增加

If (NULL!=pszVal){free(pszVal);pszVal==NULL;}

              搞定!至此,内存泄漏问题定位完成。

              定位内存泄漏的大体思路:压测过程中,发现infosvr进程的内存使用异常,使用valgrind memcheck工具收集infosvr进程的内存泄漏信息,分析数据主要关注definitely lost部分,并且屏蔽使用的库函数。发现内存泄漏后,依次排查函数栈中的各函数,最后找到问题。

3.                 函数级性能问题定位总结

3.1  了解系统

    首先,对系统要有一定的了解,包括整体的架构,流程时序,计算过程。

                其次,对系统进行分析,可能出现问题的点,不可能出现问题的点,并做好记录。

3.2  关注被测系统的性能情况

在压测过程中,对于被测系统的表现情况需要关注,一系列命令可以帮助查看系统表现,比如,topVmstat netstatmpstatsar等。发现可疑点,追查到底。

3.3  工欲善其事必先利其器

               函数级性能定位工具,不单单只有valgrind,还有perf,gprof等。

    perl文章参考

    http://km.oa.com/group/799/articles/show/99048

gprof 用户手册网站

http://sourceware.org/binutils/docs-2.17/gprof/index.html

 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引