Solaris 动态跟踪指南

第 11 章 缓冲区和缓冲

数据缓冲和管理是 DTrace 框架为其客户机(如 dtrace(1M))提供的基本服务。本章详细介绍了数据缓冲,以及可用于更改 DTrace 的缓冲区管理策略的选项。

主体缓冲区

在每个 DTrace 调用中都会使用主体缓冲区,它是缺省情况下跟踪操作记录其数据的缓冲区。这些操作包括:

exit()

printf()

trace()

ustack()

printa()

stack()

tracemem()

 

主体缓冲区始终基于每个 CPU 进行分配。此策略不可以调整,但可以使用 cpu 选项将跟踪和缓冲区分配限制为单个 CPU。

主体缓冲区策略

DTrace 允许在高约束的内核上下文中使用跟踪。需要特别指出的是,DTrace 允许在内核软件不能可靠分配内存的上下文中使用跟踪。这种灵活上下文的后果是:始终存在这样一种可能性,即 DTrace 会在没有可用空间时尝试跟踪数据。出现这样的情况时,DTrace 必须具有处理此类情况的策略,但是您可能希望根据给定实验的需要来调整策略。有时,相应的策略可能是放弃新数据。在另外一些时候,可能需要重用最早记录的数据所在的空间以跟踪新数据。在大多数情况下,所需策略是尽可能避免用尽第一个位置中的可用空间。为了适应这些不同的需要,DTrace 支持多种不同的缓冲策略。此支持使用 bufpolicy 选项实现,可以基于每个使用者进行设置。有关设置选项的更多详细信息,请参见第 16 章

switch 策略

缺省情况下,主体缓冲区具有 switch 缓冲区策略。在此策略下,每个 CPU 的缓冲区都成对分配:一个缓冲区处于活动状态,另一个缓冲区处于非活动状态。在 DTrace 使用者尝试读取缓冲区时,内核首先切换非活动缓冲区和活动缓冲区。缓冲区的切换方式应保证任何窗口中的跟踪数据都不会丢失。切换缓冲区后,新的非活动缓冲区将复制给 DTrace 使用者。此策略确保使用者始终看到前后一致的缓冲区:不能同时跟踪和复制缓冲区。此方法还避免了引入跟踪被暂停或被阻止的窗口。切换和读出缓冲区的速率由使用者通过 switchrate 选项控制。与任何速率选项一样,可以使用任何时间后缀指定 switchrate,但缺省为每秒的速率。有关 switchrate 和其他选项的更多详细信息,请参见第 16 章


注 –

要在用户级别以比缺省的每秒一次更快的速率处理主体缓冲区,请调整 switchrate 的值。当处理主体缓冲区中的对应记录时,系统将处理引发用户级别活动的操作(如 printa()system())。switchrate 指定系统处理此类操作时的速率。


switch 策略下,如果给定的已启用探测器跟踪的数据超出了活动主体缓冲区中的可用空间,则会删除多余数据,并递增每个 CPU 的删除计数。在发生一次或多次删除时,dtrace(1M) 显示一条与以下示例类似的消息:


dtrace: 11 drops on CPU 0

如果给定的记录大于总计缓冲区大小,则不管缓冲区策略是什么,都将删除记录。您可以通过使用 bufsize 选项增加主体缓冲区的大小或者使用 switchrate 选项增加切换速率,来降低或消除删除次数。

switch 策略下,在活动缓冲区外部分配 copyin()copyinstr()alloca() 的临时空间。

fill 策略

对于某些问题,您可能希望使用一个内核内部的缓冲区。虽然此方法可以使用 switch 策略和相应的 D 结构(通过在 D 中递增变量并相应地预测 exit() 操作)实现,但这样的实现不能消除发生删除的可能性。要请求内核中的单个大缓冲区,并继续跟踪,直到一个或多个每 CPU 缓冲区已填充,请使用 fill 缓冲区策略。在此策略下,跟踪将继续,直到已启用的探测器尝试跟踪的数据多于剩余主体缓冲区空间中可以容纳的数据。在剩余空间不足时,缓冲区将标记为已填充,并且将通知使用者,至少有一个每 CPU 缓冲区已填充。在 dtrace(1M) 检测到一个已填充的缓冲区后,将停止跟踪,并处理所有缓冲区,然后 dtrace 退出。即使缓冲区中还可容纳一些数据,也不会在已填充缓冲区中跟踪更多的数据。

要使用 fill 策略,请将 bufpolicy 选项设置为 fill。例如,以下命令使用设置为 fill 的缓冲策略,在每 CPU 2K 的缓冲区中跟踪每个系统调用项:


# dtrace -n syscall:::entry -b 2k -x bufpolicy=fill

