loadavg_read_proc
ロードアベレージの算出方法
- runqueue
- TASK_RUNNING, TASK_UNINTERRUPTIBLE
- procfs
- タイマ割り込み
- ticks , HZ
63 /* 64 * These are the constant used to fake the fixed-point load-average 65 * counting. Some notes: // faction .. 分数、割合 66 * - 11 bit fractions expand to 22 bits by the multiplies: this gives 67 * a load-average precision of 10 bits integer + 11 bits fractional 68 * - if you want to count load-averages more often, you need more 69 * precision, or rounding will get you. With 2-second counting freq, 70 * the EXP_n values would be 1981, 2034 and 2043 if still using only 71 * 11 bit fractions. 72 */ 73 extern unsigned long avenrun[]; /* Load averages */ 74 75 #define FSHIFT 11 /* nr of bits of precision */ 76 #define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */ 77 #define LOAD_FREQ (5*HZ) /* 5 sec intervals */ 78 #define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */ 79 #define EXP_5 2014 /* 1/exp(5sec/5min) */ 80 #define EXP_15 2037 /* 1/exp(5sec/15min) */ 81 82 #define CALC_LOAD(load,exp,n) \ 83 load *= exp; \ 84 load += n*(FIXED_1-exp); \ 85 load >>= FSHIFT; // FSHIFT ... 11? /* #define LOAD_INT(x) ((x) >> FSHIFT) */ /* #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) */ static int loadavg_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int a, b, c; int len; // avenrun ... kernel/timer.cのグローバル変数 a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), // TASK_RUNNINGの数 .. kernel/sched.c // スレッドの数 // 最後のプロセスのpid nr_running(), nr_threads, last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } /* * nr_running, nr_uninterruptible and nr_context_switches: * * externally visible scheduler statistics: current number of runnable * threads, current number of uninterruptible-sleeping threads, total * number of context switches performed since bootup. */ // TASK_RUNNING と TASK_UNINTERRUPTIBLE unsigned long nr_running(void) { unsigned long i, sum = 0; // CPUごとのrunqueueを見て、nr_runningを足す for_each_online_cpu(i) sum += cpu_rq(i)->nr_running; // TASK_RUNNING return sum; } unsigned long nr_uninterruptible(void) { unsigned long i, sum = 0; // CPUごとのrunqueue, TASK_UNINTERRUPTIBLEの数を総計する for_each_cpu(i) sum += cpu_rq(i)->nr_uninterruptible; // TASK_UNINTERRUPTIBLE return sum; } /* * Nr of active tasks - counted in fixed-point numbers */ static unsigned long count_active_tasks(void) { // 全てのCPUのTASK_RUNNING + TASK_UNINTERRUPTIBLE return (nr_running() + nr_uninterruptible()) * FIXED_1; } /* * calc_load - given tick count, update the avenrun load estimates. * This is called while holding a write_lock on xtime_lock. */ static inline void calc_load(unsigned long ticks) { unsigned long active_tasks; /* fixed-point */ static int count = LOAD_FREQ; count -= ticks; if (count < 0) { count += LOAD_FREQ; active_tasks = count_active_tasks(); // TASK_RUNNING + TASK_UNINTERRUPTIBLE CALC_LOAD(avenrun[0], EXP_1, active_tasks); CALC_LOAD(avenrun[1], EXP_5, active_tasks); CALC_LOAD(avenrun[2], EXP_15, active_tasks); } } /* * Called by the timer interrupt. xtime_lock must already be taken * by the timer IRQ! */ // タイマ割り込み 1/1000 とか 1/100 秒とかで static inline void update_times(void) { unsigned long ticks; ticks = jiffies - wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); } // ここで計算 calc_load(ticks); }