Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 May 1996 15:33:24 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        p.richards@elsevier.co.uk, rgrimes@gndrsh.aac.dev.com
Cc:        FreeBSD-current@freebsd.org
Subject:   Re: ahc driver no longer sees one of my disks
Message-ID:  <199605080533.PAA25448@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>One of the biggest problems with high speed systems is that DELAY(n) for
>n < 20 is _ASSUMED_ to be the call/return overhead.  This is horribly
>wrong for loops that call DELAY(n) reapeadly due to cashing, branch prediction
>and a whole lot of other things.  

Expecting DELAY(small) to be accurate is horribly wrong anyway.

>See the source code in clock.c:
>        /*      
>         * Read the counter first, so that the rest of the setup overhead is
>         * counted.  Guess the initial overhead is 20 usec (on most systems it
>         * takes about 1.5 usec for each of the i/o's in getit().  The loop
>         * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
>         * multiplications and divisions to scale the count take a while).
>         */     
>        prev_tick = getit();
>        n -= 20;
>        /*      
>...

Perhaps the right thing to do is to remove the 20 usec hack and document
that DELAY(n) is guaranteed to delay for _at least_ n usec and that _no_
maximum is guaranteed.  DELAY(n) may sometimes take (n + 100000) usec if
it is interrupted and it may usually take (n + 20) usec on slow machines.
Generic driver must be programmed to work on both slow and fast machines.

However, this would be less flexible.  It is easy to add 20 to get the same
result.  Perhaps 20 should be replaced by DELAYZERO and added to hundreds,
if not thousands of DELAY() calls :-).

I have problems with lost keyboard interrupts causing keyboard hangs and
and removed the 20 usec hack for a while.  This seemed to make the problem
worse :-).

>On a P133 this looks to be closer to 4uS, on a 166 it is down to 2 or 3uS,

Probably not that small.  There's always a getit() call, and on my ASUS
P55TP4XE P133 this does 3 slow i/o's:

0x43 (timer mode)      (write)  1180 ns
0x40 (timer counter 0) (read)    703 ns
0x40 (timer counter 0) (read)    703 ns
                                -------
                                2586 ns

>and I have no idea what it is on a P6.  This value should probably be
>calibrated, perhaps bruces recent changes could be enhanced to calibrate
>this as well...

Here's the lkm syscall template hacked to calibrate DELAY(1).  It takes
about 3780 ns on the P55TP4XE.  DELAY(100) takes about 83000 nsec.  20
is about 17 too large.

---
BINDIR=	/tmp
SRCS=	mycall.c
KMOD=	newsyscall_mod
NOMAN=	none

CLEANFILES+= ${KMOD}

.include <bsd.kmod.mk>
---
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/sysent.h>
#include <sys/lkm.h>

#include <machine/clock.h>

static int mycall(struct proc *p, void *uap, int *retval);

static struct sysent newent = { 0, mycall, };
MOD_SYSCALL("newsyscall_mod", -1, &newent);

extern int newsyscall_mod(struct lkm_table *lkmtp, int cmd, int ver);
int newsyscall_mod(struct lkm_table *lkmtp, int cmd, int ver)
{
    DISPATCH(lkmtp, cmd, ver, lkm_nullcmd, lkm_nullcmd, lkm_nullcmd)
}

static int mycall(struct proc *p, void *uap, int *retval)
{
    int i;
    struct timeval f, s;

    microtime(&s);
    for (i = 0; i < 1000000; ++i)
	DELAY(1);
    microtime(&f);
    *retval = 1000000 * (f.tv_sec - s.tv_sec) + f.tv_usec - s.tv_usec;
    return 0;
}
---

It has also been reported that DELAY() has a long term error of 10% on
some systems.  I haven't seen any evidence or explanations for this.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199605080533.PAA25448>