Commit cc8d1f97 authored by william's avatar william

build Lua module

parent cde9df2c
...@@ -34,6 +34,9 @@ else ...@@ -34,6 +34,9 @@ else
SOFLAGS = -shared SOFLAGS = -shared
endif endif
bench.so: bench.c
$(CC) -o $@ $< $(CPPFLAGS) -DLUA_COMPAT_ALL $(CFLAGS) -Wno-unused-function $(SOFLAGS)
bench-wheel8.so: CPPFLAGS+=-DWHEEL_BIT=3 -DWHEEL_NUM=$(WHEEL_NUM) bench-wheel8.so: CPPFLAGS+=-DWHEEL_BIT=3 -DWHEEL_NUM=$(WHEEL_NUM)
bench-wheel8.so: timeout.c bench-wheel8.so: timeout.c
......
...@@ -40,6 +40,7 @@ typedef struct min_heap ...@@ -40,6 +40,7 @@ typedef struct min_heap
{ {
struct timeout** p; struct timeout** p;
unsigned n, a; unsigned n, a;
timeout_t curtime;
} min_heap_t; } min_heap_t;
static inline void min_heap_ctor(min_heap_t* s); static inline void min_heap_ctor(min_heap_t* s);
...@@ -155,61 +156,81 @@ void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct timeout* e) ...@@ -155,61 +156,81 @@ void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct timeout* e)
#endif /* _MIN_HEAP_H_ */ #endif /* _MIN_HEAP_H_ */
static timeout_t curtime; static void *init(struct timeout *timeout, size_t count, int verbose) {
static min_heap_t timeouts; min_heap_t *H;
static void init(struct timeout *timeout, size_t count, int verbose) {
size_t i; size_t i;
min_heap_ctor(&timeouts); H = calloc(1, sizeof *H);
if (0 != min_heap_reserve(&timeouts, count))
min_heap_ctor(H);
if (0 != min_heap_reserve(H, count))
err(1, "realloc"); err(1, "realloc");
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
min_heap_elem_init(&timeout[i]); min_heap_elem_init(&timeout[i]);
} }
return H;
} /* init() */ } /* init() */
static void add(struct timeout *to, timeout_t expires) { static void add(void *ctx, struct timeout *to, timeout_t expires) {
min_heap_erase(&timeouts, to); min_heap_t *H = ctx;
to->expires = curtime + expires; min_heap_erase(H, to);
if (0 != min_heap_push(&timeouts, to)) to->expires = H->curtime + expires;
if (0 != min_heap_push(H, to))
err(1, "realloc"); err(1, "realloc");
} /* add() */ } /* add() */
static void del(struct timeout *to) { static void del(void *ctx, struct timeout *to) {
min_heap_erase(&timeouts, to); min_heap_erase(ctx, to);
} /* del() */ } /* del() */
static struct timeout *get(void) { static struct timeout *get(void *ctx) {
min_heap_t *H = ctx;
struct timeout *to; struct timeout *to;
if ((to = min_heap_top(&timeouts)) && to->expires <= curtime) if ((to = min_heap_top(H)) && to->expires <= H->curtime)
return min_heap_pop(&timeouts); return min_heap_pop(H);
return NULL; return NULL;
} /* get() */ } /* get() */
static void update(timeout_t ts) { static void update(void *ctx, timeout_t ts) {
curtime = ts; min_heap_t *H = ctx;
H->curtime = ts;
} /* update() */ } /* update() */
static void check(void) { static void check(void *ctx) {
return; return;
} /* check() */ } /* check() */
const struct vops VOPS = { static int empty(void *ctx) {
.init = &init, min_heap_t *H = ctx;
.add = &add,
.del = &del, return (NULL == min_heap_top(H));
.get = &get, } /* empty() */
.update = &update,
.check = &check,
static void destroy(void *H) {
free(H);
return;
} /* destroy() */
const struct benchops benchops = {
.init = &init,
.add = &add,
.del = &del,
.get = &get,
.update = &update,
.check = &check,
.empty = &empty,
.destroy = &destroy,
}; };
#include <stdlib.h>
#include "timeout.h" #include "timeout.h"
#include "timeout.c" #include "timeout.c"
#include "bench.h" #include "bench.h"
static struct timeouts timeouts; static void *init(struct timeout *timeout, size_t count, int verbose) {
struct timeouts *T;
static void init(struct timeout *timeout, size_t count, int verbose) {
size_t i; size_t i;
int error;
timeouts_init(&timeouts, TIMEOUT_mHZ); T = timeouts_open(TIMEOUT_mHZ, &error);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
timeout_init(&timeout[i], 0); timeout_init(&timeout[i], 0);
...@@ -17,41 +19,55 @@ static void init(struct timeout *timeout, size_t count, int verbose) { ...@@ -17,41 +19,55 @@ static void init(struct timeout *timeout, size_t count, int verbose) {
#if TIMEOUT_DEBUG - 0 #if TIMEOUT_DEBUG - 0
timeout_debug = verbose; timeout_debug = verbose;
#endif #endif
return T;
} /* init() */ } /* init() */
static void add(struct timeout *to, timeout_t expires) { static void add(void *T, struct timeout *to, timeout_t expires) {
timeouts_add(&timeouts, to, expires); timeouts_add(T, to, expires);
} /* add() */ } /* add() */
static void del(struct timeout *to) { static void del(void *T, struct timeout *to) {
timeouts_del(&timeouts, to); timeouts_del(T, to);
} /* del() */ } /* del() */
static struct timeout *get(void) { static struct timeout *get(void *T) {
return timeouts_get(&timeouts); return timeouts_get(T);
} /* get() */ } /* get() */
static void update(timeout_t ts) { static void update(void *T, timeout_t ts) {
timeouts_update(&timeouts, ts); timeouts_update(T, ts);
} /* update() */ } /* update() */
static void (check)(void) { static void (check)(void *T) {
if (!timeouts_check(&timeouts, stderr)) if (!timeouts_check(T, stderr))
_Exit(1); _Exit(1);
} /* check() */ } /* check() */
const struct vops VOPS = { static int empty(void *T) {
.init = &init, return !(timeouts_pending(T) || timeouts_expired(T));
.add = &add, } /* empty() */
.del = &del,
.get = &get,
.update = &update, static void destroy(void *T) {
.check = &check, timeouts_close(T);
} /* destroy() */
const struct benchops benchops = {
.init = &init,
.add = &add,
.del = &del,
.get = &get,
.update = &update,
.check = &check,
.empty = &empty,
.destroy = &destroy
}; };
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <locale.h>
#include <time.h> #include <time.h>
#include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <err.h> #include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "timeout.h" #include "timeout.h"
#include "bench.h" #include "bench.h"
#ifndef countof
#define countof(a) (sizeof (a) / sizeof *(a))
#endif
struct { struct bench {
const char *path; const char *path;
void *solib; void *solib;
size_t count; size_t count;
timeout_t maximum; timeout_t maximum;
int verbose; int verbose;
void *state;
struct timeout *timeout; struct timeout *timeout;
struct vops vops; struct benchops ops;
timeout_t curtime; timeout_t curtime;
} MAIN = { }; /* struct bench */
.path = "bench-wheel.so",
.count = 32678,
.maximum = 60000, // 60 seconds in milliseconds
};
static int split(char **argv, int max, char *src) { static int bench_new(lua_State *L) {
char **ap = argv, **pe = argv + max; const char *path = luaL_checkstring(L, 1);
size_t count = luaL_optlong(L, 2, 1000000);
timeout_t tmax = luaL_optlong(L, 3, 60 * 1000);
int verbose = (lua_isnone(L, 4))? 0 : lua_toboolean(L, 4);
struct bench *B;
struct benchops *ops;
while (ap < pe && (*ap = strsep(&src, " \t\n"))) { B = lua_newuserdata(L, sizeof *B);
if (**ap) memset(B, 0, sizeof *B);
++ap;
} luaL_getmetatable(L, "BENCH*");
lua_setmetatable(L, -2);
B->count = count;
B->maximum = tmax;
B->verbose = verbose;
if (!(B->timeout = calloc(count, sizeof *B->timeout)))
return luaL_error(L, "%s", strerror(errno));
if (!(B->solib = dlopen(path, RTLD_NOW|RTLD_LOCAL)))
return luaL_error(L, "%s: %s", path, dlerror());
if (!(ops = dlsym(B->solib, "benchops")))
return luaL_error(L, "%s: %s", path, dlerror());
B->ops = *ops;
B->state = B->ops.init(B->timeout, B->count, B->verbose);
return 1;
} /* bench_new() */
static int bench_add(lua_State *L) {
struct bench *B = lua_touserdata(L, 1);
unsigned i;
timeout_t t;
i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checklong(L, 2);
t = (lua_isnoneornil(L, 3))? random() % B->maximum : (unsigned)luaL_checklong(L, 3);
B->ops.add(B->state, &B->timeout[i], t);
return ap - argv; return 0;
} /* split() */ } /* bench_add() */
struct op *parseop(struct op *op, char *ln) { static int bench_del(lua_State *L) {
char *arg[8]; struct bench *B = lua_touserdata(L, 1);
int argc; unsigned i;
if (!(argc = split(arg, countof(arg), ln))) i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checklong(L, 2);
return NULL;
B->ops.del(B->state, &B->timeout[i]);
return 0;
} /* bench_del() */
switch (**arg) {
case 'q': /* quit */
op->type = OP_QUIT;
break; static int bench_fill(lua_State *L) {
case 'h': /* help */ struct bench *B = lua_touserdata(L, 1);
op->type = OP_HELP; size_t i;
break; for (i = 0; i < B->count; i++) {
case 'a': /* add */ B->ops.add(B->state, &B->timeout[i], random() % B->maximum);
if (argc != 3) }
goto badargc;
return 0;
} /* bench_fill() */
op->type = OP_ADD;
op->add.id = strtoul(arg[1], NULL, 0) % MAIN.count;
op->add.timeout = strtoul(arg[2], NULL, 0);
break; static int bench_expire(lua_State *L) {
case 'd': /* del */ struct bench *B = lua_touserdata(L, 1);
if (argc != 2) unsigned count = luaL_optlong(L, 2, B->count);
goto badargc; unsigned step = luaL_optlong(L, 3, 300);
size_t i = 0;
op->type = OP_DEL; while (i < count && !B->ops.empty(B->state)) {
op->del.id = strtoul(arg[1], NULL, 0) % MAIN.count; B->curtime += step;
B->ops.update(B->state, B->curtime);
break; while (B->ops.get(B->state))
case 'g': /* get */ i++;
op->type = OP_GET; }
op->get.verbose = (argc > 1)? strtol(arg[1], NULL, 0) : 0;
break; return 0;
case 's': /* step */ } /* bench_expire() */
if (argc != 2)
goto badargc;
op->type = OP_STEP;
op->step.time = strtoul(arg[1], NULL, 0);
break; static int bench__gc(lua_State *L) {
case 'u': /* update */ struct bench *B = lua_touserdata(L, 1);
if (argc != 2)
goto badargc;
op->type = OP_UPDATE; if (B->state) {
op->update.time = strtoul(arg[1], NULL, 0); B->ops.destroy(B->state);
B->state = NULL;
}
break; return 0;
case 'c': /* check */ } /* bench_expire() */
op->type = OP_CHECK;
break;
case 'f': /* fill */
op->type = OP_FILL;
break; static const luaL_Reg bench_methods[] = {
case '#': { "add", &bench_add },
/* FALL THROUGH */ { "del", &bench_del },
case 'n': { "fill", &bench_fill },
op->type = OP_NONE; { "expire", &bench_expire },
{ NULL, NULL }
};
break; static const luaL_Reg bench_metatable[] = {
case 't': { "__gc", &bench__gc },
op->type = OP_TIME; { NULL, NULL }
};
break; static const luaL_Reg bench_globals[] = {
default: { "new", &bench_new },
op->type = OP_OOPS; { NULL, NULL }
snprintf(op->oops.why, sizeof op->oops.why, "%.8s: illegal op", *arg); };
break; int luaopen_bench(lua_State *L) {
} /* switch() */ if (luaL_newmetatable(L, "BENCH*")) {
luaL_register(L, NULL, bench_metatable);
lua_newtable(L);
luaL_register(L, NULL, bench_methods);
lua_setfield(L, -2, "__index");
}
return op; lua_pop(L, 1);
badargc:
op->type = OP_OOPS;
snprintf(op->oops.why, sizeof op->oops.why, "wrong number of arguments");
return op; lua_newtable(L);
} /* parseop() */ luaL_register(L, NULL, bench_globals);
return 1;
} /* luaopen_bench() */
#define SHORT_OPTS "n:t:vh"
static void usage(FILE *fp) {
fprintf(fp,
"bench [-%s] LIBRARY\n" \
" -n MAX maximum number of timeouts\n" \
" -t MAX maximum timeout\n" \
" -v increase log level\n" \
" -h print usage message\n" \
"\n" \
"[commands]\n" \
" help print usage message\n" \
" quit exit program\n" \
"\n" \
"Report bugs to <william@25thandClement.com>\n",
SHORT_OPTS);
} /* usage() */
#if 0
int main(int argc, char **argv) { int main(int argc, char **argv) {
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
...@@ -285,3 +295,5 @@ int main(int argc, char **argv) { ...@@ -285,3 +295,5 @@ int main(int argc, char **argv) {
quit: quit:
return 0; return 0;
} /* main() */ } /* main() */
#endif
struct benchops {
struct op { void *(*init)(struct timeout *, size_t, int);
enum { void (*add)(void *, struct timeout *, timeout_t);
OP_OOPS, void (*del)(void *, struct timeout *);
OP_QUIT, struct timeout *(*get)(void *);
OP_HELP, void (*update)(void *, timeout_t);
OP_ADD, void (*check)(void *);
OP_DEL, int (*empty)(void *);
OP_GET, void (*destroy)(void *);
OP_STEP, }; /* struct benchops() */
OP_UPDATE,
OP_CHECK,
OP_FILL,
OP_NONE,
OP_TIME,
} type;
union {
struct {
char why[32];
} oops;
struct {
unsigned id;
timeout_t timeout;
} add;
struct {
unsigned id;
} del;
struct {
int verbose;
} get;
struct {
timeout_t time;
} step, update;
};
}; /* struct op */
struct op *parseop(struct op *, char *ln);
struct vops {
void (*init)(struct timeout *, size_t, int);
void (*add)(struct timeout *, timeout_t);
void (*del)(struct timeout *);
struct timeout *(*get)(void);
void (*update)(timeout_t);
void (*check)(void);
}; /* struct vops() */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment