diff --git a/Makefile b/Makefile index 3f83e0aa..01bf2802 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ service/harbor.so : service-src/service_harbor.c service/logger.so : skynet-src/skynet_logger.c gcc $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -service/snlua.so : service-src/service_lua.c service-src/luacode_cache.c +service/snlua.so : service-src/service_lua.c service-src/luacode_cache.c service-src/luaalloc.c gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ -Iskynet-src service/gate.so : service-src/service_gate.c diff --git a/service-src/luaalloc.c b/service-src/luaalloc.c new file mode 100644 index 00000000..2d0b0b14 --- /dev/null +++ b/service-src/luaalloc.c @@ -0,0 +1,161 @@ +#include "luaalloc.h" +#include +#include +#include + +#define ALLOCCHUNK (16 * 1024 + sizeof(struct memchunk)) + +struct freenode { + struct freenode * next; +}; + +struct memchunk { + struct memchunk * next; +}; + +struct skynet_lalloc { + // small memory list : 8,16,32,64,128,256,512 + struct freenode * freelist[7]; + struct memchunk * chunklist; + char * ptr; + char * end; +}; + +static void +new_chunk(struct skynet_lalloc *lalloc) { + struct memchunk * mc = malloc(ALLOCCHUNK); + mc->next = lalloc->chunklist; + lalloc->ptr = (char *)(mc+1); + lalloc->end = ((char *)mc) + ALLOCCHUNK; + lalloc->chunklist = mc; +} + +inline static int +size_index(size_t sz) { + if (sz > 32) { + if (sz > 128) { + if (sz > 256) + return 6; + else + return 5; + } else { + if (sz > 64) + return 4; + else + return 3; + } + } else { + if (sz > 16) + return 2; + else if (sz > 8) + return 1; + else + return 0; + } +} + +#define REALSIZE(idx) (1<<((idx)+3)) + +static void * +new_small_block(struct skynet_lalloc *lalloc, int idx) { + struct freenode * fn = lalloc->freelist[idx]; + if (fn) { + lalloc->freelist[idx] = fn->next; + return fn; + } else { + int rsz = REALSIZE(idx); + if ((lalloc->end - lalloc->ptr) < rsz) { + new_chunk(lalloc); + } + void * ret = lalloc->ptr; + lalloc->ptr += rsz; + return ret; + } +} + +static void +delete_small_block(struct skynet_lalloc *lalloc, void * ptr, int idx) { + struct freenode * fn = lalloc->freelist[idx]; + struct freenode * node = (struct freenode *)ptr; + node->next = fn; + lalloc->freelist[idx] = node; +} + +static void * +extend_small_block(struct skynet_lalloc *lalloc, void * ptr, size_t osize, size_t nsize) { + int oidx = size_index(osize); + int nidx = size_index(nsize); + if (oidx == nidx) { + return ptr; + } + void * ret = new_small_block(lalloc,nidx); + memcpy(ret, ptr, osize < nsize ? osize : nsize); + delete_small_block(lalloc, ptr, oidx); + return ret; +} + +void * +skynet_lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { + struct skynet_lalloc *lalloc = ud; + if (ptr == NULL) { + if (nsize > 512) { + return malloc(nsize); + } + int idx = size_index(nsize); + return new_small_block(lalloc, idx); + } else if (nsize == 0) { + if (osize > 512) { + free(ptr); + return NULL; + } + int idx = size_index(osize); + delete_small_block(lalloc, ptr, idx); + return NULL; + } else { + if (osize > 512) { + if (nsize > 512) { + return realloc(ptr, nsize); + } else { + int idx = size_index(nsize); + void * ret = new_small_block(lalloc, idx); + memcpy(ret, ptr, nsize); + free(ptr); + return ret; + } + } + if (nsize > 512) { + void * buffer = malloc(nsize); + memcpy(buffer, ptr, osize); + int idx = size_index(osize); + delete_small_block(lalloc, ptr, idx); + return buffer; + } else { + return extend_small_block(lalloc, ptr, osize, nsize); + } + } +} + +struct skynet_lalloc * +skynet_lalloc_new(size_t prealloc) { + assert(prealloc > sizeof(struct skynet_lalloc)); + struct skynet_lalloc * lalloc = malloc(prealloc); + int i; + for (i=0;ifreelist)/sizeof(lalloc->freelist[0]);i++) { + lalloc->freelist[i] = NULL; + } + lalloc->chunklist = NULL; + lalloc->ptr = (char *)(lalloc+1); + lalloc->end = ((char *)lalloc) + prealloc; + return lalloc; +} + +void +skynet_lalloc_delete(struct skynet_lalloc *lalloc) { + struct memchunk * mc = lalloc->chunklist; + while(mc) { + struct memchunk * tmp = mc; + mc = mc->next; + free(tmp); + } + free(lalloc); +} diff --git a/service-src/luaalloc.h b/service-src/luaalloc.h new file mode 100644 index 00000000..a5a426b8 --- /dev/null +++ b/service-src/luaalloc.h @@ -0,0 +1,14 @@ +#ifndef skynet_lua_alloc_h +#define skynet_lua_alloc_h + +#include +#include + +struct skynet_lalloc; + +struct skynet_lalloc * skynet_lalloc_new(size_t prealloc); +void skynet_lalloc_delete(struct skynet_lalloc *); + +void * skynet_lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize); + +#endif diff --git a/service-src/service_lua.c b/service-src/service_lua.c index d4c5eaa5..bfb256a4 100644 --- a/service-src/service_lua.c +++ b/service-src/service_lua.c @@ -7,12 +7,15 @@ #include "luacompat52.h" #include "service_lua.h" #include "luacode_cache.h" +#include "luaalloc.h" #include #include #include #include +#define PREALLOCMEM (1024 * 1024) + // time #include @@ -245,13 +248,25 @@ struct snlua * snlua_create(void) { struct snlua * l = malloc(sizeof(*l)); memset(l,0,sizeof(*l)); +#ifdef PREALLOCMEM + l->L = lua_newstate(skynet_lua_alloc, skynet_lalloc_new(PREALLOCMEM)); +#else l->L = luaL_newstate(); +#endif l->init = _init; return l; } void snlua_release(struct snlua *l) { + void * ud = NULL; +#ifdef PREALLOCMEM + lua_Alloc lalloc = lua_getallocf(l->L, &ud); + assert(lalloc == skynet_lua_alloc); lua_close(l->L); + skynet_lalloc_delete(ud); +#else + lua_close(l->L); +#endif free(l); }