123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <lua.h>
- #include <stdio.h>
- #include "malloc_hook.h"
- #include "skynet.h"
- #include "atomic.h"
- // turn on MEMORY_CHECK can do more memory check, such as double free
- #define MEMORY_CHECK
- #define MEMORY_ALLOCTAG 0x20140605
- #define MEMORY_FREETAG 0x0badf00d
- static ATOM_SIZET _used_memory = 0;
- static ATOM_SIZET _memory_block = 0;
- struct mem_data {
- ATOM_ULONG handle;
- ATOM_SIZET allocated;
- };
- struct mem_cookie {
- uint32_t handle;
- #ifdef MEMORY_CHECK
- uint32_t dogtag;
- #endif
- };
- #define SLOT_SIZE 0x10000
- #define PREFIX_SIZE sizeof(struct mem_cookie)
- static struct mem_data mem_stats[SLOT_SIZE];
- #ifndef NOUSE_JEMALLOC
- #include "jemalloc.h"
- // for skynet_lalloc use
- #define raw_realloc je_realloc
- #define raw_free je_free
- static ATOM_SIZET *
- get_allocated_field(uint32_t handle) {
- int h = (int)(handle & (SLOT_SIZE - 1));
- struct mem_data *data = &mem_stats[h];
- uint32_t old_handle = data->handle;
- ssize_t old_alloc = (ssize_t)data->allocated;
- if(old_handle == 0 || old_alloc <= 0) {
- // data->allocated may less than zero, because it may not count at start.
- if(!ATOM_CAS_ULONG(&data->handle, old_handle, handle)) {
- return 0;
- }
- if (old_alloc < 0) {
- ATOM_CAS_SIZET(&data->allocated, (size_t)old_alloc, 0);
- }
- }
- if(data->handle != handle) {
- return 0;
- }
- return &data->allocated;
- }
- inline static void
- update_xmalloc_stat_alloc(uint32_t handle, size_t __n) {
- ATOM_FADD(&_used_memory, __n);
- ATOM_FINC(&_memory_block);
- ATOM_SIZET * allocated = get_allocated_field(handle);
- if(allocated) {
- ATOM_FADD(allocated, __n);
- }
- }
- inline static void
- update_xmalloc_stat_free(uint32_t handle, size_t __n) {
- ATOM_FSUB(&_used_memory, __n);
- ATOM_FDEC(&_memory_block);
- ATOM_SIZET * allocated = get_allocated_field(handle);
- if(allocated) {
- ATOM_FSUB(allocated, __n);
- }
- }
- inline static void*
- fill_prefix(char* ptr) {
- uint32_t handle = skynet_current_handle();
- size_t size = je_malloc_usable_size(ptr);
- struct mem_cookie *p = (struct mem_cookie *)(ptr + size - sizeof(struct mem_cookie));
- memcpy(&p->handle, &handle, sizeof(handle));
- #ifdef MEMORY_CHECK
- uint32_t dogtag = MEMORY_ALLOCTAG;
- memcpy(&p->dogtag, &dogtag, sizeof(dogtag));
- #endif
- update_xmalloc_stat_alloc(handle, size);
- return ptr;
- }
- inline static void*
- clean_prefix(char* ptr) {
- size_t size = je_malloc_usable_size(ptr);
- struct mem_cookie *p = (struct mem_cookie *)(ptr + size - sizeof(struct mem_cookie));
- uint32_t handle;
- memcpy(&handle, &p->handle, sizeof(handle));
- #ifdef MEMORY_CHECK
- uint32_t dogtag;
- memcpy(&dogtag, &p->dogtag, sizeof(dogtag));
- if (dogtag == MEMORY_FREETAG) {
- fprintf(stderr, "xmalloc: double free in :%08x\n", handle);
- }
- assert(dogtag == MEMORY_ALLOCTAG); // memory out of bounds
- dogtag = MEMORY_FREETAG;
- memcpy(&p->dogtag, &dogtag, sizeof(dogtag));
- #endif
- update_xmalloc_stat_free(handle, size);
- return ptr;
- }
- static void malloc_oom(size_t size) {
- fprintf(stderr, "xmalloc: Out of memory trying to allocate %zu bytes\n",
- size);
- fflush(stderr);
- abort();
- }
- void
- memory_info_dump(const char* opts) {
- je_malloc_stats_print(0,0, opts);
- }
- bool
- mallctl_bool(const char* name, bool* newval) {
- bool v = 0;
- size_t len = sizeof(v);
- if(newval) {
- je_mallctl(name, &v, &len, newval, sizeof(bool));
- } else {
- je_mallctl(name, &v, &len, NULL, 0);
- }
- return v;
- }
- int
- mallctl_cmd(const char* name) {
- return je_mallctl(name, NULL, NULL, NULL, 0);
- }
- size_t
- mallctl_int64(const char* name, size_t* newval) {
- size_t v = 0;
- size_t len = sizeof(v);
- if(newval) {
- je_mallctl(name, &v, &len, newval, sizeof(size_t));
- } else {
- je_mallctl(name, &v, &len, NULL, 0);
- }
- // skynet_error(NULL, "name: %s, value: %zd\n", name, v);
- return v;
- }
- int
- mallctl_opt(const char* name, int* newval) {
- int v = 0;
- size_t len = sizeof(v);
- if(newval) {
- int ret = je_mallctl(name, &v, &len, newval, sizeof(int));
- if(ret == 0) {
- skynet_error(NULL, "set new value(%d) for (%s) succeed\n", *newval, name);
- } else {
- skynet_error(NULL, "set new value(%d) for (%s) failed: error -> %d\n", *newval, name, ret);
- }
- } else {
- je_mallctl(name, &v, &len, NULL, 0);
- }
- return v;
- }
- // hook : malloc, realloc, free, calloc
- void *
- skynet_malloc(size_t size) {
- void* ptr = je_malloc(size + PREFIX_SIZE);
- if(!ptr) malloc_oom(size);
- return fill_prefix(ptr);
- }
- void *
- skynet_realloc(void *ptr, size_t size) {
- if (ptr == NULL) return skynet_malloc(size);
- void* rawptr = clean_prefix(ptr);
- void *newptr = je_realloc(rawptr, size+PREFIX_SIZE);
- if(!newptr) malloc_oom(size);
- return fill_prefix(newptr);
- }
- void
- skynet_free(void *ptr) {
- if (ptr == NULL) return;
- void* rawptr = clean_prefix(ptr);
- je_free(rawptr);
- }
- void *
- skynet_calloc(size_t nmemb,size_t size) {
- void* ptr = je_calloc(nmemb + ((PREFIX_SIZE+size-1)/size), size );
- if(!ptr) malloc_oom(size);
- return fill_prefix(ptr);
- }
- void *
- skynet_memalign(size_t alignment, size_t size) {
- void* ptr = je_memalign(alignment, size + PREFIX_SIZE);
- if(!ptr) malloc_oom(size);
- return fill_prefix(ptr);
- }
- void *
- skynet_aligned_alloc(size_t alignment, size_t size) {
- void* ptr = je_aligned_alloc(alignment, size + (size_t)((PREFIX_SIZE + alignment -1) & ~(alignment-1)));
- if(!ptr) malloc_oom(size);
- return fill_prefix(ptr);
- }
- int
- skynet_posix_memalign(void **memptr, size_t alignment, size_t size) {
- int err = je_posix_memalign(memptr, alignment, size + PREFIX_SIZE);
- if (err) malloc_oom(size);
- fill_prefix(*memptr);
- return err;
- }
- #else
- // for skynet_lalloc use
- #define raw_realloc realloc
- #define raw_free free
- void
- memory_info_dump(const char* opts) {
- skynet_error(NULL, "No jemalloc");
- }
- size_t
- mallctl_int64(const char* name, size_t* newval) {
- skynet_error(NULL, "No jemalloc : mallctl_int64 %s.", name);
- return 0;
- }
- int
- mallctl_opt(const char* name, int* newval) {
- skynet_error(NULL, "No jemalloc : mallctl_opt %s.", name);
- return 0;
- }
- bool
- mallctl_bool(const char* name, bool* newval) {
- skynet_error(NULL, "No jemalloc : mallctl_bool %s.", name);
- return 0;
- }
- int
- mallctl_cmd(const char* name) {
- skynet_error(NULL, "No jemalloc : mallctl_cmd %s.", name);
- return 0;
- }
- #endif
- size_t
- malloc_used_memory(void) {
- return ATOM_LOAD(&_used_memory);
- }
- size_t
- malloc_memory_block(void) {
- return ATOM_LOAD(&_memory_block);
- }
- void
- dump_c_mem() {
- int i;
- size_t total = 0;
- skynet_error(NULL, "dump all service mem:");
- for(i=0; i<SLOT_SIZE; i++) {
- struct mem_data* data = &mem_stats[i];
- if(data->handle != 0 && data->allocated != 0) {
- total += data->allocated;
- skynet_error(NULL, ":%08x -> %zdkb %db", data->handle, data->allocated >> 10, (int)(data->allocated % 1024));
- }
- }
- skynet_error(NULL, "+total: %zdkb",total >> 10);
- }
- char *
- skynet_strdup(const char *str) {
- size_t sz = strlen(str);
- char * ret = skynet_malloc(sz+1);
- memcpy(ret, str, sz+1);
- return ret;
- }
- void *
- skynet_lalloc(void *ptr, size_t osize, size_t nsize) {
- if (nsize == 0) {
- raw_free(ptr);
- return NULL;
- } else {
- return raw_realloc(ptr, nsize);
- }
- }
- int
- dump_mem_lua(lua_State *L) {
- int i;
- lua_newtable(L);
- for(i=0; i<SLOT_SIZE; i++) {
- struct mem_data* data = &mem_stats[i];
- if(data->handle != 0 && data->allocated != 0) {
- lua_pushinteger(L, data->allocated);
- lua_rawseti(L, -2, (lua_Integer)data->handle);
- }
- }
- return 1;
- }
- size_t
- malloc_current_memory(void) {
- uint32_t handle = skynet_current_handle();
- int i;
- for(i=0; i<SLOT_SIZE; i++) {
- struct mem_data* data = &mem_stats[i];
- if(data->handle == (uint32_t)handle && data->allocated != 0) {
- return (size_t) data->allocated;
- }
- }
- return 0;
- }
- void
- skynet_debug_memory(const char *info) {
- // for debug use
- uint32_t handle = skynet_current_handle();
- size_t mem = malloc_current_memory();
- fprintf(stderr, "[:%08x] %s %p\n", handle, info, (void *)mem);
- }
|