1
0

rules.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright © 2012 Ran Benita <ran234@gmail.com>
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include <getopt.h>
  7. #include <stdlib.h>
  8. #include "xkbcommon/xkbcommon.h"
  9. #include "../test/test.h"
  10. #include "xkbcomp/rules.h"
  11. #include "bench.h"
  12. static const unsigned int DEFAULT_ITERATIONS = 20000;
  13. static const double DEFAULT_STDEV = 0.05;
  14. static void
  15. usage(char **argv)
  16. {
  17. printf("Usage: %s [OPTIONS]\n"
  18. "\n"
  19. "Benchmark compilation of the given RMLVO\n"
  20. "\n"
  21. "Options:\n"
  22. " --help\n"
  23. " Print this help and exit\n"
  24. " --iter\n"
  25. " Exact number of iterations to run\n"
  26. " --stdev\n"
  27. " Minimal relative standard deviation (percentage) to reach.\n"
  28. " (default: %f)\n"
  29. "Note: --iter and --stdev are mutually exclusive.\n"
  30. "\n"
  31. "XKB-specific options:\n"
  32. " --rules <rules>\n"
  33. " The XKB ruleset (default: '%s')\n"
  34. " --model <model>\n"
  35. " The XKB model (default: '%s')\n"
  36. " --layout <layout>\n"
  37. " The XKB layout (default: '%s')\n"
  38. " --variant <variant>\n"
  39. " The XKB layout variant (default: '%s')\n"
  40. " --options <options>\n"
  41. " The XKB options (default: '%s')\n"
  42. "\n",
  43. argv[0], DEFAULT_STDEV * 100, DEFAULT_XKB_RULES,
  44. DEFAULT_XKB_MODEL, DEFAULT_XKB_LAYOUT,
  45. DEFAULT_XKB_VARIANT ? DEFAULT_XKB_VARIANT : "<none>",
  46. DEFAULT_XKB_OPTIONS ? DEFAULT_XKB_OPTIONS : "<none>");
  47. }
  48. int
  49. main(int argc, char *argv[])
  50. {
  51. struct bench bench;
  52. struct bench_time elapsed;
  53. struct estimate est;
  54. bool explicit_iterations = false;
  55. struct xkb_rule_names rmlvo = {
  56. .rules = DEFAULT_XKB_RULES,
  57. .model = DEFAULT_XKB_MODEL,
  58. /* layout and variant are tied together, so we either get user-supplied for
  59. * both or default for both, see below */
  60. .layout = NULL,
  61. .variant = NULL,
  62. .options = DEFAULT_XKB_OPTIONS,
  63. };
  64. unsigned int max_iterations = DEFAULT_ITERATIONS;
  65. double stdev = DEFAULT_STDEV;
  66. enum options {
  67. OPT_RULES,
  68. OPT_MODEL,
  69. OPT_LAYOUT,
  70. OPT_VARIANT,
  71. OPT_OPTION,
  72. OPT_ITERATIONS,
  73. OPT_STDEV,
  74. };
  75. static struct option opts[] = {
  76. {"help", no_argument, 0, 'h'},
  77. {"rules", required_argument, 0, OPT_RULES},
  78. {"model", required_argument, 0, OPT_MODEL},
  79. {"layout", required_argument, 0, OPT_LAYOUT},
  80. {"variant", required_argument, 0, OPT_VARIANT},
  81. {"options", required_argument, 0, OPT_OPTION},
  82. {"iter", required_argument, 0, OPT_ITERATIONS},
  83. {"stdev", required_argument, 0, OPT_STDEV},
  84. {0, 0, 0, 0},
  85. };
  86. while (1) {
  87. int c;
  88. int option_index = 0;
  89. c = getopt_long(argc, argv, "h", opts, &option_index);
  90. if (c == -1)
  91. break;
  92. switch (c) {
  93. case 'h':
  94. usage(argv);
  95. exit(EXIT_SUCCESS);
  96. case OPT_RULES:
  97. rmlvo.rules = optarg;
  98. break;
  99. case OPT_MODEL:
  100. rmlvo.model = optarg;
  101. break;
  102. case OPT_LAYOUT:
  103. rmlvo.layout = optarg;
  104. break;
  105. case OPT_VARIANT:
  106. rmlvo.variant = optarg;
  107. break;
  108. case OPT_OPTION:
  109. rmlvo.options = optarg;
  110. break;
  111. case OPT_ITERATIONS:
  112. if (max_iterations == 0) {
  113. usage(argv);
  114. exit(EXIT_INVALID_USAGE);
  115. }
  116. {
  117. errno = 0;
  118. char *endp = optarg;
  119. const unsigned long raw = strtoul(optarg, &endp, 10);
  120. if (errno || optarg == endp || *endp != '\0' ||
  121. !raw || raw > UINT_MAX) {
  122. fprintf(stderr,
  123. "ERROR: invalid 'iter' parameter; "
  124. "using default: %u\n", DEFAULT_ITERATIONS);
  125. max_iterations = DEFAULT_ITERATIONS;
  126. } else {
  127. max_iterations = (unsigned int)raw;
  128. }
  129. }
  130. explicit_iterations = true;
  131. break;
  132. case OPT_STDEV:
  133. if (explicit_iterations) {
  134. usage(argv);
  135. exit(EXIT_INVALID_USAGE);
  136. }
  137. {
  138. errno = 0;
  139. char *endp = optarg;
  140. stdev = strtod(optarg, &endp) / 100;
  141. if (errno || optarg == endp || *endp != '\0' || stdev <= 0) {
  142. fprintf(stderr,
  143. "ERROR: invalid 'stdev' parameter; "
  144. "using default: %.3f\n", DEFAULT_STDEV);
  145. stdev = DEFAULT_STDEV;
  146. }
  147. }
  148. max_iterations = 0;
  149. break;
  150. default:
  151. usage(argv);
  152. exit(EXIT_INVALID_USAGE);
  153. }
  154. }
  155. /* Now fill in the layout */
  156. if (!rmlvo.layout || !*rmlvo.layout) {
  157. if (rmlvo.variant && *rmlvo.variant) {
  158. fprintf(stderr, "Error: a variant requires a layout\n");
  159. return EXIT_INVALID_USAGE;
  160. }
  161. rmlvo.layout = DEFAULT_XKB_LAYOUT;
  162. rmlvo.variant = DEFAULT_XKB_VARIANT;
  163. }
  164. struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  165. if (!context)
  166. exit(EXIT_FAILURE);
  167. xkb_enable_quiet_logging(context);
  168. if (explicit_iterations) {
  169. stdev = 0;
  170. bench_start2(&bench);
  171. for (unsigned int i = 0; i < max_iterations; i++) {
  172. struct xkb_component_names kccgst;
  173. assert(xkb_components_from_rules_names(context, &rmlvo, &kccgst, NULL));
  174. free(kccgst.keycodes);
  175. free(kccgst.types);
  176. free(kccgst.compatibility);
  177. free(kccgst.symbols);
  178. free(kccgst.geometry);
  179. }
  180. bench_stop2(&bench);
  181. bench_elapsed(&bench, &elapsed);
  182. est.elapsed = (bench_time_elapsed_nanoseconds(&elapsed)) / max_iterations;
  183. est.stdev = 0;
  184. } else {
  185. bench_start2(&bench);
  186. BENCH(stdev, max_iterations, elapsed, est,
  187. struct xkb_component_names kccgst;
  188. assert(xkb_components_from_rules_names(context, &rmlvo, &kccgst, NULL));
  189. free(kccgst.keycodes);
  190. free(kccgst.types);
  191. free(kccgst.compatibility);
  192. free(kccgst.symbols);
  193. free(kccgst.geometry);
  194. );
  195. bench_stop2(&bench);
  196. }
  197. struct bench_time total_elapsed;
  198. bench_elapsed(&bench, &total_elapsed);
  199. if (explicit_iterations) {
  200. fprintf(stderr,
  201. "mean: %lld µs; compiled %u rules in %ld.%06lds\n",
  202. est.elapsed / 1000, max_iterations,
  203. total_elapsed.seconds, total_elapsed.nanoseconds / 1000);
  204. } else {
  205. fprintf(stderr,
  206. "mean: %lld µs; stdev: %Lf%% (target: %f%%); "
  207. "last run: compiled %u rules in %ld.%06lds; "
  208. "total time: %ld.%06lds\n", est.elapsed / 1000,
  209. (long double) est.stdev * 100.0 / (long double) est.elapsed,
  210. stdev * 100,
  211. max_iterations, elapsed.seconds, elapsed.nanoseconds / 1000,
  212. total_elapsed.seconds, total_elapsed.nanoseconds / 1000);
  213. }
  214. xkb_context_unref(context);
  215. return EXIT_SUCCESS;
  216. }