# define GET_HZ 18 /* get HZ value */
# define GET_WHOAMI 19 /* get own name and endpoint */
# define GET_RANDOMNESS_BIN 20 /* get one randomness bin */
+# define GET_IDLETSC 21 /* get cumulative idle time stamp counter */
#define I_ENDPT m7_i4 /* calling process */
#define I_VAL_PTR m7_p1 /* virtual address at caller */
#define I_VAL_LEN m7_i1 /* max length of value */
#define SIU_LOADINFO 1 /* retrieve load info data */
#define SIU_SYSTEMHZ 2 /* retrieve system clock frequency */
+#define SIU_IDLETSC 3 /* retrieve cumulative idle timestamp count */
/* Exported system parameters. */
#define sys_getschedinfo(v1,v2) sys_getinfo(GET_SCHEDINFO, v1,0, v2,0)
#define sys_getlocktimings(dst) sys_getinfo(GET_LOCKTIMING, dst, 0,0,0)
#define sys_getprivid(nr) sys_getinfo(GET_PRIVID, 0, 0,0, nr)
+#define sys_getidletsc(dst) sys_getinfo(GET_IDLETSC, dst, 0,0,0)
_PROTOTYPE(int sys_getinfo, (int request, void *val_ptr, int val_len,
void *val_ptr2, int val_len2) );
_PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen));
void *ctl_ptr, void *mem_ptr) );
_PROTOTYPE( int sys_profbuf, (void *ctl_ptr, void *mem_ptr) );
-/* read_tsc() and friends. */
-_PROTOTYPE( void read_tsc_64, (u64_t *t) );
-_PROTOTYPE( void read_tsc, (u32_t *hi, u32_t *lo) );
-
#endif /* _SYSLIB_H */
_PROTOTYPE( int tickdelay, (clock_t ticks));
_PROTOTYPE( int micro_delay_calibrate, (void));
_PROTOTYPE( u32_t sys_hz, (void));
+_PROTOTYPE( double getidle, (void));
_PROTOTYPE( void util_stacktrace, (void));
_PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) );
_PROTOTYPE( void util_stacktrace_strcat, (char *));
typedef struct util_timingdata util_timingdata_t;
+/* read_tsc() and friends. */
+_PROTOTYPE( void read_tsc_64, (u64_t *t) );
+_PROTOTYPE( void read_tsc, (u32_t *hi, u32_t *lo) );
+
#endif /* _MINIX_SYSUTIL_H */
#include <signal.h>
#include <stdio.h>
#include <string.h>
-#include <minix/sysutil.h>
#include "../../proc.h"
#include "../../proto.h"
#include "../../vm.h"
#include <minix/type.h>
#include <minix/syslib.h>
-#include <minix/sysutil.h>
#include <minix/cpufeature.h>
#include <string.h>
EXTERN struct tss_s tss;
-_PROTOTYPE( void prot_init, (void) );
_PROTOTYPE( void idt_init, (void) );
_PROTOTYPE( void init_codeseg, (struct segdesc_s *segdp, phys_bytes base,
vir_bytes size, int privilege) );
#include <ibm/bios.h>
#include <minix/portio.h>
#include <minix/u64.h>
-#include <minix/sysutil.h>
#include <a.out.h>
#include "proto.h"
{
unsigned ticks;
+ IDLE_STOP;
+
if(minix_panicing)
return 0;
int expired = 0;
struct proc * p, * billp;
+ IDLE_STOP;
+
/* Update user and system accounting times. Charge the current process
* for user time. If the current process is not billable, that is, if a
* non-user process is running, charge the billable process for system
#define lock reallock
#define unlock realunlock
+#ifdef CONFIG_IDLE_TSC
+#define IDLE_STOP if(idle_active) { read_tsc_64(&idle_stop); idle_active = 0; }
+#else
+#define IDLE_STOP
+#endif
+
/* args to intr_init() */
#define INTS_ORIG 0 /* restore interrupts */
#define INTS_MINIX 1 /* initialize interrupts for minix */
#ifndef GLO_H
#define GLO_H
-#include <minix/sysutil.h>
-
/* Global variables used in the kernel. This file contains the declarations;
* storage space for the variables is allocated in table.c, because EXTERN is
* defined as extern unless the _TABLE definition is seen. We rely on the
EXTERN int config_no_apic; /* optionaly turn off apic */
#endif
+#ifdef CONFIG_IDLE_TSC
+EXTERN u64_t idle_tsc;
+EXTERN u64_t idle_stop;
+EXTERN int idle_active;
+#endif
+
/* VM */
EXTERN int vm_running;
EXTERN int catch_pagefaults;
{
irq_hook_t * hook;
+ IDLE_STOP;
+
/* here we need not to get this IRQ until all the handlers had a say */
hw_intr_mask(irq);
hook = irq_handlers[irq];
#define CONFIG_APIC
/* boot verbose */
#define CONFIG_BOOT_VERBOSE
+/* measure cumulative idle timestamp counter ticks */
+#undef CONFIG_IDLE_TSC
/* This is the master header for the kernel. It includes some other files
* and defines the principal constants.
#include <minix/const.h> /* MINIX specific constants */
#include <minix/type.h> /* MINIX specific types, e.g. message */
#include <minix/ipc.h> /* MINIX run-time system */
+#include <minix/sysutil.h> /* MINIX utility library functions */
#include <timers.h> /* watchdog timer management */
#include <errno.h> /* return codes and error numbers */
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/endpoint.h>
+#include <minix/u64.h>
#include "proc.h"
#include "debug.h"
#include "clock.h"
#endif /* SPROFILE */
cprof_procs_no = 0; /* init nr of hash table slots used */
+#ifdef CONFIG_IDLE_TSC
+ idle_tsc = cvu64(0);
+#endif
+
vm_running = 0;
krandom.random_sources = RANDOM_SOURCES;
krandom.random_elements = RANDOM_ELEMENTS;
#include <signal.h>
#include <minix/portio.h>
#include <minix/u64.h>
+#include <minix/syslib.h>
#include "debug.h"
#include "kernel.h"
* other parts of the kernel through lock_...(). The lock temporarily disables
* interrupts to prevent race conditions.
*/
+FORWARD _PROTOTYPE( void idle, (void));
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst_e,
message *m_ptr, int flags));
FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
NOREC_RETURN(queuemess, OK);
}
+/*===========================================================================*
+ * idle *
+ *===========================================================================*/
+PRIVATE void idle()
+{
+ /* This function is called whenever there is no work to do.
+ * Halt the CPU, and measure how many timestamp counter ticks are
+ * spent not doing anything. This allows test setups to measure
+ * the CPU utiliziation of certain workloads with high precision.
+ */
+#ifdef CONFIG_IDLE_TSC
+ u64_t idle_start;
+
+ read_tsc_64(&idle_start);
+ idle_active = 1;
+#endif
+
+ halt_cpu();
+
+#ifdef CONFIG_IDLE_TSC
+ if (idle_active) {
+ IDLE_STOP;
+ printf("Kernel: idle active after resuming CPU\n");
+ }
+
+ idle_tsc = add64(idle_tsc, sub64(idle_stop, idle_start));
+#endif
+}
+
/*===========================================================================*
* schedcheck *
*===========================================================================*/
proc_ptr = proc_addr(IDLE);
if (priv(proc_ptr)->s_flags & BILLABLE)
bill_ptr = proc_ptr;
- halt_cpu();
+ idle();
}
check_misc_flags:
_PROTOTYPE( void ser_dump_proc, (void) );
/* main.c */
+_PROTOTYPE( void main, (void) );
_PROTOTYPE( void prepare_shutdown, (int how) );
_PROTOTYPE( void minix_shutdown, (struct timer *tp) );
#endif
/* functions defined in architecture-dependent files. */
+_PROTOTYPE( void prot_init, (void) );
_PROTOTYPE( phys_bytes phys_copy, (phys_bytes source, phys_bytes dest,
phys_bytes count) );
_PROTOTYPE( void phys_copy_fault, (void));
break;
}
#endif
-
case GET_IRQACTIDS: {
length = sizeof(irq_actids);
src_vir = (vir_bytes) irq_actids;
break;
}
-
- case GET_PRIVID:
+ case GET_PRIVID: {
if (!isokendpt(m_ptr->I_VAL_LEN2_E, &proc_nr))
return EINVAL;
return proc_addr(proc_nr)->p_priv->s_id;
-
+ }
+ case GET_IDLETSC: {
+#ifdef CONFIG_IDLE_TSC
+ length = sizeof(idle_tsc);
+ src_vir = (vir_bytes) &idle_tsc;
+ break;
+#else
+ kprintf("do_getinfo: kernel not compiled with CONFIG_IDLE_TSC\n");
+ return(EINVAL);
+#endif
+ }
default:
kprintf("do_getinfo: invalid request %d\n", m_ptr->I_REQUEST);
return(EINVAL);
#include <signal.h>
#include <string.h>
-#include <minix/sysutil.h>
#include <minix/sys_config.h>
/*===========================================================================*
kputc.c \
tickdelay.c \
get_randomness.c \
+ getidle.c \
getuptime.c \
getuptime2.c \
env_get_prm.c \
--- /dev/null
+/* getidle.c - by David van Moolenbroek <dcvmoole@cs.vu.nl> */
+
+/* Usage:
+ *
+ * double idleperc;
+ * getidle();
+ * ...
+ * idleperc = getidle();
+ * printf("CPU usage: %lg%%\n", 100.0 - idleperc);
+ *
+ * This routine goes through PM to get the idle time, rather than making the
+ * sys_getinfo() call to the kernel directly. This means that it can be used
+ * by non-system processes as well, but it will incur some extra overhead in
+ * the system case. The overhead does not end up being measured, because the
+ * system is clearly not idle while the system calls are being made. In any
+ * case, for this reason, only one getidle() run is allowed at a time.
+ *
+ * Note that the kernel has to be compiled with CONFIG_IDLE_TSC support.
+ */
+
+#define _MINIX 1
+#define _SYSTEM 1
+#include <minix/sysinfo.h>
+#include <minix/u64.h>
+#include <minix/sysutil.h>
+
+static u64_t start, idle;
+static int running = 0;
+
+static double make_double(u64_t d)
+{
+/* Convert a 64-bit fixed point value into a double.
+ * This whole thing should be replaced by something better eventually.
+ */
+ double value;
+ int i;
+
+ value = (double) ex64hi(d);
+ for (i = 0; i < sizeof(unsigned long); i += 2)
+ value *= 65536.0;
+
+ value += (double) ex64lo(d);
+
+ return value;
+}
+
+double getidle(void)
+{
+ u64_t stop, idle2;
+ u64_t idelta, tdelta;
+ double ifp, tfp, rfp;
+ int r;
+
+ if (!running) {
+ r = getsysinfo_up(PM_PROC_NR, SIU_IDLETSC, sizeof(idle), &idle);
+ if (r != sizeof(idle))
+ return -1.0;
+
+ running = 1;
+
+ read_tsc_64(&start);
+
+ return 0.0;
+ }
+ else {
+ read_tsc_64(&stop);
+
+ running = 0;
+
+ r = getsysinfo_up(PM_PROC_NR, SIU_IDLETSC, sizeof(idle2), &idle2);
+ if (r != sizeof(idle2))
+ return -1.0;
+
+ idelta = sub64(idle2, idle);
+ tdelta = sub64(stop, start);
+
+ if (cmp64(idelta, tdelta) >= 0)
+ return 100.0;
+
+ ifp = make_double(idelta);
+ tfp = make_double(tdelta);
+
+ rfp = ifp / tfp * 100.0;
+
+ if (rfp < 0.0) rfp = 0.0;
+ else if (rfp > 100.0) rfp = 100.0;
+
+ return rfp;
+ }
+
+ running = !running;
+}
#include <stdlib.h>
#include <string.h>
#include <minix/profile.h>
-#include <minix/syslib.h>
+#include <minix/sysutil.h>
#include <minix/u64.h>
PRIVATE char cpath[CPROF_CPATH_MAX_LEN]; /* current call path string */
if (cprof_locked) return; else cprof_locked = 1;
/* Read CPU cycle count into local variable. */
- read_tsc(&start.hi, &start.lo);
+ read_tsc_64(&start);
/* Run init code once after system boot. */
if (init == 0) {
}
/* Save initial cycle count on stack. */
- cprof_stk[cprof_stk_top].start_1.hi = start.hi;
- cprof_stk[cprof_stk_top].start_1.lo = start.lo;
+ cprof_stk[cprof_stk_top].start_1 = start;
/* Check available call path len. */
if (cpath_len + strlen(name) + 1 > CPROF_CPATH_MAX_LEN) {
cprof_stk[cprof_stk_top].slot = cprof_slot;
/* Again save CPU cycle count on stack. */
- read_tsc(&cprof_stk[cprof_stk_top].start_2.hi,
- &cprof_stk[cprof_stk_top].start_2.lo);
+ read_tsc_64(&cprof_stk[cprof_stk_top].start_2);
cprof_locked = 0;
}
sub64(spent, cprof_stk[cprof_stk_top].spent_deeper));
/* Clear spent_deeper for call level we're leaving. */
- cprof_stk[cprof_stk_top].spent_deeper.lo = 0;
- cprof_stk[cprof_stk_top].spent_deeper.hi = 0;
+ cprof_stk[cprof_stk_top].spent_deeper = cvu64(0);
/* Adjust call path string and stack. */
cpath_len = cprof_stk[cprof_stk_top].cpath_len;
for (i=0; i<CPROF_STACK_SIZE; i++) {
cprof_stk[i].cpath_len = 0;
cprof_stk[i].slot = 0;
- cprof_stk[i].start_1.lo = 0;
- cprof_stk[i].start_1.hi = 0;
- cprof_stk[i].start_2.lo = 0;
- cprof_stk[i].start_2.hi = 0;
- cprof_stk[i].spent_deeper.lo = 0;
- cprof_stk[i].spent_deeper.hi = 0;
+ cprof_stk[i].start_1 = cvu64(0);
+ cprof_stk[i].start_2 = cvu64(0);
+ cprof_stk[i].spent_deeper = cvu64(0);
}
}
vir_bytes src_addr, dst_addr;
struct loadinfo loadinfo;
size_t len, real_len;
+ u64_t idle_tsc;
int s;
switch(m_in.SIU_WHAT) {
case SIU_LOADINFO: /* loadinfo is obtained via PM */
- sys_getloadinfo(&loadinfo);
+ if ((s = sys_getloadinfo(&loadinfo)) != OK)
+ return s;
src_addr = (vir_bytes) &loadinfo;
real_len = sizeof(struct loadinfo);
break;
src_addr = (vir_bytes) &system_hz;
real_len = sizeof(system_hz);
break;
+ case SIU_IDLETSC:
+ if ((s = sys_getidletsc(&idle_tsc)) != OK)
+ return s;
+ src_addr = (vir_bytes) &idle_tsc;
+ real_len = sizeof(idle_tsc);
+ break;
default:
return(EINVAL);
}