custom-parsers.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * Copyright © 2025 Pierre Le Marre <dev@wismill.eu>
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include <fcntl.h>
  7. #include <time.h>
  8. #include <getopt.h>
  9. #include <stdint.h>
  10. #include "utils.h"
  11. #include "utils-numbers.h"
  12. #include "bench.h"
  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. " --stdev\n"
  25. " Minimal relative standard deviation (percentage) to reach.\n"
  26. " (default: %f)\n"
  27. "\n",
  28. argv[0], DEFAULT_STDEV * 100);
  29. }
  30. static void
  31. print_stats(double stdev, unsigned int max_iterations,
  32. struct bench_time *elapsed, struct bench *bench,
  33. struct estimate *est)
  34. {
  35. struct bench_time total_elapsed;
  36. bench_elapsed(bench, &total_elapsed);
  37. fprintf(stderr,
  38. "mean: %lld µs; stdev: %Lf%% (target: %f%%); "
  39. "last run: parsed %u times in %ld.%06lds; "
  40. "total time: %ld.%06lds\n", est->elapsed / 1000,
  41. (long double) est->stdev * 100.0 / (long double) est->elapsed,
  42. stdev * 100,
  43. max_iterations, elapsed->seconds, elapsed->nanoseconds / 1000,
  44. total_elapsed.seconds, total_elapsed.nanoseconds / 1000);
  45. }
  46. /* NOTE: Old parser, for comparison */
  47. static bool
  48. parse_keysym_hex(const char *s, uint32_t *out)
  49. {
  50. uint32_t result = 0;
  51. unsigned int i;
  52. for (i = 0; i < 8 && s[i] != '\0'; i++) {
  53. result <<= 4;
  54. if ('0' <= s[i] && s[i] <= '9')
  55. result += s[i] - '0';
  56. else if ('a' <= s[i] && s[i] <= 'f')
  57. result += 10 + s[i] - 'a';
  58. else if ('A' <= s[i] && s[i] <= 'F')
  59. result += 10 + s[i] - 'A';
  60. else
  61. return false;
  62. }
  63. *out = result;
  64. return s[i] == '\0' && i > 0;
  65. }
  66. int
  67. main(int argc, char **argv)
  68. {
  69. struct bench bench;
  70. struct bench_time elapsed;
  71. struct estimate est;
  72. int ret = 0;
  73. double stdev = DEFAULT_STDEV;
  74. enum options {
  75. OPT_STDEV,
  76. };
  77. static struct option opts[] = {
  78. {"help", no_argument, 0, 'h'},
  79. {"stdev", required_argument, 0, OPT_STDEV},
  80. {0, 0, 0, 0},
  81. };
  82. while (1) {
  83. int c;
  84. int option_index = 0;
  85. c = getopt_long(argc, argv, "h", opts, &option_index);
  86. if (c == -1)
  87. break;
  88. switch (c) {
  89. case 'h':
  90. usage(argv);
  91. exit(EXIT_SUCCESS);
  92. case OPT_STDEV:
  93. {
  94. errno = 0;
  95. char *endp = optarg;
  96. stdev = strtod(optarg, &endp) / 100;
  97. if (errno || optarg == endp || *endp != '\0' || stdev <= 0){
  98. fprintf(stderr,
  99. "ERROR: invalid 'stdev' parameter; "
  100. "using default: %.3f\n", DEFAULT_STDEV);
  101. stdev = DEFAULT_STDEV;
  102. }
  103. }
  104. break;
  105. default:
  106. usage(argv);
  107. exit(EXIT_INVALID_USAGE);
  108. }
  109. }
  110. FILE *file = fopen(__FILE__, "r");
  111. assert(file);
  112. size_t size = 0;
  113. char *content = NULL;
  114. map_file(file, &content, &size);
  115. assert(content);
  116. /*
  117. * Some numbers for the parsers, do not delete.
  118. *
  119. * 0x0000000000000000 0x0000000000000002 0x0000000000000003
  120. * 0x0000000000000001 0x00000000000000FE 0x00000000000001FE
  121. * 0x000000000000000A 0x0000000000000200 0x0000000000000400
  122. * 0x00000000000000FF 0x0000000000020000 0x0000000000040000
  123. * 0x0000000000000100 0x0000000002000000 0x0000000004000000
  124. * 0x0000000000001000 0x0000000200000000 0x0000000400000000
  125. * 0x0000000000010000 0x0000020000000000 0x0000040000000000
  126. * 0x0000000001000000 0x0002000000000000 0x0004000000000000
  127. * 0x0000000100000000 0x0200000000000000 0x0400000000000000
  128. * 0x0000010000000000 0x2000000000000000 0x4000000000000001
  129. * 0x0001000000000000 0x4000000000000000 0x3FFFFFFFFFFFFFFF
  130. * 0x0100000000000000 0x6FFFFFFFFFFFFFFF 0xA000000000000000
  131. * 0x1000000000000000 0x9000000000000000 0xCFFFFFFFFFFFFFFF
  132. * 0x7FFFFFFFFFFFFFFF 0xEFFFFFFFFFFFFFFF 0xD000000000000000
  133. * 0x8000000000000000 0xF000000000000000 0xE000000000000000
  134. * 0xFFFFFFFFFFFFFFFF 0x1A2B3C4D5E6F7089 0x0807060504030201
  135. * 0x123456789ABCDEF0 0x89706F5E4D3C2B1A 0xF1E2D3C4B5A69788
  136. * 0xFEDCBA9876543210 0x5A5A5A5A5A5A5A5A 0x6B6B6B6B6B6B6B6B
  137. * 0xABABABABABABABAB 0xA5A5A5A5A5A5A5A5 0xB6B6B6B6B6B6B6B6
  138. * 0xCDCDCDCDCDCDCDCD 0xC3D2E1F00F1E2D3C 0x1122334455667788
  139. * 0x0123456789ABCDEF 0x3C2D1E0F0FE1D2C3 0x8877665544332211
  140. * 0x9876543210FEDCBA 0x0000000080000000 0x0000000040000000
  141. * 0x00000000FFFFFFFF 0x8000000000000000 0x4000000000000000
  142. * 0xFFFFFFFF00000000 0x6666666666666666 0x7777777777777777
  143. * 0x5555555555555555 0x9999999999999999 0x8888888888888888
  144. * 0x0AAAAAAAAAAAAAAA 0x0000000200000002 0x0000000300000003
  145. * 0x0000000100000001 0x4444444444444444 0x5F5F5F5F5F5F5F5F
  146. * 0x1111111111111111 0xBBBBBBBBBBBBBBBB 0xC0C0C0C0C0C0C0C0
  147. * 0x2222222222222222 0xCCCCCCCCCCCCCCCC 0xE1E1E1E1E1E1E1E1
  148. * 0x3333333333333333 0xDDDDDDDDDDDDDDDD 0xF2F2F2F2F2F2F2F2
  149. * 0x1A3F5C7E9D2B4A68 0x8E6D4C2B1A0F9E7D 0x3F9A8B7C6D5E4F2A
  150. * 0x7B6C5D4E3F2A1B09 0x2D4E6F8A9C0B1D3E 0x5A4B3C2D1E0F9A8B
  151. * 0x9E8D7C6B5A4F3E2D 0x1C3E5F7A9D0B2E4F 0x6D5E4F3A2B1C0D9E
  152. * 0xA0B1C2D3E4F56789 0x3B4D5F6E7A8C9D0E 0x7E8F9A0B1C2D3E4F
  153. * 0x2C3D4E5F6A7B8C9D 0x9A8B7C6D5E4F3A2B 0x1E2D3C4B5A6F7E8D
  154. * 0x4D5E6F7A8B9C0D1E 0x3A2B1C0D9E8F7A6B 0x8C9D0E1F2A3B4C5D
  155. * 0x5F6E7D8C9B0A1F2E 0x0A1B2C3D4E5F6A7B 0x9C0D1E2F3A4B5C6D
  156. * 0x6A7B8C9D0E1F2A3B 0x2E3F4A5B6C7D8E9F 0x1D2C3B4A5F6E7D8C
  157. * 0x7D8E9F0A1B2C3D4E 0x4B5C6D7E8F9A0B1C 0x0F1E2D3C4B5A6F7E
  158. * 0x8B9C0D1E2F3A4B5C 0x5A6B7C8D9E0F1A2B 0x3C4D5E6F7A8B9C0D
  159. * 0x9D0E1F2A3B4C5D6E 0x6B7C8D9E0F1A2B3C 0x2A3B4C5D6E7F8A9B
  160. * 0x0E1F2A3B4C5D6E7F 0x7C8D9E0F1A2B3C4D 0x4A5B6C7D8E9F0A1B
  161. * 0x1F2A3B4C5D6E7F8A 0x8D9E0F1A2B3C4D5E 0x5B6C7D8E9F0A1B2C
  162. * 0x2B3C4D5E6F7A8B9C 0x9E0F1A2B3C4D5E6F 0x6C7D8E9F0A1B2C3D
  163. * 0x0A1B2C3D4E5F6A7B 0x7E8F9A0B1C2D3E4F 0x3D4E5F6A7B8C9D0E
  164. * 0x1B2C3D4E5F6A7B8C 0x8F9A0B1C2D3E4F5A 0x4E5F6A7B8C9D0E1F
  165. * 0x3A4B5C6D7E8F9A0B 0x9F0A1B2C3D4E5F6A 0x5C6D7E8F9A0B1C2D
  166. * 0x0B1C2D3E4F5A6B7C 0x7F8A9B0C1D2E3F4A 0x2D3E4F5A6B7C8D9E
  167. * 0x1C2D3E4F5A6B7C8D 0x9A0B1C2D3E4F5A6B 0x4F5A6B7C8D9E0F1A
  168. * 0x6D7E8F9A0B1C2D3E 0x0C1D2E3F4A5B6C7D 0x3B4C5D6E7F8A9B0C
  169. * 0x8E9F0A1B2C3D4E5F 0x5D6E7F8A9B0C1D2E 0x1A2B3C4D5E6F7A8B
  170. * 0x0D1E2F3A4B5C6D7E 0x7A8B9C0D1E2F3A4B 0x2E3F4A5B6C7D8E9F
  171. * 0x9B0C1D2E3F4A5B6C 0x6E7F8A9B0C1D2E3F 0x0F1A2B3C4D5E6F7A
  172. */
  173. volatile uint32_t __attribute__((unused)) dummy32 = 0;
  174. volatile uint64_t __attribute__((unused)) dummy64 = 0;
  175. unsigned int max_iterations;
  176. printf("*** parse_hex_to_uint32_t ***\n");
  177. bench_start2(&bench);
  178. BENCH(stdev, max_iterations, elapsed, est,
  179. for (size_t n = 0; n < size; n++) {
  180. uint32_t val = 0;
  181. parse_hex_to_uint32_t(content + n, 8, &val);
  182. dummy32 += val;
  183. }
  184. );
  185. bench_stop2(&bench);
  186. print_stats(stdev, max_iterations, &elapsed, &bench, &est);
  187. printf("*** parse_keysym_hex ***\n");
  188. bench_start2(&bench);
  189. BENCH(stdev, max_iterations, elapsed, est,
  190. for (size_t n = 0; n < size; n++) {
  191. uint32_t val = 0;
  192. parse_keysym_hex(content + n, &val);
  193. dummy32 += val;
  194. }
  195. );
  196. bench_stop2(&bench);
  197. print_stats(stdev, max_iterations, &elapsed, &bench, &est);
  198. printf("*** parse_dec_to_uint64_t ***\n");
  199. bench_start2(&bench);
  200. BENCH(stdev, max_iterations, elapsed, est,
  201. for (size_t n = 0; n < size; n++) {
  202. uint64_t val = 0;
  203. parse_dec_to_uint64_t(content + n, size - n, &val);
  204. dummy64 += val;
  205. }
  206. );
  207. bench_stop2(&bench);
  208. print_stats(stdev, max_iterations, &elapsed, &bench, &est);
  209. printf("*** strtol, base 10 ***\n");
  210. bench_start2(&bench);
  211. BENCH(stdev, max_iterations, elapsed, est,
  212. for (size_t n = 0; n < size; n++) {
  213. dummy64 += (uint64_t)strtol(content + n, NULL, 10);
  214. }
  215. );
  216. bench_stop2(&bench);
  217. print_stats(stdev, max_iterations, &elapsed, &bench, &est);
  218. printf("*** parse_hex_to_uint64_t ***\n");
  219. bench_start2(&bench);
  220. BENCH(stdev, max_iterations, elapsed, est,
  221. for (size_t n = 0; n < size; n++) {
  222. uint64_t val = 0;
  223. parse_hex_to_uint64_t(content + n, size - n, &val);
  224. dummy64 += val;
  225. }
  226. );
  227. bench_stop2(&bench);
  228. print_stats(stdev, max_iterations, &elapsed, &bench, &est);
  229. printf("*** strtol, base 16 ***\n");
  230. bench_start2(&bench);
  231. BENCH(stdev, max_iterations, elapsed, est,
  232. for (size_t n = 0; n < size; n++) {
  233. dummy64 += (uint64_t)strtol(content + n, NULL, 16);
  234. }
  235. );
  236. bench_stop2(&bench);
  237. print_stats(stdev, max_iterations, &elapsed, &bench, &est);
  238. unmap_file(content, size);
  239. fclose(file);
  240. return ret;
  241. }