diff --git a/Makefile b/Makefile index d67e9852..7092729e 100644 --- a/Makefile +++ b/Makefile @@ -60,8 +60,8 @@ service/snlua.so : service-src/service_lua.c service/gate.so : gate/mread.c gate/ringbuffer.c gate/main.c gcc $(CFLAGS) $(SHARED) $^ -o $@ -Igate -Iskynet-src -luaclib/skynet.so : lualib-src/lua-skynet.c lualib-src/lua-seri.c lualib-src/lua-remoteobj.c | luaclib - gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ -Iskynet-src +luaclib/skynet.so : lualib-src/lua-skynet.c lualib-src/lua-seri.c lualib-src/lua-remoteobj.c lualib-src/trace_service.c | luaclib + gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ -Iskynet-src -Ilualib-src service/client.so : service-src/service_client.c gcc $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src diff --git a/lualib-src/lua-skynet.c b/lualib-src/lua-skynet.c index 51267737..eaf97b52 100644 --- a/lualib-src/lua-skynet.c +++ b/lualib-src/lua-skynet.c @@ -1,4 +1,5 @@ #include "skynet.h" +#include "trace_service.h" #include "lua-seri.h" #include "luacompat52.h" @@ -10,13 +11,12 @@ #include #include -#define NANOSEC 1000000000 - struct stat { lua_State *L; int count; uint32_t ti_sec; uint32_t ti_nsec; + struct trace_pool *trace; }; static void @@ -25,23 +25,9 @@ _stat_begin(struct stat *S, struct timespec *ti) { clock_gettime(CLOCK_THREAD_CPUTIME_ID, ti); } -static void +inline static void _stat_end(struct stat *S, struct timespec *ti) { - struct timespec end; - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); - int diffsec = end.tv_sec - ti->tv_sec; - assert(diffsec>=0); - int diffnsec = end.tv_nsec - ti->tv_nsec; - if (diffnsec < 0) { - --diffsec; - diffnsec += NANOSEC; - } - S->ti_nsec += diffnsec; - if (S->ti_nsec > NANOSEC) { - ++S->ti_sec; - S->ti_nsec -= NANOSEC; - } - S->ti_sec += diffsec; + diff_time(ti, &S->ti_sec, &S->ti_nsec); } static int @@ -61,6 +47,10 @@ _stat(lua_State *L) { lua_pushnumber(L, t); return 1; } + if (strcmp(what,"trace")==0) { + lua_pushlightuserdata(L, S->trace); + return 1; + } return 0; } @@ -111,6 +101,13 @@ _cb(struct skynet_context * context, void * ud, int type, int session, uint32_t return 0; } +static int +_delete_stat(lua_State *L) { + struct stat * S = lua_touserdata(L,1); + trace_release(S->trace); + return 0; +} + static int _callback(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); @@ -128,6 +125,12 @@ _callback(lua_State *L) { struct stat * S = lua_newuserdata(L, sizeof(*S)); memset(S, 0, sizeof(*S)); S->L = gL; + S->trace = trace_create(); + + lua_createtable(L,0,1); + lua_pushcfunction(L, _delete_stat); + lua_setfield(L,-1,"__gc"); + lua_setmetatable(L, -2); lua_rawsetp(L, LUA_REGISTRYINDEX, _stat); @@ -337,6 +340,51 @@ _harbor(lua_State *L) { return 2; } +// trace api +static int +_trace_new(lua_State *L) { + struct trace_pool *p = lua_touserdata(L,1); + struct trace_info *t = trace_new(p); + lua_pushlightuserdata(L,t); + return 1; +} + +static int +_trace_delete(lua_State *L) { + struct trace_pool *p = lua_touserdata(L,1); + struct trace_info *t = lua_touserdata(L,2); + double ti = trace_delete(p,t); + lua_pushnumber(L, ti); + return 1; +} + +static int +_trace_switch(lua_State *L) { + struct trace_pool *p = lua_touserdata(L,1); + int session = luaL_checkinteger(L,2); + trace_switch(p, session); + return 0; +} + +static int +_trace_yield(lua_State *L) { + struct trace_pool *p = lua_touserdata(L,1); + struct trace_info * t = trace_yield(p); + if (t) { + lua_pushlightuserdata(L,t); + return 1; + } + return 0; +} + +static int +_trace_register(lua_State *L) { + struct trace_pool *p = lua_touserdata(L,1); + int session = luaL_checkinteger(L,2); + trace_register(p, session); + return 0; +} + // define in lua-remoteobj.c int remoteobj_init(lua_State *L); @@ -379,10 +427,14 @@ luaopen_skynet_c(lua_State *L) { luaL_Reg l2[] = { { "stat", _stat }, { "remote_init", remoteobj_init }, + { "trace_new", _trace_new }, + { "trace_delete", _trace_delete }, + { "trace_switch", _trace_switch }, + { "trace_yield", _trace_yield }, + { "trace_register", _trace_register }, { NULL, NULL }, }; - luaL_setfuncs(L,l2,0); return 1; diff --git a/lualib-src/trace_service.c b/lualib-src/trace_service.c new file mode 100644 index 00000000..f6040581 --- /dev/null +++ b/lualib-src/trace_service.c @@ -0,0 +1,146 @@ +#include "trace_service.h" +#include +#include +#include +#include +#include + +#define HASH_SIZE 32 + +void +diff_time(struct timespec *ti, uint32_t *sec, uint32_t *nsec) { + struct timespec end; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); + int diffsec = end.tv_sec - ti->tv_sec; + assert(diffsec>=0); + int diffnsec = end.tv_nsec - ti->tv_nsec; + if (diffnsec < 0) { + --diffsec; + diffnsec += NANOSEC; + } + *nsec += diffnsec; + if (*nsec > NANOSEC) { + ++*sec; + *nsec -= NANOSEC; + } + *sec += diffsec; +} + +struct trace_info { + int session; + struct trace_info * prev; + struct trace_info * next; + struct timespec ti; + uint32_t ti_sec; + uint32_t ti_nsec; +}; + +struct trace_pool { + struct trace_info * current; + struct trace_info * slot[HASH_SIZE]; +}; + +struct trace_pool * +trace_create() { + struct trace_pool * p = malloc(sizeof(*p)); + memset(p, 0, sizeof(*p)); + return p; +} + +static void +_free_slot(struct trace_info *t) { + while (t) { + struct trace_info *next = t->next; + free(t); + t = next; + } +} + +void +trace_release(struct trace_pool *p) { + int i; + for (i=0;islot[i]); + } + free(p->current); +} + +struct trace_info * +trace_new(struct trace_pool *p) { + assert(p->current == NULL); + struct trace_info *t = malloc(sizeof(*t)); + p->current = t; + t->session = 0; + t->prev = NULL; + t->next = NULL; + t->ti_sec = 0; + t->ti_nsec = 0; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t->ti); + return t; +} + +void +trace_register(struct trace_pool *p, int session) { + struct trace_info *t = p->current; + int hash = session % HASH_SIZE; + assert(t->session == 0); + t->session = session; + t->prev = NULL; + t->next = p->slot[hash]; + if (p->slot[hash]) { + p->slot[hash]->prev = t; + } +} + +struct trace_info * +trace_yield(struct trace_pool *p) { + struct trace_info *t = p->current; + if (t == NULL) + return NULL; + p->current = NULL; + + diff_time(&t->ti,&t->ti_sec,&t->ti_nsec); + + if (t->session == 0) { + return t; + } else { + return NULL; + } +} + +void +trace_switch(struct trace_pool *p, int session) { + assert(p->current == NULL); + struct trace_info *t = p->slot[session % HASH_SIZE]; + struct trace_info *prev = NULL; + while (t) { + if (t->session == session) { + p->current = t; + t->session = 0; + if (prev == NULL) { + p->slot[session % HASH_SIZE] = t->next; + } else { + prev->next = t->next; + } + if (t->next) { + t->next->prev = prev; + } + return; + } + prev = t; + t=t->next; + } +} + +double +trace_delete(struct trace_pool *p, struct trace_info *t) { + assert(p->current == t); + p->current = NULL; + if (t) { + double ti = (double)t->ti_sec + (double)t->ti_nsec / NANOSEC; + free(t); + return ti; + } else { + return 0; + } +} diff --git a/lualib-src/trace_service.h b/lualib-src/trace_service.h new file mode 100644 index 00000000..61fbc79a --- /dev/null +++ b/lualib-src/trace_service.h @@ -0,0 +1,22 @@ +#ifndef TRACE_SERVICE_H +#define TRACE_SERVICE_H + +#include +#include + +#define NANOSEC 1000000000 + +void diff_time(struct timespec *ti, uint32_t *sec, uint32_t *nsec); + +struct trace_pool; +struct trace_info; + +struct trace_pool * trace_create(); +void trace_release(struct trace_pool *); +struct trace_info * trace_new(struct trace_pool *); +void trace_register(struct trace_pool *, int session); +void trace_switch(struct trace_pool *, int session); +struct trace_info * trace_yield(struct trace_pool *); +double trace_delete(struct trace_pool *, struct trace_info *); + +#endif