Solaris 使用基于计时单元的 CPU 记帐(其中系统时钟中断会按固定时间间隔触发)并将 CPU 的使用情况归结到计时单元时间运行的线程和进程。以下示例说明如何使用 tick 探测器来观察这一归结情况:
# dtrace -n sched:::tick'{@[stringof(args[1]->pr_fname)] = count()}'
^C
arch 1
sh 1
sed 1
echo 1
ls 1
FvwmAuto 1
pwd 1
awk 2
basename 2
expr 2
resize 2
tput 2
uname 2
fsflush 2
dirname 4
vim 9
fvwm2 10
ksh 19
xterm 21
Xsun 93
MozillaFirebird 260
|
系统时钟频率随操作系统不同而变化,但通常会在 25 赫兹到 1024 赫兹之间。Solaris 系统时钟频率是可调整的,但缺省值为 100 赫兹。
仅当系统时钟检测到可运行线程时,tick 探测器才会触发。要使用 tick 探测器来观察系统时钟的频率,必须具有始终可运行的线程。在一个窗口中创建循环 shell,如下例所示:
$ while true ; do let i=0 ; done |
在另一个窗口中运行以下脚本:
uint64_t last[int];
sched:::tick
/last[cpu]/
{
@[cpu] = min(timestamp - last[cpu]);
}
sched:::tick
{
last[cpu] = timestamp;
}
# dtrace -s ./ticktime.d dtrace: script './ticktime.d' matched 2 probes ^C 0 9883789 |
最短时间间隔为 9.8 毫秒,它指示缺省时钟周期频率为 10 毫秒(100 赫兹)。因为抖动,所以观察到的最短时间间隔略小于 10 毫秒。
基于计时单元的记帐的一个缺点是,执行记帐的系统时钟通常还负责分派任何与时间有关的调度活动。因此,如果线程要在每个时钟周期(即每 10 毫秒)执行一定量的工作,则根据记帐是在与时间有关的分派调度活动之前还是之后完成,系统会对线程的工作量记帐过多或过少。在 Solaris 中,记帐是在与时间有关的分派之前完成的。因此,系统会对定期运行的线程工作量记帐过少。如果这类线程运行的时间小于时钟周期的时间间隔,它们可以有效地“隐藏”在时钟周期中。以下示例显示系统中这类线程的情况:
sched:::tick,
sched:::enqueue
{
@[probename] = lquantize((timestamp / 1000000) % 10, 0, 10);
}
示例脚本的输出在 10 毫秒时间间隔内分为两个毫秒偏移部分,一个对应于 tick 探测器,另一个对应于 enqueue:
# dtrace -s ./tick.d
dtrace: script './tick.d' matched 4 probes
^C
tick
value -------------- Distribution ------------ count
6 | 0
7 |@ 3
8 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 79
9 | 0
enqueue
value -------------- Distribution ------------ count
< 0 | 0
0 |@@ 267
1 |@@ 300
2 |@@ 259
3 |@@ 291
4 |@@@ 360
5 |@@ 305
6 |@@ 295
7 |@@@@ 522
8 |@@@@@@@@@@@@ 1315
9 |@@@ 337
|
名为 tick 的输出直方图显示时钟周期在 8 毫秒偏移处触发。如果调度与时钟周期完全无关,enqueue 的输出将平均分布在 10 毫秒时间间隔内。但是,输出显示同一 8 毫秒偏移处有一个峰值,指示系统中至少有一些线程是根据时间调度的。