Add 'getidle' CPU utilization measurement infrastructure
This commit is contained in:
@@ -10,6 +10,7 @@ libsys_FILES=" \
|
||||
kputc.c \
|
||||
tickdelay.c \
|
||||
get_randomness.c \
|
||||
getidle.c \
|
||||
getuptime.c \
|
||||
getuptime2.c \
|
||||
env_get_prm.c \
|
||||
|
||||
92
lib/sysutil/getidle.c
Normal file
92
lib/sysutil/getidle.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
#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 */
|
||||
@@ -61,7 +61,7 @@ char *name;
|
||||
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) {
|
||||
@@ -105,8 +105,7 @@ char *name;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
@@ -167,8 +166,7 @@ char *name;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -201,8 +199,7 @@ char *name;
|
||||
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;
|
||||
@@ -246,12 +243,9 @@ PRIVATE void cprof_init() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user