diff --git a/kernel/arch/i386/apic_asm.S b/kernel/arch/i386/apic_asm.S index 28c53b414..4025b56db 100644 --- a/kernel/arch/i386/apic_asm.S +++ b/kernel/arch/i386/apic_asm.S @@ -36,12 +36,16 @@ TEST_INT_IN_KERNEL(4, 0f) ;\ \ SAVE_PROCESS_CTX(0) ;\ + push %ebp ;\ + call cycles_accounting_stop ;\ + add $4, %esp ;\ movl $0, %ebp /* for stack trace */ ;\ APIC_IRQ_HANDLER(irq) ;\ jmp restart ;\ \ 0: \ pusha ;\ + call cycles_accounting_stop_idle ;\ APIC_IRQ_HANDLER(irq) ;\ popa ;\ iret ; @@ -142,12 +146,16 @@ apic_hwint15: TEST_INT_IN_KERNEL(4, 0f) ;\ \ SAVE_PROCESS_CTX(0) ;\ + push %ebp ;\ + call cycles_accounting_stop ;\ + add $4, %esp ;\ movl $0, %ebp /* for stack trace */ ;\ LAPIC_INTR_HANDLER(func) ;\ jmp restart ;\ \ 0: \ pusha ;\ + call cycles_accounting_stop_idle ;\ LAPIC_INTR_HANDLER(func) ;\ popa ;\ iret ; diff --git a/kernel/arch/i386/clock.c b/kernel/arch/i386/clock.c index 377312ae7..cbc48d02b 100644 --- a/kernel/arch/i386/clock.c +++ b/kernel/arch/i386/clock.c @@ -7,6 +7,9 @@ #include "../../kernel.h" #include "../../clock.h" +#include "../../proc.h" +#include + #ifdef CONFIG_APIC #include "apic.h" @@ -22,6 +25,9 @@ #define TIMER_FREQ 1193182 /* clock frequency for timer in PC and AT */ #define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/ +/* FIXME make it cpu local! */ +PRIVATE u64_t tsc_ctr_switch; /* when did we switched time accounting */ + PRIVATE irq_hook_t pic_timer_hook; /* interrupt handler hook */ /*===========================================================================* @@ -119,3 +125,22 @@ PUBLIC int arch_register_local_timer_handler(irq_handler_t handler) return 0; } + +PUBLIC void cycles_accounting_init(void) +{ + read_tsc_64(&tsc_ctr_switch); +} + +PUBLIC void cycles_accounting_stop(struct proc * p) +{ + u64_t tsc; + + read_tsc_64(&tsc); + p->p_cycles = add64(p->p_cycles, sub64(tsc, tsc_ctr_switch)); + tsc_ctr_switch = tsc; +} + +PUBLIC void cycles_accounting_stop_idle(void) +{ + cycles_accounting_stop(proc_addr(IDLE)); +} diff --git a/kernel/arch/i386/mpx386.S b/kernel/arch/i386/mpx386.S index ed3a7c2b8..539948d0b 100644 --- a/kernel/arch/i386/mpx386.S +++ b/kernel/arch/i386/mpx386.S @@ -253,6 +253,9 @@ csinit: TEST_INT_IN_KERNEL(4, 0f) ;\ \ SAVE_PROCESS_CTX(0) ;\ + push %ebp ;\ + call cycles_accounting_stop ;\ + add $4, %esp ;\ movl $0, %ebp /* for stack trace */ ;\ PIC_IRQ_HANDLER(irq) ;\ movb $END_OF_INT, %al ;\ @@ -261,6 +264,7 @@ csinit: \ 0: \ pusha ;\ + call cycles_accounting_stop_idle ;\ PIC_IRQ_HANDLER(irq) ;\ movb $END_OF_INT, %al ;\ outb $INT_CTL /* reenable interrupts in master pic */ ;\ @@ -316,6 +320,9 @@ hwint07: TEST_INT_IN_KERNEL(4, 0f) ;\ \ SAVE_PROCESS_CTX(0) ;\ + push %ebp ;\ + call cycles_accounting_stop ;\ + add $4, %esp ;\ movl $0, %ebp /* for stack trace */ ;\ PIC_IRQ_HANDLER(irq) ;\ movb $END_OF_INT, %al ;\ @@ -325,6 +332,7 @@ hwint07: \ 0: \ pusha ;\ + call cycles_accounting_stop_idle ;\ PIC_IRQ_HANDLER(irq) ;\ movb $END_OF_INT, %al ;\ outb $INT_CTL /* reenable interrupts in master pic */ ;\ @@ -395,6 +403,11 @@ ipc_entry: push %eax push %ecx + /* stop user process cycles */ + push %ebp + call cycles_accounting_stop + add $4, %esp + /* for stack trace */ movl $0, %ebp @@ -420,9 +433,6 @@ kernel_call_entry: /* save the pointer to the current process */ push %ebp - /* for stack trace */ - movl $0, %ebp - /* * pass the syscall arguments from userspace to the handler. * SAVE_PROCESS_CTX() does not clobber these registers, they are still @@ -430,6 +440,14 @@ kernel_call_entry: */ push %eax + /* stop user process cycles */ + push %ebp + call cycles_accounting_stop + add $4, %esp + + /* for stack trace */ + movl $0, %ebp + call kernel_call /* restore the current process pointer and save the return value */ @@ -458,6 +476,11 @@ exception_entry_from_user: SAVE_PROCESS_CTX(8) + /* stop user process cycles */ + push %ebp + call cycles_accounting_stop + add $4, %esp + /* for stack trace clear %ebp */ movl $0, %ebp @@ -604,6 +627,10 @@ copr_not_available: jnz 0f /* jump if FPU is already initialized */ orw $MF_FPU_INITIALIZED, (%ebx) fninit + /* stop user process cycles */ + push %ebp + call cycles_accounting_stop + add $4, %esp jmp copr_return 0: /* load FPU context for current process */ mov %ss:FP_SAVE_AREA_P(%ebp), %eax diff --git a/kernel/arch/i386/system.c b/kernel/arch/i386/system.c index ee1979379..d54dc63a4 100644 --- a/kernel/arch/i386/system.c +++ b/kernel/arch/i386/system.c @@ -325,10 +325,10 @@ PRIVATE void printslot(struct proc *pp, int level) COL - kprintf("%d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s misc %s", + kprintf("%d: %s %d prio %d/%d time %d/%d cycles 0x%x%08x cr3 0x%lx rts %s misc %s", proc_nr(pp), pp->p_name, pp->p_endpoint, pp->p_priority, pp->p_max_priority, pp->p_user_time, - pp->p_sys_time, pp->p_seg.p_cr3, + pp->p_sys_time, pp->p_cycles.hi, pp->p_cycles.lo, pp->p_seg.p_cr3, rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags)); if(pp->p_rts_flags & RTS_SENDING) { diff --git a/kernel/clock.c b/kernel/clock.c index 7ffe414de..fd57a3e2f 100644 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -78,8 +78,6 @@ PUBLIC int bsp_timer_int_handler(void) { unsigned ticks; - IDLE_STOP; - if(minix_panicing) return 0; @@ -192,8 +190,6 @@ PUBLIC int ap_timer_int_handler(void) int expired = 0; struct proc * p, * billp; - IDLE_STOP; - #ifdef CONFIG_WATCHDOG /* * we need to know whether local timer ticks are happening or whether diff --git a/kernel/const.h b/kernel/const.h index d650bb88e..3f40ef9bb 100644 --- a/kernel/const.h +++ b/kernel/const.h @@ -25,12 +25,6 @@ #define unset_sys_bit(map,bit) \ ( MAP_CHUNK(map.chunk,bit) &= ~(1 << CHUNK_OFFSET(bit) ) -#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 */ diff --git a/kernel/glo.h b/kernel/glo.h index 3e48708aa..85e0b0321 100644 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -58,12 +58,6 @@ EXTERN int verboseflags; 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 - EXTERN unsigned cpu_hz[CONFIG_MAX_CPUS]; #define cpu_set_freq(cpu, freq) do {cpu_hz[cpu] = freq;} while (0) diff --git a/kernel/interrupt.c b/kernel/interrupt.c index ca4311f46..33380b5ef 100644 --- a/kernel/interrupt.c +++ b/kernel/interrupt.c @@ -111,8 +111,6 @@ PUBLIC void irq_handle(int irq) { 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]; diff --git a/kernel/kernel.h b/kernel/kernel.h index 97809c1d2..b1ccf6097 100644 --- a/kernel/kernel.h +++ b/kernel/kernel.h @@ -13,8 +13,6 @@ /* We only support 1 cpu now */ #define CONFIG_MAX_CPUS 1 #define cpuid 0 -/* 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. diff --git a/kernel/main.c b/kernel/main.c index d1f82a311..ddd8c284c 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -218,10 +218,6 @@ PUBLIC void main() #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; @@ -255,6 +251,8 @@ PUBLIC void main() FIXME("PROC check enabled"); #endif + cycles_accounting_init(); + restart(); NOT_REACHABLE; } diff --git a/kernel/proc.c b/kernel/proc.c index 5e957767f..57022e81a 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -119,30 +119,21 @@ PRIVATE int QueueMess(endpoint_t ep, vir_bytes msg_lin, struct proc *dst) /*===========================================================================* * idle * *===========================================================================*/ -PRIVATE void idle() +PRIVATE void idle(void) { /* 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 + /* start accounting for the idle time */ + cycles_accounting_stop(proc_addr(KERNEL)); 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 + /* + * end of accounting for the idle task does not happen here, the kernel + * is handling stuff for quite a while before it gets back here! + */ } /*===========================================================================* @@ -274,6 +265,7 @@ check_misc_flags: #endif proc_ptr = arch_finish_schedcheck(); + cycles_accounting_stop(proc_addr(KERNEL)); NOREC_RETURN(schedch, proc_ptr); } diff --git a/kernel/proc.h b/kernel/proc.h index 467bfbe8b..a144a4cb0 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -40,6 +40,8 @@ struct proc { clock_t p_virt_left; /* number of ticks left on virtual timer */ clock_t p_prof_left; /* number of ticks left on profile timer */ + u64_t p_cycles; /* how many cycles did the process use */ + struct proc *p_nextready; /* pointer to next ready process */ struct proc *p_caller_q; /* head of list of procs wishing to send */ struct proc *p_q_link; /* link to next proc wishing to send */ diff --git a/kernel/proto.h b/kernel/proto.h index 1aafbc76f..1d03c6f26 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -18,6 +18,18 @@ _PROTOTYPE( void set_timer, (struct timer *tp, clock_t t, tmr_func_t f) ); _PROTOTYPE( void reset_timer, (struct timer *tp) ); _PROTOTYPE( void ser_dump_proc, (void) ); +_PROTOTYPE( void cycles_accounting_init, (void) ); +/* + * This functions start and stop accounting for process, kernel or idle cycles. + * It inherently have to account for some kernel cycles for process too, + * therefore it should be called asap after trapping to kernel and as late as + * possible before returning to userspace. These function is architecture + * dependent + */ +_PROTOTYPE( void cycles_accounting_stop, (struct proc * p) ); +/* this is a wrapper to make calling it from assembly easier */ +_PROTOTYPE( void cycles_accounting_stop_idle, (void) ); + /* main.c */ _PROTOTYPE( void main, (void) ); _PROTOTYPE( void prepare_shutdown, (int how) ); diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index 98400404c..4aea7020b 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -152,14 +152,12 @@ PUBLIC int do_getinfo(struct proc * caller, message * m_ptr) break; } case GET_IDLETSC: { -#ifdef CONFIG_IDLE_TSC - length = sizeof(idle_tsc); - src_vir = (vir_bytes) &idle_tsc; + struct proc * idl; + + idl = proc_addr(IDLE); + length = sizeof(idl->p_cycles); + src_vir = (vir_bytes) &idl->p_cycles; break; -#else - kprintf("do_getinfo: kernel not compiled with CONFIG_IDLE_TSC\n"); - return(EINVAL); -#endif } case GET_AOUTHEADER: { int hdrindex, index = m_ptr->I_VAL_LEN2_E;