Tor  0.4.7.0-alpha-dev
bench.c
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 
8 #if __APPLE__
9 #include <mach/mach_time.h>
10 #endif
11 
12 #include <lua.h>
13 #include <lualib.h>
14 #include <lauxlib.h>
15 
16 #include "timeout.h"
17 #include "bench.h"
18 
19 #if LUA_VERSION_NUM < 502
20 static int lua_absindex(lua_State *L, int idx) {
21  return (idx > 0 || idx <= LUA_REGISTRYINDEX)? idx : lua_gettop(L) + idx + 1;
22 } /* lua_absindex() */
23 
24 static void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) {
25  int i, t = lua_absindex(L, -1 - nup);
26 
27  for (; l->name; l++) {
28  for (i = 0; i < nup; i++)
29  lua_pushvalue(L, -nup);
30  lua_pushcclosure(L, l->func, nup);
31  lua_setfield(L, t, l->name);
32  }
33 
34  lua_pop(L, nup);
35 } /* luaL_setfuncs() */
36 
37 #define luaL_newlibtable(L, l) \
38  lua_createtable(L, 0, (sizeof (l) / sizeof *(l)) - 1)
39 
40 #define luaL_newlib(L, l) \
41  (luaL_newlibtable((L), (l)), luaL_setfuncs((L), (l), 0))
42 #endif
43 
44 #ifndef MAX
45 #define MAX(a, b) (((a) > (b))? (a) : (b))
46 #endif
47 
48 
49 struct bench {
50  const char *path;
51  void *solib;
52  size_t count;
53  timeout_t timeout_max;
54  int verbose;
55 
56  void *state;
57  struct timeout *timeout;
58  struct benchops ops;
59  timeout_t curtime;
60 }; /* struct bench */
61 
62 
63 #if __APPLE__
64 static mach_timebase_info_data_t timebase;
65 #endif
66 
67 
68 static int long long monotime(void) {
69 #if __APPLE__
70  unsigned long long abt;
71 
72  abt = mach_absolute_time();
73  abt = abt * timebase.numer / timebase.denom;
74 
75  return abt / 1000LL;
76 #else
77  struct timespec ts;
78 
79  clock_gettime(CLOCK_MONOTONIC, &ts);
80 
81  return (ts.tv_sec * 1000000L) + (ts.tv_nsec / 1000L);
82 #endif
83 } /* monotime() */
84 
85 
86 static int bench_clock(lua_State *L) {
87  lua_pushnumber(L, (double)monotime() / 1000000L);
88 
89  return 1;
90 } /* bench_clock() */
91 
92 
93 static int bench_new(lua_State *L) {
94  const char *path = luaL_checkstring(L, 1);
95  size_t count = luaL_optinteger(L, 2, 1000000);
96  timeout_t timeout_max = luaL_optinteger(L, 3, 300 * 1000000L);
97  int verbose = (lua_isnone(L, 4))? 0 : lua_toboolean(L, 4);
98  struct bench *B;
99  struct benchops *ops;
100 
101  B = lua_newuserdata(L, sizeof *B);
102  memset(B, 0, sizeof *B);
103 
104  luaL_getmetatable(L, "BENCH*");
105  lua_setmetatable(L, -2);
106 
107  B->count = count;
108  B->timeout_max = timeout_max;
109  B->verbose = verbose;
110 
111  if (!(B->timeout = calloc(count, sizeof *B->timeout)))
112  return luaL_error(L, "%s", strerror(errno));
113 
114  if (!(B->solib = dlopen(path, RTLD_NOW|RTLD_LOCAL)))
115  return luaL_error(L, "%s: %s", path, dlerror());
116 
117  if (!(ops = dlsym(B->solib, "benchops")))
118  return luaL_error(L, "%s: %s", path, dlerror());
119 
120  B->ops = *ops;
121  B->state = B->ops.init(B->timeout, B->count, B->verbose);
122 
123  return 1;
124 } /* bench_new() */
125 
126 
127 static int bench_add(lua_State *L) {
128  struct bench *B = lua_touserdata(L, 1);
129  unsigned i;
130  timeout_t t;
131 
132  i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checkinteger(L, 2);
133  t = (lua_isnoneornil(L, 3))? random() % B->timeout_max : (unsigned)luaL_checkinteger(L, 3);
134 
135  B->ops.add(B->state, &B->timeout[i], t);
136 
137  return 0;
138 } /* bench_add() */
139 
140 
141 static int bench_del(lua_State *L) {
142  struct bench *B = lua_touserdata(L, 1);
143  size_t i = luaL_optinteger(L, 2, random() % B->count);
144  size_t j = luaL_optinteger(L, 3, i);
145 
146  while (i <= j && i < B->count) {
147  B->ops.del(B->state, &B->timeout[i]);
148  ++i;
149  }
150 
151  return 0;
152 } /* bench_del() */
153 
154 
155 static int bench_fill(lua_State *L) {
156  struct bench *B = lua_touserdata(L, 1);
157  size_t count = luaL_optinteger(L, 2, B->count);
158  long timeout_inc = luaL_optinteger(L, 3, -1), timeout_max = 0, timeout;
159  size_t i;
160 
161  if (timeout_inc < 0) {
162  for (i = 0; i < count; i++) {
163  timeout = random() % B->timeout_max;
164  B->ops.add(B->state, &B->timeout[i], timeout);
165  timeout_max = MAX(timeout, timeout_max);
166  }
167  } else {
168  for (i = 0; i < count; i++) {
169  timeout = timeout_inc + i;
170  B->ops.add(B->state, &B->timeout[i], timeout_inc + i);
171  timeout_max = MAX(timeout, timeout_max);
172  }
173  }
174 
175  lua_pushinteger(L, (lua_Integer)count);
176  lua_pushinteger(L, (lua_Integer)timeout_max);
177 
178  return 2;
179 } /* bench_fill() */
180 
181 
182 static int bench_expire(lua_State *L) {
183  struct bench *B = lua_touserdata(L, 1);
184  unsigned count = luaL_optinteger(L, 2, B->count);
185  unsigned step = luaL_optinteger(L, 3, 300000);
186  size_t i = 0;
187 
188  while (i < count && !B->ops.empty(B->state)) {
189  B->curtime += step;
190  B->ops.update(B->state, B->curtime);
191 
192  while (B->ops.get(B->state))
193  i++;
194  }
195 
196  lua_pushinteger(L, (lua_Integer)i);
197 
198  return 1;
199 } /* bench_expire() */
200 
201 
202 static int bench_empty(lua_State *L) {
203  struct bench *B = lua_touserdata(L, 1);
204 
205  lua_pushboolean(L, B->ops.empty(B->state));
206 
207  return 1;
208 } /* bench_empty() */
209 
210 
211 static int bench__next(lua_State *L) {
212  struct bench *B = lua_touserdata(L, lua_upvalueindex(1));
213  struct timeouts_it *it = lua_touserdata(L, lua_upvalueindex(2));
214  struct timeout *to;
215 
216  if (!B->ops.next || !(to = B->ops.next(B->state, it)))
217  return 0;
218 
219  lua_pushinteger(L, luaL_optinteger(L, 2, 0) + 1);
220 
221  lua_newtable(L);
222  lua_pushinteger(L, to->expires);
223  lua_setfield(L, -2, "expires");
224 
225  return 2;
226 } /* bench__next() */
227 
228 static int bench__pairs(lua_State *L) {
229  struct timeouts_it *it;
230 
231  lua_settop(L, 1);
232 
233  it = lua_newuserdata(L, sizeof *it);
234  TIMEOUTS_IT_INIT(it, TIMEOUTS_ALL);
235 
236  lua_pushcclosure(L, &bench__next, 2);
237  lua_pushvalue(L, 1);
238  lua_pushinteger(L, 0);
239 
240  return 3;
241 } /* bench__pairs() */
242 
243 
244 static int bench__gc(lua_State *L) {
245  struct bench *B = lua_touserdata(L, 1);
246 
247  if (B->state) {
248  B->ops.destroy(B->state);
249  B->state = NULL;
250  }
251 
252  return 0;
253 } /* bench__gc() */
254 
255 
256 static const luaL_Reg bench_methods[] = {
257  { "add", &bench_add },
258  { "del", &bench_del },
259  { "fill", &bench_fill },
260  { "expire", &bench_expire },
261  { "empty", &bench_empty },
262  { "close", &bench__gc },
263  { NULL, NULL }
264 };
265 
266 static const luaL_Reg bench_metatable[] = {
267  { "__pairs", &bench__pairs },
268  { "__gc", &bench__gc },
269  { NULL, NULL }
270 };
271 
272 static const luaL_Reg bench_globals[] = {
273  { "new", &bench_new },
274  { "clock", &bench_clock },
275  { NULL, NULL }
276 };
277 
278 int luaopen_bench(lua_State *L) {
279 #if __APPLE__
280  mach_timebase_info(&timebase);
281 #endif
282 
283  if (luaL_newmetatable(L, "BENCH*")) {
284  luaL_setfuncs(L, bench_metatable, 0);
285  luaL_newlib(L, bench_methods);
286  lua_setfield(L, -2, "__index");
287  }
288 
289  luaL_newlib(L, bench_globals);
290 
291  return 1;
292 } /* luaopen_bench() */
293 
#define MAX(a, b)
Definition: cmp.h:22
Definition: bench.c:49
Definition: bench.h:1
Definitions for timing-related constants.