c语言状态机编程思路及方法(利用systemtap分析cc)
c语言状态机编程思路及方法(利用systemtap分析cc)}exit()printf("%s %d cost:%ld us" probefunc() pid() gettimeofday_us() - @entry(gettimeofday_us())}probe timer.s(10) {#10秒触发后将会退出来
通常情况下我们开发服务时为了更好的性能往往需要借助一些工具来辅助优化,发现性能的瓶颈所在。
比如:
- perf 用于分析哪些方法调用cpu比较高、cpu cache 命中率、分支预测等
- valgrind 的helgrind 工具用于分析资源竞争
- gprofile 用于分析一些包括函数调用次数、函数调用耗时等(编译时需要带上-pg),原理就是在函数入口、退出地方插入两个function来进行统计对源码是侵入式的。原来跟-finstrument-function 类似
- oprofile 用于分析cpu cache命中率等 [关于该工具介绍可以参考:https://www.ibm.com/developerworks/cn/linux/l-oprof/]
我这里主要是介绍下如何通过systemtap 系统钩子,来分析耗时比较高的函数(包括用户态的、系统调用:比如read\write\epoll_ctl等)。对应的脚本:(保存名字为first.stp)
probe process("/usr/xxx/a.out").function("*").return {
printf("%s %d cost:%ld us" probefunc() pid() gettimeofday_us() - @entry(gettimeofday_us())
}
probe timer.s(10) {#10秒触发后将会退出来
exit()
}
假定a.out 的进程id是1123
stap -x 1123 first.stp -v
(第一次时可能会比较慢)
。。。。。
最后输出结果:
xxxfunc 1123 cost: 10 us
当然system还是统计方法调用次数、打印调用栈、调用方法的参数等,详细使用可以看附录中的连接的。
1.systemtap 安装
yum install systemtap systemtap-runtime
其次运行这个命令检查一下看需要安装哪些依赖:
stap-prep
Could not find a package for: kernel-4.9.184-linuxkit.x86_64
No debuginfo packages available to install
package kernel-4.9.184-linuxkit.x86_64 is not installed
package kernel-devel-4.9.184-linuxkit.x86_64 is not installed
package kernel-debuginfo-4.9.184-linuxkit.x86_64 is not installed
problem installing rpm(s) kernel-4.9.184-linuxkit.x86_64
kernel-devel-4.9.184-linuxkit.x86_64
kernel-debuginfo-4.9.184-linuxkit.x86_64
in case of file conflicts try again after # yum erase kernel-debuginfo
此时运行测试测试也是无法运行的:
stap -e 'probe begin{printf("hello world");exit();}' -v
Checking "/lib/modules/4.9.184-linuxkit/build/.config failed with error: No such file or directory
2. 系统依赖安装
1)首先要确认系统版本:uname -r
yum install kernel-devel-`uname -r`
yum install kernel-debuginfo-common-`uname-r`
yum install kernel-debuginfo-`uname -r`
不建议直接采用yum install kernel-devel kernel-debuginfo kernel-debuginfo-common
检查依赖包是否安装:stap-prep
这一步对了,一般不会在stap的时候包 ko sysm no found 的问题
注意:如果yum没法找到对应的包,那么需要到网上下载对应的rpm包进行离线安装。
2)stap 报: CONFIG_RETPOLINE=y,but not supported by compiler,Toolchain update recommed 问题
其实这个问题最简单的解决办法是直接修改报错的文件,把对应的Makefile文件报错的地方注释掉。
3)stap 时提示:not found compiler-gccx.h
一般是版本不匹配导致,最简单的办法是修改文件引用上面1)中安装的对应版本
find / -name "compile-gcc*.h" 查看有哪些版本可以引用
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc5.h
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc4.h
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc3.h
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc.h
直接修改:/usr/src/kernels/`uname -r`/include/linux/compiler-gcc.h
将:
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
修改为:
#define _gcc_header(x) __gcc_header(linux/compiler-gcc5.h) ##注意根据自己上面find找到的版本
4)version 不匹配:ERROR:module version mismatch
$stap -e 'probe begin{printf("hello world");exit();}' -v
....
Pass 3: using .....xxx.c
Pass 4: using ....xxx.ko
ERROR: module version mismatch(#1 SMP Tue Sep 12 10:10:26 CDT 2017 vs #1 SMP Tue Sep 12 22:26:13 UTC 2017) release ....
把/usr/src/kernels/`uname -r`/include/generated/compile.h 对应的VERSION 值改成
stap 输出的即可,比如上面的可以修改成:
#define UTS_VERSION "#1 SMP Tue Sep 12 22:26:13 UTC 2017"
然后把上面输出的xx.c xx.ko 文件删掉重新编译即可。
5) 测试:stap-prep
附录:
[SystemTapLinux 下我万能的观测工具] https://max.book118.com/html/2017/0219/92636072.shtm
[systemtap lang] http://sourceware.org/systemtap/langref/