int0.c 2.3 KB
#include <limits.h>
#include <os.h>
#include <os_internal.h>
#include <rmon.h>
#include <R4300.h>
#include "perf.h"

/*
 * int0
 *
 *  Measures: 
 *	Interrupt latency, or more specifically:
 *
 *	The time from when an interrupt condition becomes true and a
 *	thread blocking on the interrupt message wakes up reads the message.
 *
 */

#define	NUM_ITER	1000

static void slave(void *);

static OSMesgQueue	sw1MesgQueue;
static OSMesg		sw1MesgBuf[1];

static OSMesgQueue	slaveMesgQueue;
static OSMesg		slaveMesgBuf[1];

static OSThread		slaveThread;
static char		slaveStack[STACKSIZE];

void
int0(void)
{
    OSIntMask savedMask;
    unsigned int before, after, elapsed;
    unsigned high, low, average;
    register int i;

    high = 0;
    low = UINT_MAX;
    average = 0;

    savedMask = osSetIntMask(OS_IM_SW1);

    osCreateMesgQueue(&sw1MesgQueue, sw1MesgBuf, 1);
    osSetEventMesg(OS_EVENT_SW1, &sw1MesgQueue, (OSMesg)NULL);

    osCreateMesgQueue(&slaveMesgQueue, sw1MesgBuf, 1);

    osCreateThread(&slaveThread, 101, slave, (void *)0,
		   slaveStack+STACKSIZE, 20);
    osStartThread(&slaveThread);

    /*
     * The master will snapshot the time and then trigger a SW1 interrupt,
     * which will cause the slave to wake up.  The slave will then immediately
     * snapshot the time and return it to the master to do a difference.
     */
     
    for (i = 0; i < NUM_ITER; i++) {
	before = osGetCount();
	__osSetCause(CAUSE_SW1);
	(void)osRecvMesg(&slaveMesgQueue, (OSMesg *)&after, OS_MESG_BLOCK);
	elapsed = after - before;
	if (elapsed > high)
		high = elapsed;
	if (elapsed < low)
		low = elapsed;
	average += elapsed;
    }

    average = average / NUM_ITER;

    rmonPrintf("interrupt latency (cycles) average %d high %d low %d\n",
	average, high, low);
    rmonPrintf("interrupt latency (ns)     average %lld high %lld low %lld\n",
	OS_CYCLES_TO_NSEC(average),
	OS_CYCLES_TO_NSEC(high),
	OS_CYCLES_TO_NSEC(low));

    (void)osSetIntMask(savedMask);
}

static void
slave(void *arg)
{
    OSMesg mesg;
    register int i;

    /*
     * Block for the SW1 interrupt.  When it wakes up, snapshot the
     * time and send it to the master.
     */
    for (i = 0; i < NUM_ITER; i++) {
	(void)osRecvMesg(&sw1MesgQueue, &mesg, OS_MESG_BLOCK);
	mesg = (OSMesg)osGetCount();
	(void)osSendMesg(&slaveMesgQueue, mesg, OS_MESG_BLOCK);
    }
}