fill 策略和 END 探测器

在 DTrace 使用者显式停止跟踪之前,END 探测器通常不会触发。END 探测器一定仅在一个 CPU 中触发,而且是将触发探测器的未定义的 CPU。使用 fill 缓冲区时,如果至少有一个每 CPU 主体缓冲区标记为已填充,便会显式停止跟踪。如果选择了 fill 策略,则 END 探测器可能在有已填充缓冲区的 CPU 中触发。为了适应 fill 缓冲区中的 END 跟踪,DTrace 将计算 END 探测器可能使用的空间的数量,然后从主体缓冲区的大小中减去此空间。如果净大小为负数,DTrace 将拒绝启动,dtrace(1M) 将输出相应的错误消息:


dtrace: END enablings exceed size of principal buffer

预留空间机制可确保,对于任何 END 探测器,整个缓冲区始终有足够的空间。

ring 策略

使用 DTrace ring 缓冲区策略,可以跟踪事件直到失败为止。如果重新生成失败需要几个小时或几天时间,您可能希望仅保留最新的数据。在填充某个主体缓冲区后,跟踪将会绕回到第一项,从而覆盖旧的跟踪数据。可以通过将 bufpolicy 选项设置为字符串 ring 来建立环形缓冲区:


# dtrace -s foo.d -x bufpolicy=ring

用于创建环形缓冲区时,dtrace(1M) 将不会显示任何输出,直到终止进程为止。此时,将会使用并处理环形缓冲区。dtrace 按照 CPU 顺序处理每个环形缓冲区。在 CPU 的缓冲区中,跟踪记录按照从旧到新的顺序显示。与使用 switch 缓冲策略一样,不会对不同 CPU 之间的记录进行排序。如果需要这样的排序,应将 timestamp 变量作为跟踪请求的一部分进行跟踪。

以下示例演示了如何使用 #pragma option 指令启用环形缓冲:

#pragma D option bufpolicy=ring
#pragma D option bufsize=16k

syscall:::entry
/execname == $1/
{
	trace(timestamp);
}

syscall::rexit:entry
{
	exit(0);
}

其他缓冲区

每个 DTrace 启用中都存在主体缓冲区。除了主体缓冲区,一些 DTrace 使用者可能有其他内核中的数据缓冲区:聚合缓冲区(在第 9 章中讨论)和一个或多个推理缓冲区(在第 13 章中讨论)。

缓冲区大小

可以基于每个使用者调整每个缓冲区的大小。为每个缓冲区提供了不同的用于调整缓冲区大小的选项,如下表中所示:

缓冲区 

大小选项 

主体 

bufsize

推理 

specsize

聚合 

aggsize

这些选项的每一个都使用表示大小的值设置。与任何大小选项一样,该值可以具有可选的大小后缀。有关更多详细信息,请参见第 16 章。例如,要在 dtrace 的命令行上将缓冲区大小设置为 1MB,可以使用 -x 设置该选项:


# dtrace -P syscall -x bufsize=1m

或者,可以将 -b 选项用于 dtrace


# dtrace -P syscall -b 1m

最后,可以使用 #pragma D option 设置 bufsize

#pragma D option bufsize=1m

所选择的缓冲区大小表示每个 CPU 中的缓冲区的大小。而且,对于 switch 缓冲区策略,bufsize 表示每个 CPU 中每个缓冲区的大小。缓冲区大小缺省为 4 MB。

缓冲区调整大小策略

偶尔,系统可能会因为没有足够的可用内存,或者 DTrace 使用者超出第 16 章中说明的某项可调整限制,而没有足够可用的内核内存来分配所需大小的缓冲区。可以使用 bufresize 选项(缺省为 auto)配置缓冲区分配失败的策略。在 auto 缓冲区调整大小策略下,将平均分配缓冲区大小,直到成功进行分配。如果分配的缓冲区小于请求的大小,dtrace(1M) 将生成一条消息:


# dtrace -P syscall -b 4g
dtrace: description 'syscall' matched 430 probes
dtrace: buffer size lowered to 128m
...

或者:


# dtrace -P syscall'{@a[probefunc] = count()}' -x aggsize=1g
dtrace: description 'syscall' matched 430 probes
dtrace: aggregation size lowered to 128m
...

或者,可以通过将 bufresize 设置为 manual,要求在缓冲区分配失败之后进行手动干预。在此策略下,分配失败将会导致 DTrace 启动失败:


# dtrace -P syscall -x bufsize=1g -x bufresize=manual
dtrace: description 'syscall' matched 430 probes
dtrace: could not enable tracing: Not enough space
#

所有缓冲区(主体、推理和聚合)的缓冲区调整大小策略都由 bufresize 选项指定。