Asterisk - The Open Source Telephony Project  18.5.0
test_sched.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Russell Bryant <[email protected]>
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 <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <depend>TEST_FRAMEWORK</depend>
28  <support_level>core</support_level>
29  ***/
30 
31 #include "asterisk.h"
32 
33 #include <inttypes.h>
34 
35 #include "asterisk/module.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/sched.h"
38 #include "asterisk/test.h"
39 #include "asterisk/cli.h"
40 
41 static int sched_cb(const void *data)
42 {
43  return 0;
44 }
45 
46 static int order_check;
47 static int order_check_failed;
48 
49 static void sched_order_check(struct ast_test *test, int order)
50 {
51  ++order_check;
52  if (order_check != order) {
53  ast_test_status_update(test, "Unexpected execution order: expected:%d got:%d\n",
54  order, order_check);
56  }
57 }
58 
59 static int sched_order_1_cb(const void *data)
60 {
61  sched_order_check((void *) data, 1);
62  return 0;
63 }
64 
65 static int sched_order_2_cb(const void *data)
66 {
67  sched_order_check((void *) data, 2);
68  return 0;
69 }
70 
71 static int sched_order_3_cb(const void *data)
72 {
73  sched_order_check((void *) data, 3);
74  return 0;
75 }
76 
77 static int sched_order_4_cb(const void *data)
78 {
79  sched_order_check((void *) data, 4);
80  return 0;
81 }
82 
83 static int sched_order_5_cb(const void *data)
84 {
85  sched_order_check((void *) data, 5);
86  return 0;
87 }
88 
89 static int sched_order_6_cb(const void *data)
90 {
91  sched_order_check((void *) data, 6);
92  return 0;
93 }
94 
95 static int sched_order_7_cb(const void *data)
96 {
97  sched_order_check((void *) data, 7);
98  return 0;
99 }
100 
101 static int sched_order_8_cb(const void *data)
102 {
103  sched_order_check((void *) data, 8);
104  return 0;
105 }
106 
107 AST_TEST_DEFINE(sched_test_order)
108 {
109  struct ast_sched_context *con;
111  int id1, id2, id3, wait;
112 
113  switch (cmd) {
114  case TEST_INIT:
115  info->name = "sched_test_order";
116  info->category = "/main/sched/";
117  info->summary = "Test ordering of events in the scheduler API";
118  info->description =
119  "This test ensures that events are properly ordered by the "
120  "time they are scheduled to execute in the scheduler API.";
121  return AST_TEST_NOT_RUN;
122  case TEST_EXECUTE:
123  break;
124  }
125 
126  if (!(con = ast_sched_context_create())) {
128  "Test failed - could not create scheduler context\n");
129  return AST_TEST_FAIL;
130  }
131 
132  /* Add 3 scheduler entries, and then remove them, ensuring that the result
133  * of ast_sched_wait() looks appropriate at each step along the way. */
134 
135  if ((wait = ast_sched_wait(con)) != -1) {
137  "ast_sched_wait() should have returned -1, returned '%d'\n",
138  wait);
139  goto return_cleanup;
140  }
141 
142  if ((id1 = ast_sched_add(con, 100000, sched_cb, NULL)) == -1) {
143  ast_test_status_update(test, "Failed to add scheduler entry\n");
144  goto return_cleanup;
145  }
146 
147  if ((wait = ast_sched_wait(con)) > 100000) {
149  "ast_sched_wait() should have returned <= 100000, returned '%d'\n",
150  wait);
151  goto return_cleanup;
152  }
153 
154  if ((id2 = ast_sched_add(con, 10000, sched_cb, NULL)) == -1) {
155  ast_test_status_update(test, "Failed to add scheduler entry\n");
156  goto return_cleanup;
157  }
158 
159  if ((wait = ast_sched_wait(con)) > 10000) {
161  "ast_sched_wait() should have returned <= 10000, returned '%d'\n",
162  wait);
163  goto return_cleanup;
164  }
165 
166  if ((id3 = ast_sched_add(con, 1000, sched_cb, NULL)) == -1) {
167  ast_test_status_update(test, "Failed to add scheduler entry\n");
168  goto return_cleanup;
169  }
170 
171  if ((wait = ast_sched_wait(con)) > 1000) {
173  "ast_sched_wait() should have returned <= 1000, returned '%d'\n",
174  wait);
175  goto return_cleanup;
176  }
177 
178  if (ast_sched_del(con, id3) == -1) {
179  ast_test_status_update(test, "Failed to remove scheduler entry\n");
180  goto return_cleanup;
181  }
182 
183  if ((wait = ast_sched_wait(con)) <= 1000) {
185  "ast_sched_wait() should have returned > 1000, returned '%d'\n",
186  wait);
187  goto return_cleanup;
188  }
189 
190  if (ast_sched_del(con, id2) == -1) {
191  ast_test_status_update(test, "Failed to remove scheduler entry\n");
192  goto return_cleanup;
193  }
194 
195  if ((wait = ast_sched_wait(con)) <= 10000) {
197  "ast_sched_wait() should have returned > 10000, returned '%d'\n",
198  wait);
199  goto return_cleanup;
200  }
201 
202  if (ast_sched_del(con, id1) == -1) {
203  ast_test_status_update(test, "Failed to remove scheduler entry\n");
204  goto return_cleanup;
205  }
206 
207  if ((wait = ast_sched_wait(con)) != -1) {
209  "ast_sched_wait() should have returned -1, returned '%d'\n",
210  wait);
211  goto return_cleanup;
212  }
213 
214  /*
215  * Schedule immediate and delayed entries to check the order
216  * that they get executed. They must get executed at the
217  * time they expire in the order they were added.
218  */
219 #define DELAYED_SAME_EXPIRE 300 /* ms */
220  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_1_cb, test), res, return_cleanup);
221  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_1_cb, test), res, return_cleanup);
222  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_2_cb, test), res, return_cleanup);
223  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_2_cb, test), res, return_cleanup);
224  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_3_cb, test), res, return_cleanup);
225  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_3_cb, test), res, return_cleanup);
226  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_4_cb, test), res, return_cleanup);
227  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_4_cb, test), res, return_cleanup);
228  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_5_cb, test), res, return_cleanup);
229  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_5_cb, test), res, return_cleanup);
230  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_6_cb, test), res, return_cleanup);
231  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_6_cb, test), res, return_cleanup);
232  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_7_cb, test), res, return_cleanup);
233  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_7_cb, test), res, return_cleanup);
234  ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_8_cb, test), res, return_cleanup);
235 
236  /* Check order of scheduled immediate entries. */
237  order_check = 0;
238  order_check_failed = 0;
239  usleep(50 * 1000);/* Ensure that all the immediate entries are ready to expire */
240  ast_test_validate_cleanup(test, 7 == ast_sched_runq(con), res, return_cleanup);
241  ast_test_validate_cleanup(test, !order_check_failed, res, return_cleanup);
242 
243  /* Check order of scheduled entries expiring at the same time. */
244  order_check = 0;
245  order_check_failed = 0;
246  usleep((DELAYED_SAME_EXPIRE + 50) * 1000);/* Ensure that all the delayed entries are ready to expire */
247  ast_test_validate_cleanup(test, 8 == ast_sched_runq(con), res, return_cleanup);
248  ast_test_validate_cleanup(test, !order_check_failed, res, return_cleanup);
249 
250  if ((wait = ast_sched_wait(con)) != -1) {
252  "ast_sched_wait() should have returned -1, returned '%d'\n",
253  wait);
254  goto return_cleanup;
255  }
256 
257  res = AST_TEST_PASS;
258 
259 return_cleanup:
261 
262  return res;
263 }
264 
265 static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
266 {
267  struct ast_sched_context *con;
268  struct timeval start;
269  unsigned int num, i;
270  int *sched_ids = NULL;
271 
272  switch (cmd) {
273  case CLI_INIT:
274  e->command = "sched benchmark";
275  e->usage = ""
276  "Usage: sched benchmark <num>\n"
277  "";
278  return NULL;
279  case CLI_GENERATE:
280  return NULL;
281  }
282 
283  if (a->argc != e->args + 1) {
284  return CLI_SHOWUSAGE;
285  }
286 
287  if (sscanf(a->argv[e->args], "%u", &num) != 1) {
288  return CLI_SHOWUSAGE;
289  }
290 
291  if (!(con = ast_sched_context_create())) {
292  ast_cli(a->fd, "Test failed - could not create scheduler context\n");
293  return CLI_FAILURE;
294  }
295 
296  if (!(sched_ids = ast_malloc(sizeof(*sched_ids) * num))) {
297  ast_cli(a->fd, "Test failed - memory allocation failure\n");
298  goto return_cleanup;
299  }
300 
301  ast_cli(a->fd, "Testing ast_sched_add() performance - timing how long it takes "
302  "to add %u entries at random time intervals from 0 to 60 seconds\n", num);
303 
304  start = ast_tvnow();
305 
306  for (i = 0; i < num; i++) {
307  long when = labs(ast_random()) % 60000;
308  if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) {
309  ast_cli(a->fd, "Test failed - sched_add returned -1\n");
310  goto return_cleanup;
311  }
312  }
313 
314  ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));
315 
316  ast_cli(a->fd, "Testing ast_sched_del() performance - timing how long it takes "
317  "to delete %u entries with random time intervals from 0 to 60 seconds\n", num);
318 
319  start = ast_tvnow();
320 
321  for (i = 0; i < num; i++) {
322  if (ast_sched_del(con, sched_ids[i]) == -1) {
323  ast_cli(a->fd, "Test failed - sched_del returned -1\n");
324  goto return_cleanup;
325  }
326  }
327 
328  ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));
329 
330 return_cleanup:
332  if (sched_ids) {
333  ast_free(sched_ids);
334  }
335 
336  return CLI_SUCCESS;
337 }
338 
339 static struct ast_cli_entry cli_sched[] = {
340  AST_CLI_DEFINE(handle_cli_sched_bench, "Benchmark ast_sched add/del performance"),
341 };
342 
343 static int unload_module(void)
344 {
345  AST_TEST_UNREGISTER(sched_test_order);
346  ast_cli_unregister_multiple(cli_sched, ARRAY_LEN(cli_sched));
347  return 0;
348 }
349 
350 static int load_module(void)
351 {
352  AST_TEST_REGISTER(sched_test_order);
353  ast_cli_register_multiple(cli_sched, ARRAY_LEN(cli_sched));
355 }
356 
357 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ast_sched performance test module");
static char * handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: test_sched.c:265
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int load_module(void)
Definition: test_sched.c:350
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:755
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
static int sched_order_2_cb(const void *data)
Definition: test_sched.c:65
Test Framework API.
AST_TEST_DEFINE(sched_test_order)
Definition: test_sched.c:107
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
Definition: cli.h:152
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
static int sched_order_7_cb(const void *data)
Definition: test_sched.c:95
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define DELAYED_SAME_EXPIRE
Utility functions.
int args
This gets set in ast_cli_register()
Definition: cli.h:185
static int order_check
Definition: test_sched.c:46
static int sched_order_5_cb(const void *data)
Definition: test_sched.c:83
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
const int fd
Definition: cli.h:159
integer order
Definition: analys.c:66
Scheduler Routines (derived from cheops)
long int ast_random(void)
Definition: main/utils.c:2064
static int sched_order_4_cb(const void *data)
Definition: test_sched.c:77
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
static int sched_order_1_cb(const void *data)
Definition: test_sched.c:59
static int sched_cb(const void *data)
Definition: test_sched.c:41
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
const char *const * argv
Definition: cli.h:161
static struct ast_cli_entry cli_sched[]
Definition: test_sched.c:339
static int unload_module(void)
Definition: test_sched.c:343
static int order_check_failed
Definition: test_sched.c:47
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
#define CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result
Deletes a scheduled event.
Definition: sched.c:610
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:565
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
static int sched_order_8_cb(const void *data)
Definition: test_sched.c:101
Definition: test.c:65
Standard Command Line Interface.
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:431
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:78
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269
static void sched_order_check(struct ast_test *test, int order)
Definition: test_sched.c:49
ast_test_result_state
Definition: test.h:200
static int sched_order_6_cb(const void *data)
Definition: test_sched.c:89
static int sched_order_3_cb(const void *data)
Definition: test_sched.c:71
static struct test_val a