bench.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <time.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <dlfcn.h>
  7. #if __APPLE__
  8. #include <mach/mach_time.h>
  9. #endif
  10. #include <lua.h>
  11. #include <lualib.h>
  12. #include <lauxlib.h>
  13. #include "timeout.h"
  14. #include "bench.h"
  15. #if LUA_VERSION_NUM < 502
  16. static int lua_absindex(lua_State *L, int idx) {
  17. return (idx > 0 || idx <= LUA_REGISTRYINDEX)? idx : lua_gettop(L) + idx + 1;
  18. } /* lua_absindex() */
  19. static void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) {
  20. int i, t = lua_absindex(L, -1 - nup);
  21. for (; l->name; l++) {
  22. for (i = 0; i < nup; i++)
  23. lua_pushvalue(L, -nup);
  24. lua_pushcclosure(L, l->func, nup);
  25. lua_setfield(L, t, l->name);
  26. }
  27. lua_pop(L, nup);
  28. } /* luaL_setfuncs() */
  29. #define luaL_newlibtable(L, l) \
  30. lua_createtable(L, 0, (sizeof (l) / sizeof *(l)) - 1)
  31. #define luaL_newlib(L, l) \
  32. (luaL_newlibtable((L), (l)), luaL_setfuncs((L), (l), 0))
  33. #endif
  34. #ifndef MAX
  35. #define MAX(a, b) (((a) > (b))? (a) : (b))
  36. #endif
  37. struct bench {
  38. const char *path;
  39. void *solib;
  40. size_t count;
  41. timeout_t timeout_max;
  42. int verbose;
  43. void *state;
  44. struct timeout *timeout;
  45. struct benchops ops;
  46. timeout_t curtime;
  47. }; /* struct bench */
  48. #if __APPLE__
  49. static mach_timebase_info_data_t timebase;
  50. #endif
  51. static int long long monotime(void) {
  52. #if __APPLE__
  53. unsigned long long abt;
  54. abt = mach_absolute_time();
  55. abt = abt * timebase.numer / timebase.denom;
  56. return abt / 1000LL;
  57. #else
  58. struct timespec ts;
  59. clock_gettime(CLOCK_MONOTONIC, &ts);
  60. return (ts.tv_sec * 1000000L) + (ts.tv_nsec / 1000L);
  61. #endif
  62. } /* monotime() */
  63. static int bench_clock(lua_State *L) {
  64. lua_pushnumber(L, (double)monotime() / 1000000L);
  65. return 1;
  66. } /* bench_clock() */
  67. static int bench_new(lua_State *L) {
  68. const char *path = luaL_checkstring(L, 1);
  69. size_t count = luaL_optinteger(L, 2, 1000000);
  70. timeout_t timeout_max = luaL_optinteger(L, 3, 300 * 1000000L);
  71. int verbose = (lua_isnone(L, 4))? 0 : lua_toboolean(L, 4);
  72. struct bench *B;
  73. struct benchops *ops;
  74. B = lua_newuserdata(L, sizeof *B);
  75. memset(B, 0, sizeof *B);
  76. luaL_getmetatable(L, "BENCH*");
  77. lua_setmetatable(L, -2);
  78. B->count = count;
  79. B->timeout_max = timeout_max;
  80. B->verbose = verbose;
  81. if (!(B->timeout = calloc(count, sizeof *B->timeout)))
  82. return luaL_error(L, "%s", strerror(errno));
  83. if (!(B->solib = dlopen(path, RTLD_NOW|RTLD_LOCAL)))
  84. return luaL_error(L, "%s: %s", path, dlerror());
  85. if (!(ops = dlsym(B->solib, "benchops")))
  86. return luaL_error(L, "%s: %s", path, dlerror());
  87. B->ops = *ops;
  88. B->state = B->ops.init(B->timeout, B->count, B->verbose);
  89. return 1;
  90. } /* bench_new() */
  91. static int bench_add(lua_State *L) {
  92. struct bench *B = lua_touserdata(L, 1);
  93. unsigned i;
  94. timeout_t t;
  95. i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checkinteger(L, 2);
  96. t = (lua_isnoneornil(L, 3))? random() % B->timeout_max : (unsigned)luaL_checkinteger(L, 3);
  97. B->ops.add(B->state, &B->timeout[i], t);
  98. return 0;
  99. } /* bench_add() */
  100. static int bench_del(lua_State *L) {
  101. struct bench *B = lua_touserdata(L, 1);
  102. size_t i = luaL_optinteger(L, 2, random() % B->count);
  103. size_t j = luaL_optinteger(L, 3, i);
  104. while (i <= j && i < B->count) {
  105. B->ops.del(B->state, &B->timeout[i]);
  106. ++i;
  107. }
  108. return 0;
  109. } /* bench_del() */
  110. static int bench_fill(lua_State *L) {
  111. struct bench *B = lua_touserdata(L, 1);
  112. size_t count = luaL_optinteger(L, 2, B->count);
  113. long timeout_inc = luaL_optinteger(L, 3, -1), timeout_max = 0, timeout;
  114. size_t i;
  115. if (timeout_inc < 0) {
  116. for (i = 0; i < count; i++) {
  117. timeout = random() % B->timeout_max;
  118. B->ops.add(B->state, &B->timeout[i], timeout);
  119. timeout_max = MAX(timeout, timeout_max);
  120. }
  121. } else {
  122. for (i = 0; i < count; i++) {
  123. timeout = timeout_inc + i;
  124. B->ops.add(B->state, &B->timeout[i], timeout_inc + i);
  125. timeout_max = MAX(timeout, timeout_max);
  126. }
  127. }
  128. lua_pushinteger(L, (lua_Integer)count);
  129. lua_pushinteger(L, (lua_Integer)timeout_max);
  130. return 2;
  131. } /* bench_fill() */
  132. static int bench_expire(lua_State *L) {
  133. struct bench *B = lua_touserdata(L, 1);
  134. unsigned count = luaL_optinteger(L, 2, B->count);
  135. unsigned step = luaL_optinteger(L, 3, 300000);
  136. size_t i = 0;
  137. while (i < count && !B->ops.empty(B->state)) {
  138. B->curtime += step;
  139. B->ops.update(B->state, B->curtime);
  140. while (B->ops.get(B->state))
  141. i++;
  142. }
  143. lua_pushinteger(L, (lua_Integer)i);
  144. return 1;
  145. } /* bench_expire() */
  146. static int bench_empty(lua_State *L) {
  147. struct bench *B = lua_touserdata(L, 1);
  148. lua_pushboolean(L, B->ops.empty(B->state));
  149. return 1;
  150. } /* bench_empty() */
  151. static int bench__next(lua_State *L) {
  152. struct bench *B = lua_touserdata(L, lua_upvalueindex(1));
  153. struct timeouts_it *it = lua_touserdata(L, lua_upvalueindex(2));
  154. struct timeout *to;
  155. if (!B->ops.next || !(to = B->ops.next(B->state, it)))
  156. return 0;
  157. lua_pushinteger(L, luaL_optinteger(L, 2, 0) + 1);
  158. lua_newtable(L);
  159. lua_pushinteger(L, to->expires);
  160. lua_setfield(L, -2, "expires");
  161. return 2;
  162. } /* bench__next() */
  163. static int bench__pairs(lua_State *L) {
  164. struct timeouts_it *it;
  165. lua_settop(L, 1);
  166. it = lua_newuserdata(L, sizeof *it);
  167. TIMEOUTS_IT_INIT(it, TIMEOUTS_ALL);
  168. lua_pushcclosure(L, &bench__next, 2);
  169. lua_pushvalue(L, 1);
  170. lua_pushinteger(L, 0);
  171. return 3;
  172. } /* bench__pairs() */
  173. static int bench__gc(lua_State *L) {
  174. struct bench *B = lua_touserdata(L, 1);
  175. if (B->state) {
  176. B->ops.destroy(B->state);
  177. B->state = NULL;
  178. }
  179. return 0;
  180. } /* bench__gc() */
  181. static const luaL_Reg bench_methods[] = {
  182. { "add", &bench_add },
  183. { "del", &bench_del },
  184. { "fill", &bench_fill },
  185. { "expire", &bench_expire },
  186. { "empty", &bench_empty },
  187. { "close", &bench__gc },
  188. { NULL, NULL }
  189. };
  190. static const luaL_Reg bench_metatable[] = {
  191. { "__pairs", &bench__pairs },
  192. { "__gc", &bench__gc },
  193. { NULL, NULL }
  194. };
  195. static const luaL_Reg bench_globals[] = {
  196. { "new", &bench_new },
  197. { "clock", &bench_clock },
  198. { NULL, NULL }
  199. };
  200. int luaopen_bench(lua_State *L) {
  201. #if __APPLE__
  202. mach_timebase_info(&timebase);
  203. #endif
  204. if (luaL_newmetatable(L, "BENCH*")) {
  205. luaL_setfuncs(L, bench_metatable, 0);
  206. luaL_newlib(L, bench_methods);
  207. lua_setfield(L, -2, "__index");
  208. }
  209. luaL_newlib(L, bench_globals);
  210. return 1;
  211. } /* luaopen_bench() */