when lock timing is enabled in minix/config.h.
Added phys_zero() routine to klib386.s that zeroes a range of memory, and
added corresponding system call.
*/
#include "kernel.h"
+#include "debug.h"
#include "proc.h"
#include <signal.h>
#include <minix/com.h>
receive(ANY, &m);
/* Transfer ticks seen by the low level handler. */
- lock();
+ lock(8, "realtime");
realtime += pending_ticks;
pending_ticks = 0;
- unlock();
+ unlock(8);
/* Handle the request. */
switch (m.m_type) {
*/
clock_t uptime;
- lock();
+ lock(9, "get_uptime");
uptime = realtime + pending_ticks;
- unlock();
+ unlock(9);
return(uptime);
}
*/
unsigned count;
- lock();
+ lock(10, "read_clock");
outb(TIMER_MODE, LATCH_COUNT);
count = inb(TIMER0);
count |= (inb(TIMER0) << 8);
- unlock();
+ unlock(10);
return count;
}
#include <ibm/interrupt.h> /* interrupt numbers and hardware vectors */
#include <ibm/ports.h> /* port addresses and magic numbers */
#include <ibm/bios.h> /* BIOS addresses, sizes and magic numbers */
+#include <minix/config.h>
/* To translate an address in kernel space to a physical address. This is
* the same as umap_local(proc_ptr, D, vir, sizeof(*vir)), but less costly.
#define IF_MASK 0x00000200
#define IOPL_MASK 0x003000
+#if ENABLE_LOCK_TIMING
+#define locktimestart(c, v) timer_start(c, v)
+#define locktimeend(c) timer_end(c)
+#else
+#define locktimestart(c, v)
+#define locktimeend(c)
+#endif
+
/* Disable/Enable hardware interrupts. */
-#define lock() intr_disable()
-#define unlock() intr_enable()
+#define lock(c, v) do { intr_disable(); locktimestart(c, v); } while(0);
+#define unlock(c) do { locktimeend(c); intr_enable(); } while(0);
/* Sizes of memory tables. The boot monitor distinguishes three memory areas,
* namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed
/* M68000 specific constants go here. */
#endif /* (CHIP == M68000) */
+#if ENABLE_INT_TIMING
+#define INT_TIMING_BITS 12
+#define INT_TIMING_ELEMENTS (1L << 12)
+#endif
--- /dev/null
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <minix/config.h>
+
+#if ENABLE_LOCK_TIMING
+_PROTOTYPE( void timer_start, (int cat, char *name) );
+_PROTOTYPE( void timer_end, (int cat) );
+#endif
+
+#if ENABLE_K_DEBUGGING /* debugging */
+_PROTOTYPE( void check_runqueues, (char *when) );
+#endif
+
+#endif /* DEBUG_H */
#include "kernel.h"
#include <signal.h>
#include "proc.h"
+#include "debug.h"
/*==========================================================================*
* exception *
}
if (k_reenter == 0 && ! istaskp(saved_proc)) {
- unlock(); /* this is protected like sys_call() */
+ unlock(7); /* this is protected like sys_call() */
cause_sig(proc_nr(saved_proc), ep->signum);
return;
}
#define EXTERN
#endif
+#include "const.h"
+#include <minix/config.h>
+
/* MINIX' shutdown sequence uses watchdog timers to stop system services. The
* flag shutting_down must be initialized to FALSE. We rely on the compiler's
* default initialization (0) of global variables here.
EXTERN int irq_actids[NR_IRQ_VECTORS]; /* IRQ ID bits active */
EXTERN int irq_use; /* bit map of all in-use irq's */
+/* lock() timing data. */
+#if ENABLE_LOCK_TIMING
+EXTERN struct lock_timedata timingdata[TIMING_CATEGORIES];
+#endif
+
/* Miscellaneous. */
EXTERN reg_t mon_ss, mon_sp; /* monitor stack */
EXTERN int mon_return; /* true if return to the monitor possible */
/* M68000 specific variables go here. */
#endif
-
#include "kernel.h"
#include "proc.h"
+#include "debug.h"
#include <minix/com.h>
#define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */
*/
int i;
- lock();
+ lock(6, "intr_init");
if (machine.protected) {
/* The AT and newer PS/2 have two interrupt controllers, one master,
* one slaved at IRQ 2. (We don't have to deal with the PC that
.define _enable_irq ! enable an irq at the 8259 controller
.define _disable_irq ! disable an irq
.define _phys_copy ! copy data from anywhere to anywhere in memory
+.define _phys_zero ! zero data anywhere in memory
.define _mem_rdw ! copy one word from [segment:offset]
.define _reset ! reset the system
.define _idle_task ! task executed when there is no work
pop esi
ret
+!*===========================================================================*
+!* phys_zero *
+!*===========================================================================*
+! PUBLIC void phys_zero(phys_bytes source, phys_bytes bytecount);
+! Zero a block of physical memory.
+
+ .align 16
+
+_phys_zero:
+ push ebp
+ mov ebp, esp
+ push esi
+ push ebx
+ push ds
+ mov esi, 8(ebp)
+ mov eax, 12(ebp)
+ mov ebx, FLAT_DS_SELECTOR
+ mov ds, bx
+ shr eax, 2
+zero_start:
+ mov (esi), 0
+ add esi, 4
+ dec eax
+ jnz zero_start
+zero_done:
+ pop ds
+ pop ebx
+ pop esi
+ pop ebp
+ ret
!*===========================================================================*
!* mem_rdw *
!*===========================================================================*
!* read_tsc *
!*===========================================================================*
-! PUBLIC void read_tsc(unsigned long *low, unsigned long *high);
+! PUBLIC void read_tsc(unsigned long *high, unsigned long *low);
! Read the cycle counter of the CPU. Pentium and up.
.align 16
_read_tsc:
#include <minix/callnr.h>
#include <minix/com.h>
#include "proc.h"
+#include "debug.h"
#include "ipc.h"
#include "sendmask.h"
int result;
struct proc *caller_ptr;
- lock();
+ lock(0, "notify");
kinfo.lock_notify ++;
caller_ptr = (k_reenter >= 0) ? proc_addr(HARDWARE) : proc_ptr;
result = mini_notify(caller_ptr, dst, m_ptr);
- unlock();
+ unlock(0);
return(result);
}
PUBLIC void lock_pick_proc()
{
/* Safe gateway to pick_proc() for tasks. */
- lock();
+ lock(1, "pick_proc");
pick_proc();
- unlock();
+ unlock(1);
}
{
/* Safe gateway to mini_send() for tasks. */
int result;
- lock();
+ lock(2, "send");
kinfo.lock_send ++;
result = mini_send(proc_ptr, dst, m_ptr, NON_BLOCKING);
- unlock();
+ unlock(2);
return(result);
}
struct proc *rp; /* this process is now runnable */
{
/* Safe gateway to ready() for tasks. */
- lock();
+ lock(3, "ready");
ready(rp);
- unlock();
+ unlock(3);
}
/*==========================================================================*
struct proc *rp; /* this process is no longer runnable */
{
/* Safe gateway to unready() for tasks. */
- lock();
+ lock(4, "unready");
unready(rp);
- unlock();
+ unlock(4);
}
/*==========================================================================*
int queue;
{
/* Safe gateway to sched() for tasks. */
- lock();
+ lock(5, "sched");
sched(queue);
- unlock();
+ unlock(5);
}
_PROTOTYPE( u16_t mem_rdw, (U16_t segm, vir_bytes offset) );
_PROTOTYPE( void phys_copy, (phys_bytes source, phys_bytes dest,
phys_bytes count) );
+_PROTOTYPE( void phys_zero, (phys_bytes source, phys_bytes count) );
_PROTOTYPE( void phys_insb, (U16_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count));
_PROTOTYPE( void reset, (void) );
_PROTOTYPE( void level0, (void (*func)(void)) );
_PROTOTYPE( void monitor, (void) );
-_PROTOTYPE( void read_tsc, (unsigned long *low, unsigned long *high) );
+_PROTOTYPE( void read_tsc, (unsigned long *high, unsigned long *low) );
/* mpx*.s */
_PROTOTYPE( void idle_task, (void) );
map(SYS_UMAP, do_umap); /* map virtual to physical address */
map(SYS_VIRCOPY, do_vircopy); /* use pure virtual addressing */
map(SYS_PHYSCOPY, do_physcopy); /* use physical addressing */
+ map(SYS_PHYSZERO, do_physzero); /* zero physical memory region */
map(SYS_VIRVCOPY, do_virvcopy); /* vector with copy requests */
map(SYS_PHYSVCOPY, do_physvcopy); /* vector with copy requests */
/* Common includes for the system library. */
#include <minix/com.h>
+#include <minix/config.h>
#include "proc.h"
#include "assert.h"
#define do_trace do_unused
#endif
-#if ENABLE_K_DEBUGGING /* debugging */
-_PROTOTYPE( void check_runqueues, (char *when) );
-#endif
-
_PROTOTYPE( int do_vircopy, (message *m_ptr) );
_PROTOTYPE( int do_physcopy, (message *m_ptr) );
+_PROTOTYPE( int do_physzero, (message *m_ptr) );
_PROTOTYPE( int do_biosio, (message *m_ptr) );
#endif /* SYSTEM_H */
#include "../kernel.h"
#include "../system.h"
+#include "../debug.h"
#include <signal.h>
/*===========================================================================*
proc_nr = (m_ptr->T_PROC_NR == SELF) ? m_ptr->m_source : m_ptr->T_PROC_NR;
if (isokprocn(proc_nr)) {
rp = proc_addr(m_ptr->T_PROC_NR);
-
- lock(); /* halt the volatile time counters in rp */
+ lock(11, "do_times"); /* halt the volatile time counters in rp */
m_ptr->T_USER_TIME = rp->p_user_time;
m_ptr->T_SYSTEM_TIME = rp->p_sys_time;
- unlock();
+ unlock(11);
}
m_ptr->T_BOOT_TICKS = get_uptime();
return(OK);
/* The system call implemented in this file:
- * m_type: SYS_VIRCOPY, SYS_PHYSCOPY
+ * m_type: SYS_VIRCOPY, SYS_PHYSCOPY, SYS_PHYSZERO
*
* The parameters for this system call are:
* m5_c1: CP_SRC_SPACE
return(OK);
}
+/*===========================================================================*
+ * do_physzero *
+ *===========================================================================*/
+PUBLIC int do_physzero(m_ptr)
+register message *m_ptr;
+{
+/* Handle sys_physzero(). */
+ phys_zero((phys_bytes) m_ptr->PZ_MEM_PTR, (phys_bytes) m_ptr->PZ_COUNT);
+ return(OK);
+}
+
/* The system call implemented in this file:
* m_type: SYS_UMAP
#include "../kernel.h"
#include "../system.h"
#include "../proc.h"
+#include "../glo.h"
+#include <limits.h>
+
+#if ENABLE_LOCK_TIMING
+
+static unsigned long starttimes[TIMING_CATEGORIES][2];
+
+#define HIGHCOUNT 0
+#define LOWCOUNT 1
+
+void timer_start(int cat, char *name)
+{
+ static int init = 0;
+ unsigned long h, l;
+ int i;
+
+ if(cat < 0 || cat >= TIMING_CATEGORIES) return;
+
+ for(i = 0; i < sizeof(timingdata[0].names) && *name; i++)
+ timingdata[cat].names[i] = *name++;
+ timingdata[0].names[sizeof(timingdata[0].names)-1] = '\0';
+
+ if(starttimes[cat][HIGHCOUNT]) { return; }
+
+ if(!init) {
+ int t, f;
+ init = 1;
+ for(t = 0; t < TIMING_CATEGORIES; t++) {
+ timingdata[t].lock_timings_range[0] = 0;
+ timingdata[t].resets = timingdata[t].misses =
+ timingdata[t].measurements = 0;
+ }
+ }
+
+ read_tsc(&starttimes[cat][HIGHCOUNT], &starttimes[cat][LOWCOUNT]);
+
+ return;
+}
+
+void timer_end(int cat)
+{
+ unsigned long h, l, d = 0, binsize;
+ int bin;
+
+ read_tsc(&h, &l);
+ if(cat < 0 || cat >= TIMING_CATEGORIES) return;
+ if(!starttimes[cat][HIGHCOUNT]) {
+ timingdata[cat].misses++;
+ return;
+ }
+ if(starttimes[cat][HIGHCOUNT] == h) {
+ d = (l - starttimes[cat][1]);
+ } else if(starttimes[cat][HIGHCOUNT] == h-1 &&
+ starttimes[cat][LOWCOUNT] > l) {
+ d = ((ULONG_MAX - starttimes[cat][LOWCOUNT]) + l);
+ } else {
+ timingdata[cat].misses++;
+ return;
+ }
+ starttimes[cat][HIGHCOUNT] = 0;
+ if(!timingdata[cat].lock_timings_range[0] ||
+ d < timingdata[cat].lock_timings_range[0] ||
+ d > timingdata[cat].lock_timings_range[1]) {
+ int t;
+ if(!timingdata[cat].lock_timings_range[0] ||
+ d < timingdata[cat].lock_timings_range[0])
+ timingdata[cat].lock_timings_range[0] = d;
+ if(!timingdata[cat].lock_timings_range[1] ||
+ d > timingdata[cat].lock_timings_range[1])
+ timingdata[cat].lock_timings_range[1] = d;
+ for(t = 0; t < TIMING_POINTS; t++)
+ timingdata[cat].lock_timings[t] = 0;
+ timingdata[cat].binsize =
+ (timingdata[cat].lock_timings_range[1] -
+ timingdata[cat].lock_timings_range[0])/(TIMING_POINTS+1);
+ if(timingdata[cat].binsize < 1)
+ timingdata[cat].binsize = 1;
+ timingdata[cat].resets++;
+ }
+ bin = (d-timingdata[cat].lock_timings_range[0]) /
+ timingdata[cat].binsize;
+ if(bin < 0 || bin >= TIMING_POINTS) {
+ int t;
+ /* this indicates a bug, but isn't really serious */
+ for(t = 0; t < TIMING_POINTS; t++)
+ timingdata[cat].lock_timings[t] = 0;
+ timingdata[cat].misses++;
+ } else {
+ timingdata[cat].lock_timings[bin]++;
+ timingdata[cat].measurements++;
+ }
+
+ return;
+}
+
+#endif
#if ENABLE_K_DEBUGGING /* only include code if enabled */
#include "../kernel.h"
#include "../system.h"
+#include "../debug.h"
#include <minix/devio.h>
/*===========================================================================*
* batch from being interrupted. It may be cleaner to do this just around
* the for loops, but this results in rather lenghty code.
*/
- lock();
+ lock(13, "do_vdevio");
switch (m_ptr->DIO_TYPE) {
case DIO_BYTE: /* byte values */
pvb_pairs = (pvb_pair_t *) vdevio_pv_buf;
outl(pvb_pairs[i].port, pvl_pairs[i].value);
}
}
- unlock();
+ unlock(13);
/* Almost done, copy back results for input requests. */
if (DIO_INPUT == m_ptr->REQUEST)
#include "../kernel.h"
#include "../system.h"
#include <unistd.h>
+#include <minix/config.h>
INIT_ASSERT
src_phys = vir2phys(&kmess);
break;
}
+#if ENABLE_LOCK_TIMING
+ case GET_LOCKTIMING: {
+ length = sizeof(timingdata);
+ src_phys = vir2phys(timingdata);
+ break;
+ }
+#endif
default:
return(EINVAL);
}
#if (CHIP == INTEL)
#include "../protect.h"
#endif
+#include "../debug.h"
INIT_ASSERT
if (! isokprocn(exit_proc_nr)) return(EINVAL);
rc = proc_addr(exit_proc_nr);
+#if DEAD_CODE
+ /* If this is a user process and the PM passed in a valid parent process,
+ * accumulate the child times at the parent.
+ */
+ if (isuserp(rc) && isokprocn(m_ptr->PR_PPROC_NR)) {
+ rp = proc_addr(m_ptr->PR_PPROC_NR);
+ lock(15, "do_xit");
+ rp->child_utime += rc->user_time + rc->child_utime;
+ rp->child_stime += rc->sys_time + rc->child_stime;
+ unlock(15);
+ }
+#endif
+
/* Now call the routine to clean up of the process table slot. This cancels
* outstanding timers, possibly removes the process from the message queues,
* and resets important process table fields.