18c2ecf20Sopenharmony_ci/* Measure mqueue timeout latency
28c2ecf20Sopenharmony_ci *              by: john stultz (john.stultz@linaro.org)
38c2ecf20Sopenharmony_ci *		(C) Copyright Linaro 2013
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *		Inspired with permission from example test by:
68c2ecf20Sopenharmony_ci *			Romain Francoise <romain@orebokech.com>
78c2ecf20Sopenharmony_ci *              Licensed under the GPLv2
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  To build:
108c2ecf20Sopenharmony_ci *	$ gcc mqueue-lat.c -o mqueue-lat -lrt
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *   This program is free software: you can redistribute it and/or modify
138c2ecf20Sopenharmony_ci *   it under the terms of the GNU General Public License as published by
148c2ecf20Sopenharmony_ci *   the Free Software Foundation, either version 2 of the License, or
158c2ecf20Sopenharmony_ci *   (at your option) any later version.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
188c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
198c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
208c2ecf20Sopenharmony_ci *   GNU General Public License for more details.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <stdio.h>
248c2ecf20Sopenharmony_ci#include <stdlib.h>
258c2ecf20Sopenharmony_ci#include <time.h>
268c2ecf20Sopenharmony_ci#include <sys/time.h>
278c2ecf20Sopenharmony_ci#include <sys/timex.h>
288c2ecf20Sopenharmony_ci#include <string.h>
298c2ecf20Sopenharmony_ci#include <signal.h>
308c2ecf20Sopenharmony_ci#include <errno.h>
318c2ecf20Sopenharmony_ci#include <mqueue.h>
328c2ecf20Sopenharmony_ci#include "../kselftest.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define NSEC_PER_SEC 1000000000ULL
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define TARGET_TIMEOUT		100000000	/* 100ms in nanoseconds */
378c2ecf20Sopenharmony_ci#define UNRESONABLE_LATENCY	40000000	/* 40ms in nanosecs */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cilong long timespec_sub(struct timespec a, struct timespec b)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec;
458c2ecf20Sopenharmony_ci	return ret;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistruct timespec timespec_add(struct timespec ts, unsigned long long ns)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	ts.tv_nsec += ns;
518c2ecf20Sopenharmony_ci	while (ts.tv_nsec >= NSEC_PER_SEC) {
528c2ecf20Sopenharmony_ci		ts.tv_nsec -= NSEC_PER_SEC;
538c2ecf20Sopenharmony_ci		ts.tv_sec++;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci	return ts;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ciint mqueue_lat_test(void)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	mqd_t q;
628c2ecf20Sopenharmony_ci	struct mq_attr attr;
638c2ecf20Sopenharmony_ci	struct timespec start, end, now, target;
648c2ecf20Sopenharmony_ci	int i, count, ret;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	q = mq_open("/foo", O_CREAT | O_RDONLY, 0666, NULL);
678c2ecf20Sopenharmony_ci	if (q < 0) {
688c2ecf20Sopenharmony_ci		perror("mq_open");
698c2ecf20Sopenharmony_ci		return -1;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci	mq_getattr(q, &attr);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	count = 100;
758c2ecf20Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &start);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
788c2ecf20Sopenharmony_ci		char buf[attr.mq_msgsize];
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		clock_gettime(CLOCK_REALTIME, &now);
818c2ecf20Sopenharmony_ci		target = now;
828c2ecf20Sopenharmony_ci		target = timespec_add(now, TARGET_TIMEOUT); /* 100ms */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci		ret = mq_timedreceive(q, buf, sizeof(buf), NULL, &target);
858c2ecf20Sopenharmony_ci		if (ret < 0 && errno != ETIMEDOUT) {
868c2ecf20Sopenharmony_ci			perror("mq_timedreceive");
878c2ecf20Sopenharmony_ci			return -1;
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &end);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	mq_close(q);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if ((timespec_sub(start, end)/count) > TARGET_TIMEOUT + UNRESONABLE_LATENCY)
958c2ecf20Sopenharmony_ci		return -1;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciint main(int argc, char **argv)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	printf("Mqueue latency :                          ");
1058c2ecf20Sopenharmony_ci	fflush(stdout);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	ret = mqueue_lat_test();
1088c2ecf20Sopenharmony_ci	if (ret < 0) {
1098c2ecf20Sopenharmony_ci		printf("[FAILED]\n");
1108c2ecf20Sopenharmony_ci		return ksft_exit_fail();
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci	printf("[OK]\n");
1138c2ecf20Sopenharmony_ci	return ksft_exit_pass();
1148c2ecf20Sopenharmony_ci}
115