Dear Xenomai Users,

I want to measure the context switch times between primary and secondary
 execution modes. Therefore I made some small modifications to the
already present Latency-Test located in
$(XENOMAI_ROOT)/src/testsuite/latency

Basically I just changed few things in the latency-Task:

---snip---

err = rt_task_wait_period(&ov);
before_tsc = rt_timer_tsc();
printf("This is a teststring for entering in secondary mode!\n");
after_tsc = rt_timer_tsc();

dt = after_tsc - before_tsc;


if (dt > maxj)
    maxj = dt;
if (dt < minj)
    minj = dt;
sumj += dt;

---snap---

After that I configured a kernel with CONFIG_PREEMPT and one without. In
theory I should resolve much lower switch-times when I am running the
kernel with CONFIG_PREEMPT, right? However, I can't prove this theory.
The Switch-Times in the non-CONFIG_PREEMPT case are a bit lower than in
the CONFIG_PREEMPT - Case.

The complete Test-Code is attached.

My System is:

Linux Kernel 2.6.17
Adeos Patch: adeos-ipipe-2.6.17-i386-1.5-00.patch
Xenomai 2.2.4

Thanks for help,
Markus Franke

---


#include <sys/mman.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <time.h>
#include <native/task.h>
#include <native/timer.h>
#include <native/sem.h>
#include <rtdm/rttesting.h>

RT_TASK switch_task, display_task;

RT_SEM display_sem;

#define ONE_BILLION  1000000000
#define TEN_MILLION    10000000

long minjitter, maxjitter, avgjitter;
long gminjitter = TEN_MILLION, gmaxjitter = -TEN_MILLION, goverrun = 0;
long long gavgjitter = 0;

long long period_ns = 0;
int test_duration = 0;		/* sec of testing, via -T <sec>, 0 is inf */
int data_lines = 21;		/* data lines per header line, -l <lines> to change */
int quiet = 0;			/* suppress printing of RTH, RTD lines when -T given */
int benchdev_no = 0;
int benchdev = -1;
int freeze_max = 0;
int priority = T_HIPRIO;

time_t test_start, test_end;	/* report test duration */
int test_loops = 0;		/* outer loop count */

#define MEASURE_PERIOD ONE_BILLION
#define SAMPLE_COUNT (MEASURE_PERIOD / period_ns)

/* Warmup time : in order to avoid spurious cache effects on low-end machines. */
#define WARMUP_TIME 1
#define HISTOGRAM_CELLS 100
int histogram_size = HISTOGRAM_CELLS;
long *histogram_avg = NULL, *histogram_max = NULL, *histogram_min = NULL;

int do_histogram = 0, do_stats = 0, finished = 0;
int bucketsize = 1000;		/* default = 1000ns, -B <size> to override */

static inline void add_histogram(long *histogram, long addval)
{
	/* bucketsize steps */
	long inabs =
	    rt_timer_tsc2ns(addval >= 0 ? addval : -addval) / bucketsize;
	histogram[inabs < histogram_size ? inabs : histogram_size - 1]++;
}

