4febcdf2db0c08688ca3bb6d411e1d3f5081bc54
[asterisk/asterisk.git] / tests / test_sched.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief ast_sched performance test module
22  *
23  * \author Russell Bryant <russell@digium.com>
24  */
25
26 /*** MODULEINFO
27         <defaultenabled>no</defaultenabled>
28  ***/
29
30 #include "asterisk.h"
31
32 #include <inttypes.h>
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/module.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/sched.h"
39 #include "asterisk/test.h"
40
41 static int sched_cb(const void *data)
42 {
43         return 0;
44 }
45
46 AST_TEST_DEFINE(sched_test_order)
47 {
48         struct sched_context *con;
49         enum ast_test_result_state res = AST_TEST_FAIL;
50         int id1, id2, id3, wait;
51
52         switch (cmd) {
53         case TEST_INIT:
54                 info->name = "sched_test_order";
55                 info->category = "main/sched/";
56                 info->summary = "Test ordering of events in the scheduler API";
57                 info->description =
58                         "This test ensures that events are properly ordered by the "
59                         "time they are scheduled to execute in the scheduler API.";
60                 return AST_TEST_NOT_RUN;
61         case TEST_EXECUTE:
62                 break;
63         }
64
65         if (!(con = sched_context_create())) {
66                 ast_str_set(&args->ast_test_error_str, 0,
67                                 "Test failed - could not create scheduler context\n");
68                 return AST_TEST_FAIL;
69         }
70
71         /* Add 3 scheduler entries, and then remove them, ensuring that the result
72          * of ast_sched_wait() looks appropriate at each step along the way. */
73
74         if ((wait = ast_sched_wait(con)) != -1) {
75                 ast_str_set(&args->ast_test_error_str, 0,
76                                 "ast_sched_wait() should have returned -1, returned '%d'\n",
77                                 wait);
78                 goto return_cleanup;
79         }
80
81         if ((id1 = ast_sched_add(con, 100000, sched_cb, NULL)) == -1) {
82                 ast_str_set(&args->ast_test_error_str, 0,  "Failed to add scheduler entry\n");
83                 goto return_cleanup;
84         }
85
86         if ((wait = ast_sched_wait(con)) > 100000) {
87                 ast_str_set(&args->ast_test_error_str, 0,
88                                 "ast_sched_wait() should have returned <= 100000, returned '%d'\n",
89                                 wait);
90                 goto return_cleanup;
91         }
92
93         if ((id2 = ast_sched_add(con, 10000, sched_cb, NULL)) == -1) {
94                 ast_str_set(&args->ast_test_error_str, 0, "Failed to add scheduler entry\n");
95                 goto return_cleanup;
96         }
97
98         if ((wait = ast_sched_wait(con)) > 10000) {
99                 ast_str_set(&args->ast_test_error_str, 0,
100                                 "ast_sched_wait() should have returned <= 10000, returned '%d'\n",
101                                 wait);
102                 goto return_cleanup;
103         }
104
105         if ((id3 = ast_sched_add(con, 1000, sched_cb, NULL)) == -1) {
106                 ast_str_set(&args->ast_test_error_str, 0, "Failed to add scheduler entry\n");
107                 goto return_cleanup;
108         }
109
110         if ((wait = ast_sched_wait(con)) > 1000) {
111                 ast_str_set(&args->ast_test_error_str, 0,
112                                 "ast_sched_wait() should have returned <= 1000, returned '%d'\n",
113                                 wait);
114                 goto return_cleanup;
115         }
116
117         if (ast_sched_del(con, id3) == -1) {
118                 ast_str_set(&args->ast_test_error_str, 0, "Failed to remove scheduler entry\n");
119                 goto return_cleanup;
120         }
121
122         if ((wait = ast_sched_wait(con)) <= 1000) {
123                 ast_str_set(&args->ast_test_error_str, 0,
124                                 "ast_sched_wait() should have returned > 1000, returned '%d'\n",
125                                 wait);
126                 goto return_cleanup;
127         }
128
129         if (ast_sched_del(con, id2) == -1) {
130                 ast_str_set(&args->ast_test_error_str, 0, "Failed to remove scheduler entry\n");
131                 goto return_cleanup;
132         }
133
134         if ((wait = ast_sched_wait(con)) <= 10000) {
135                 ast_str_set(&args->ast_test_error_str, 0,
136                                 "ast_sched_wait() should have returned > 10000, returned '%d'\n",
137                                 wait);
138                 goto return_cleanup;
139         }
140
141         if (ast_sched_del(con, id1) == -1) {
142                 ast_str_set(&args->ast_test_error_str, 0,  "Failed to remove scheduler entry\n");
143                 goto return_cleanup;
144         }
145
146         if ((wait = ast_sched_wait(con)) != -1) {
147                 ast_str_set(&args->ast_test_error_str, 0,
148                                 "ast_sched_wait() should have returned -1, returned '%d'\n",
149                                 wait);
150                 goto return_cleanup;
151         }
152
153         res = AST_TEST_PASS;
154
155 return_cleanup:
156         sched_context_destroy(con);
157
158         return res;
159 }
160
161 static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
162 {
163         struct sched_context *con;
164         struct timeval start;
165         unsigned int num, i;
166         int *sched_ids = NULL;
167
168         switch (cmd) {
169         case CLI_INIT:
170                 e->command = "sched benchmark";
171                 e->usage = ""
172                         "Usage: sched benchmark <num>\n"
173                         "";
174                 return NULL;
175         case CLI_GENERATE:
176                 return NULL;
177         }
178
179         if (a->argc != e->args + 1) {
180                 return CLI_SHOWUSAGE;
181         }
182
183         if (sscanf(a->argv[e->args], "%u", &num) != 1) {
184                 return CLI_SHOWUSAGE;
185         }
186
187         if (!(con = sched_context_create())) {
188                 ast_cli(a->fd, "Test failed - could not create scheduler context\n");
189                 return CLI_FAILURE;
190         }
191
192         if (!(sched_ids = ast_malloc(sizeof(*sched_ids) * num))) {
193                 ast_cli(a->fd, "Test failed - memory allocation failure\n");
194                 goto return_cleanup;
195         }
196
197         ast_cli(a->fd, "Testing ast_sched_add() performance - timing how long it takes "
198                         "to add %u entries at random time intervals from 0 to 60 seconds\n", num);
199
200         start = ast_tvnow();
201
202         for (i = 0; i < num; i++) {
203                 int when = abs(ast_random()) % 60000;
204                 if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) {
205                         ast_cli(a->fd, "Test failed - sched_add returned -1\n");
206                         goto return_cleanup;
207                 }
208         }
209
210         ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));
211
212         ast_cli(a->fd, "Testing ast_sched_del() performance - timing how long it takes "
213                         "to delete %u entries with random time intervals from 0 to 60 seconds\n", num);
214
215         start = ast_tvnow();
216
217         for (i = 0; i < num; i++) {
218                 if (ast_sched_del(con, sched_ids[i]) == -1) {
219                         ast_cli(a->fd, "Test failed - sched_del returned -1\n");
220                         goto return_cleanup;
221                 }
222         }
223
224         ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));
225
226 return_cleanup:
227         sched_context_destroy(con);
228         if (sched_ids) {
229                 ast_free(sched_ids);
230         }
231
232         return CLI_SUCCESS;
233 }
234
235 static struct ast_cli_entry cli_sched[] = {
236         AST_CLI_DEFINE(handle_cli_sched_bench, "Benchmark ast_sched add/del performance"),
237 };
238
239 static int unload_module(void)
240 {
241         AST_TEST_UNREGISTER(sched_test_order);
242         ast_cli_unregister_multiple(cli_sched, ARRAY_LEN(cli_sched));
243         return 0;
244 }
245
246 static int load_module(void)
247 {
248         AST_TEST_REGISTER(sched_test_order);
249         ast_cli_register_multiple(cli_sched, ARRAY_LEN(cli_sched));
250         return AST_MODULE_LOAD_SUCCESS;
251 }
252
253 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ast_sched performance test module");