Home | History | Annotate | Download | only in timers
      1 /* Measure mqueue timeout latency
      2  *              by: john stultz (john.stultz (at) linaro.org)
      3  *		(C) Copyright Linaro 2013
      4  *
      5  *		Inspired with permission from example test by:
      6  *			Romain Francoise <romain (at) orebokech.com>
      7  *              Licensed under the GPLv2
      8  *
      9  *  To build:
     10  *	$ gcc mqueue-lat.c -o mqueue-lat -lrt
     11  *
     12  *   This program is free software: you can redistribute it and/or modify
     13  *   it under the terms of the GNU General Public License as published by
     14  *   the Free Software Foundation, either version 2 of the License, or
     15  *   (at your option) any later version.
     16  *
     17  *   This program is distributed in the hope that it will be useful,
     18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20  *   GNU General Public License for more details.
     21  */
     22 
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <time.h>
     26 #include <sys/time.h>
     27 #include <sys/timex.h>
     28 #include <string.h>
     29 #include <signal.h>
     30 #include <errno.h>
     31 #include <mqueue.h>
     32 #include "../kselftest.h"
     33 
     34 #define NSEC_PER_SEC 1000000000ULL
     35 
     36 #define TARGET_TIMEOUT		100000000	/* 100ms in nanoseconds */
     37 #define UNRESONABLE_LATENCY	40000000	/* 40ms in nanosecs */
     38 
     39 
     40 long long timespec_sub(struct timespec a, struct timespec b)
     41 {
     42 	long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
     43 
     44 	ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec;
     45 	return ret;
     46 }
     47 
     48 struct timespec timespec_add(struct timespec ts, unsigned long long ns)
     49 {
     50 	ts.tv_nsec += ns;
     51 	while (ts.tv_nsec >= NSEC_PER_SEC) {
     52 		ts.tv_nsec -= NSEC_PER_SEC;
     53 		ts.tv_sec++;
     54 	}
     55 	return ts;
     56 }
     57 
     58 int mqueue_lat_test(void)
     59 {
     60 
     61 	mqd_t q;
     62 	struct mq_attr attr;
     63 	struct timespec start, end, now, target;
     64 	int i, count, ret;
     65 
     66 	q = mq_open("/foo", O_CREAT | O_RDONLY, 0666, NULL);
     67 	if (q < 0) {
     68 		perror("mq_open");
     69 		return -1;
     70 	}
     71 	mq_getattr(q, &attr);
     72 
     73 
     74 	count = 100;
     75 	clock_gettime(CLOCK_MONOTONIC, &start);
     76 
     77 	for (i = 0; i < count; i++) {
     78 		char buf[attr.mq_msgsize];
     79 
     80 		clock_gettime(CLOCK_REALTIME, &now);
     81 		target = now;
     82 		target = timespec_add(now, TARGET_TIMEOUT); /* 100ms */
     83 
     84 		ret = mq_timedreceive(q, buf, sizeof(buf), NULL, &target);
     85 		if (ret < 0 && errno != ETIMEDOUT) {
     86 			perror("mq_timedreceive");
     87 			return -1;
     88 		}
     89 	}
     90 	clock_gettime(CLOCK_MONOTONIC, &end);
     91 
     92 	mq_close(q);
     93 
     94 	if ((timespec_sub(start, end)/count) > TARGET_TIMEOUT + UNRESONABLE_LATENCY)
     95 		return -1;
     96 
     97 	return 0;
     98 }
     99 
    100 int main(int argc, char **argv)
    101 {
    102 	int ret;
    103 
    104 	printf("Mqueue latency :                          ");
    105 
    106 	ret = mqueue_lat_test();
    107 	if (ret < 0) {
    108 		printf("[FAILED]\n");
    109 		return ksft_exit_fail();
    110 	}
    111 	printf("[OK]\n");
    112 	return ksft_exit_pass();
    113 }
    114