void switch_primsek(void *cookie)
{
	int err, count, nsamples, warmup = 1;
	RTIME expected_tsc, period_tsc, start_ticks;
	RT_TIMER_INFO timer_info;

	err = rt_timer_inquire(&timer_info);

	if (err) {
		fprintf(stderr, "switch_primsek: rt_timer_inquire, code %d\n", err);
		return;
	}

	nsamples = ONE_BILLION / period_ns;
	period_tsc = rt_timer_ns2tsc(period_ns);
	/* start time: one millisecond from now. */
	start_ticks = timer_info.date + rt_timer_ns2ticks(1000000);
	expected_tsc = timer_info.tsc + rt_timer_ns2tsc(1000000);

	err =
	    rt_task_set_periodic(NULL, start_ticks,
				 rt_timer_ns2ticks(period_ns));

	if (err) {
		fprintf(stderr, "switch_primsek: failed to set periodic, code %d\n",
			err);
		return;
	}

	for (;;) {
		long minj = TEN_MILLION, maxj = -TEN_MILLION, dt;
		long overrun = 0;
		long long sumj;
		test_loops++;
		long before_tsc;
		long after_tsc;

		for (count = sumj = 0; count < nsamples; count++) {
			unsigned long ov;

			expected_tsc += period_tsc;
			err = rt_task_wait_period(&ov);

			before_tsc = rt_timer_tsc();
			printf("This is a teststring for entering in secondary mode!\n");
			after_tsc = rt_timer_tsc();
			dt = after_tsc - before_tsc;

			
			if (dt > maxj)
				maxj = dt;
			if (dt < minj)
				minj = dt;
			sumj += dt;

			if (err) {
				if (err != -ETIMEDOUT) {
					fprintf(stderr,
						"switch_primsek: wait period failed, code %d\n",
						err);
					rt_task_delete(NULL);	/* Timer stopped. */
				}

				overrun += ov;
				expected_tsc += period_tsc * ov;
			}
			
			if (freeze_max && (dt > gmaxjitter)
			    && !(finished || warmup)) {
				xntrace_user_freeze(rt_timer_tsc2ns(dt), 0);
				gmaxjitter = dt;
			}

			if (!(finished || warmup) && (do_histogram || do_stats))
				add_histogram(histogram_avg, dt);
		}

		if (!warmup) {
			if (!finished && (do_histogram || do_stats)) {
				add_histogram(histogram_max, maxj);
				add_histogram(histogram_min, minj);
			}

			minjitter = minj;
			if (minj < gminjitter)
				gminjitter = minj;

			maxjitter = maxj;
			if (maxj > gmaxjitter)
				gmaxjitter = maxj;

			avgjitter = sumj / nsamples;
			gavgjitter += avgjitter;
			goverrun += overrun;

			rt_sem_v(&display_sem);
		}

		if (warmup && test_loops == WARMUP_TIME) {
			test_loops = 0;
			warmup = 0;
		}
	}
}

void display(void *cookie)
{
	int err, n = 0;
	time_t start;
	char sem_name[16];
	
	snprintf(sem_name, sizeof(sem_name), "dispsem-%d", getpid());
	
	err = rt_sem_create(&display_sem, sem_name, 0, S_FIFO);

	if (err) {
		fprintf(stderr,
			"switch_primsek: cannot create semaphore: %s\n",
			strerror(-err));
		return;

	} 

	time(&start);

	if (WARMUP_TIME)
		printf("warming up...\n");

	if (quiet)
		printf("running quietly for %d seconds\n",
			test_duration);

	for (;;) {
		long minj, gminj, maxj, gmaxj, avgj;

		err = rt_sem_p(&display_sem, TM_INFINITE);
		if (err) {
			if (err != -EIDRM)
				fprintf(stderr,
					"switch_primsek: failed to pend on semaphore, code %d\n",
					err);

			return;
		}

		/* convert jitters to nanoseconds. */
		minj = rt_timer_tsc2ns(minjitter);
		gminj = rt_timer_tsc2ns(gminjitter);
		avgj = rt_timer_tsc2ns(avgjitter);
		maxj = rt_timer_tsc2ns(maxjitter);
		gmaxj = rt_timer_tsc2ns(gmaxjitter);

		if (!quiet) {
			if (data_lines && (n++ % data_lines) == 0) {
				time_t now, dt;
				time(&now);
				dt = now - start - WARMUP_TIME;
				printf
				    ("RTT|  %.2ld:%.2ld:%.2ld  (%s, %Ld us period, "
				     "priority %d)\n", dt / 3600,
				     (dt / 60) % 60, dt % 60,
				     "User Mode",
				     period_ns / 1000, priority);
				printf("RTH|%12s|%12s|%12s|%8s|%12s|%12s\n",
				       "-----lat min", "-----lat avg",
				       "-----lat max", "-overrun",
				       "----lat best", "---lat worst");
			}

			printf("RTD|%12.3f|%12.3f|%12.3f|%8ld|%12.3f|%12.3f\n",
			       (double)minj / 1000,
			       (double)avgj / 1000,
			       (double)maxj / 1000,
			       goverrun,
			       (double)gminj / 1000, (double)gmaxj / 1000);
		}
	}
}

