Home | History | Annotate | Line # | Download | only in latency1
      1 /*	$NetBSD: latency1.c,v 1.1 2008/05/23 22:22:36 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * THIS IS NOT A GOOD TEST OF REALTIME DISPATCH LATENCY AND SHOULD NOT
     31  * BE USED AS ONE.
     32  *
     33  * Two threads are involved in the test.  Every 100ms the first thread
     34  * writes a byte down a pipe.  The second thread waits to read it.  The
     35  * time taken for the byte to move between threads is measured.  With
     36  * no arguments, it uses timeshared threads.  When given any argument
     37  * (junk will do) it uses realtime threads.  Ctrl-C ends the test.
     38  */
     39 
     40 #include <sys/mman.h>
     41 #include <sys/resource.h>
     42 
     43 #include <pthread.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <unistd.h>
     47 #include <sched.h>
     48 #include <limits.h>
     49 #include <signal.h>
     50 #include <err.h>
     51 
     52 pthread_barrier_t	barrier;
     53 struct timespec		start;
     54 int			fds[2];
     55 int 			done;
     56 long			max = 0;
     57 long			min = LONG_MAX;
     58 
     59 static void
     60 sigint(int junk)
     61 {
     62 
     63 	done = 1;
     64 }
     65 
     66 static void *
     67 reader(void *cookie)
     68 {
     69 	struct timespec end;
     70 	char buf[1];
     71 	long val;
     72 
     73 	for (;;) {
     74 		(void)pthread_barrier_wait(&barrier);
     75 		if (read(fds[0], buf, sizeof(buf)) == -1) {
     76 			err(1, "read");
     77 		}
     78 		clock_gettime(CLOCK_MONOTONIC, &end);
     79 		timespecsub(&end, &start, &end);
     80 		val = (long)end.tv_sec * 1000000000 + (long)end.tv_nsec;
     81 		printf("%ld\n", val);
     82 		if (val > max)
     83 			max = val;
     84 		if (val < min)
     85 			min = val;
     86 	}
     87 }
     88 
     89 int
     90 main(int argc, char *argv[])
     91 {
     92 	static struct timespec delay = { 0, 100000000 };	/* 100ms */
     93 	struct sched_param sp;
     94 	pthread_t pt;
     95 	char buf[1];
     96 
     97 	if (geteuid() != 0) {
     98 		errx(1, "run me as root");
     99 	}
    100 	if (pipe(fds)) {
    101 		err(1, "pipe");
    102 	}
    103 	pthread_barrier_init(&barrier, NULL, 2);
    104 	if (pthread_create(&pt, NULL, reader, NULL)) {
    105 		errx(1, "pthread_create failed");
    106 	}
    107 	if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
    108 		err(1, "mlockall");
    109 	}
    110 	if (signal(SIGINT, sigint)) {
    111 		err(1, "siginal");
    112 	}
    113 	if (argc != 1) {
    114 		/* Have an argument, use realtime priorities. */
    115 		sp.sched_priority = sched_get_priority_max(SCHED_FIFO) - 2;
    116 		if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
    117 			errx(1, "pthread_setschedparam");
    118 		}
    119 		sp.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
    120 		if (pthread_setschedparam(pt, SCHED_FIFO, &sp)) {
    121 			errx(1, "pthread_setschedparam");
    122 		}
    123 	} else {
    124 		/* Not realtime, set the maximum timeshared priority. */
    125 		if (setpriority(PRIO_PROCESS, 0, -20)) {
    126 			err(1, "setpriority");
    127 		}
    128 	}
    129 
    130 	do {
    131 		(void)pthread_barrier_wait(&barrier);
    132 		while (nanosleep(&delay, NULL) != 0) {
    133 			/* nothing */
    134 		}
    135 		clock_gettime(CLOCK_MONOTONIC, &start);
    136 		if (write(fds[1], buf, sizeof(buf)) == -1) {
    137 			err(1, "write");
    138 		}
    139 	} while (!done);
    140 
    141 	printf("\nmin %ldns, max=%ldns\n", min, max);
    142 	return 0;
    143 }
    144