timer.cのdo_timer()からsched.cのnr_active()まで追ってみる
以前、他人のブログを見ながらロードアベレージの計算を学んだが、 おさらい兼ねて、実際にLinuxカーネル2.6.22のtimer.cから順番に処理を見てみる。(本も見ながら)
kernel/timer.cのdo_timer()
void do_timer(struct pt_regs *regs)
{
jiffies_64++;
update_times();
softlockup_tics(regs);
}
static inline viod update_times(void)
{
unsigned long ticks;
ticks = jiffies - wall_jiffies;
if (ticks) {
wall_jiffies - wall_jiffies;
update_wall_times(ticks);
}
calc_load(ticks);
}
1.システム起動後に発生したタイマー割り込み回数をjiffies_64に1を加算 2.update_times関数でLinux内部時計を進める 3.calc_load(ticks)でロードアベレージを計算 calc_load()
static inline void calc_load(unsigned long ticks)
{
unsigned long active_tasks; /* fixed-point */
static int count = LOAD_FREQ;
count -= ticks;
if (unlikely(count < 0)) {
active_tasks = count_active_tasks();
do {
CALC_LOAD(avenrun[0], EXP_1, active_tasks);
CALC_LOAD(avenrun[1], EXP_5, active_tasks);
CALC_LOAD(avenrun[2], EXP_15, active_tasks);
count += LOAD_FREQ;
} while (count < 0);
}
}
count_active_tasks()の結果をactive_tasksに入れ、1分、5分、15分の平均値をavenrun[]に入れている。 これが多分、/proc/loadavgに反映されてるんだろう。 count_active_tasks()
static unsigned long count_active_tasks(void)
{
return nr_active() * FIXED_1;
}
count_active_tasks()を見ると、nr_activeの結果を返している。 nr_activeはkernel/sched.cにある。 nr_active()
unsigned long nr_active(void)
{
unsigned long i, running = 0, uninterruptible = 0;
for_each_online_cpu(i) {
running += cpu_rq(i)->nr_running;
uninterruptible += cpu_rq(i)->nr_uninterruptible;
}
if (unlikely((long)uninterruptible < 0))
uninterruptible = 0;
return running + uninterruptible;
}
runningとunninterruptibleを足したのを返していて、何が入っているかって言うと、 runningにはnr_runningが入っていて、unninterruptibleにはnr_uninterruptibleが入っている。 nr_runningとnr_uninterruptibleはinclude/linux/sched.hに、 待機状態のプロセスの状態として定義されている。 ・TASK_RUNNING:実行状態・実行可能な状態なプロセス ・TASK_UNINTERRUPTIBLE:シグナル受信しても起床できないプロセスの状態(I/O待ちとか?) でもって、uptimeとかtopとかwとかのコマンドで引っ張ってくるのは、/proc/loadavgの値。