blob: 3775151ce6d943a4347342a115fcc41df6112d68 [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 Welteec8b4502010-02-20 20:34:29 +010029
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020030#include <osmocom/core/talloc.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010031#include <osmocom/core/timer.h>
32#include <osmocom/core/select.h>
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020033#include <osmocom/core/linuxlist.h>
Harald Welteec8b4502010-02-20 20:34:29 +010034
Harald Weltee94ad582010-02-20 22:06:24 +010035#include "../../config.h"
Harald Welteec8b4502010-02-20 20:34:29 +010036
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020037static void main_timer_fired(void *data);
38static void secondary_timer_fired(void *data);
Harald Welteec8b4502010-02-20 20:34:29 +010039
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020040static unsigned int main_timer_step = 0;
41static struct osmo_timer_list main_timer = {
42 .cb = main_timer_fired,
43 .data = &main_timer_step,
Harald Welteec8b4502010-02-20 20:34:29 +010044};
45
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020046static LLIST_HEAD(timer_test_list);
47
48struct test_timer {
49 struct llist_head head;
50 struct osmo_timer_list timer;
51 struct timeval start;
52 struct timeval stop;
Harald Welteec8b4502010-02-20 20:34:29 +010053};
54
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020055/* number of test steps. We add fact(steps) timers in the whole test. */
56#define MAIN_TIMER_NSTEPS 16
Harald Welteec8b4502010-02-20 20:34:29 +010057
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020058/* time between two steps, in secs. */
59#define TIME_BETWEEN_STEPS 1
60
61/* timer imprecision that we accept for this test: 10 milliseconds. */
62#define TIMER_PRES_SECS 0
63#define TIMER_PRES_USECS 10000
64
Pablo Neira Ayusof1418372011-11-13 02:02:12 +010065static int timer_nsteps = MAIN_TIMER_NSTEPS;
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020066static unsigned int expired_timers = 0;
67static unsigned int total_timers = 0;
68static unsigned int too_late = 0;
69
70static void main_timer_fired(void *data)
Harald Welteec8b4502010-02-20 20:34:29 +010071{
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020072 unsigned int *step = data;
73 unsigned int add_in_this_step;
74 int i;
Harald Welteec8b4502010-02-20 20:34:29 +010075
Pablo Neira Ayusof1418372011-11-13 02:02:12 +010076 if (*step == timer_nsteps) {
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +010077 fprintf(stderr, "Main timer has finished, please, "
78 "wait a bit for the final report.\n");
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +020079 return;
80 }
81 /* add 2^step pair of timers per step. */
82 add_in_this_step = (1 << *step);
83
84 for (i=0; i<add_in_this_step; i++) {
85 struct test_timer *v;
86
87 v = talloc_zero(NULL, struct test_timer);
88 if (v == NULL) {
89 fprintf(stderr, "timer_test: OOM!\n");
90 return;
91 }
92 gettimeofday(&v->start, NULL);
93 v->timer.cb = secondary_timer_fired;
94 v->timer.data = v;
95 unsigned int seconds = (random() % 10) + 1;
96 v->stop.tv_sec = v->start.tv_sec + seconds;
97 osmo_timer_schedule(&v->timer, seconds, 0);
98 llist_add(&v->head, &timer_test_list);
99 }
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +0100100 fprintf(stderr, "added %d timers in step %u (expired=%u)\n",
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200101 add_in_this_step, *step, expired_timers);
102 total_timers += add_in_this_step;
103 osmo_timer_schedule(&main_timer, TIME_BETWEEN_STEPS, 0);
104 (*step)++;
105}
106
107static void secondary_timer_fired(void *data)
108{
109 struct test_timer *v = data, *this, *tmp;
110 struct timeval current, res, precision = { 1, 0 };
111
112 gettimeofday(&current, NULL);
113
114 timersub(&current, &v->stop, &res);
115 if (timercmp(&res, &precision, >)) {
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +0100116 fprintf(stderr, "ERROR: timer %p has expired too late!\n",
117 v->timer);
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200118 too_late++;
119 }
120
121 llist_del(&v->head);
122 talloc_free(data);
123 expired_timers++;
124 if (expired_timers == total_timers) {
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +0100125 fprintf(stdout, "test over: added=%u expired=%u too_late=%u \n",
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200126 total_timers, expired_timers, too_late);
127 exit(EXIT_SUCCESS);
128 }
129
130 /* randomly (10%) deletion of timers. */
131 llist_for_each_entry_safe(this, tmp, &timer_test_list, head) {
132 if ((random() % 100) < 10) {
133 osmo_timer_del(&this->timer);
134 llist_del(&this->head);
135 talloc_free(this);
136 expired_timers++;
137 }
138 }
Harald Welteec8b4502010-02-20 20:34:29 +0100139}
140
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +0100141static void alarm_handler(int signum)
142{
143 fprintf(stderr, "ERROR: We took too long to run the timer test, "
144 "something seems broken, aborting.\n");
145 exit(EXIT_FAILURE);
146}
147
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100148int main(int argc, char *argv[])
Harald Welteec8b4502010-02-20 20:34:29 +0100149{
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100150 int c;
151
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +0100152 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
153 perror("cannot register signal handler");
154 exit(EXIT_FAILURE);
155 }
156
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100157 while ((c = getopt_long(argc, argv, "s:", NULL, NULL)) != -1) {
158 switch(c) {
159 case 's':
160 timer_nsteps = atoi(optarg);
161 if (timer_nsteps <= 0) {
162 fprintf(stderr, "%s: steps must be > 0\n",
163 argv[0]);
164 exit(EXIT_FAILURE);
165 }
166 break;
167 default:
168 exit(EXIT_FAILURE);
169 }
170 }
171
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +0100172 fprintf(stdout, "Running timer test for %u steps, accepting "
173 "imprecision of %u.%.6u seconds\n",
Pablo Neira Ayusof1418372011-11-13 02:02:12 +0100174 timer_nsteps, TIMER_PRES_SECS, TIMER_PRES_USECS);
Harald Welteec8b4502010-02-20 20:34:29 +0100175
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200176 osmo_timer_schedule(&main_timer, 1, 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100177
Pablo Neira Ayuso72eb44c2011-11-13 17:40:09 +0100178 /* if the test takes too long, we may consider that the timer scheduler
179 * has hung. We set some maximum wait time which is the double of the
180 * maximum timeout randomly set (10 seconds, worst case) plus the
181 * number of steps (since some of them are reset each step). */
182 alarm(2 * (10 + timer_nsteps));
183
Harald Welteec8b4502010-02-20 20:34:29 +0100184#ifdef HAVE_SYS_SELECT_H
Pablo Neira Ayuso9ebc5052011-09-26 11:46:32 +0200185 while (1) {
186 osmo_select_main(0);
187 }
Harald Welteec8b4502010-02-20 20:34:29 +0100188#else
Pablo Neira Ayuso7a0ca162011-11-13 17:22:33 +0100189 fprintf(stdout, "Select not supported on this platform!\n");
Harald Welteec8b4502010-02-20 20:34:29 +0100190#endif
191}