From 87f2236ad2a470e66196c41a761481513306a6bd Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Mon, 14 Nov 2005 15:50:46 +0000 Subject: [PATCH] load average measurement implementation, accessable through getloadavg() system call in the library. --- kernel/clock.c | 31 +++++++++++++++++++++++++++++++ kernel/glo.h | 1 + kernel/main.c | 3 +++ kernel/proc.c | 6 ++++++ kernel/start.c | 7 +++++++ kernel/system/do_getinfo.c | 5 +++++ servers/pm/misc.c | 6 ++++++ 7 files changed, 59 insertions(+) diff --git a/kernel/clock.c b/kernel/clock.c index 1dafb33b2..d8dfb0d2c 100755 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -38,6 +38,7 @@ FORWARD _PROTOTYPE( void init_clock, (void) ); FORWARD _PROTOTYPE( int clock_handler, (irq_hook_t *hook) ); FORWARD _PROTOTYPE( int do_clocktick, (message *m_ptr) ); +FORWARD _PROTOTYPE( void load_update, (void)); /* Clock parameters. */ #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using square wave */ @@ -205,6 +206,9 @@ irq_hook_t *hook; bill_ptr->p_ticks_left -= ticks; } + /* Update load average. */ + load_update(); + /* Check if do_clocktick() must be called. Done for alarms and scheduling. * Some processes, such as the kernel tasks, cannot be preempted. */ @@ -272,3 +276,30 @@ PUBLIC unsigned long read_clock() return count; } + +/*===========================================================================* + * load_update * + *===========================================================================*/ +PRIVATE void load_update(void) +{ + u16_t slot; + + /* Load average data is stored as a list of numbers in a circular + * buffer. Each slot accumulates _LOAD_UNIT_SECS of samples of + * the number of runnable processes. Computations can then + * be made of the load average over variable periods, in the + * user library (see getloadavg(3)). + */ + slot = (realtime / HZ / _LOAD_UNIT_SECS) % _LOAD_HISTORY; + if(slot != kloadinfo.proc_last_slot) { + kloadinfo.proc_load_history[slot] = 0; + kloadinfo.proc_last_slot = slot; + } + + /* Cumulation. */ + kloadinfo.proc_load_history[slot] += kloadinfo.procs_enqueued; + + /* Up-to-dateness. */ + kloadinfo.last_clock = realtime; +} + diff --git a/kernel/glo.h b/kernel/glo.h index e37b7a4d4..ada3607ed 100755 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -24,6 +24,7 @@ EXTERN struct kinfo kinfo; /* kernel information for users */ EXTERN struct machine machine; /* machine information for users */ EXTERN struct kmessages kmess; /* diagnostic messages in kernel */ EXTERN struct randomness krandom; /* gather kernel random information */ +EXTERN struct loadinfo kloadinfo; /* status of load average */ /* Process scheduling information and the kernel reentry count. */ EXTERN struct proc *prev_ptr; /* previously running process */ diff --git a/kernel/main.c b/kernel/main.c index 74c33b2ca..8295a7859 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -142,6 +142,9 @@ PUBLIC void main() alloc_segments(rp); } + /* Special compensation for IDLE - don't let it count in the load average. */ + kloadinfo.procs_enqueued--; + #if ENABLE_BOOTDEV /* Expect an image of the boot device to be loaded into memory as well. * The boot device is the last module that is loaded into memory, and, diff --git a/kernel/proc.c b/kernel/proc.c index 125c34363..f4d7eafaf 100755 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -500,6 +500,8 @@ register struct proc *rp; /* this process is now runnable */ /* Now select the next process to run. */ pick_proc(); + kloadinfo.procs_enqueued++; + #if DEBUG_SCHED_CHECK rp->p_ready = 1; check_runqueues("enqueue"); @@ -548,10 +550,14 @@ register struct proc *rp; /* this process is no longer runnable */ } prev_xp = *xpp; /* save previous in chain */ } + + kloadinfo.procs_enqueued--; #if DEBUG_SCHED_CHECK rp->p_ready = 0; check_runqueues("dequeue"); + if(kloadinfo.procs_enqueued < 0) + kprintf("%d processes enqueued\n", kloadinfo.procs_enqueued); #endif } diff --git a/kernel/start.c b/kernel/start.c index dd860f705..f137f4c6e 100755 --- a/kernel/start.c +++ b/kernel/start.c @@ -29,6 +29,7 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ char params[128*sizeof(char *)]; /* boot monitor parameters */ register char *value; /* value in key=value pair */ extern int etext, end; + int h; /* Decide if mode is protected; 386 or higher implies protected mode. * This must be done first, because it is needed for, e.g., seg2phys(). @@ -64,6 +65,12 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */ kinfo.kmem_base = vir2phys(0); kinfo.kmem_size = (phys_bytes) &end; + /* Load average data initialization. */ + kloadinfo.procs_enqueued = 0; + kloadinfo.proc_last_slot = 0; + for(h = 0; h < _LOAD_HISTORY; h++) + kloadinfo.proc_load_history[h] = 0; + /* Processor? 86, 186, 286, 386, ... * Decide if mode is protected for older machines. */ diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index f6bed77a3..33b7bb7a3 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -42,6 +42,11 @@ register message *m_ptr; /* pointer to request message */ src_phys = vir2phys(&kinfo); break; } + case GET_LOADINFO: { + length = sizeof(struct loadinfo); + src_phys = vir2phys(&kloadinfo); + break; + } case GET_IMAGE: { length = sizeof(struct boot_image) * NR_BOOT_PROCS; src_phys = vir2phys(image); diff --git a/servers/pm/misc.c b/servers/pm/misc.c index aadd84b6a..a9fbbe78a 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -59,6 +59,7 @@ PUBLIC int do_getsysinfo() struct mproc *proc_addr; vir_bytes src_addr, dst_addr; struct kinfo kinfo; + struct loadinfo loadinfo; size_t len; static struct pm_mem_info pmi; int s, r; @@ -87,6 +88,11 @@ PUBLIC int do_getsysinfo() src_addr = (vir_bytes) &pmi; len = sizeof(pmi); break; + case SI_LOADINFO: /* loadinfo is obtained via PM */ + sys_getloadinfo(&loadinfo); + src_addr = (vir_bytes) &loadinfo; + len = sizeof(struct loadinfo); + break; default: return(EINVAL); }