软件性能较差,占用CPU较多,往往是由于某段代码逻辑算法不佳导致,那如何在数以千计的函数中找到问题函数呢?
这类问题的排查有很多方法,这里介绍如何用神器Windbg是排查。
其中,排查步骤如下
步聚1:在使用!runaway命令比较不同时间各线程占用CPU时间,找到CPU时间增涨较多的线程,那么就初步定位了问题函数所在的问题线程,
步聚2:然后在不同的时刻观察问题线程的调用栈,如果多次观察到截取的调用栈在执行某个函数,那么就有理由相信该函数调用存在性能问题。
步聚3:修改代码指令,屏敝对问题函数的调用,观察CPU占用率是否有明显下降,若是,则说明第2步骤找到的问题函数存在性能瓶颈,需进一步优化。
现在来实战一下,现在有一进程test(pid=3032)占用CPU 为30,如下图所示,现在按前面所述的步聚执行;
步聚一:使用!runaway命令比较不同时间各线程占用CPU时间
0:002> !runaway
User Mode Time
Thread Time
1:d9c 0 days 0:04:10.506
0:be8 0 days 0:00:00.046
2:a34 0 days 0:00:00.000
0:002> g
(ad8.9e4): Break instruction exception - code 80000003 (first chance)
eax=7ffdd000 ebx=00000000 ecx=00000000 edx=77f5d5cb esi=00000000 edi=00000000
eip=77ef3258 esp=0290ff5c ebp=0290ff88 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
77ef3258 cc int 3
0:002> !runaway
User Mode Time
Thread Time
1:d9c 0 days 0:04:12.690
0:be8 0 days 0:00:00.046
2:9e4 0 days 0:00:00.000
0:002> g
(ad8.f8c): Break instruction exception - code 80000003 (first chance)
eax=7ffdd000 ebx=00000000 ecx=00000000 edx=77f5d5cb esi=00000000 edi=00000000
eip=77ef3258 esp=0290ff5c ebp=0290ff88 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
77ef3258 cc int 3
0:002> !runaway
User Mode Time
Thread Time
1:d9c 0 days 0:04:15.420
0:be8 0 days 0:00:00.046
2:f8c 0 days 0:00:00.000
以上三次执行!runaway命令时间间隔在几秒左右,发现1号线程占用cpu时间相比其它线程有较大的增涨。
步聚2:多次观察到截取的调用栈情况,是否在多次执行某个函数
0:001> k
ChildEBP RetAddr
0280ff28 00401d33 test!d+0x3c [E:\test\test\testDlg.cpp @ 183]
0280ff88 77e31154 test!Test+0x33 [E:\test\test\testDlg.cpp @ 194]
WARNING: Stack unwind information not available. Following frames may be wrong.
0280ff94 77f1b299 kernel32!BaseThreadInitThunk+0x12
0280ffd4 77f1b26c ntdll!__RtlUserThreadStart+0x70
0280ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:001> g
(ad8.a80): Break instruction exception - code 80000003 (first chance)
eax=7ffdd000 ebx=00000000 ecx=00000000 edx=77f5d5cb esi=00000000 edi=00000000
eip=77ef3258 esp=0290ff5c ebp=0290ff88 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
77ef3258 cc int 3
0:002> ~1s
eax=00017355 ebx=00000000 ecx=0002e6ab edx=0040105f esi=00000000 edi=0280ff28
eip=00401cd3 esp=0280fed8 ebp=0280ff28 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283
test!d+0x33:
00401cd3 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:0280ff30=0002e6ab
0:001> k
ChildEBP RetAddr
0280ff28 00401d33 test!d+0x33 [E:\test\test\testDlg.cpp @ 182]
0280ff88 77e31154 test!Test+0x33 [E:\test\test\testDlg.cpp @ 194]
WARNING: Stack unwind information not available. Following frames may be wrong.
0280ff94 77f1b299 kernel32!BaseThreadInitThunk+0x12
0280ffd4 77f1b26c ntdll!__RtlUserThreadStart+0x70
0280ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
多次截取1号线程调用栈,发现其一直在test!d函数执行,怀疑d函数调用存在性能瓶颈。
步聚3:修改代码指令,屏敝对问题函数的调用
修改前指令:
修改后指令:
此时进程test(pid=3032)程序占用的cpu为0,屏敝对函数d的调用,cpu下降达到30!!!
至此说明函数d执行效率较差,应做优化。
Ps 以上方法适用于不允许重启进程的情况下操作