Tor 0.4.9.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
20static 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
24static 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
49struct 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__
64static mach_timebase_info_data_t timebase;
65#endif
66
67
68static 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
86static int bench_clock(lua_State *L) {
87 lua_pushnumber(L, (double)monotime() / 1000000L);
88
89 return 1;
90} /* bench_clock() */
91
92
93static 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
127static 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
141static 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
155static 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
182static 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
202static 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
211static 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
228static 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
244static 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
256static 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
266static const luaL_Reg bench_metatable[] = {
267 { "__pairs", &bench__pairs },
268 { "__gc", &bench__gc },
269 { NULL, NULL }
270};
271
272static const luaL_Reg bench_globals[] = {
273 { "new", &bench_new },
274 { "clock", &bench_clock },
275 { NULL, NULL }
276};
277
278int 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.