test_sched.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. /*! \file
  19. *
  20. * \brief ast_sched performance test module
  21. *
  22. * \author Russell Bryant <russell@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <depend>TEST_FRAMEWORK</depend>
  26. <support_level>core</support_level>
  27. ***/
  28. #include "asterisk.h"
  29. #include <inttypes.h>
  30. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  31. #include "asterisk/module.h"
  32. #include "asterisk/utils.h"
  33. #include "asterisk/sched.h"
  34. #include "asterisk/test.h"
  35. #include "asterisk/cli.h"
  36. static int sched_cb(const void *data)
  37. {
  38. return 0;
  39. }
  40. static int order_check;
  41. static int order_check_failed;
  42. static void sched_order_check(struct ast_test *test, int order)
  43. {
  44. ++order_check;
  45. if (order_check != order) {
  46. ast_test_status_update(test, "Unexpected execution order: expected:%d got:%d\n",
  47. order, order_check);
  48. order_check_failed = 1;
  49. }
  50. }
  51. static int sched_order_1_cb(const void *data)
  52. {
  53. sched_order_check((void *) data, 1);
  54. return 0;
  55. }
  56. static int sched_order_2_cb(const void *data)
  57. {
  58. sched_order_check((void *) data, 2);
  59. return 0;
  60. }
  61. static int sched_order_3_cb(const void *data)
  62. {
  63. sched_order_check((void *) data, 3);
  64. return 0;
  65. }
  66. static int sched_order_4_cb(const void *data)
  67. {
  68. sched_order_check((void *) data, 4);
  69. return 0;
  70. }
  71. static int sched_order_5_cb(const void *data)
  72. {
  73. sched_order_check((void *) data, 5);
  74. return 0;
  75. }
  76. static int sched_order_6_cb(const void *data)
  77. {
  78. sched_order_check((void *) data, 6);
  79. return 0;
  80. }
  81. static int sched_order_7_cb(const void *data)
  82. {
  83. sched_order_check((void *) data, 7);
  84. return 0;
  85. }
  86. static int sched_order_8_cb(const void *data)
  87. {
  88. sched_order_check((void *) data, 8);
  89. return 0;
  90. }
  91. AST_TEST_DEFINE(sched_test_order)
  92. {
  93. struct ast_sched_context *con;
  94. enum ast_test_result_state res = AST_TEST_FAIL;
  95. int id1, id2, id3, wait;
  96. switch (cmd) {
  97. case TEST_INIT:
  98. info->name = "sched_test_order";
  99. info->category = "/main/sched/";
  100. info->summary = "Test ordering of events in the scheduler API";
  101. info->description =
  102. "This test ensures that events are properly ordered by the "
  103. "time they are scheduled to execute in the scheduler API.";
  104. return AST_TEST_NOT_RUN;
  105. case TEST_EXECUTE:
  106. break;
  107. }
  108. if (!(con = ast_sched_context_create())) {
  109. ast_test_status_update(test,
  110. "Test failed - could not create scheduler context\n");
  111. return AST_TEST_FAIL;
  112. }
  113. /* Add 3 scheduler entries, and then remove them, ensuring that the result
  114. * of ast_sched_wait() looks appropriate at each step along the way. */
  115. if ((wait = ast_sched_wait(con)) != -1) {
  116. ast_test_status_update(test,
  117. "ast_sched_wait() should have returned -1, returned '%d'\n",
  118. wait);
  119. goto return_cleanup;
  120. }
  121. if ((id1 = ast_sched_add(con, 100000, sched_cb, NULL)) == -1) {
  122. ast_test_status_update(test, "Failed to add scheduler entry\n");
  123. goto return_cleanup;
  124. }
  125. if ((wait = ast_sched_wait(con)) > 100000) {
  126. ast_test_status_update(test,
  127. "ast_sched_wait() should have returned <= 100000, returned '%d'\n",
  128. wait);
  129. goto return_cleanup;
  130. }
  131. if ((id2 = ast_sched_add(con, 10000, sched_cb, NULL)) == -1) {
  132. ast_test_status_update(test, "Failed to add scheduler entry\n");
  133. goto return_cleanup;
  134. }
  135. if ((wait = ast_sched_wait(con)) > 10000) {
  136. ast_test_status_update(test,
  137. "ast_sched_wait() should have returned <= 10000, returned '%d'\n",
  138. wait);
  139. goto return_cleanup;
  140. }
  141. if ((id3 = ast_sched_add(con, 1000, sched_cb, NULL)) == -1) {
  142. ast_test_status_update(test, "Failed to add scheduler entry\n");
  143. goto return_cleanup;
  144. }
  145. if ((wait = ast_sched_wait(con)) > 1000) {
  146. ast_test_status_update(test,
  147. "ast_sched_wait() should have returned <= 1000, returned '%d'\n",
  148. wait);
  149. goto return_cleanup;
  150. }
  151. if (ast_sched_del(con, id3) == -1) {
  152. ast_test_status_update(test, "Failed to remove scheduler entry\n");
  153. goto return_cleanup;
  154. }
  155. if ((wait = ast_sched_wait(con)) <= 1000) {
  156. ast_test_status_update(test,
  157. "ast_sched_wait() should have returned > 1000, returned '%d'\n",
  158. wait);
  159. goto return_cleanup;
  160. }
  161. if (ast_sched_del(con, id2) == -1) {
  162. ast_test_status_update(test, "Failed to remove scheduler entry\n");
  163. goto return_cleanup;
  164. }
  165. if ((wait = ast_sched_wait(con)) <= 10000) {
  166. ast_test_status_update(test,
  167. "ast_sched_wait() should have returned > 10000, returned '%d'\n",
  168. wait);
  169. goto return_cleanup;
  170. }
  171. if (ast_sched_del(con, id1) == -1) {
  172. ast_test_status_update(test, "Failed to remove scheduler entry\n");
  173. goto return_cleanup;
  174. }
  175. if ((wait = ast_sched_wait(con)) != -1) {
  176. ast_test_status_update(test,
  177. "ast_sched_wait() should have returned -1, returned '%d'\n",
  178. wait);
  179. goto return_cleanup;
  180. }
  181. /*
  182. * Schedule immediate and delayed entries to check the order
  183. * that they get executed. They must get executed at the
  184. * time they expire in the order they were added.
  185. */
  186. #define DELAYED_SAME_EXPIRE 300 /* ms */
  187. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_1_cb, test), res, return_cleanup);
  188. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_1_cb, test), res, return_cleanup);
  189. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_2_cb, test), res, return_cleanup);
  190. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_2_cb, test), res, return_cleanup);
  191. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_3_cb, test), res, return_cleanup);
  192. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_3_cb, test), res, return_cleanup);
  193. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_4_cb, test), res, return_cleanup);
  194. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_4_cb, test), res, return_cleanup);
  195. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_5_cb, test), res, return_cleanup);
  196. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_5_cb, test), res, return_cleanup);
  197. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_6_cb, test), res, return_cleanup);
  198. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_6_cb, test), res, return_cleanup);
  199. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_7_cb, test), res, return_cleanup);
  200. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_7_cb, test), res, return_cleanup);
  201. ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_8_cb, test), res, return_cleanup);
  202. /* Check order of scheduled immediate entries. */
  203. order_check = 0;
  204. order_check_failed = 0;
  205. usleep(50 * 1000);/* Ensure that all the immediate entries are ready to expire */
  206. ast_test_validate_cleanup(test, 7 == ast_sched_runq(con), res, return_cleanup);
  207. ast_test_validate_cleanup(test, !order_check_failed, res, return_cleanup);
  208. /* Check order of scheduled entries expiring at the same time. */
  209. order_check = 0;
  210. order_check_failed = 0;
  211. usleep((DELAYED_SAME_EXPIRE + 50) * 1000);/* Ensure that all the delayed entries are ready to expire */
  212. ast_test_validate_cleanup(test, 8 == ast_sched_runq(con), res, return_cleanup);
  213. ast_test_validate_cleanup(test, !order_check_failed, res, return_cleanup);
  214. if ((wait = ast_sched_wait(con)) != -1) {
  215. ast_test_status_update(test,
  216. "ast_sched_wait() should have returned -1, returned '%d'\n",
  217. wait);
  218. goto return_cleanup;
  219. }
  220. res = AST_TEST_PASS;
  221. return_cleanup:
  222. ast_sched_context_destroy(con);
  223. return res;
  224. }
  225. static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  226. {
  227. struct ast_sched_context *con;
  228. struct timeval start;
  229. unsigned int num, i;
  230. int *sched_ids = NULL;
  231. switch (cmd) {
  232. case CLI_INIT:
  233. e->command = "sched benchmark";
  234. e->usage = ""
  235. "Usage: sched benchmark <num>\n"
  236. "";
  237. return NULL;
  238. case CLI_GENERATE:
  239. return NULL;
  240. }
  241. if (a->argc != e->args + 1) {
  242. return CLI_SHOWUSAGE;
  243. }
  244. if (sscanf(a->argv[e->args], "%u", &num) != 1) {
  245. return CLI_SHOWUSAGE;
  246. }
  247. if (!(con = ast_sched_context_create())) {
  248. ast_cli(a->fd, "Test failed - could not create scheduler context\n");
  249. return CLI_FAILURE;
  250. }
  251. if (!(sched_ids = ast_malloc(sizeof(*sched_ids) * num))) {
  252. ast_cli(a->fd, "Test failed - memory allocation failure\n");
  253. goto return_cleanup;
  254. }
  255. ast_cli(a->fd, "Testing ast_sched_add() performance - timing how long it takes "
  256. "to add %u entries at random time intervals from 0 to 60 seconds\n", num);
  257. start = ast_tvnow();
  258. for (i = 0; i < num; i++) {
  259. long when = labs(ast_random()) % 60000;
  260. if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) {
  261. ast_cli(a->fd, "Test failed - sched_add returned -1\n");
  262. goto return_cleanup;
  263. }
  264. }
  265. ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));
  266. ast_cli(a->fd, "Testing ast_sched_del() performance - timing how long it takes "
  267. "to delete %u entries with random time intervals from 0 to 60 seconds\n", num);
  268. start = ast_tvnow();
  269. for (i = 0; i < num; i++) {
  270. if (ast_sched_del(con, sched_ids[i]) == -1) {
  271. ast_cli(a->fd, "Test failed - sched_del returned -1\n");
  272. goto return_cleanup;
  273. }
  274. }
  275. ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start));
  276. return_cleanup:
  277. ast_sched_context_destroy(con);
  278. if (sched_ids) {
  279. ast_free(sched_ids);
  280. }
  281. return CLI_SUCCESS;
  282. }
  283. static struct ast_cli_entry cli_sched[] = {
  284. AST_CLI_DEFINE(handle_cli_sched_bench, "Benchmark ast_sched add/del performance"),
  285. };
  286. static int unload_module(void)
  287. {
  288. AST_TEST_UNREGISTER(sched_test_order);
  289. ast_cli_unregister_multiple(cli_sched, ARRAY_LEN(cli_sched));
  290. return 0;
  291. }
  292. static int load_module(void)
  293. {
  294. AST_TEST_REGISTER(sched_test_order);
  295. ast_cli_register_multiple(cli_sched, ARRAY_LEN(cli_sched));
  296. return AST_MODULE_LOAD_SUCCESS;
  297. }
  298. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ast_sched performance test module");