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