分类: 嵌入式
2011-06-23 22:03:51
许多处理器都包含专用的性能监视硬件。该硬件能够在某些事件发生时(如所请求的数据不在缓存内)检测到它们。硬件通常是一个或多个计数器(counters),它们在每次事件发生时都递增一位。当计数器的值“翻转还原”,中断就会生成,从而能够控制性能监视的详细程度(以及由此带来的费用)。
OProfile 使用这个硬件(若没有性能监视硬件则使用一个基于计时器的代用品)来在每次计数器生成中断时收集与性能相关的数据样品(samples)。这些样品被定期写入磁盘;稍后,其中的数据就会被用来生成系统级别和应用程序级别的性能报告。
OProfile 是一个很有用的工具,但是请了解使用它的一些局限性:
对共享库的使用 — 除非使用 --separate=library 选项,共享库中的编码样品不会成为某个特定应用程序的属性。
性能监视样品不精确 — 当性能监视注册器引发了抽样行动,中断处理将不会明确给出例外的类型。由于处理器要无序地执行指令,样品可能会在附近的指令上被抽取。
oprofpp 不能够正确地归类内联函数样品 — oprofpp 使用一个简单的地址范围机制来决定它所在的是哪个函数的地址。内联函数样品不从属于那个内联函数,而是从属于那个内联函数所插入的函数。
OProfile 从多次运行中积累数据 — OProfile 是一个系统范围内的建档器,它预计进程会被多次启动和关闭。这样,样品就会从多次运行实例中被积累下来。使用 opcontrol --reset 来清除从以前运行实例中抽取的样品。
非 CPU 约束的性能问题 — OProfile 能够找出受 CPU 约束的进程的问题。OProfile 不会识别正处于睡眠状态的进程,因为这些进程正在等待锁或其它事件的发生(如等待 I/O 设备完成操作)。
在Redhat Enterprise Linux 中,只有多处理器(SMP)内核才启用了 OProfile 支持。要判定运行的是哪个内核,使用以下命令:
uname -r |
如果返回的内核版本以 .entsmp 结束,运行的就是多处理器内核。否则,即使系统不是多处理器系统,也请通过红帽网络或发行光盘来安装它。多处理器内核可以在单处理器内核上运行。
提供了对 oprofile 软件包中包括的工具的总览。
命令 | 描述 |
---|---|
opcontrol |
配置要收集的数据。详情请参阅。 |
op_help |
显示系统处理器的可用事件以及每个事件的简单描述。 |
op_merge |
合并同一可执行文件的多个样品。详情请参阅。 |
op_time | 提供对所有建档的可执行文件的总览。详情请参阅。 |
op_to_source | 如果应用程序使用调试符号编译了,创建带注解的源码。详情请参阅。 |
oprofiled |
作为守护进程来运行,定期把样品数据写入磁盘。 |
oprofpp |
检索档案数据。详情请参阅。 |
op_import |
把样品数据库文件从异类二进制格式转换成系统的本地原始格式。只有在分析不同体系的样品数据库时才使用该选项。 |
表1. OProfile 命令
在运行 OProfile 之前,它必须被配置。至少需要选择是否要监视内核。以下各节描述了如何使用 opcontrol 工具来配置 OProfile。在 opcontrol 命令被执行时,设置选项就会被保存到 /root/.oprofile/daemonrc 文件中。
首先,配置 OProfile 是否应该监视内核。这是在启动 OProfile 前唯一所需的配置选项。其它选项都是可选的。
要监视内核,以根用户身份执行以下命令:
opcontrol --vmlinux=/boot/vmlinux-`uname -r` |
要配置 OProfile 不监视内核,以根用户身份执行以下命令:
opcontrol --no-vmlinux |
这个命令还会载入 oprofile 内核模块(如果还没有被载入),并创建 /dev/oprofile/ 目录(如果不存在)。关于这个目录的详情,请参阅第 43.6 节。
注记 | |
---|---|
即便 OProfile 被配置成不为内核建档,SMP 内核仍旧必须运行,这样,oprofile 模块才会被载入。 |
设置样品是否应在内核中收集只会改变所收集的数据,而不会改变收集数据的方法或贮存地点。要为内核和应用程序库生成不同的样品文件,请参阅。
多数处理器包含计数器(counters)。它们被 OProfile 用来监视指定的事件。如所示,可用的计数器的数量要根据处理器而定。
处理器 | cpu_type | 计数器数量 |
---|---|---|
Pentium Pro | i386/ppro | 2 |
Pentium II | i386/pii | 2 |
Pentium III | i386/piii | 2 |
Pentium 4 (无超线程) | i386/p4 | 8 |
Pentium 4 (有超线程) | i386/p4-ht | 4 |
Athlon | i386/athlon | 4 |
AMD64 | x86-64/hammer | 4 |
Itanium | ia64/itanium | 4 |
Itanium 2 | ia64/itanium2 | 4 |
TIMER_INT | 计时器(timer) | 1 |
IBM eServer iSeries | 计时器(timer) | 1 |
IBM eServer pSeries | 计时器(timer) | 1 |
IBM eServer S/390 | 计时器(timer) | 1 |
IBM eServer zSeries | 计时器(timer) | 1 |
表2. OProfile 处理器和计数器
使用的信息来校验所检测到的处理器类型是否正确,并且判定能够被同时监视的事件数量。如果处理器没有支持的性能监视硬件,计时器(timer)就会被用作处理器类型。
如果使用了 timer,事件就不能为任何处理器设置,因为硬件不支持硬件性能计数器。相反,计时器中断会被用来建档。
如果 timer 没有被用作处理器类型,监视的事件就可以被改变,处理器的计数器0就会被默认设置为基于时间的事件。如果处理器上有多个计数器,0以外的计数器就不会被默认设置任何事件。被监视的默认事件显示在中。
处理器 | 计数器0的默认事件 | 描述 |
---|---|---|
Pentium Pro, Pentium II, Pentium III, Athlon, AMD64 | CPU_CLK_UNHALTED | 处理器的时钟没有停止 |
Pentium 4 (HT 和非 HT) | GLOBAL_POWER_EVENTS | 处理器没有停止的时间 |
Itanium 2 | CPU_CYCLES | CPU 周期 |
TIMER_INT | (none) | 每个计时器中断的抽样 |
表3. 默认事件
可以被同时监视的事件数量是由处理器的计数器数量决定的。不过,这不是一对一的情况;在某些处理器上,某些事件必须被映射到指定的计数器上。要判定可用的计数器数量,执行以下命令:
cat /dev/oprofile/cpu_type |
可用的事件要根据处理器类型而定。要判定可被建档的事件,以根用户身份执行以下命令(该列表是针对系统处理器类型特有的):
op_help |
每个计数器的事件都可以通过命令行被配置,也可以使用图形化界面配置。如果计数器没有被设置给指定的事件,错误消息就会被显示。
要通过命令行来为每个可配置的计数器设置事件,使用 opcontrol:
opcontrol --ctrlN-event= |
把 N 替换成计数器号码(从0开始),把
默认设置会选择基于时间的事件设置。它大约会创建每处理器每秒2000个样品。如果使用了计时器中断,计时器就被设置成两幅画面的最小时间间隔率,而且还不能被用户设置。如果 cpu_type 不是 timer,每个事件就必须设置了一个抽样率(sampling rate)。抽样率是每次抽样之间发生的事件数量。
在为计数器设置事件时,还可以指定一个抽样率:
opcontrol --ctrN-event= |
把
小心 | |
---|---|
在设置抽样率时务必小心。抽样率太频繁会使系统超载,导致系统似乎僵住或者真的僵住了。 |
如果 cpu_type 不是 timer,那么就可能还需要单元屏蔽(unit masks)来进一步确定事件。
每个事件的单元屏蔽可以使用 op_help 命令列举。每个单元屏蔽的值都以十六进制格式显示。要指定一个以上单元屏蔽,十六进制的值必须使用逐位“或”(or)算符来组合。
opcontrol --ctrN-event= |
按照默认设置,每个事件都收集内核模式和用户模式的信息。要配置 OProfile 在某个指定的计数器中不计数内核模式的事件,执行以下命令(这里的 N 是计数器号码):
opcontrol --ctrN-kernel=0 |
执行以下命令来再次启动计数器的建档内核模式:
opcontrol --ctrN-kernel=1 |
要配置 OProfile 不计数某个指定计数器的用户模式的事件,执行以下命令(这里的 N 是计数器号码):
opcontrol --ctrN-user=0 |
执行以下命令来再次启动计数器的建档用户模式:
opcontrol --ctrN-user=1 |
当 OProfile 守护进程把档案数据写入样品文件,它可以把内核和库档案的数据分成两个单独的样品文件。要配置守护进程写入样品文件的方式,以根用户身份执行以下命令:
opcontrol --separate= |
none — 不要分离档案(默认)
library — 为库生成每个应用程序的档案
kernel — 为内核和内核模块生成每个应用程序的档案
all — 为库生成每个应用程序的档案,为内核和内核模块生成每个应用程序的档案
如果 --separate=library 被使用,抽样文件名在包括可执行文件名称的同时还包括库的名称。
第3节 启动和停止 OProfile要使用 OProfile 来开始监视系统,以根用户身份执行以下命令:
opcontrol --start |
所显示的输出和下面相似:
Using log file /var/lib/oprofile/oprofiled.log Daemon started. Profiler running. |
/root/.oprofile/daemonrc 中的设置被使用。
OProfile 守护进程 oprofiled 被启动;它定期把样品数据写入 /var/lib/oprofile/samples/ 目录。该守护进程的日志位于 /var/lib/oprofile/oprofiled.log。
如果 OProfile 使用不同的配置选项被重新启动,以前会话中的样品文件就会被自动备份到 /var/lib/oprofile/samples/session-N 目录中,这里的 N 是前一次备份会话数量再加1。
Backing up samples file to directory /var/lib/oprofile/samples//session-1 Using log file /var/lib/oprofile/oprofiled.log Daemon started. Profiler running. |
要停止建档器,以根用户身份执行以下命令:
opcontrol --shutdown |
有时,在指定时间保存样品会很有用。例如,在给可执行文件建档的时候,根据不同的输入数据来收集不同的样品可能会很有用。如果要监视的事件数量超过了处理器可用的计数器数量,你可以运行多次 OProfile 来收集数据,每次都把样品数据保存到不同的文件中。
要保存当前的抽样文件集合,执行以下命令,把
opcontrol --save= |
目录 /var/lib/oprofile/samples/name/ 被创建,当前的抽样文件被复制到其中。
第5节 分析数据OProfile 守护进程 oprofiled 定期收集样品,并把它们写入 /var/lib/oprofile/samples/ 目录。在读取数据之前,请以根用户身份执行以下命令来确定所有数据都被写入这个目录中了:
opcontrol --dump |
每个样品文件名称都基于可执行文件的名称,使用右括号(})来代替每个正斜线(/)。文件名的结尾是井号(#)和用于该样品文件的计数器号码。例如,以下文件包括了计数器0所收集的 /sbin/syslogd 这个可执行文件的样品数据:
}sbin}syslogd#0 |
一旦抽样数据被收集,你可以使用以下工具来分析它们:
op_time
oprofpp
op_to_source
op_merge
使用这些工具以及被建档的二进制文件来生成可以进一步被分析的报告。
警告 | |
---|---|
被建档的可执行文件必须使用这些工具来分析数据。如果它在数据收集后必须被改变,请备份用来创建样品的可执行文件,以及这些样品文件。 |
每个可执行文件的样品都被写入一个样品文件。每个动态链接库的样品也被写入一个样品文件。在 OProfile 运行的时候,如果被监视的可执行文件改变了,而且用于这个可执行文件的样品文件存在,这个现存的样品文件就会被自动删除。因此,如果这个样品文件要被保留,它就必须在可执行文件被新版本替代前和所用的可执行文件一起备份。关于如何备份样品文件的详情,请参阅。
op_time 提供了对所有建档的可执行文件的总览。
以下是输出示例的一部分:
581 0.2949 0.0000 /usr/bin/oprofiled 966 0.4904 0.0000 /usr/sbin/cupsd 1028 0.5218 0.0000 /usr/sbin/irqbalance 1187 0.6026 0.0000 /bin/bash 1480 0.7513 0.0000 /usr/bin/slocate 2039 1.0351 0.0000 /usr/lib/rpm/rpmq 6249 3.1722 0.0000 /usr/X11R6/bin/XFree86 8842 4.4885 0.0000 /bin/sed 31342 15.9103 0.0000 /usr/bin/gdmgreeter 58283 29.5865 0.0000 /no-vmlinux 82853 42.0591 0.0000 /usr/bin/perl |
每个可执行文件都在它自己的行上列出。第一列是为该可执行文件记录的样品数量。第二列是样品和样品总数的百分比。第三列没有被使用,第四列是这个可执行文件的名称。
关于 op_time 命令行选项的列表,请参阅它的说明书页。例如 -r 选项被用来按照样品数量的大小给输出排序;-c 选项在指定计数器号码时有用。
要检索关于指定可执行文件的详细信息,使用 oprofpp:
oprofpp |
按照符号列举样品数据。例如:以下是运行命令 oprofpp -l /usr/X11R6/bin/XFree86 的部分输出:
vma samples % symbol name ... 08195d10 4 3.0303 miComputeCompositeClip 080b9180 5 3.78788 Dispatch 080cdce0 5 3.78788 FreeResource 080ce4a0 5 3.78788 LegalNewID 080ce640 5 3.78788 SecurityLookupIDByClass 080dd470 9 6.81818 WaitForSomething 080e1360 12 9.09091 StandardReadRequestFromClient ... |
第一列是虚拟内存地址(vma)的起点。第二列是该符号的样品数量。第三列是该符号的样品和该可执行文件的总体样品的百分比。第四列是符号的名称。
要把输出按照样品的数量多少排序(反向),使用 -r 和 -l 选项。
-s列举某个符号名称特有的样品数据。例如:以下输出是从命令 oprofpp -s StandardReadRequestFromClient /usr/X11R6/bin/XFree86 中截取的:
vma samples % symbol name 080e1360 12 100 StandardReadRequestFromClient 080e1360 1 8.33333 080e137f 1 8.33333 080e13bb 1 8.33333 080e13f4 1 8.33333 080e13fb 1 8.33333 080e144a 1 8.33333 080e15aa 1 8.33333 080e1668 1 8.33333 080e1803 1 8.33333 080e1873 1 8.33333 080e190a 2 16.6667 |
第一行是符号/可执行文件组合的摘要。
第一列包括抽样的虚拟内存地址。第二列是该内存地址的抽样数量。第三列是该内存地址的样品和该符号的样品总数的百分比。
-L按照符号列举样品数据,比 -l 更详细。例如:
vma samples % symbol name 08083630 2 1.51515 xf86Wakeup 08083641 1 50 080836a1 1 50 080b8150 1 0.757576 Ones 080b8179 1 100 080b8fb0 2 1.51515 FlushClientCaches 080b8fb9 1 50 080b8fba 1 50 ... |
数据和 -l 选项一样,只不过,对于每个符号来说,每个所用的虚拟内存地址都被显示。对于每个虚拟内存地址,样品数量以及样品和该符号的样品数量的百分比也被显示。
-g按照 gprof 格式把输出生成到文件中。如果生成的文件叫做gmon.out,gprof 就能够被用来进一步分析数据。详情请参阅 gprof 的说明书页。
能够进一步限定数据的其它选项如下:
使用指定的样品文件
使用
给 C++ 符号名称解码(demangle)。
-D给 C++ 符号名称解码(demangle),简化 STL 库的解码名称。
--counter为指定计数器收集信息。若没有指定,默认的计数器是0。
-o每个样品都显示源码中的行号。当可执行文件被编译时,应该使用 GCC 的 -g 选项。否则,该选项将无法显示行号。红帽企业 Linux 的可执行文件默认都没有使用这个选项编译。
vma samples % symbol name linear info 0806cbb0 0 0 _start ../sysdeps/i386/elf/start.S:47 |
在输出中不包括用逗号分隔的符号列表。
-k显示包含共享库的附加列。这个选项只有在配置 OProfile 时指定了 --separate=library 选项,同时又没有指定 --dump-gprof-file 选项时才会生成结果。
-t按照指定列顺序来显示输出。该选项不能和 -g 一起使用。
使用以下字母来代表列:
字母 | 描述 |
---|---|
v | 虚拟内存地址 |
s | 样品数量 |
S | 样品的累计数量 |
p | 样品和该可执行文件的样品总数的相对百分比 |
P | 样品和该可执行文件的样品总数的累计百分比 |
q | 相对于所有抽样的可执行文件的样品百分比 |
Q | 相对于所有抽样的可执行文件的样品累计百分比 |
n | 符号名称 |
l | 源文件的名称和行号,包括完整路径 |
L | 源码文件名的基准名称和行号 |
i | 可执行文件的名称,包括完整路径 |
I | 可执行文件的基准名称 |
d | 样品的细节 |
h | 显示列标头 |
表 43-4. 用字母代表列的顺序
指定到会话的完整路径或相对于 /var/lib/oprofile/samples/ 目录的目录。
-p指定要分析的可执行文件所在的用逗号分隔的路径列表。
op_to_source 工具试图匹配特定指令的样品和源码中相对应的行。所生成的文件应该在左侧列出这些行的样品。它还会在每个函数的开头插入注释,列举该函数的样品总数。
要使用这个工具,可执行文件必须使用 GCC 的 -g 选项编译。红帽企业 Linux 软件包没有默认使用这个选项编译。
op_to_source 的一般语法是:
op_to_source --source-dir |
必须指定包含要被分析的源码和可执行文件的目录。关于额外命令行选项的列表,请参阅 op_to_source 的说明书页。
如果存在多个用于同一可执行文件或库的样品文件,样品文件可以被合并来简化分析。
例如:要合并 /usr/lib/library-1.2.3.so 库的文件,以根用户身份运行以下命令:
op_merge /usr/lib/library-1.2.3.so |
结果文件是 /var/lib/oprofile/samples/}usr}lib}library-1.2.3.so。
要限制样品文件被合并到指定的计数器,使用 -c 选项,再跟随一个计数器号码。
第6节 理解 /dev/profile/ 文件/dev/oprofile/ 目录包含 OProfile 的文件系统。使用 cat 命令来显示这个文件系统的虚拟文件值。例如:以下命令显示 OProfile 检测到的处理器类型:
cat /dev/oprofile/cpu_type |
/dev/oprofile/ 中有用于每个计数器的目录。例如:如果计数器有两个,其中就会有 /dev/oprofile/0/ 和 dev/oprofile/1/ 这两个目录。
计数器的每个目录中都包含以下文件:
count — 抽样间隔
enabled — 如果是0,计数器就被关闭,不会为它收集样品;如果是1,计数器就被开启,样品就会为它收集。
event — 要监视的事件
kernel — 如果是0,当处理器在内核空间时,样品就不会为这个计数器事件而收集;如果是1,即便处理器在内核空间时,样品也会被收集。
unit_mask — 为计数器启用的是哪些单元屏蔽
user — 如果是0,当处理器在用户空间时,样品就不会为计数器事件收集;如果是1,即便处理器在用户空间时,样品也会被收集。
这些文件的值可以使用 cat 命令来检索。例如:
cat /dev/oprofile/0/count |
用法示例
OProfile 不但能够被开发者用来分析应用程序的性能,它还能够被系统管理员用来进行系统性能分析。例如:
判定哪些应用程序和服务在系统上被使用得最多 — op_time 可以被用来判定应用程序或服务使用了多少处理器时间。如果系统被用于多种服务,但是却表现不佳,使用最多处理器时间的服务就可以被转移到专职系统上。
判定处理器用量 — CPU_CLK_UNHALTED 事件可以被监视,以便判定某段给定时间内的处理器载量。然后,这个数据就可以被用来判断另加一个处理器或更快的处理器是否会提高系统性能。
其它资料
本文仅突出讨论了一些 OProfile 特性以及配置和使用它的信息。要进一步学习,请参考以下资料。
/usr/share/doc/oprofile-0.5.4/oprofile.html — OProfile 手册
oprofile 的说明书页 — 讨论了 opcontrol、oprofpp、op_to_source、op_time、op_merge、和 op_help 等命令