bench.c (6255B)
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() */