我正在调试一个 C 应用程序,我想知道它在特定功能上花费了多少时间。
我可以更改源代码并添加更多代码来进行测量,但这对我来说似乎不合适。我宁愿用外部应用程序来做,而不是每次都重新编译。
我发现可以在 GDB 中设置断点,所以我想,必须可以通过简单的过程使用类似的工具跟踪时间: - 设置断点 - 停止时,测量实际时间并运行函数 - 离开函数时,再次测量时间但是,我还没有找到如何在 gdb 中执行此操作的方法:(
有任何想法吗?谢谢
如果您使用的是 GCC,则需要编译选项“-pg”和应用程序gprof
.
gprof
只有当您静态链接-pg
每个库(包括 C 库)的编译版本时,才是可靠的——根据我的经验,它完全有效。您可以尝试使用 gcc 的-profile
选项来执行此操作(它会-pg
执行 plus 尝试在-pg
库中进行子化的操作),但问题是,GNU libc 确实不喜欢静态链接,并且您的发行版可能不会提供-pg
您需要的每个库的编译版本。
我建议你试试cachegrind
,这是一种valgrind
操作模式,只需要所有的调试信息。这更容易获得。问题是,它有巨大的间接成本;如此之大,以至于它可能会使您的测试无效。预计至少会放缓 2 倍。
你也可以试试perf
——如果你能拿到一份副本。它非常聪明,但它适用于那些认为人们喜欢从头开始构建东西的内核黑客。我的运气好坏参半。(请阅读http://web.eecs.utk.edu/~vweaver1/projects/perf-events/,它是关于底层 API 的,而不是实用程序,但仍然可以为您节省大量时间。)
我的 ~/.gdbinit 中有一个辅助函数:
define timeme
set $last=clock()
n
set $timing=clock() - $last
if $timing>$arg0
printf "***long***\n"
end
printf "%d cycles, %f seconds\n", $timing, (float)$timing / 1000000
end
您可能需要根据您的平台上的 CLOCKS_PER_SEC 实现来调整 1000000。
使用是微不足道的;运行将执行下一步的助手并提供时间信息:
Breakpoint 2, install_new_payload_from_meta (snmp_meta=0x7eee81c0, pkt=0x0, entry=0x7d4f4e58) at /home/sgillibr/savvi-dc-snmp/recipies.c:187
(gdb) timeme 100000
***long***
580000 cycles, 0.580000 seconds
(gdb)
显然,分辨率可能不足以满足某些需求,尽管它确实非常有用。
把它放到你的 ~/.gdbinit
define timeme
python import time
python starttime=time.time()
next
python print("Previous takes: " + (str)(time.time()-starttime) + "s")
end
document timeme
Measure executing time of next function
Usage: timeme or ti
end
类型timeme
或ti
当你想测量下一个功能的时间。
分析可能是您想要的。看看 prof 或 gprof。
更新:用“cc -Wall -ggdb -pg -g3 -O2 diskhash.c -o diskhash”(并运行程序)编译后,“gprof -p diskhash”给了我:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
32.60 0.41 0.41 1 410.75 646.18 create_hashtab
31.80 0.81 0.40 5087692 0.00 0.00 hash_func
27.83 1.16 0.35 2543846 0.00 0.00 find_hash
2.78 1.20 0.04 2543846 0.00 0.00 chop_a_line
1.59 1.22 0.02 main
0.40 1.22 0.01 frame_dummy
0.00 1.22 0.00 4 0.00 0.00 map_da_file