Return to BSD News archive
Received: by minnie.vk1xwt.ampr.org with NNTP
id AA5939 ; Sat, 02 Jan 93 01:02:59 EST
Path: sserve!manuel.anu.edu.au!munnari.oz.au!uunet!ogicse!pdxgate!jrb@rigel.cs.pdx.edu
From: jrb@rigel.cs.pdx.edu (James Binkley)
Newsgroups: comp.unix.bsd
Subject: bug in setitimer?
Message-ID: <6648@pdxgate.UUCP>
Date: 3 Jan 93 21:23:26 GMT
Article-I.D.: pdxgate.6648
Sender: news@pdxgate.UUCP
Lines: 289
I'm trying to use setitimer with the REAL TIMER (ITIMER_REAL) to
get so many interrupts per second on 386BSD; .e.g,
setitimer(ITIMER_REAL, &ival, NULL);
So far I can't make it work correctly in terms of time. You get
ALARM signals but you seemingly can't get better
than 10 intr/sec. Anybody else have any ideas?
I'll start digging into the kernel but wondered
if anybody else might have encountered this or might
have a logical explanation?
There is sample code at the end and the output
results from 3 runs below. The first on a Sun,
the 2nd two on a 386BSD system. The total elapsed
time should roughly be 5 seconds as it is on the
Sun. The input to clk is in "bpm" or beats per minute
and is translated into hertz and usecs for the setitimer
call. (I'm porting some pc music code to 386bsd and at
least I have a mpu driver working.)
Jim Binkley
jrb@cs.pdx.edu
----------------------------------------------------------
sun run:
bash$ /bin/time clk 48
hertz 19 bpm 48
setclock: START: hertz bpm usecs 19 48 52631
closeClock: interrupts == 95
count 95
5.3 real 4.7 user 0.1 sys
----------------------------------------------------------
386bsd run:
bash% /usr/bin/time clk 48
hertz 19 bpm 48
setclock: START: hertz bpm usecs 19 48 52631
closeClock: interrupts == 97
count 95
9.27 real 8.80 user 0.31 sys
interrupts/time == 10hz roughly
----------------------------------------------------------
bash% /usr/bin/time clk 100
hertz 40 bpm 100
setclock: START: hertz bpm usecs 40 100 25000
closeClock: interrupts == 201
count 200
17.92 real 17.66 user 0.14 sys
interrupts/time == still 10hz roughly
-----------------------------------slice here-----------------
/*
* clk.c
*
* To compile:
* cc -o clk clk.c
* To run:
* /usr/bin/time (or /bin/time) clk 48
* /usr/bin/time (or /bin/time) clk 255
*
* Should take roughly 5 seconds in both cases approximately.
*
* Uses setitimer(2), ITIMER_REAL for interrupt clock.
*/
#ifdef unix
#include <stdio.h>
#include <sys/signal.h>
#include <sys/time.h>
#endif
#define DEBUG
#define TESTMAIN
#define QEVENTS 24 /* no of events per beat */
#define LOWBPM 48 /* lowest acceptable metronome */
#define HIBPM 255 /* highest acceptable metronome */
#define TRUE 1
#define FALSE 0
/* bpm is a module input that is translated into hertz
*/
static unsigned int hertz; /* current hertz */
static int bpm; /* current beats per minute */
/* scheduling flags. Flags shared between interrupt routine
* and scheduler.
*/
int inevents; /* true if sched executing event code */
int timewow; /* true if clock interrupt during event code */
int pendclk; /* True if no clk interrupt yet */
/* error string printed if attempt occurs to set hbeat clk out of range
*/
static char *bpmsyntax = "error: bpm range 48..255";
static int clockon=0;
unsigned long interrupts;
openClock()
{
/* set new clock rate according to bpm. setclock
* fiddles with hw.
*/
setclock(FALSE);
clockon = 1;
interrupts = 0L;
}
closeClock()
{
if (clockon == 0)
return;
setclock(TRUE); /* restore pc time */
clockon = 0;
#ifdef DEBUG
printf("closeClock: interrupts == %ld\n", interrupts);
#endif
}
/* check bpm semantics. must be between LOWBPM..HIBPM
* inclusive.
*/
chkbpm(newbpm)
{
if ( newbpm < LOWBPM ) {
setError(bpmsyntax);
return(0);
}
if ( newbpm > HIBPM ) {
setError(bpmsyntax);
return(0);
}
return(1);
}
setbpm(newbpm)
{
unsigned int timebase;
if (chkbpm(newbpm) == 0)
return;
bpm = newbpm;
hertz = (unsigned int) ((bpm * QEVENTS) / 60);
}
/* outside code can interrogate module to find out what bpm is
*/
getbpm()
{
return(bpm);
}
/* setclock
*
* modifies runtime clock. Only routine in this module that
* actually touches hardware.
*/
#ifdef unix
struct itimerval ival;
struct itimerval oval;
#endif
static
setclock(stopflag)
{
extern unsigned int hertz;
unsigned int count;
unsigned int low;
unsigned int hi;
#ifdef unix
unsigned long t;
if (stopflag == TRUE) {
unixStopClock();
}
else {
unixStopClock();
if ( hertz > 100 )
hertz = 100;
if ( hertz == 0 )
hertz = 1;
t = 1000000L / hertz;
ival.it_interval.tv_sec = 0;
ival.it_interval.tv_usec = t;
ival.it_value.tv_sec = 0;
ival.it_value.tv_usec = t;
#ifdef DEBUG
printf("setclock: START: hertz bpm usecs %d %d %ld\n", hertz, bpm, t);
#endif
unixStartClock();
}
return;
#endif
}
#ifdef unix
extern void tintr();
static
unixStartClock()
{
ival.it_interval.tv_sec = 0;
ival.it_value.tv_sec = 0;
signal(SIGALRM, tintr);
setitimer(ITIMER_REAL, &ival, NULL);
}
unixStopClock()
{
ival.it_value.tv_sec = 0;
ival.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &ival, NULL);
}
void
tintr()
{
pendclk = FALSE; /* interrupt has occured */
/* clock occured during event execution; i.e., timewow
* error has occurred
*/
if ( inevents == TRUE )
timewow = TRUE;
#ifdef DEBUG
interrupts++;
#endif
}
#endif
#ifdef TESTMAIN
/* module clocktimer test routine
*
* syntax:
* clk [bpm]
* bpm can vary from 48.255 (beats per minute)
* Results:
* should take approximately 5 seconds for bpm
* == 48 to 255, just more interrupts per second.
* e.g.,
* /bin/time clk 100
*/
main(argc, argv)
int argc;
char **argv;
{
int count=0;
int lbpm = 120;
int delaycount;
if (argc == 2)
lbpm = atoi(argv[1]);
/* 120 bpm means 2 beats per second.
* 24 "ticks" per quarter note (ppq).
*/
setbpm(lbpm); /* compute hertz */
printf("hertz %d bpm %d\n",hertz, bpm);
delaycount = 5 * hertz; /* 5 seconds * intrs/sec */
openClock();
do {
pendclk = TRUE;
while(pendclk)
;
count++;
}
while ( count < delaycount );
closeClock();
printf("count %d\n",count);
}
setError(s)
char *s;
{
printf("%s\n",s);
}
#endif