Looking for SMP-capable tester

Colin Plumb (colin@nyx.net)
Thu, 3 Dec 1998 23:21:41 -0700 (MST)


The following program should, if all works well, measure the TSC
skew between two processors on an SMP Intel machine. It runs (very slowly)
on my uniprocessor box but, of course, returns nonsense related
to task switching.

If run on an SMP machine with two idle processors, hopefully
master() and slave() will run on two different processors
simultaneously, and won't context switch in that time, leading
to more consistent and interesting output.

Could someone try it for me?

This is to test whether SMP machines have synchronized time stamp counters.
I've got conflicting reports, so I'd like to find out.

The theory of operation is that there is a minimum time between
one processor setting a flag in memory and the other processor
reading it. Here, the master waits until the slave is spinning
reading signal_sent, then records its time stamp counter and
sets the flag. As soon as the slave sees the flag set, it records
its time stamp counter. Then the same thing happens in the
opposite direction.

After several repetitions, it finds the minimum measured delay in
each direction, and uses the difference to compute an estimate of the
clock skew. I'm curious if the results are consistent, and if
they're zero.

Thanks!

-- 
	-Colin

#include <stdio.h>

#include <sched.h>

static volatile int receive_ready; static volatile int pad1[15]; static volatile int signal_sent; static volatile int pad2[15];

static char child_stack[100000];

#define NSAMPLES 25

unsigned master_send[NSAMPLES], master_receive[NSAMPLES]; unsigned slave_send[NSAMPLES], slave_receive[NSAMPLES];

#define rdtsc(hi,lo) asm volatile("rdtsc" : "=a" (lo), "=d" (hi))

static int master(void *arg) { unsigned hi, lo; int i;

(void)arg;

for (i = 0; i < NSAMPLES; i++) { /* Send to slave */ signal_sent = 0; while (!receive_ready) ; rdtsc(hi,lo); /* Waste time */ receive_ready = 0; rdtsc(hi,lo); signal_sent = 1; master_send[i] = lo;

/* Receive from slave */ while (signal_sent) ; receive_ready = 1; while (!signal_sent) ; rdtsc(hi,lo); master_receive[i] = lo; }

/* Wait for slave to store last datum */ while (!receive_ready) ;

return 0; }

static int slave(void *arg) { unsigned hi, lo; int i;

(void)arg;

for (i = 0; i < NSAMPLES; i++) { /* Receive from master */ while (signal_sent) ; receive_ready = 1; while (!signal_sent) ; rdtsc(hi,lo); slave_receive[i] = lo;

/* Send to master */ signal_sent = 0; while (!receive_ready) ; rdtsc(hi,lo); /* Waste time */ receive_ready = 0; rdtsc(hi,lo); signal_sent = 1; slave_send[i] = lo; }

/* Tell master we're done */ receive_ready = 1; _exit(); }

int main(void) { int i; int min1, min2, delta; #define CLONE_ALL (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PID)

/* * We want master and slave running simultaneously, each on a * different processor. Unfortunately, user space offers no * guarantees, but on an idle machine, it should work. */ clone(slave, child_stack + sizeof(child_stack), CLONE_ALL, 0); master(0);

min1 = min2 = (unsigned)-1; for (i = 0; i < NSAMPLES; i++) { delta = slave_receive[i] - master_send[i]; if (min1 > delta) min1 = delta; printf("%9d ", delta); delta = master_receive[i] - slave_send[i]; if (min2 > delta) min2 = delta; printf("%9d\n", delta); } printf("min1 = %d, min2 = %d, skew = %d\n", min1, min2, min1 - min2); return 0; }

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/