double dump_histogram(long *histogram, char *kind)
{
	int n, total_hits = 0;
	double avg = 0;		/* used to sum hits 1st */

	if (do_histogram)
		printf("---|--param|----range-|--samples\n");

	for (n = 0; n < histogram_size; n++) {
		long hits = histogram[n];

		if (hits) {
			total_hits += hits;
			avg += n * hits;
			if (do_histogram)
				printf("HSD|    %s| %3d -%3d | %8ld\n",
				       kind, n, n + 1, hits);
		}
	}

	avg /= total_hits;	/* compute avg, reuse variable */

	return avg;
}

void dump_stats(long *histogram, char *kind, double avg)
{
	int n, total_hits = 0;
	double variance = 0;

	for (n = 0; n < histogram_size; n++) {
		long hits = histogram[n];

		if (hits) {
			total_hits += hits;
			variance += hits * (n - avg) * (n - avg);
		}
	}

	/* compute std-deviation (unbiased form) */
	variance /= total_hits - 1;
	variance = sqrt(variance);

	printf("HSS|    %s| %9d| %10.3f| %10.3f\n",
	       kind, total_hits, avg, variance);
}

void dump_hist_stats(void)
{
	double minavg, maxavg, avgavg;

	/* max is last, where its visible w/o scrolling */
	minavg = dump_histogram(histogram_min, "min");
	avgavg = dump_histogram(histogram_avg, "avg");
	maxavg = dump_histogram(histogram_max, "max");

	printf("HSH|--param|--samples-|--average--|---stddev--\n");

	dump_stats(histogram_min, "min", minavg);
	dump_stats(histogram_avg, "avg", avgavg);
	dump_stats(histogram_max, "max", maxavg);
}

void cleanup(void)
{
	time_t actual_duration;
	long gmaxj, gminj, gavgj;

	rt_sem_delete(&display_sem);

	gavgjitter /= (test_loops > 1 ? test_loops : 2) - 1;

	gminj = rt_timer_tsc2ns(gminjitter);
	gmaxj = rt_timer_tsc2ns(gmaxjitter);
	gavgj = rt_timer_tsc2ns(gavgjitter);

	if (do_histogram || do_stats)
		dump_hist_stats();

	time(&test_end);
	actual_duration = test_end - test_start - WARMUP_TIME;
	if (!test_duration)
		test_duration = actual_duration;

	printf
	    ("---|------------|------------|------------|--------|-------------------------\n"
	     "RTS|%12.3f|%12.3f|%12.3f|%8ld|    %.2ld:%.2ld:%.2ld/%.2d:%.2d:%.2d\n",
	     (double)gminj / 1000, (double)gavgj / 1000, (double)gmaxj / 1000,
	     goverrun, actual_duration / 3600, (actual_duration / 60) % 60,
	     actual_duration % 60, test_duration / 3600,
	     (test_duration / 60) % 60, test_duration % 60);

	if (histogram_avg)
		free(histogram_avg);
	if (histogram_max)
		free(histogram_max);
	if (histogram_min)
		free(histogram_min);

	exit(0);
}

void sighand(int sig __attribute__ ((unused)))
{
        if (sig == SIGXCPU)
                printf("---!! uh oh, switched to secondary mode !!--\n");
	else
		finished = 1;
}

