Solaris 动态跟踪指南

tick

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 毫秒偏移处有一个峰值,指示系统中至少有一些线程根据时间调度的。