getloadavg() system call in the library.
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 */
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.
*/
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;
+}
+
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 */
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,
/* Now select the next process to run. */
pick_proc();
+ kloadinfo.procs_enqueued++;
+
#if DEBUG_SCHED_CHECK
rp->p_ready = 1;
check_runqueues("enqueue");
}
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
}
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().
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.
*/
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);
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;
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);
}