int main(int argc, char **argv)
{
	int c, err;
	char task_name[16];
	int cpu = 0;
	
	while ((c = getopt(argc, argv, "hp:l:T:qH:B:sD:t:fc:P:")) != EOF)
		switch (c) {
		case 'h':

			do_histogram = 1;
			break;

		case 's':

			do_stats = 1;
			break;

		case 'H':

			histogram_size = atoi(optarg);
			break;

		case 'B':

			bucketsize = atoi(optarg);
			break;

		case 'p':

			period_ns = atoi(optarg) * 1000LL;
			break;

		case 'l':

			data_lines = atoi(optarg);
			break;

		case 'T':

			test_duration = atoi(optarg);
			alarm(test_duration + WARMUP_TIME);
			break;

		case 'q':

			quiet = 1;
			break;

		case 'D':

			benchdev_no = atoi(optarg);
			break;

		case 't':

			break;

		case 'f':

			freeze_max = 1;
			break;

		case 'c':
			cpu = T_CPU(atoi(optarg));
			break;

		case 'P':
			priority = atoi(optarg);
			break;

		default:

			fprintf(stderr, "usage: switch_primsek [options]\n"
				"  [-h]                         # print histograms of min, avg, max latencies\n"
				"  [-s]                         # print statistics of min, avg, max latencies\n"
				"  [-H <histogram-size>]        # default = 200, increase if your last bucket is full\n"
				"  [-B <bucket-size>]           # default = 1000ns, decrease for more resolution\n"
				"  [-p <period_us>]             # sampling period\n"
				"  [-l <data-lines per header>] # default=21, 0 to supress headers\n"
				"  [-T <test_duration_seconds>] # default=0, so ^C to end\n"
				"  [-q]                         # supresses RTD, RTH lines if -T is used\n"
				"  [-D <testing_device_no>]     # number of testing device, default=0\n"
				"  [-t <test_mode>]             # 0=user task (default), 1=kernel task, 2=timer IRQ\n"
				"  [-f]                         # freeze trace for each new max latency\n"
				"  [-c <cpu>]                   # pin measuring task down to given CPU\n"
				"  [-P <priority>]              # task priority (test mode 0 and 1 only)\n");
			exit(2);
		}

	time(&test_start);

	histogram_avg = calloc(histogram_size, sizeof(long));
	histogram_max = calloc(histogram_size, sizeof(long));
	histogram_min = calloc(histogram_size, sizeof(long));

	if (!(histogram_avg && histogram_max && histogram_min))
		cleanup();

	if (period_ns == 0)
		//period_ns = 1000000000LL;	/* ns */
		period_ns = 1000000LL;	/* ns */

	if (priority <= T_LOPRIO)
		priority = T_LOPRIO + 1;
	else if (priority > T_HIPRIO)
		priority = T_HIPRIO;

	signal(SIGINT, sighand);
	signal(SIGTERM, sighand);
	signal(SIGHUP, sighand);
	signal(SIGALRM, sighand);

	setlinebuf(stdout);

	printf("== Sampling period: %Ld us\n"
	       "== All results in microseconds\n",
	       period_ns / 1000);

	mlockall(MCL_CURRENT | MCL_FUTURE);

	err = rt_timer_set_mode(TM_ONESHOT);	/* Force aperiodic timing. */
	
	if (err) {
		fprintf(stderr,
			"switch_primsek: failed to start timer, code %d\n",
			err);
		return 0;
	}
	
	snprintf(task_name, sizeof(task_name), "display-%d", getpid());
	err = rt_task_create(&display_task, task_name, 0, 0, T_FPU);

	if (err) {
		fprintf(stderr,
			"switch_primsek: failed to create display task, code %d\n",
			err);
		return 0;
	}

	err = rt_task_start(&display_task, &display, NULL);

	if (err) {
		fprintf(stderr,
			"switch_primsek: failed to start display task, code %d\n",
			err);
		return 0;
	}

	snprintf(task_name, sizeof(task_name), "sampling-%d", getpid());
	err =
	    rt_task_create(&switch_task, task_name, 0, priority,
		   T_FPU | cpu);

	if (err) {
		fprintf(stderr,
			"switch_primsek: failed to create switch_primsek task, code %d\n",
			err);
		return 0;
	}

	err = rt_task_start(&switch_task, &switch_primsek, NULL);

	if (err) {
		fprintf(stderr,
			"switch_primsek: failed to start switch_primsek task, code %d\n",
			err);
		return 0;
	}

	while (!finished)
		pause();

	cleanup();

	return 0;
}

begin:vcard
fn:Markus Franke
n:Franke;Markus
adr;quoted-printable:;;Vettersstra=C3=9Fe 64/722;Chemnitz;Saxony;09126;Germany
email;internet:[EMAIL PROTECTED]
x-mozilla-html:FALSE
url:http://www.tu-chemnitz.de/~franm
version:2.1
end:vcard

_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help

Reply via email to