1 | /* Measure mqueue timeout latency |
2 | * by: john stultz (john.stultz@linaro.org) |
3 | * (C) Copyright Linaro 2013 |
4 | * |
5 | * Inspired with permission from example test by: |
6 | * Romain Francoise <romain@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(a: start, b: 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 | fflush(stdout); |
106 | |
107 | ret = mqueue_lat_test(); |
108 | if (ret < 0) { |
109 | printf("[FAILED]\n" ); |
110 | return ksft_exit_fail(); |
111 | } |
112 | printf("[OK]\n" ); |
113 | return ksft_exit_pass(); |
114 | } |
115 | |