OProfile的原理比较简单:现在的很多CPU都提供一个所谓性能计数器的东西(performance counter),大致的原理就是程序可以注册告诉CPU对什么event感兴趣(比如CPU_CYCLE,CPU经历了一次时钟周期),然后CPU在执行了相应的操作后,就会在性能计数器上加1,这样程序就可以取出。所以,使用OProfile来定位CPU使用率的问题,就变成了让oprofile收集程序运行过程中哪个可执行程序(或是so)中的哪个function,消耗的CPU CYCLE最多。
OProfile不是每次有了event都会记录下来的,OProfile有一个sample(采样)的概念,其实就是定义经历了多少次event之后,记录下一个sample。所以,如果我们设置经历10000个CPU_CYCLE event之后记录一个sample,那么,最后在oprofile的输出中,一个sample就表示使用了10000个CPU CYCLE。
下面就是如何使用oprofile了。OProfile需要一个内核module,这个module已经被集成进入了Linux 2.6.x内核;此外还有一个用户态的daemon程序,用来收集信息;再此外就是一些utilities了,用来控制oprofile和打印结果。
所以在PC上调试就非常简单,现在大部分的Linux distribution的内核都打开了oprofile的这个module开关,所以只需要下载oprofile的源码,编译就OK了。但是在板子上就有一些麻烦了,如果板子上的内核编译时没有打开oprofile开关,那么就需要重新编译内核。
==================================== Separator ============================================
在PC上,查看内核是否编译了oprofile可以通过这样:
cat /boot/config-`uname -r` | grep OPROFILE
应该有这样两行:
CONFIG_HAVE_OPROFILE=y
CONFIG_OPROFILE=m
这表示打开了OPROFILE,而且oprofile被编译成了一个module。
在板子上的话,就检查板子的kernel包中提供的config文件,看其中的OPROFILE部分,我的ZOOM板子上的信息是:
CONFIG_HAVE_OPROFILE=y
CONFIG_OPROFILE=y
这表示打开了OPROFILE,但是没有编译成module,直接编译进内核了。
==================================== Separator ============================================
OK,接下来就是在scratchbox中编译oprofile的源码,将prefix指到一个自定义的目录,然后将编译好的文件传到板子上。建议将所有东西都拷贝到/usr目录下即可。
接下来就是:
// 不监控linux kernel
opcontrol --no-vmlinux
// 如果要监控linux kernel,那要提供没有压缩过的,而且包含symbol信息的linux kernel文件,也就是vmlinux那个文件
// uImage是去掉了symbol信息的内核文件,zImage是压缩过的内核文件(该文件的开头有一段解压代码,从而是自解压的文件)
opcontrol --vmlinux=<your vmlinux file path>
// 监控CPU_CYCLES event,每10000个event采样一次,内核和用户态的event都监控,生成最多10级的callgraph
// --event中的0是unitmask,1表示监控内核态event,第二个1表示监控用户态event
opcontrol --event=CPU_CYCLES:10000:0:1:1 --callgraph=10
// 启动
opcontrol --start
// 启动要监控的应用程序
......
// 关闭oprofile(这让oprofiled将所有收集到的数据都写入文件)
// oprofile manual中建议使用opcontrol --dump来flush数据从而不用shutdown oprofiled,应该也是可以的
opcontrol --shutdown
// 查看总体summary数据
opreport
// 查看带symbol信息的数据(能看到哪个so/可执行程序的哪个函数使用了多少sample)
opreport -l
// 查看带callgraph的数据(最详尽的数据)
opreport -l -c
==================================== Separator ============================================
基本上就是这样了,更详细的信息去看oprofile的manual(网站上)。这里还有几点需要提一下:
1. 板子上的是busybox,所以shell是ash,功能不是很全。这里opcontrol第一次运行的时候,就会报告有一行syntax error,大致是这样的一句代码:
temp=${1/cell/CELL}
我使用这样一句来代替的:
temp=`echo $1|sed 's/cell/CELL/g'`
2. opcontrol运行会报告oprofile内核module没有ready。但其实刚才已经看到了,oprofile已经在内核中了。这是由于opcontrol脚本的问题所导致的,这可以通过分析opcontrol脚本来解决。大致需要fix的几个地方是:
a. opcontrol会检查/etc/mtab文件中是否有oprofilefs这一行,没有就认为oprofile在内核中没有。于是我手动在/etc/mtab中添加了一行:
nodev /dev/oprofile oprofilefs rw
b. oprofile会在/dev/oprofile目录下mount oprofilefs,他是通过检查/proc/filesystems文件中是否有oprofile这一行来判断mount是否做过了。由于我们修改了/etc/mtab,所以有时这里判断会出问题。如果发生了opcontrol报告说/dev/oprofile目录下某个文件找不到时,就是没有mount,手动帮他做一下就OK:
mkdir /dev/oprofile
mount -t oprofilefs nodev /dev/oprofile
这些都可以通过阅读opcontrol这个脚本来解决。只要确定内核中有oprofile,就不用怀疑的去Fix就好了。
3. opcontrol --start的时候,报告说wc -m执行出错,因为busybox中的wc不支持-m这个option,我用wc -c来代替。
OProfile不是每次有了event都会记录下来的,OProfile有一个sample(采样)的概念,其实就是定义经历了多少次event之后,记录下一个sample。所以,如果我们设置经历10000个CPU_CYCLE event之后记录一个sample,那么,最后在oprofile的输出中,一个sample就表示使用了10000个CPU CYCLE。
下面就是如何使用oprofile了。OProfile需要一个内核module,这个module已经被集成进入了Linux 2.6.x内核;此外还有一个用户态的daemon程序,用来收集信息;再此外就是一些utilities了,用来控制oprofile和打印结果。
所以在PC上调试就非常简单,现在大部分的Linux distribution的内核都打开了oprofile的这个module开关,所以只需要下载oprofile的源码,编译就OK了。但是在板子上就有一些麻烦了,如果板子上的内核编译时没有打开oprofile开关,那么就需要重新编译内核。
==================================== Separator ============================================
在PC上,查看内核是否编译了oprofile可以通过这样:
cat /boot/config-`uname -r` | grep OPROFILE
应该有这样两行:
CONFIG_HAVE_OPROFILE=y
CONFIG_OPROFILE=m
这表示打开了OPROFILE,而且oprofile被编译成了一个module。
在板子上的话,就检查板子的kernel包中提供的config文件,看其中的OPROFILE部分,我的ZOOM板子上的信息是:
CONFIG_HAVE_OPROFILE=y
CONFIG_OPROFILE=y
这表示打开了OPROFILE,但是没有编译成module,直接编译进内核了。
==================================== Separator ============================================
OK,接下来就是在scratchbox中编译oprofile的源码,将prefix指到一个自定义的目录,然后将编译好的文件传到板子上。建议将所有东西都拷贝到/usr目录下即可。
接下来就是:
// 不监控linux kernel
opcontrol --no-vmlinux
// 如果要监控linux kernel,那要提供没有压缩过的,而且包含symbol信息的linux kernel文件,也就是vmlinux那个文件
// uImage是去掉了symbol信息的内核文件,zImage是压缩过的内核文件(该文件的开头有一段解压代码,从而是自解压的文件)
opcontrol --vmlinux=<your vmlinux file path>
// 监控CPU_CYCLES event,每10000个event采样一次,内核和用户态的event都监控,生成最多10级的callgraph
// --event中的0是unitmask,1表示监控内核态event,第二个1表示监控用户态event
opcontrol --event=CPU_CYCLES:10000:0:1:1 --callgraph=10
// 启动
opcontrol --start
// 启动要监控的应用程序
......
// 关闭oprofile(这让oprofiled将所有收集到的数据都写入文件)
// oprofile manual中建议使用opcontrol --dump来flush数据从而不用shutdown oprofiled,应该也是可以的
opcontrol --shutdown
// 查看总体summary数据
opreport
// 查看带symbol信息的数据(能看到哪个so/可执行程序的哪个函数使用了多少sample)
opreport -l
// 查看带callgraph的数据(最详尽的数据)
opreport -l -c
==================================== Separator ============================================
基本上就是这样了,更详细的信息去看oprofile的manual(网站上)。这里还有几点需要提一下:
1. 板子上的是busybox,所以shell是ash,功能不是很全。这里opcontrol第一次运行的时候,就会报告有一行syntax error,大致是这样的一句代码:
temp=${1/cell/CELL}
我使用这样一句来代替的:
temp=`echo $1|sed 's/cell/CELL/g'`
2. opcontrol运行会报告oprofile内核module没有ready。但其实刚才已经看到了,oprofile已经在内核中了。这是由于opcontrol脚本的问题所导致的,这可以通过分析opcontrol脚本来解决。大致需要fix的几个地方是:
a. opcontrol会检查/etc/mtab文件中是否有oprofilefs这一行,没有就认为oprofile在内核中没有。于是我手动在/etc/mtab中添加了一行:
nodev /dev/oprofile oprofilefs rw
b. oprofile会在/dev/oprofile目录下mount oprofilefs,他是通过检查/proc/filesystems文件中是否有oprofile这一行来判断mount是否做过了。由于我们修改了/etc/mtab,所以有时这里判断会出问题。如果发生了opcontrol报告说/dev/oprofile目录下某个文件找不到时,就是没有mount,手动帮他做一下就OK:
mkdir /dev/oprofile
mount -t oprofilefs nodev /dev/oprofile
这些都可以通过阅读opcontrol这个脚本来解决。只要确定内核中有oprofile,就不用怀疑的去Fix就好了。
3. opcontrol --start的时候,报告说wc -m执行出错,因为busybox中的wc不支持-m这个option,我用wc -c来代替。