blob: 6308113ccd259f70d3c94789d64133a97054fd82 [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/*
2 * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +02003 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
Harald Welteec8b4502010-02-20 20:34:29 +01004 * All Rights Reserved
5 *
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +02006 * Authors: Holger Hans Peter Freyther <zecke@selfish.org>
7 * Pablo Neira Ayuso <pablo@gnumonks.org>
8 *
Harald Welteec8b4502010-02-20 20:34:29 +01009 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <stdio.h>
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020026#include <stdlib.h>
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +010027#include <signal.h>
Pablo Neira Ayusof1418372011-11-13 02:02:12 +010028#include <getopt.h>
Harald Welteb53717f2012-08-02 08:42:59 +020029#include <unistd.h>
Harald Welteec8b4502010-02-20 20:34:29 +010030
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020031#include <osmocom/core/talloc.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010032#include <osmocom/core/timer.h>
33#include <osmocom/core/select.h>
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020034#include <osmocom/core/linuxlist.h>
Harald Welteec8b4502010-02-20 20:34:29 +010035
Alex Badea695e5fb2013-01-05 20:59:00 +020036#include "../config.h"
Harald Welteec8b4502010-02-20 20:34:29 +010037
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020038static void main_timer_fired(void *data);
39static void secondary_timer_fired(void *data);
Harald Welteec8b4502010-02-20 20:34:29 +010040
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020041static unsigned int main_timer_step = 0;
42static struct osmo_timer_list main_timer = {
43 .cb = main_timer_fired,
44 .data = &main_timer_step,
Harald Welteec8b4502010-02-20 20:34:29 +010045};
46
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020047static LLIST_HEAD(timer_test_list);
48
49struct test_timer {
50 struct llist_head head;
51 struct osmo_timer_list timer;
52 struct timeval start;
53 struct timeval stop;
Harald Welteec8b4502010-02-20 20:34:29 +010054};
55
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020056/* number of test steps. We add fact(steps) timers in the whole test. */
57#define MAIN_TIMER_NSTEPS 16
Harald Welteec8b4502010-02-20 20:34:29 +010058
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020059/* time between two steps, in secs. */
60#define TIME_BETWEEN_STEPS 1
61
Pablo Neira Ayusof1418372011-11-13 02:02:12 +010062static int timer_nsteps = MAIN_TIMER_NSTEPS;
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020063static unsigned int expired_timers = 0;
64static unsigned int total_timers = 0;
65static unsigned int too_late = 0;
Neels Hofmeyr9c9a0472016-09-22 04:23:34 +020066static unsigned int too_soon = 0;
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020067
68static void main_timer_fired(void *data)
Harald Welteec8b4502010-02-20 20:34:29 +010069{
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020070 unsigned int *step = data;
71 unsigned int add_in_this_step;
72 int i;
Harald Welteec8b4502010-02-20 20:34:29 +010073
Pablo Neira Ayusof1418372011-11-13 02:02:12 +010074 if (*step == timer_nsteps) {
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +010075 fprintf(stderr, "Main timer has finished, please, "
76 "wait a bit for the final report.\n");
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020077 return;
78 }
79 /* add 2^step pair of timers per step. */
80 add_in_this_step = (1 << *step);
81
82 for (i=0; i<add_in_this_step; i++) {
83 struct test_timer *v;
84
85 v = talloc_zero(NULL, struct test_timer);
86 if (v == NULL) {
87 fprintf(stderr, "timer_test: OOM!\n");
88 return;
89 }
Neels Hofmeyr8e2f7e82016-09-22 03:58:13 +020090 osmo_gettimeofday(&v->start, NULL);
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020091 v->timer.cb = secondary_timer_fired;
92 v->timer.data = v;
93 unsigned int seconds = (random() % 10) + 1;
94 v->stop.tv_sec = v->start.tv_sec + seconds;
Neels Hofmeyr633a0e72016-09-22 04:24:38 +020095 v->stop.tv_usec = v->start.tv_usec;
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020096 osmo_timer_schedule(&v->timer, seconds, 0);
97 llist_add(&v->head, &timer_test_list);
98 }
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +010099 fprintf(stderr, "added %d timers in step %u (expired=%u)\n",
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200100 add_in_this_step, *step, expired_timers);
101 total_timers += add_in_this_step;
102 osmo_timer_schedule(&main_timer, TIME_BETWEEN_STEPS, 0);
103 (*step)++;
104}
105
106static void secondary_timer_fired(void *data)
107{
108 struct test_timer *v = data, *this, *tmp;
109 struct timeval current, res, precision = { 1, 0 };
110
Neels Hofmeyr8e2f7e82016-09-22 03:58:13 +0200111 osmo_gettimeofday(&current, NULL);
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200112
113 timersub(&current, &v->stop, &res);
114 if (timercmp(&res, &precision, >)) {
Neels Hofmeyr9c9a0472016-09-22 04:23:34 +0200115 fprintf(stderr, "ERROR: timer has expired too late:"
116 " wanted %d.%06d now %d.%06d diff %d.%06d\n",
117 (int)v->stop.tv_sec, (int)v->stop.tv_usec,
118 (int)current.tv_sec, (int)current.tv_usec,
119 (int)res.tv_sec, (int)res.tv_usec
120 );
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200121 too_late++;
122 }
Neels Hofmeyr9c9a0472016-09-22 04:23:34 +0200123 else if (timercmp(&current, &v->stop, <)) {
124 fprintf(stderr, "ERROR: timer has expired too soon:"
125 " wanted %d.%06d now %d.%06d diff %d.%06d\n",
126 (int)v->stop.tv_sec, (int)v->stop.tv_usec,
127 (int)current.tv_sec, (int)current.tv_usec,
128 (int)res.tv_sec, (int)res.tv_usec
129 );
130 too_soon++;
131 }
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200132
133 llist_del(&v->head);
134 talloc_free(data);
135 expired_timers++;
136 if (expired_timers == total_timers) {
Neels Hofmeyr9c9a0472016-09-22 04:23:34 +0200137 fprintf(stdout, "test over: added=%u expired=%u too_soon=%u too_late=%u\n",
138 total_timers, expired_timers, too_soon, too_late);
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200139 exit(EXIT_SUCCESS);
140 }
141
142 /* randomly (10%) deletion of timers. */
143 llist_for_each_entry_safe(this, tmp, &timer_test_list, head) {
144 if ((random() % 100) < 10) {
145 osmo_timer_del(&this->timer);
146 llist_del(&this->head);
147 talloc_free(this);
148 expired_timers++;
149 }
150 }
Harald Welteec8b4502010-02-20 20:34:29 +0100151}
152
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +0100153static void alarm_handler(int signum)
154{
155 fprintf(stderr, "ERROR: We took too long to run the timer test, "
156 "something seems broken, aborting.\n");
157 exit(EXIT_FAILURE);
158}
159
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100160int main(int argc, char *argv[])
Harald Welteec8b4502010-02-20 20:34:29 +0100161{
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100162 int c;
163
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +0100164 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
165 perror("cannot register signal handler");
166 exit(EXIT_FAILURE);
167 }
168
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100169 while ((c = getopt_long(argc, argv, "s:", NULL, NULL)) != -1) {
170 switch(c) {
171 case 's':
172 timer_nsteps = atoi(optarg);
173 if (timer_nsteps <= 0) {
174 fprintf(stderr, "%s: steps must be > 0\n",
175 argv[0]);
176 exit(EXIT_FAILURE);
177 }
178 break;
179 default:
180 exit(EXIT_FAILURE);
181 }
182 }
183
Neels Hofmeyr13a8fb82016-09-22 04:45:26 +0200184 fprintf(stdout, "Running timer test for %u steps\n", timer_nsteps);
Harald Welteec8b4502010-02-20 20:34:29 +0100185
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200186 osmo_timer_schedule(&main_timer, 1, 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100187
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +0100188 /* if the test takes too long, we may consider that the timer scheduler
189 * has hung. We set some maximum wait time which is the double of the
190 * maximum timeout randomly set (10 seconds, worst case) plus the
191 * number of steps (since some of them are reset each step). */
192 alarm(2 * (10 + timer_nsteps));
193
Harald Welteec8b4502010-02-20 20:34:29 +0100194#ifdef HAVE_SYS_SELECT_H
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200195 while (1) {
196 osmo_select_main(0);
197 }
Harald Welteec8b4502010-02-20 20:34:29 +0100198#else
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +0100199 fprintf(stdout, "Select not supported on this platform!\n");
Harald Welteec8b4502010-02-20 20:34:29 +0100200#endif
201}