Add 'getidle' CPU utilization measurement infrastructure
This commit is contained in:
parent
be2087ecf9
commit
fce9fd4b4e
22 changed files with 190 additions and 31 deletions
|
@ -482,6 +482,7 @@
|
||||||
# define GET_HZ 18 /* get HZ value */
|
# define GET_HZ 18 /* get HZ value */
|
||||||
# define GET_WHOAMI 19 /* get own name and endpoint */
|
# define GET_WHOAMI 19 /* get own name and endpoint */
|
||||||
# define GET_RANDOMNESS_BIN 20 /* get one randomness bin */
|
# 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_ENDPT m7_i4 /* calling process */
|
||||||
#define I_VAL_PTR m7_p1 /* virtual address at caller */
|
#define I_VAL_PTR m7_p1 /* virtual address at caller */
|
||||||
#define I_VAL_LEN m7_i1 /* max length of value */
|
#define I_VAL_LEN m7_i1 /* max length of value */
|
||||||
|
|
|
@ -11,6 +11,7 @@ _PROTOTYPE( ssize_t getsysinfo_up, (endpoint_t who, int what, size_t size,
|
||||||
|
|
||||||
#define SIU_LOADINFO 1 /* retrieve load info data */
|
#define SIU_LOADINFO 1 /* retrieve load info data */
|
||||||
#define SIU_SYSTEMHZ 2 /* retrieve system clock frequency */
|
#define SIU_SYSTEMHZ 2 /* retrieve system clock frequency */
|
||||||
|
#define SIU_IDLETSC 3 /* retrieve cumulative idle timestamp count */
|
||||||
|
|
||||||
/* Exported system parameters. */
|
/* Exported system parameters. */
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,7 @@ _PROTOTYPE(int sys_segctl, (int *index, u16_t *seg, vir_bytes *off,
|
||||||
#define sys_getschedinfo(v1,v2) sys_getinfo(GET_SCHEDINFO, v1,0, v2,0)
|
#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_getlocktimings(dst) sys_getinfo(GET_LOCKTIMING, dst, 0,0,0)
|
||||||
#define sys_getprivid(nr) sys_getinfo(GET_PRIVID, 0, 0,0, nr)
|
#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,
|
_PROTOTYPE(int sys_getinfo, (int request, void *val_ptr, int val_len,
|
||||||
void *val_ptr2, int val_len2) );
|
void *val_ptr2, int val_len2) );
|
||||||
_PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen));
|
_PROTOTYPE(int sys_whoami, (endpoint_t *ep, char *name, int namelen));
|
||||||
|
@ -242,9 +243,5 @@ _PROTOTYPE( int sys_cprof, (int action, int size, endpoint_t endpt,
|
||||||
void *ctl_ptr, void *mem_ptr) );
|
void *ctl_ptr, void *mem_ptr) );
|
||||||
_PROTOTYPE( int sys_profbuf, (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 */
|
#endif /* _SYSLIB_H */
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ _PROTOTYPE( int getuptime2, (clock_t *ticks, time_t *boottime));
|
||||||
_PROTOTYPE( int tickdelay, (clock_t ticks));
|
_PROTOTYPE( int tickdelay, (clock_t ticks));
|
||||||
_PROTOTYPE( int micro_delay_calibrate, (void));
|
_PROTOTYPE( int micro_delay_calibrate, (void));
|
||||||
_PROTOTYPE( u32_t sys_hz, (void));
|
_PROTOTYPE( u32_t sys_hz, (void));
|
||||||
|
_PROTOTYPE( double getidle, (void));
|
||||||
_PROTOTYPE( void util_stacktrace, (void));
|
_PROTOTYPE( void util_stacktrace, (void));
|
||||||
_PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) );
|
_PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) );
|
||||||
_PROTOTYPE( void util_stacktrace_strcat, (char *));
|
_PROTOTYPE( void util_stacktrace_strcat, (char *));
|
||||||
|
@ -81,5 +82,9 @@ struct util_timingdata {
|
||||||
|
|
||||||
typedef struct util_timingdata util_timingdata_t;
|
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 */
|
#endif /* _MINIX_SYSUTIL_H */
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <minix/sysutil.h>
|
|
||||||
#include "../../proc.h"
|
#include "../../proc.h"
|
||||||
#include "../../proto.h"
|
#include "../../proto.h"
|
||||||
#include "../../vm.h"
|
#include "../../vm.h"
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <minix/type.h>
|
#include <minix/type.h>
|
||||||
#include <minix/syslib.h>
|
#include <minix/syslib.h>
|
||||||
#include <minix/sysutil.h>
|
|
||||||
#include <minix/cpufeature.h>
|
#include <minix/cpufeature.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,6 @@ struct tss_s {
|
||||||
|
|
||||||
EXTERN struct tss_s tss;
|
EXTERN struct tss_s tss;
|
||||||
|
|
||||||
_PROTOTYPE( void prot_init, (void) );
|
|
||||||
_PROTOTYPE( void idt_init, (void) );
|
_PROTOTYPE( void idt_init, (void) );
|
||||||
_PROTOTYPE( void init_codeseg, (struct segdesc_s *segdp, phys_bytes base,
|
_PROTOTYPE( void init_codeseg, (struct segdesc_s *segdp, phys_bytes base,
|
||||||
vir_bytes size, int privilege) );
|
vir_bytes size, int privilege) );
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <ibm/bios.h>
|
#include <ibm/bios.h>
|
||||||
#include <minix/portio.h>
|
#include <minix/portio.h>
|
||||||
#include <minix/u64.h>
|
#include <minix/u64.h>
|
||||||
#include <minix/sysutil.h>
|
|
||||||
#include <a.out.h>
|
#include <a.out.h>
|
||||||
|
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
|
|
@ -118,6 +118,8 @@ PUBLIC int bsp_timer_int_handler(void)
|
||||||
{
|
{
|
||||||
unsigned ticks;
|
unsigned ticks;
|
||||||
|
|
||||||
|
IDLE_STOP;
|
||||||
|
|
||||||
if(minix_panicing)
|
if(minix_panicing)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -228,6 +230,8 @@ PUBLIC int ap_timer_int_handler(void)
|
||||||
int expired = 0;
|
int expired = 0;
|
||||||
struct proc * p, * billp;
|
struct proc * p, * billp;
|
||||||
|
|
||||||
|
IDLE_STOP;
|
||||||
|
|
||||||
/* Update user and system accounting times. Charge the current process
|
/* Update user and system accounting times. Charge the current process
|
||||||
* for user time. If the current process is not billable, that is, if a
|
* 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
|
* non-user process is running, charge the billable process for system
|
||||||
|
|
|
@ -45,6 +45,12 @@
|
||||||
#define lock reallock
|
#define lock reallock
|
||||||
#define unlock realunlock
|
#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() */
|
/* args to intr_init() */
|
||||||
#define INTS_ORIG 0 /* restore interrupts */
|
#define INTS_ORIG 0 /* restore interrupts */
|
||||||
#define INTS_MINIX 1 /* initialize interrupts for minix */
|
#define INTS_MINIX 1 /* initialize interrupts for minix */
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#ifndef GLO_H
|
#ifndef GLO_H
|
||||||
#define GLO_H
|
#define GLO_H
|
||||||
|
|
||||||
#include <minix/sysutil.h>
|
|
||||||
|
|
||||||
/* Global variables used in the kernel. This file contains the declarations;
|
/* Global variables used in the kernel. This file contains the declarations;
|
||||||
* storage space for the variables is allocated in table.c, because EXTERN is
|
* 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
|
* defined as extern unless the _TABLE definition is seen. We rely on the
|
||||||
|
@ -66,6 +64,12 @@ EXTERN int verboseflags;
|
||||||
EXTERN int config_no_apic; /* optionaly turn off apic */
|
EXTERN int config_no_apic; /* optionaly turn off apic */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDLE_TSC
|
||||||
|
EXTERN u64_t idle_tsc;
|
||||||
|
EXTERN u64_t idle_stop;
|
||||||
|
EXTERN int idle_active;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* VM */
|
/* VM */
|
||||||
EXTERN int vm_running;
|
EXTERN int vm_running;
|
||||||
EXTERN int catch_pagefaults;
|
EXTERN int catch_pagefaults;
|
||||||
|
|
|
@ -112,6 +112,8 @@ PUBLIC void irq_handle(int irq)
|
||||||
{
|
{
|
||||||
irq_hook_t * hook;
|
irq_hook_t * hook;
|
||||||
|
|
||||||
|
IDLE_STOP;
|
||||||
|
|
||||||
/* here we need not to get this IRQ until all the handlers had a say */
|
/* here we need not to get this IRQ until all the handlers had a say */
|
||||||
hw_intr_mask(irq);
|
hw_intr_mask(irq);
|
||||||
hook = irq_handlers[irq];
|
hook = irq_handlers[irq];
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#define CONFIG_APIC
|
#define CONFIG_APIC
|
||||||
/* boot verbose */
|
/* boot verbose */
|
||||||
#define CONFIG_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
|
/* This is the master header for the kernel. It includes some other files
|
||||||
* and defines the principal constants.
|
* and defines the principal constants.
|
||||||
|
@ -20,6 +22,7 @@
|
||||||
#include <minix/const.h> /* MINIX specific constants */
|
#include <minix/const.h> /* MINIX specific constants */
|
||||||
#include <minix/type.h> /* MINIX specific types, e.g. message */
|
#include <minix/type.h> /* MINIX specific types, e.g. message */
|
||||||
#include <minix/ipc.h> /* MINIX run-time system */
|
#include <minix/ipc.h> /* MINIX run-time system */
|
||||||
|
#include <minix/sysutil.h> /* MINIX utility library functions */
|
||||||
#include <timers.h> /* watchdog timer management */
|
#include <timers.h> /* watchdog timer management */
|
||||||
#include <errno.h> /* return codes and error numbers */
|
#include <errno.h> /* return codes and error numbers */
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <minix/callnr.h>
|
#include <minix/callnr.h>
|
||||||
#include <minix/com.h>
|
#include <minix/com.h>
|
||||||
#include <minix/endpoint.h>
|
#include <minix/endpoint.h>
|
||||||
|
#include <minix/u64.h>
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
|
@ -189,6 +190,10 @@ PUBLIC void main()
|
||||||
#endif /* SPROFILE */
|
#endif /* SPROFILE */
|
||||||
cprof_procs_no = 0; /* init nr of hash table slots used */
|
cprof_procs_no = 0; /* init nr of hash table slots used */
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDLE_TSC
|
||||||
|
idle_tsc = cvu64(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
vm_running = 0;
|
vm_running = 0;
|
||||||
krandom.random_sources = RANDOM_SOURCES;
|
krandom.random_sources = RANDOM_SOURCES;
|
||||||
krandom.random_elements = RANDOM_ELEMENTS;
|
krandom.random_elements = RANDOM_ELEMENTS;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <minix/portio.h>
|
#include <minix/portio.h>
|
||||||
#include <minix/u64.h>
|
#include <minix/u64.h>
|
||||||
|
#include <minix/syslib.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
* other parts of the kernel through lock_...(). The lock temporarily disables
|
* other parts of the kernel through lock_...(). The lock temporarily disables
|
||||||
* interrupts to prevent race conditions.
|
* interrupts to prevent race conditions.
|
||||||
*/
|
*/
|
||||||
|
FORWARD _PROTOTYPE( void idle, (void));
|
||||||
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst_e,
|
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst_e,
|
||||||
message *m_ptr, int flags));
|
message *m_ptr, int flags));
|
||||||
FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
|
FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
|
||||||
|
@ -123,6 +125,35 @@ PRIVATE int QueueMess(endpoint_t ep, vir_bytes msg_lin, struct proc *dst)
|
||||||
NOREC_RETURN(queuemess, OK);
|
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 *
|
* schedcheck *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -166,7 +197,7 @@ not_runnable_pick_new:
|
||||||
proc_ptr = proc_addr(IDLE);
|
proc_ptr = proc_addr(IDLE);
|
||||||
if (priv(proc_ptr)->s_flags & BILLABLE)
|
if (priv(proc_ptr)->s_flags & BILLABLE)
|
||||||
bill_ptr = proc_ptr;
|
bill_ptr = proc_ptr;
|
||||||
halt_cpu();
|
idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
check_misc_flags:
|
check_misc_flags:
|
||||||
|
|
|
@ -19,6 +19,7 @@ _PROTOTYPE( void reset_timer, (struct timer *tp) );
|
||||||
_PROTOTYPE( void ser_dump_proc, (void) );
|
_PROTOTYPE( void ser_dump_proc, (void) );
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
|
_PROTOTYPE( void main, (void) );
|
||||||
_PROTOTYPE( void prepare_shutdown, (int how) );
|
_PROTOTYPE( void prepare_shutdown, (int how) );
|
||||||
_PROTOTYPE( void minix_shutdown, (struct timer *tp) );
|
_PROTOTYPE( void minix_shutdown, (struct timer *tp) );
|
||||||
|
|
||||||
|
@ -102,6 +103,7 @@ _PROTOTYPE( void stop_profile_clock, (void) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* functions defined in architecture-dependent files. */
|
/* functions defined in architecture-dependent files. */
|
||||||
|
_PROTOTYPE( void prot_init, (void) );
|
||||||
_PROTOTYPE( phys_bytes phys_copy, (phys_bytes source, phys_bytes dest,
|
_PROTOTYPE( phys_bytes phys_copy, (phys_bytes source, phys_bytes dest,
|
||||||
phys_bytes count) );
|
phys_bytes count) );
|
||||||
_PROTOTYPE( void phys_copy_fault, (void));
|
_PROTOTYPE( void phys_copy_fault, (void));
|
||||||
|
|
|
@ -141,18 +141,26 @@ register message *m_ptr; /* pointer to request message */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case GET_IRQACTIDS: {
|
case GET_IRQACTIDS: {
|
||||||
length = sizeof(irq_actids);
|
length = sizeof(irq_actids);
|
||||||
src_vir = (vir_bytes) irq_actids;
|
src_vir = (vir_bytes) irq_actids;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GET_PRIVID: {
|
||||||
case GET_PRIVID:
|
|
||||||
if (!isokendpt(m_ptr->I_VAL_LEN2_E, &proc_nr))
|
if (!isokendpt(m_ptr->I_VAL_LEN2_E, &proc_nr))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
return proc_addr(proc_nr)->p_priv->s_id;
|
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:
|
default:
|
||||||
kprintf("do_getinfo: invalid request %d\n", m_ptr->I_REQUEST);
|
kprintf("do_getinfo: invalid request %d\n", m_ptr->I_REQUEST);
|
||||||
return(EINVAL);
|
return(EINVAL);
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <minix/sysutil.h>
|
|
||||||
#include <minix/sys_config.h>
|
#include <minix/sys_config.h>
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -10,6 +10,7 @@ libsys_FILES=" \
|
||||||
kputc.c \
|
kputc.c \
|
||||||
tickdelay.c \
|
tickdelay.c \
|
||||||
get_randomness.c \
|
get_randomness.c \
|
||||||
|
getidle.c \
|
||||||
getuptime.c \
|
getuptime.c \
|
||||||
getuptime2.c \
|
getuptime2.c \
|
||||||
env_get_prm.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 <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <minix/profile.h>
|
#include <minix/profile.h>
|
||||||
#include <minix/syslib.h>
|
#include <minix/sysutil.h>
|
||||||
#include <minix/u64.h>
|
#include <minix/u64.h>
|
||||||
|
|
||||||
PRIVATE char cpath[CPROF_CPATH_MAX_LEN]; /* current call path string */
|
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;
|
if (cprof_locked) return; else cprof_locked = 1;
|
||||||
|
|
||||||
/* Read CPU cycle count into local variable. */
|
/* Read CPU cycle count into local variable. */
|
||||||
read_tsc(&start.hi, &start.lo);
|
read_tsc_64(&start);
|
||||||
|
|
||||||
/* Run init code once after system boot. */
|
/* Run init code once after system boot. */
|
||||||
if (init == 0) {
|
if (init == 0) {
|
||||||
|
@ -105,8 +105,7 @@ char *name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save initial cycle count on stack. */
|
/* Save initial cycle count on stack. */
|
||||||
cprof_stk[cprof_stk_top].start_1.hi = start.hi;
|
cprof_stk[cprof_stk_top].start_1 = start;
|
||||||
cprof_stk[cprof_stk_top].start_1.lo = start.lo;
|
|
||||||
|
|
||||||
/* Check available call path len. */
|
/* Check available call path len. */
|
||||||
if (cpath_len + strlen(name) + 1 > CPROF_CPATH_MAX_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;
|
cprof_stk[cprof_stk_top].slot = cprof_slot;
|
||||||
|
|
||||||
/* Again save CPU cycle count on stack. */
|
/* Again save CPU cycle count on stack. */
|
||||||
read_tsc(&cprof_stk[cprof_stk_top].start_2.hi,
|
read_tsc_64(&cprof_stk[cprof_stk_top].start_2);
|
||||||
&cprof_stk[cprof_stk_top].start_2.lo);
|
|
||||||
cprof_locked = 0;
|
cprof_locked = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +199,7 @@ char *name;
|
||||||
sub64(spent, cprof_stk[cprof_stk_top].spent_deeper));
|
sub64(spent, cprof_stk[cprof_stk_top].spent_deeper));
|
||||||
|
|
||||||
/* Clear spent_deeper for call level we're leaving. */
|
/* 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 = cvu64(0);
|
||||||
cprof_stk[cprof_stk_top].spent_deeper.hi = 0;
|
|
||||||
|
|
||||||
/* Adjust call path string and stack. */
|
/* Adjust call path string and stack. */
|
||||||
cpath_len = cprof_stk[cprof_stk_top].cpath_len;
|
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++) {
|
for (i=0; i<CPROF_STACK_SIZE; i++) {
|
||||||
cprof_stk[i].cpath_len = 0;
|
cprof_stk[i].cpath_len = 0;
|
||||||
cprof_stk[i].slot = 0;
|
cprof_stk[i].slot = 0;
|
||||||
cprof_stk[i].start_1.lo = 0;
|
cprof_stk[i].start_1 = cvu64(0);
|
||||||
cprof_stk[i].start_1.hi = 0;
|
cprof_stk[i].start_2 = cvu64(0);
|
||||||
cprof_stk[i].start_2.lo = 0;
|
cprof_stk[i].spent_deeper = cvu64(0);
|
||||||
cprof_stk[i].start_2.hi = 0;
|
|
||||||
cprof_stk[i].spent_deeper.lo = 0;
|
|
||||||
cprof_stk[i].spent_deeper.hi = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,11 +274,13 @@ PUBLIC int do_getsysinfo_up()
|
||||||
vir_bytes src_addr, dst_addr;
|
vir_bytes src_addr, dst_addr;
|
||||||
struct loadinfo loadinfo;
|
struct loadinfo loadinfo;
|
||||||
size_t len, real_len;
|
size_t len, real_len;
|
||||||
|
u64_t idle_tsc;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
switch(m_in.SIU_WHAT) {
|
switch(m_in.SIU_WHAT) {
|
||||||
case SIU_LOADINFO: /* loadinfo is obtained via PM */
|
case SIU_LOADINFO: /* loadinfo is obtained via PM */
|
||||||
sys_getloadinfo(&loadinfo);
|
if ((s = sys_getloadinfo(&loadinfo)) != OK)
|
||||||
|
return s;
|
||||||
src_addr = (vir_bytes) &loadinfo;
|
src_addr = (vir_bytes) &loadinfo;
|
||||||
real_len = sizeof(struct loadinfo);
|
real_len = sizeof(struct loadinfo);
|
||||||
break;
|
break;
|
||||||
|
@ -286,6 +288,12 @@ PUBLIC int do_getsysinfo_up()
|
||||||
src_addr = (vir_bytes) &system_hz;
|
src_addr = (vir_bytes) &system_hz;
|
||||||
real_len = sizeof(system_hz);
|
real_len = sizeof(system_hz);
|
||||||
break;
|
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:
|
default:
|
||||||
return(EINVAL);
|
return(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue