PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/muesli-tests.c

#
C | 300 lines | 229 code | 29 blank | 42 comment | 32 complexity | d4eb7b7ba22fbf06bdb1d8e0232b74de MD5 | raw file
  1. // muesli.c -*- C -*-
  2. /* Interface to multiple interpreters.
  3. Copyright (C) 2008, 2009 University of Limerick
  4. This file is part of Muesli.
  5. Muesli is free software: you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation, either version 3 of the License, or (at your
  8. option) any later version.
  9. Muesli is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Muesli. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #ifndef _MUESLI_TESTS_
  17. #define _MUESLI_TESTS_
  18. #include "../config.h"
  19. #include "muesli.h"
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <getopt.h>
  24. #include <sys/times.h>
  25. #include <unistd.h>
  26. /**************/
  27. /* Self-tests */
  28. /**************/
  29. static int
  30. show_self_test_results(const char *label,
  31. evaluator_interface *evaluator,
  32. float reference_value,
  33. muesli_value_t result)
  34. {
  35. fprintf(stderr, "Test of %s evaluator:\n", label);
  36. if (evaluator == NULL) {
  37. fprintf(stderr, " Not present\n");
  38. return 1;
  39. } else {
  40. switch (result.type) {
  41. case muesli_value_none:
  42. fprintf(stderr, "The evaluator returned no result\n");
  43. break;
  44. case muesli_value_float:
  45. fprintf(stderr, " Number result is %f (%s)\n",
  46. result.data.as_float,
  47. (result.data.as_float == reference_value)
  48. ? "right" : "wrong");
  49. break;
  50. case muesli_value_string:
  51. fprintf(stderr, " String result is %s\n", result.data.as_string);
  52. break;
  53. case muesli_value_boolean:
  54. fprintf(stderr, " Boolean result is %s\n", result.data.as_int ? "true" : "false");
  55. break;
  56. default:
  57. break;
  58. }
  59. return ((result.data.as_float == reference_value)
  60. && (result.type == muesli_value_float));
  61. }
  62. }
  63. typedef float (*mc_test_function_t)(float, float, float);
  64. typedef struct evaluator_test {
  65. char *name;
  66. char *test_string;
  67. int reference;
  68. int verbosity;
  69. } evaluator_test;
  70. static int
  71. test_evaluator(evaluator_test *test, int seconds, float *evals_per_second_p, float seconds_per_base_loop)
  72. {
  73. char *name = test->name;
  74. char *test_string = test->test_string;
  75. int reference = test->reference;
  76. int verbosity = test->verbosity;
  77. evaluator_interface *evaluator = muesli_get_named_evaluator(name, 0);
  78. muesli_value_t result;
  79. result.data.as_float = 0.0;
  80. if (evaluator != NULL) {
  81. if (seconds > 0) {
  82. int ticks_per_sec = sysconf(_SC_CLK_TCK);
  83. printf("Timing %s on \"%s\" for %d seconds\n", name, test_string, seconds);
  84. #if 1
  85. // You won't often want this one enabled, I'd wager; but it can
  86. // be useful for tracing gradually leaking resources, etc:
  87. evaluator->language_verbosity = verbosity;
  88. #endif
  89. struct tms eval_time;
  90. times(&eval_time);
  91. clock_t start_time = eval_time.tms_utime + eval_time.tms_stime + eval_time.tms_cutime + eval_time.tms_cstime;
  92. clock_t now_time = start_time;
  93. clock_t end_time = start_time + seconds * ticks_per_sec;
  94. int count = 0;
  95. while (now_time < end_time) {
  96. result = (evaluator->eval_string)(evaluator,
  97. test_string,
  98. strlen(test_string),
  99. 0);
  100. count++;
  101. times(&eval_time);
  102. now_time = eval_time.tms_utime + eval_time.tms_stime + eval_time.tms_cutime + eval_time.tms_cstime;
  103. if (result.type == muesli_value_none) {
  104. printf("Problem in timing \"%s\"; it failed to return a result\n", name);
  105. break;
  106. }
  107. }
  108. float evals_per_second = ((float)count) / (float)seconds;
  109. float seconds_per_eval = 1.0 / evals_per_second;
  110. float adjusted_seconds_per_eval = seconds_per_eval - seconds_per_base_loop;
  111. float adjusted_evals_per_second = 1.0 / adjusted_seconds_per_eval;
  112. printf("%s: %7.0f per second (raw: %7.0f)\n", name, adjusted_evals_per_second, evals_per_second);
  113. if (evals_per_second_p) {
  114. *evals_per_second_p = evals_per_second;
  115. }
  116. } else {
  117. printf("Testing %s on \"%s\" at verbosity %d\n", name, test_string, verbosity);
  118. evaluator->language_verbosity = verbosity;
  119. result = (evaluator->eval_string)(evaluator,
  120. test_string,
  121. strlen(test_string),
  122. 0);
  123. }
  124. } else {
  125. printf("Did not find an evaluator called \"%s\"\n", name);
  126. }
  127. return show_self_test_results(name, evaluator, reference, result);
  128. }
  129. evaluator_test evaluator_zero_test = { (char*)"zero", (char*)"", 0, 0};
  130. evaluator_test evaluator_tests[] = {
  131. #if 0
  132. {(char*)"exec", (char*)"dc -e \"4 3 * 2 + p q\"", 14, 0},
  133. #endif
  134. #if 0
  135. {(char*)"pipe", (char*)"", 14, 0},
  136. {(char*)"custom", (char*)"", 14, 0},
  137. #endif
  138. #if defined(HAVE_LIBSIOD) || defined(HAVE_LIBULSIOD)
  139. {(char*)"siod", (char*)"(+ (* 4 3) 2)", 14, 0},
  140. #endif
  141. #ifdef HAVE_LIBPERL
  142. {(char*)"perl", (char*)"return (4 * 3 + 2)", 14, 0},
  143. #endif
  144. #ifdef HAVE_LIBLUA
  145. {(char*)"lua", (char*)"return (4 * 3 + 2)", 14, 0},
  146. #endif
  147. #ifdef HAVE_LIB_SLANG
  148. {(char*)"s-lang", (char*)"return (4 * 3 + 2)", 14, 0},
  149. #endif
  150. #ifdef HAVE_LIBPYTHON
  151. {(char*)"python", (char*)"return (4 * 3 + 2)", 14, 0}, // todo: what is the syntax of this?
  152. #endif
  153. #ifdef HAVE_LIBTCL
  154. {(char*)"tcl", (char*)"expr (4 * 3 + 2)", 14, 0},
  155. #endif
  156. #ifdef HAVE_LIBTCC0
  157. {(char*)"tcc", (char*)"expr (4 * 3 + 2)", 14, 0},
  158. #endif
  159. #ifdef HAVE_LIBOCTAVE
  160. {(char*)"octave", (char*)"(4 * 3 + 2)", 14, 0},
  161. #endif
  162. #ifdef HAVE_LIBMOZJS
  163. {(char*)"javascript", (char*)"(4 * 3 + 2)", 14, 0},
  164. #endif
  165. #ifdef HAVE_LIBSLANG
  166. {(char*)"slang", (char*)"expr (4 * 3 + 2)", 14, 0},
  167. #endif
  168. #ifdef HAVE_LIBPARROT
  169. {(char*)"parrot", (char*)"expr (4 * 3 + 2)", 14, 0},
  170. #endif
  171. #ifdef HAVE_LIBJVM
  172. {(char*)"jvm", (char*)"expr (4 * 3 + 2)", 14, 0},
  173. #endif
  174. {(char*)"stack-code", (char*)"cde*+", 14, 2},
  175. {NULL, NULL, 0}
  176. };
  177. int
  178. muesli_test_evaluators(int seconds)
  179. {
  180. #if 0
  181. const char* test_string ="(load \"eval-test.scm\" nil t\n(run-tests eval-tests)\n";
  182. muesli_eval_in_language("siod", test_string, strlen(test_string), NULL);
  183. #else
  184. int all_ok = 1;
  185. int i;
  186. muesli_value_t result;
  187. evaluator_interface *evaluator;
  188. // verbosity = verbose;
  189. float base_loops_per_second;
  190. float seconds_per_base_loop;
  191. test_evaluator(&evaluator_zero_test, seconds, &base_loops_per_second, 0.0);
  192. seconds_per_base_loop = 1.0 / base_loops_per_second;
  193. for (i = 0; evaluator_tests[i].name != NULL; i++) {
  194. test_evaluator(&evaluator_tests[i], seconds, NULL, seconds_per_base_loop);
  195. }
  196. #if 0
  197. evaluator = get_named_evaluator("stack-code");
  198. if (evaluator != NULL) {
  199. int all_fns_present = 1;
  200. if (evaluator->eval_clear == NULL) {
  201. fprintf(stderr, "No eval_clear defined for stack-code\n");
  202. all_fns_present = 0;
  203. }
  204. if (evaluator->eval_give == NULL) {
  205. fprintf(stderr, "No eval_give defined for stack-code\n");
  206. all_fns_present = 0;
  207. }
  208. if (evaluator->eval_given == NULL) {
  209. fprintf(stderr, "No eval_given defined for stack-code\n");
  210. all_fns_present = 0;
  211. }
  212. if (all_fns_present) {
  213. evaluator->setLanguageVerbosity(2);
  214. evaluator->eval_clear(evaluator);
  215. evaluator->eval_give(evaluator, 2.0);
  216. evaluator->eval_give(evaluator, 3.0);
  217. evaluator->eval_give(evaluator, 4.0);
  218. result.data.as_float = evaluator->eval_given(evaluator, "*+", 2);
  219. result.type = muesli_value_float;
  220. } else {
  221. result.type = muesli_value_none;
  222. }
  223. }
  224. all_ok &= show_self_test_results("stack-bytecode", evaluator, 14, result);
  225. #endif
  226. evaluator = muesli_get_named_evaluator("machine", 0);
  227. if (evaluator != NULL) {
  228. /*
  229. float
  230. test_fn(float a, float b, float c)
  231. {
  232. return a * b + c;
  233. }
  234. test_fn:
  235. 55 pushl %ebp
  236. 89E5 movl %esp, %ebp
  237. D94508 flds 8(%ebp)
  238. D84D0C fmuls 12(%ebp)
  239. D84510 fadds 16(%ebp)
  240. 5D popl %ebp
  241. C3 ret
  242. */
  243. char machine_eval_test_string[] = {
  244. 0x55, // pushl %ebp
  245. 0x89, 0xE5, // movl %esp, %ebp
  246. 0xD9, 0x45, 0x08, // flds 8(%ebp)
  247. 0xD8, 0x4D, 0x0C, // fmuls 12(%ebp)
  248. 0xD8, 0x45, 0x10, // fadds 16(%ebp)
  249. 0x5D, // popl %ebp
  250. 0xC3 // ret
  251. };
  252. #if 1
  253. result.data.as_float = ((mc_test_function_t)(machine_eval_test_string))(3.0, 4.0, 2.0);
  254. #else
  255. result = (evaluator->eval_string)(evaluator,
  256. machine_eval_test_string,
  257. sizeof(machine_eval_test_string), 0);
  258. #endif
  259. }
  260. all_ok &= show_self_test_results("machine", evaluator, 14, result);
  261. printf(all_ok ? "All tests passed\n" : "At least one test failed\n");
  262. #endif
  263. return all_ok;
  264. }
  265. #endif
  266. /* muesli-tests.c ends here */