Commit cc8d1f97 authored by william's avatar william

build Lua module

parent cde9df2c
......@@ -34,6 +34,9 @@ else
SOFLAGS = -shared
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: timeout.c
......
......@@ -40,6 +40,7 @@ typedef struct min_heap
{
struct timeout** p;
unsigned n, a;
timeout_t curtime;
} min_heap_t;
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)
#endif /* _MIN_HEAP_H_ */
static timeout_t curtime;
static min_heap_t timeouts;
static void init(struct timeout *timeout, size_t count, int verbose) {
static void *init(struct timeout *timeout, size_t count, int verbose) {
min_heap_t *H;
size_t i;
min_heap_ctor(&timeouts);
if (0 != min_heap_reserve(&timeouts, count))
H = calloc(1, sizeof *H);
min_heap_ctor(H);
if (0 != min_heap_reserve(H, count))
err(1, "realloc");
for (i = 0; i < count; i++) {
min_heap_elem_init(&timeout[i]);
}
return H;
} /* init() */
static void add(struct timeout *to, timeout_t expires) {
min_heap_erase(&timeouts, to);
to->expires = curtime + expires;
if (0 != min_heap_push(&timeouts, to))
static void add(void *ctx, struct timeout *to, timeout_t expires) {
min_heap_t *H = ctx;
min_heap_erase(H, to);
to->expires = H->curtime + expires;
if (0 != min_heap_push(H, to))
err(1, "realloc");
} /* add() */
static void del(struct timeout *to) {
min_heap_erase(&timeouts, to);
static void del(void *ctx, struct timeout *to) {
min_heap_erase(ctx, to);
} /* del() */
static struct timeout *get(void) {
static struct timeout *get(void *ctx) {
min_heap_t *H = ctx;
struct timeout *to;
if ((to = min_heap_top(&timeouts)) && to->expires <= curtime)
return min_heap_pop(&timeouts);
if ((to = min_heap_top(H)) && to->expires <= H->curtime)
return min_heap_pop(H);
return NULL;
} /* get() */
static void update(timeout_t ts) {
curtime = ts;
static void update(void *ctx, timeout_t ts) {
min_heap_t *H = ctx;
H->curtime = ts;
} /* update() */
static void check(void) {
static void check(void *ctx) {
return;
} /* check() */
const struct vops VOPS = {
static int empty(void *ctx) {
min_heap_t *H = ctx;
return (NULL == min_heap_top(H));
} /* empty() */
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.c"
#include "bench.h"
static struct timeouts timeouts;
static void init(struct timeout *timeout, size_t count, int verbose) {
static void *init(struct timeout *timeout, size_t count, int verbose) {
struct timeouts *T;
size_t i;
int error;
timeouts_init(&timeouts, TIMEOUT_mHZ);
T = timeouts_open(TIMEOUT_mHZ, &error);
for (i = 0; i < count; i++) {
timeout_init(&timeout[i], 0);
......@@ -17,41 +19,55 @@ static void init(struct timeout *timeout, size_t count, int verbose) {
#if TIMEOUT_DEBUG - 0
timeout_debug = verbose;
#endif
return T;
} /* init() */
static void add(struct timeout *to, timeout_t expires) {
timeouts_add(&timeouts, to, expires);
static void add(void *T, struct timeout *to, timeout_t expires) {
timeouts_add(T, to, expires);
} /* add() */
static void del(struct timeout *to) {
timeouts_del(&timeouts, to);
static void del(void *T, struct timeout *to) {
timeouts_del(T, to);
} /* del() */
static struct timeout *get(void) {
return timeouts_get(&timeouts);
static struct timeout *get(void *T) {
return timeouts_get(T);
} /* get() */
static void update(timeout_t ts) {
timeouts_update(&timeouts, ts);
static void update(void *T, timeout_t ts) {
timeouts_update(T, ts);
} /* update() */
static void (check)(void) {
if (!timeouts_check(&timeouts, stderr))
static void (check)(void *T) {
if (!timeouts_check(T, stderr))
_Exit(1);
} /* check() */
const struct vops VOPS = {
static int empty(void *T) {
return !(timeouts_pending(T) || timeouts_expired(T));
} /* empty() */
static void destroy(void *T) {
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 <stdio.h>
#include <string.h>
#include <locale.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "timeout.h"
#include "bench.h"
#ifndef countof
#define countof(a) (sizeof (a) / sizeof *(a))
#endif
struct {
struct bench {
const char *path;
void *solib;
size_t count;
timeout_t maximum;
int verbose;
void *state;
struct timeout *timeout;
struct vops vops;
struct benchops ops;
timeout_t curtime;
} MAIN = {
.path = "bench-wheel.so",
.count = 32678,
.maximum = 60000, // 60 seconds in milliseconds
};
}; /* struct bench */
static int split(char **argv, int max, char *src) {
char **ap = argv, **pe = argv + max;
static int bench_new(lua_State *L) {
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"))) {
if (**ap)
++ap;
}
B = lua_newuserdata(L, sizeof *B);
memset(B, 0, sizeof *B);
return ap - argv;
} /* split() */
luaL_getmetatable(L, "BENCH*");
lua_setmetatable(L, -2);
B->count = count;
B->maximum = tmax;
B->verbose = verbose;
struct op *parseop(struct op *op, char *ln) {
char *arg[8];
int argc;
if (!(B->timeout = calloc(count, sizeof *B->timeout)))
return luaL_error(L, "%s", strerror(errno));
if (!(argc = split(arg, countof(arg), ln)))
return NULL;
if (!(B->solib = dlopen(path, RTLD_NOW|RTLD_LOCAL)))
return luaL_error(L, "%s: %s", path, dlerror());
switch (**arg) {
case 'q': /* quit */
op->type = OP_QUIT;
if (!(ops = dlsym(B->solib, "benchops")))
return luaL_error(L, "%s: %s", path, dlerror());
break;
case 'h': /* help */
op->type = OP_HELP;
B->ops = *ops;
B->state = B->ops.init(B->timeout, B->count, B->verbose);
break;
case 'a': /* add */
if (argc != 3)
goto badargc;
return 1;
} /* bench_new() */
op->type = OP_ADD;
op->add.id = strtoul(arg[1], NULL, 0) % MAIN.count;
op->add.timeout = strtoul(arg[2], NULL, 0);
break;
case 'd': /* del */
if (argc != 2)
goto badargc;
static int bench_add(lua_State *L) {
struct bench *B = lua_touserdata(L, 1);
unsigned i;
timeout_t t;
op->type = OP_DEL;
op->del.id = strtoul(arg[1], NULL, 0) % MAIN.count;
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);
break;
case 'g': /* get */
op->type = OP_GET;
op->get.verbose = (argc > 1)? strtol(arg[1], NULL, 0) : 0;
B->ops.add(B->state, &B->timeout[i], t);
break;
case 's': /* step */
if (argc != 2)
goto badargc;
return 0;
} /* bench_add() */
op->type = OP_STEP;
op->step.time = strtoul(arg[1], NULL, 0);
break;
case 'u': /* update */
if (argc != 2)
goto badargc;
static int bench_del(lua_State *L) {
struct bench *B = lua_touserdata(L, 1);
unsigned i;
op->type = OP_UPDATE;
op->update.time = strtoul(arg[1], NULL, 0);
i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checklong(L, 2);
break;
case 'c': /* check */
op->type = OP_CHECK;
B->ops.del(B->state, &B->timeout[i]);
break;
case 'f': /* fill */
op->type = OP_FILL;
return 0;
} /* bench_del() */
break;
case '#':
/* FALL THROUGH */
case 'n':
op->type = OP_NONE;
break;
case 't':
op->type = OP_TIME;
static int bench_fill(lua_State *L) {
struct bench *B = lua_touserdata(L, 1);
size_t i;
break;
default:
op->type = OP_OOPS;
snprintf(op->oops.why, sizeof op->oops.why, "%.8s: illegal op", *arg);
for (i = 0; i < B->count; i++) {
B->ops.add(B->state, &B->timeout[i], random() % B->maximum);
}
break;
} /* switch() */
return 0;
} /* bench_fill() */
static int bench_expire(lua_State *L) {
struct bench *B = lua_touserdata(L, 1);
unsigned count = luaL_optlong(L, 2, B->count);
unsigned step = luaL_optlong(L, 3, 300);
size_t i = 0;
while (i < count && !B->ops.empty(B->state)) {
B->curtime += step;
B->ops.update(B->state, B->curtime);
while (B->ops.get(B->state))
i++;
}
return 0;
} /* bench_expire() */
return op;
badargc:
op->type = OP_OOPS;
snprintf(op->oops.why, sizeof op->oops.why, "wrong number of arguments");
return op;
} /* parseop() */
#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() */
static int bench__gc(lua_State *L) {
struct bench *B = lua_touserdata(L, 1);
if (B->state) {
B->ops.destroy(B->state);
B->state = NULL;
}
return 0;
} /* bench_expire() */
static const luaL_Reg bench_methods[] = {
{ "add", &bench_add },
{ "del", &bench_del },
{ "fill", &bench_fill },
{ "expire", &bench_expire },
{ NULL, NULL }
};
static const luaL_Reg bench_metatable[] = {
{ "__gc", &bench__gc },
{ NULL, NULL }
};
static const luaL_Reg bench_globals[] = {
{ "new", &bench_new },
{ NULL, NULL }
};
int luaopen_bench(lua_State *L) {
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");
}
lua_pop(L, 1);
lua_newtable(L);
luaL_register(L, NULL, bench_globals);
return 1;
} /* luaopen_bench() */
#if 0
int main(int argc, char **argv) {
extern char *optarg;
extern int optind;
......@@ -285,3 +295,5 @@ int main(int argc, char **argv) {
quit:
return 0;
} /* main() */
#endif
struct op {
enum {
OP_OOPS,
OP_QUIT,
OP_HELP,
OP_ADD,
OP_DEL,
OP_GET,
OP_STEP,
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() */
struct benchops {
void *(*init)(struct timeout *, size_t, int);
void (*add)(void *, struct timeout *, timeout_t);
void (*del)(void *, struct timeout *);
struct timeout *(*get)(void *);
void (*update)(void *, timeout_t);
void (*check)(void *);
int (*empty)(void *);
void (*destroy)(void *);
}; /* struct benchops() */
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