Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1315333
  • 博文数量: 554
  • 博客积分: 10425
  • 博客等级: 上将
  • 技术积分: 7555
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-09 09:49
文章分类

全部博文(554)

文章存档

2012年(1)

2011年(1)

2009年(8)

2008年(544)

分类:

2008-04-11 15:49:06


聚合
第9 章• 聚合111
# dtrace -s writesbycmd.d
dtrace: script ’./writesbycmd.d’ matched 1 probe
^C
dtrace 1
cat 4
sed 9
head 9
grep 14
find 15
tail 25
mountd 28
expr 72
sh 291
tee 814
def.dir.flp 1996
make.bin 2010
#
或者,您可能想要进一步查看按可执行文件的名称和文件描述符组织的输出内容。文件描
述符是write(2) 的第一个参数,所以下面示例使用由execname 和arg0 组成的关键字:
syscall::write:entry
{
@counts[execname, arg0] = count();
}
运行此命令将会生成包含可执行文件的名称和文件描述符的表,如下例所示:
聚合
112 Solaris 动态跟踪指南• 2006 年7 月
# dtrace -s writesbycmdfd.d
dtrace: script ’./writesbycmdfd.d’ matched 1 probe
^C
cat 1 58
sed 1 60
grep 1 89
tee 1 156
tee 3 156
make.bin 5 164
acomp 1 263
macrogen 4 286
cg 1 397
acomp 3 736
make.bin 1 880
iropt 4 1731
#
以下示例显示按进程名组织的用于写入的系统调用中花费的平均时间。此示例使用avg()
聚合函数,并将用于求平均值的表达式指定为参数。该示例对系统调用中花费的挂钟时间
求平均值。
syscall::write:entry
{
self->ts = timestamp;
}
聚合
第9 章• 聚合113
syscall::write:return
/self->ts/
{
@time[execname] = avg(timestamp - self->ts);
self->ts = 0;
}
以下示例输出显示了运行此命令、等待几秒钟,然后按Ctrl-C 组合键的结果:
# dtrace -s writetime.d
dtrace: script ’./writetime.d’ matched 2 probes
^C
iropt 31315
acomp 37037
make.bin 63736
tee 68702
date 84020
sh 91632
dtrace 159200
ctfmerge 321560
install 343300
mcs 394400
get 413695
ctfconvert 594400
bringover 1332465
聚合
114 Solaris 动态跟踪指南• 2006 年7 月
tail 1335260
#
平均值非常有用,但通常不能提供足够的详细信息来帮助您了解数据点的分布。要更详细
地了解分布情况,请使用quantize() 聚合函数,如下例所示:
syscall::write:entry
{
self->ts = timestamp;
}
syscall::write:return
/self->ts/
{
@time[execname] = quantize(timestamp - self->ts);
self->ts = 0;
}
因为每一行输出都会产生频数分布图,所以此脚本的输出实际上比之前的输出要长一些。
以下示例显示了选择的样本输出:
lint
value ------------- Distribution ------------- count
8192 | 0
16384 | 2
32768 | 0
65536 |@@@@@@@@@@@@@@@@@@@ 74
131072 |@@@@@@@@@@@@@@@ 59
262144 |@@@ 14
聚合
第9 章• 聚合115
524288 | 0
acomp
value ------------- Distribution ------------- count
4096 | 0
8192 |@@@@@@@@@@@@ 840
16384 |@@@@@@@@@@@ 750
32768 |@@ 165
65536 |@@@@@@ 460
131072 |@@@@@@ 446
262144 | 16
524288 | 0
1048576 | 1
2097152 | 0
iropt
value ------------- Distribution ------------- count
4096 | 0
8192 |@@@@@@@@@@@@@@@@@@@@@@@ 4149
16384 |@@@@@@@@@@ 1798
32768 |@ 332
65536 |@ 325
131072 |@@ 431
262144 | 3
聚合
116 Solaris 动态跟踪指南• 2006 年7 月
524288 | 2
1048576 | 1
2097152 | 0
请注意,频数分布的行数始终是二次方值。每一行表示大于或等于对应值,但小于下一个
更大行值的元素数目。例如,以上输出说明iropt 在8,192 纳秒和16,383 纳秒之间(含8,192
纳秒和16,383 纳秒)进行了4149 次写入操作。
虽然quantize() 可用于快速了解数据,但您可能想要检查线性值的分布情况。要显示线性
值的分布,请使用lquantize() 聚合函数。除D表达式外,lquantize() 函数还接受三个参
数: 下限、上限和步长。例如,如果想要按文件描述符查看写入分布,则使用二次方量化
可能不再有效。应改为使用范围较小的线性量化,如下例所示:
syscall::write:entry
{
@fds[execname] = lquantize(arg0, 0, 100, 1);
}
运行此脚本几秒钟后将会生成大量信息。以下示例显示了一组典型输出:
mountd
value ------------- Distribution ------------- count
11 | 0
12 |@ 4
13 | 0
14 |@@@@@@@@@@@@@@@@@@@@@@@@@ 70
15 | 0
16 |@@@@@@@@@@@@ 34
17 | 0
xemacs-20.4
聚合
第9 章• 聚合117
value ------------- Distribution ------------- count
6 | 0
7 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 521
8 | 0
9 | 1
10 | 0
make.bin
value ------------- Distribution ------------- count
0 | 0
1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3596
2 | 0
3 | 0
4 | 42
5 | 50
6 | 0
acomp
value ------------- Distribution ------------- count
0 | 0
1 |@@@@@ 1156
2 | 0
3 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6635
4 |@ 297
聚合
118 Solaris 动态跟踪指南• 2006 年7 月
5 | 0
iropt
value ------------- Distribution ------------- count
2 | 0
3 | 299
4 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 20144
5 | 0
还可使用lquantize() 聚合函数来聚合自过去某个时间点以来的时间。通过此方法,可以
观察一段时间内行为的变化。以下示例显示了执行date(1) 命令的进程的生命周期中系统调
用行为的变化:
syscall::exec:return,
syscall::exece:return
/execname == "date"/
{
self->start = vtimestamp;
}
syscall:::entry
/self->start/
{
/*
* We linearly quantize on the current virtual time minus our
* process’s start time. We divide by 1000 to yield microseconds
* rather than nanoseconds. The range runs from 0 to 10 milliseconds
聚合
第9 章• 聚合119
* in steps of 100 microseconds; we expect that no date(1) process
* will take longer than 10 milliseconds to complete.
*/
@a["system calls over time"] =
lquantize((vtimestamp - self->start) / 1000, 0, 10000, 100);
}
syscall::rexit:entry
/self->start/
{
self->start = 0;
}
执行许多date(1) 进程时,上面的脚本有助于更好地了解系统调用行为。要查看此结果,请
在一个窗口中运行sh -c ’while true; do date >/dev/null; done’,同时在另一个窗口中
执行D脚本。该脚本生成date(1) 命令的系统调用行为的配置文件:
# dtrace -s dateprof.d
dtrace: script ’./dateprof.d’ matched 218 probes
^C
system calls over time
value ------------- Distribution ------------- count
< 0 | 0
0 |@@ 20530
100 |@@@@@@ 48814
200 |@@@ 28119
聚合
120 Solaris 动态跟踪指南• 2006 年7 月
300 |@ 14646
400 |@@@@@ 41237
500 | 1259
600 | 218
700 | 116
800 |@ 12783
900 |@@@ 28133
1000 | 7897
1100 |@ 14065
1200 |@@@ 27549
1300 |@@@ 25715
1400 |@@@@ 35011
1500 |@@ 16734
1600 | 498
1700 | 256
1800 | 369
1900 | 404
2000 | 320
2100 | 555
2200 | 54
2300 | 17
2400 | 5
2500 | 1
2600 | 7
聚合
第9 章• 聚合121
2700 | 0
通过此输出,可以大致了解与内核的必需服务相关的date(1) 命令的不同阶段。为了更好地
了解这些阶段,您可能需要了解何时进行哪些系统调用。如果这样,可以更改D脚本来聚
合变量probefunc 而不是聚合常量字符串。
列显聚合
缺省情况下,多个聚合按照它们在D程序中的引入顺序显示。可使用printa() 函数列显聚
合来覆盖此行为。printa() 函数还允许您使用格式字符串精确地设置聚合数据的格式,如
第12 章中所述。
如果在D程序中未使用printa() 语句设置聚合的格式,则dtrace 命令将对聚合数据进行快
照,并在跟踪完成后使用缺省聚合格式立即列显结果。如果使用printa() 语句设置指定聚
合的格式,则将禁用缺省行为。通过将语句printa(@aggregation-name) 添加到程序的
dtrace:::END 探测器子句中,可获取相同的结果。avg()、count()、min()、max() 和sum()
聚合函数的缺省输出格式显示与每个元组的聚合值对应的十进制整数值。lquantize() 和
quantize() 聚合函数的缺省输出格式将显示结果的ASCII 表。列显聚合元组时,就像已经
对每个元组元素应用了trace() 一样。
数据标准化
在聚合数据一段时间后,您可能需要将与某个常数因子有关的数据标准化。通过此方法,
可以更容易地比较不相交的数据。例如,在聚合系统调用时,您可能需要按每秒的速率而
不是基于运行过程的绝对值来输出系统调用。DTrace normalize() 操作使您可以按此方式将
数据标准化。normalize() 的参数包括聚合和标准化因子。聚合的输出显示除以标准化因子
之后的每个值。
以下示例显示如何按系统调用聚合数据:
#pragma D option quiet
BEGIN
{
/*
* Get the start time, in nanoseconds.
*/
列显聚合
122 Solaris 动态跟踪指南• 2006 年7 月
start = timestamp;
}
syscall:::entry
{
@func[execname] = count();
}
END
{
/*
* Normalize the aggregation based on the number of seconds we have
* been running. (There are 1,000,000,000 nanoseconds in one second.)
*/
normalize(@func, (timestamp - start) / 1000000000);
}
运行以上脚本一小段时间将会在台式计算机上生成以下输出:
# dtrace -s ./normalize.d
^C
syslogd 0
rpc.rusersd 0
utmpd 0
xbiff 0
in.routed 1
数据标准化
第9 章• 聚合123
sendmail 2
echo 2
FvwmAuto 2
stty 2
cut 2
init 2
pt_chmod 3
picld 3
utmp_update 3
httpd 4
xclock 5
basename 6
tput 6
sh 7
tr 7
arch 9
expr 10
uname 11
mibiisa 15
dirname 18
dtrace 40
ksh 48
java 58
xterm 100
数据标准化
124 Solaris 动态跟踪指南• 2006 年7 月
nscd 120
fvwm2 154
prstat 180
perfbar 188
Xsun 1309
.netscape.bin 3005
normalize() 对指定的聚合设置标准化因子,但此操作不会修改基础数据。这会导致使用
denormalize() 函数将数据取消标准化。denormalize() 仅接受聚合。将取消标准化操作添
加到前面的示例中会同时返回原始系统调用的计数和每秒的速率:
#pragma D option quiet
BEGIN
{
start = timestamp;
}
syscall:::entry
{
@func[execname] = count();
}
END
{
this->seconds = (timestamp - start) / 1000000000;
printf("Ran for %d seconds.\n", this->seconds);
数据标准化
第9 章• 聚合125
printf("Per-second rate:\n");
normalize(@func, this->seconds);
printa(@func);
printf("\nRaw counts:\n");
denormalize(@func);
printa(@func);
}
运行以上脚本一小段时间将生成与以下示例类似的输出:
# dtrace -s ./denorm.d
^C
Ran for 14 seconds.
Per-second rate:
syslogd 0
in.routed 0
xbiff 1
sendmail 2
elm 2
picld 3
httpd 4
xclock 6
FvwmAuto 7
数据标准化
126 Solaris 动态跟踪指南• 2006 年7 月
mibiisa 22
dtrace 42
java 55
xterm 75
adeptedit 118
nscd 127
prstat 179
perfbar 184
fvwm2 296
Xsun 829
Raw counts:
syslogd 1
in.routed 4
xbiff 21
sendmail 30
elm 36
picld 43
httpd 56
xclock 91
FvwmAuto 104
mibiisa 314
dtrace 592
数据标准化
第9 章• 聚合127
java 774
xterm 1062
adeptedit 1665
nscd 1781
prstat 2506
perfbar 2581
fvwm2 4156
Xsun 11616
也可以重新标准化聚合。如果对同一聚合多次调用normalize(),则标准化因子将成为最新
调用中指定的因子。以下示例列显了一段时间内每秒的速率:
示例9–1 renormalize.d: 重新标准化聚合
#pragma D option quiet
BEGIN
{
start = timestamp;
}
syscall:::entry
{
@func[execname] = count();
}
tick-10sec
数据标准化
128 Solaris 动态跟踪指南• 2006 年7 月
示例9–1 renormalize.d: 重新标准化聚合(续)
{
normalize(@func, (timestamp - start) / 1000000000);
printa(@func);
}
清除聚合
使用DTrace 生成简单监视脚本时,可使用clear() 函数定期清除聚合中的值。此函数仅接
受聚合作为其参数。clear() 函数仅清除聚合的值;聚合的关键字将保留。因此,如果聚合
中的某个关键字的关联值为零,则表示该关键字具有非零值,但后来作为clear() 的一部分
被设置为零。要同时废弃聚合的值和关键字,请使用trunc()。有关详细信息,请参见第130
页中的“截断聚合”。
以下示例将clear() 添加到示例9–1 中:
#pragma D option quiet
BEGIN
{
last = timestamp;
}
syscall:::entry
{
@func[execname] = count();
}
tick-10sec
清除聚合
第9 章• 聚合129
{
normalize(@func, (timestamp - last) / 1000000000);
printa(@func);
clear(@func);
last = timestamp;
}
虽然示例9–1 显示了dtrace 调用的生命周期中系统调用的速率,但上面的示例仅显示了最
近10 秒内的系统调用速率。
截断聚合
查看聚合结果时,您通常只需关心最前面的几个结果。无需关注与最高值之外的任何其他
对象关联的关键字和值。您可能还希望废弃整个聚合结果,从而删除关键字和值。DTrace
trunc() 函数适用于这两种情况。
trunc() 的参数包括聚合和可选截断值。如果没有截断值,trunc() 将同时废弃整个聚合的
聚合值和聚合关键字。如果存在截断值n,则trunc() 将废弃聚合值和聚合关键字,但与最
高n 个值关联的值和关键字除外。即,trunc(@foo, 10)将截断前10 个值之后的名为foo 的
聚合,其中trunc(@foo) 将废弃整个聚合。如果将0 指定为截断值,将会废弃整个聚合。
要查看后n 个值(而不是前n 个值),请为trunc() 指定负的截断值。例如,trunc(@foo,
-10) 将截断后10 个值之前的名为foo 的聚合。
以下示例增加了系统调用示例,以便仅显示10 秒内最前面10 个系统调用应用程序的每秒系
统调用速率。
#pragma D option quiet
BEGIN
{
last = timestamp;
}
截断聚合
130 Solaris 动态跟踪指南• 2006 年7 月
syscall:::entry
{
@func[execname] = count();
}
tick-10sec
{
trunc(@func, 10);
normalize(@func, (timestamp - last) / 1000000000);
printa(@func);
clear(@func);
last = timestamp;
}
以下示例显示在轻负荷膝上型计算机上运行以上脚本的输出:
FvwmAuto 7
telnet 13
ping 14
dtrace 27
xclock 34
MozillaFirebird- 63
xterm 133
fvwm2 146
acroread 168
Xsun 616
截断聚合
第9 章• 聚合131
telnet 4
FvwmAuto 5
ping 14
dtrace 27
xclock 35
fvwm2 69
xterm 70
acroread 164
MozillaFirebird- 491
Xsun 1287
最小化删除
因为DTrace 将一些聚合数据缓存在内核中,所以向聚合中添加新关键字时可能会出现空间
不足的情况。在此情况下,数据将被删除并且计数器会递增,而dtrace 将生成一条消息,
指示进行了聚合删除操作。因为DTrace 在用户级(可以动态增加空间)保持长期运行状态
(由聚合的关键字和中间结果组成),所以这种情况很少发生。如果在极少数情况下发生
了聚合删除,则可以使用aggsize 选项增加聚合缓冲区大小,以减少发生删除的可能性。也
可以使用此选项将DTrace 的内存使用量减至最少。与任何大小选项一样,可以使用任何大
小后缀指定aggsize。此缓冲区的调整大小策略由bufresize 选项指示。有关缓冲的更多详
细信息,请参见第11 章。有关选项的更多详细信息,请参见第16 章。
避免聚合删除的另一个方法是提高在用户级使用聚合数据的速率。此速率缺省为每秒一
次,并且可使用aggrate 选项显式调整。与任何速率选项一样,可以使用任何时间后缀指
定aggrate,但缺省为每秒的速率。有关aggsize 选项的更多详细信息,请参见第16 章。
最小化删除
132 Solaris 动态跟踪指南• 2006 年7 月
操作和子例程
您可以使用D函数调用(如trace() 和printf())来调用由DTrace 提供的两种不同类型的
服务:操作,用于跟踪数据或修改DTrace 外部状态;子例程,仅影响内部DTrace 状态。本
章定义操作和子例程,并说明它们的语法和语义。
操作
通过操作可将DTrace 程序与DTrace 外部的系统交互。大多数常见操作将数据记录到
DTrace 缓冲区。也有其他可用操作,例如停止当前进程,提高当前进程的特定信号或停止
全部跟踪。这些操作中的一些具有破坏性,因为它们会更改系统,虽然这些操作具有可靠
的定义。只有显式启用了破坏性的操作,才可以使用这些操作。缺省情况下,数据记录操
作将数据记录到主体缓冲区。有关主体缓冲区和缓冲区策略的详细信息,请参见第11 章。
缺省操作
子句可以包含任意数量的操作和变量处理。如果将子句保留为空,则会采用缺省操作。缺
省操作将跟踪主体缓冲区已启用的探测器标识符(enabled probe identifier, EPID)。EPID 使用
特定谓词和操作标识特定探测器的特定启用。通过EPID,DTrace 使用者可以确定引起该操
作的探测器。实际上,只要跟踪数据,都必须为该数据附加EPID,以便于使用者理解数
据。这样,缺省操作将跟踪EPID,而不会执行任何其他任务。
使用缺省操作可以使dtrace(1M) 的用法很简单。例如,以下示例命令使用缺省操作启用TS
分时调度模块中的所有探测器:
# dtrace -m TS
上面的命令可能生成与以下示例类似的输出:
# dtrace -m TS
dtrace: description ’TS’ matched 80 probes
10 第1 0 章
133
CPU ID FUNCTION:NAME
0 12077 ts_trapret:entry
0 12078 ts_trapret:return
0 12069 ts_sleep:entry
0 12070 ts_sleep:return
0 12033 ts_setrun:entry
0 12034 ts_setrun:return
0 12081 ts_wakeup:entry
0 12082 ts_wakeup:return
0 12069 ts_sleep:entry
0 12070 ts_sleep:return
0 12033 ts_setrun:entry
0 12034 ts_setrun:return
0 12069 ts_sleep:entry
0 12070 ts_sleep:return
0 12033 ts_setrun:entry
0 12034 ts_setrun:return
0 12069 ts_sleep:entry
0 12070 ts_sleep:return
0 12023 ts_update:entry
0 12079 ts_update_list:entry
0 12080 ts_update_list:return
0 12079 ts_update_list:entry
...
缺省操作
134 Solaris 动态跟踪指南• 2006 年7 月
数据记录操作
数据记录操作包含核心DTrace 操作。缺省情况下,这些操作中的每一个都会将数据记录到
主体缓冲区,但每个操作也可以用于将数据记录到随机缓冲区。有关主体缓冲区的更多详
细信息,请参见第11 章。有关随机缓冲区的更多详细信息,请参见第13 章。本节中的说明
仅是指定向缓冲区,表示如果操作执行speculate(),数据将记录到主体缓冲区或随机缓冲
区。
trace()
void trace(expression)
最基本的操作是trace() 操作,此操作将D表达式用作其参数并跟踪结果到定向缓冲区。
以下语句为trace() 操作的示例:
trace(execname);
trace(curlwpsinfo->pr_pri);
trace(timestamp / 1000);
trace(‘lbolt);
trace("somehow managed to get here");
tracemem()
void tracemem(address, size_t nbytes)
tracemem() 操作将D表达式用作其第一个参数address,将常量用作其第二个参数nbytes。
tracemem() 从addr 指定的地址复制nbytes 指定长度的内存到定向缓冲区中。
printf()
void printf(string format, ...)
与trace() 一样,printf() 操作将跟踪D表达式。但是,printf() 允许详细设置printf(3C)
样式的格式。与printf(3C) 一样,参数包含format 字符串,后跟任意数量的参数。缺省情
况下,将跟踪参数到定向缓冲区。然后,dtrace(1M) 将根据指定的格式字符串对参数进行
格式化,以便输出。例如,可以将第135 页中的“trace()”中的前两个trace() 示例组合
到一个printf() 中:
printf("execname is %s; priority is %d", execname, curlwpsinfo->pr_pri);
 
 
以上文章转自于 : http://developers.sun.com.cn/
阅读(433) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~