bench.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright © 2015 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
  3. * Copyright © 2015 Ran Benita <ran234@gmail.com>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. #include "config.h"
  7. #include <assert.h>
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include "bench.h"
  11. #include "../src/utils.h"
  12. #ifndef _WIN32
  13. #include <time.h>
  14. #include <sys/time.h>
  15. #else
  16. #include <windows.h>
  17. #include <stdint.h>
  18. struct timeval {
  19. long tv_sec, tv_usec;
  20. };
  21. static int
  22. gettimeofday(struct timeval *tv, void *unused)
  23. {
  24. static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
  25. SYSTEMTIME system_time;
  26. FILETIME file_time;
  27. uint64_t t;
  28. GetSystemTime(&system_time);
  29. SystemTimeToFileTime(&system_time, &file_time);
  30. t = (uint64_t) file_time.dwLowDateTime;
  31. t += ((uint64_t) file_time.dwHighDateTime) << 32;
  32. tv->tv_sec = (long) ((t - EPOCH) / 10000000L);
  33. tv->tv_usec = (long) (system_time.wMilliseconds * 1000);
  34. return 0;
  35. }
  36. #endif
  37. void
  38. bench_start(struct bench *bench)
  39. {
  40. struct timeval val;
  41. (void) gettimeofday(&val, NULL);
  42. bench->start = (struct bench_time) {
  43. .seconds = val.tv_sec,
  44. .nanoseconds = val.tv_usec * 1000,
  45. };
  46. }
  47. void
  48. bench_stop(struct bench *bench)
  49. {
  50. struct timeval val;
  51. (void) gettimeofday(&val, NULL);
  52. bench->stop = (struct bench_time) {
  53. .seconds = val.tv_sec,
  54. .nanoseconds = val.tv_usec * 1000,
  55. };
  56. }
  57. #ifndef _WIN32
  58. static const clockid_t best_clock =
  59. #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
  60. CLOCK_PROCESS_CPUTIME_ID
  61. #elif defined(HAVE_CLOCK_MONOTONIC)
  62. CLOCK_MONOTONIC
  63. #else
  64. CLOCK_REALTIME
  65. #endif
  66. ;
  67. void
  68. bench_start2(struct bench *bench)
  69. {
  70. struct timespec t;
  71. (void) clock_gettime(best_clock, &t);
  72. bench->start = (struct bench_time) {
  73. .seconds = t.tv_sec,
  74. .nanoseconds = t.tv_nsec,
  75. };
  76. }
  77. void
  78. bench_stop2(struct bench *bench)
  79. {
  80. struct timespec t;
  81. (void) clock_gettime(best_clock, &t);
  82. bench->stop = (struct bench_time) {
  83. .seconds = t.tv_sec,
  84. .nanoseconds = t.tv_nsec,
  85. };
  86. }
  87. #endif
  88. void
  89. bench_elapsed(const struct bench *bench, struct bench_time *result)
  90. {
  91. result->seconds = bench->stop.seconds - bench->start.seconds;
  92. result->nanoseconds = bench->stop.nanoseconds - bench->start.nanoseconds;
  93. if (result->nanoseconds < 0) {
  94. result->nanoseconds += 1000000000;
  95. result->seconds--;
  96. }
  97. }
  98. char *
  99. bench_elapsed_str(const struct bench *bench)
  100. {
  101. struct bench_time elapsed;
  102. char *buf;
  103. int ret;
  104. bench_elapsed(bench, &elapsed);
  105. ret = asprintf(&buf, "%ld.%06ld", elapsed.seconds, elapsed.nanoseconds / 1000);
  106. assert(ret >= 0);
  107. return buf;
  108. }
  109. /* Utils for bench method adapted from: https://hackage.haskell.org/package/tasty-bench */
  110. #define fit(x1, x2) ((x1) / 5 + 2 * ((x2) / 5))
  111. #define sqr(x) ((x) * (x))
  112. static void
  113. predict(long long t1, long long t2, struct estimate *est)
  114. {
  115. const long long t = fit(t1, t2);
  116. est->elapsed = t;
  117. est->stdev =
  118. llroundl(sqrtl((long double)sqr(t1 - t) + (long double)sqr(t2 - 2 * t)));
  119. }
  120. #define high(t, prec) ((t) + (prec))
  121. #define low(t, prec) ((t) - (prec))
  122. #define MIN_PRECISION 1000000 /* 1ms */
  123. void
  124. predictPerturbed(const struct bench_time *b1, const struct bench_time *b2,
  125. struct estimate *est)
  126. {
  127. const long long t1 = bench_time_elapsed_nanoseconds(b1);
  128. const long long t2 = bench_time_elapsed_nanoseconds(b2);
  129. #ifndef _WIN32
  130. struct timespec ts;
  131. (void) clock_getres(best_clock, &ts);
  132. long long precision = MAX(ts.tv_sec * 1000000000 + ts.tv_nsec, MIN_PRECISION);
  133. #else
  134. long long precision = MIN_PRECISION;
  135. #endif
  136. struct estimate est1;
  137. struct estimate est2;
  138. predict(t1, t2, est);
  139. predict(low(t1, precision), high(t2, precision), &est1);
  140. predict(high(t1, precision), low(t2, precision), &est2);
  141. est->stdev = MAX(est1.stdev, est2.stdev);
  142. }