David Bacon <dbacon@qnx.com> wrote:
Regarding the use of ClockPeriod(), David, I have often seen you warn
ominously about the overhead associated with cranking up the resolution, but
when I take it right up to 10 microseconds (really ~9219 nanoseconds because
you can only put integers into that decrement counter in the timer chip) on
a 333MHz Pentium II, the desktop shelf System Monitor’s CPU display seems to
be showing only around 5% overhead, if that. Neutrino really does handle
timer interrupts quite efficiently, even 100K of them per second! > ![:slight_smile: :slight_smile:](/images/emoji/twitter/slight_smile.png?v=9)
The issue isn’t, so much, in an idle system – it is when you start
doing things.
It now, means, that say you start a calculation that would take 1s to
complete. If you had a ticksize of 1ms – that would get interrupted
1000 times, with 1000 switches into kernel space, and back out again.
If you take that ticksize down to 10 microseconds, you are now getting
interrupted 100,000 times – this means 100x as many context switches
etc.
For instance, I have a little s/r/r test program, it does a bunch
of 4K Send & 4K replies, then figures out how many clock cycles it
took to complete.
With a ticksize of 1ms – I get a ipc cost of 4850 clock cycles
(850 Mhz Pentium 3). If I take the ticksize down to 10 microseconds,
I get an ipc cost of 6140 clock cycles. That’s a little over 26%
worse.
If I do 0 length S/R/R, the numbers I get are 1950 and 2440 –
again about 25% cost.
I would consider 25% a significant overhead, which is why I warn
about the cost of doing this.
Of course, using some other interrupt at this frequency will
impose similar overhead – but if it can be used more flexibly,
e.g. only set it to interrupt once, 50 microseconds after needed,
then disable; then re-enable next time – that could significantly
reduce the interrupt overhead.
Still, choosing an interrupt where we don’t do any work
(e.g. updating time, checking the timer chain) will also
reduce the overhead at each interrupt.
-David
P.S. My S/R/R test program:
/*
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/neutrino.h>
#include <sys/stat.h>
#include <sys/syspage.h>
void *worker( void * );
#define NUM_LOOP 100000
int chid; /* the channel id that the server will receive on */
char device; / the device that the worker thread will read from */
char *progname = “sendrec”;
char buf[4096];
int
main( int argc, char **argv )
{
message_t msg;
reply_t reply;
int rcvid;
// printf(“setprio returned %d\n”, setprio(0,62));
chid = ChannelCreate( 0 );
if ( chid == -1 ) {
printf( “%s: (server) couldn’t create a channel: %s\n”,
progname, strerror(errno) );
exit( EXIT_FAILURE );
}
if (!fork()) worker(NULL);
while (1) {
rcvid = MsgReceive(chid, buf, 4096, NULL );
MsgReply( rcvid, 0, buf, 4096 );
}
return 0;
}
void *
worker( void *unused )
{
int coid;
int ret;
int i;
uint64_t before, after;
uint64_t loop_delta, ipc_delta;
uint64_t ipc_cost;
coid = ConnectAttach( 0, getppid(), chid, _NTO_SIDE_CHANNEL, 0 );
before = ClockCycles();
for(i = 0; i<NUM_LOOP; i++);
after = ClockCycles();
loop_delta = after - before;
before = ClockCycles();
for(i = 0; i<NUM_LOOP; i++)
{
ret = MsgSend( coid, buf, 4096, buf, 4096 );
}
after = ClockCycles();
ipc_delta = after - before;
printf(“loop_delta: %lld, ipc_delta: %lld\n”, loop_delta, ipc_delta );
ipc_cost = (ipc_delta-loop_delta)/NUM_LOOP;
printf(“ipc overhead = %lld\n”, ipc_cost );
printf(“cycles/sec is %lld\n”, SYSPAGE_ENTRY( qtime )->cycles_per_sec );
kill(getppid(), SIGTERM );
exit(0);
return( NULL );
}
QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.