malloc_hook.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <assert.h>
  4. #include <stdlib.h>
  5. #include <lua.h>
  6. #include <stdio.h>
  7. #include "malloc_hook.h"
  8. #include "skynet.h"
  9. #include "atomic.h"
  10. // turn on MEMORY_CHECK can do more memory check, such as double free
  11. #define MEMORY_CHECK
  12. #define MEMORY_ALLOCTAG 0x20140605
  13. #define MEMORY_FREETAG 0x0badf00d
  14. static ATOM_SIZET _used_memory = 0;
  15. static ATOM_SIZET _memory_block = 0;
  16. struct mem_data {
  17. ATOM_ULONG handle;
  18. ATOM_SIZET allocated;
  19. };
  20. struct mem_cookie {
  21. uint32_t handle;
  22. #ifdef MEMORY_CHECK
  23. uint32_t dogtag;
  24. #endif
  25. };
  26. #define SLOT_SIZE 0x10000
  27. #define PREFIX_SIZE sizeof(struct mem_cookie)
  28. static struct mem_data mem_stats[SLOT_SIZE];
  29. #ifndef NOUSE_JEMALLOC
  30. #include "jemalloc.h"
  31. // for skynet_lalloc use
  32. #define raw_realloc je_realloc
  33. #define raw_free je_free
  34. static ATOM_SIZET *
  35. get_allocated_field(uint32_t handle) {
  36. int h = (int)(handle & (SLOT_SIZE - 1));
  37. struct mem_data *data = &mem_stats[h];
  38. uint32_t old_handle = data->handle;
  39. ssize_t old_alloc = (ssize_t)data->allocated;
  40. if(old_handle == 0 || old_alloc <= 0) {
  41. // data->allocated may less than zero, because it may not count at start.
  42. if(!ATOM_CAS_ULONG(&data->handle, old_handle, handle)) {
  43. return 0;
  44. }
  45. if (old_alloc < 0) {
  46. ATOM_CAS_SIZET(&data->allocated, (size_t)old_alloc, 0);
  47. }
  48. }
  49. if(data->handle != handle) {
  50. return 0;
  51. }
  52. return &data->allocated;
  53. }
  54. inline static void
  55. update_xmalloc_stat_alloc(uint32_t handle, size_t __n) {
  56. ATOM_FADD(&_used_memory, __n);
  57. ATOM_FINC(&_memory_block);
  58. ATOM_SIZET * allocated = get_allocated_field(handle);
  59. if(allocated) {
  60. ATOM_FADD(allocated, __n);
  61. }
  62. }
  63. inline static void
  64. update_xmalloc_stat_free(uint32_t handle, size_t __n) {
  65. ATOM_FSUB(&_used_memory, __n);
  66. ATOM_FDEC(&_memory_block);
  67. ATOM_SIZET * allocated = get_allocated_field(handle);
  68. if(allocated) {
  69. ATOM_FSUB(allocated, __n);
  70. }
  71. }
  72. inline static void*
  73. fill_prefix(char* ptr) {
  74. uint32_t handle = skynet_current_handle();
  75. size_t size = je_malloc_usable_size(ptr);
  76. struct mem_cookie *p = (struct mem_cookie *)(ptr + size - sizeof(struct mem_cookie));
  77. memcpy(&p->handle, &handle, sizeof(handle));
  78. #ifdef MEMORY_CHECK
  79. uint32_t dogtag = MEMORY_ALLOCTAG;
  80. memcpy(&p->dogtag, &dogtag, sizeof(dogtag));
  81. #endif
  82. update_xmalloc_stat_alloc(handle, size);
  83. return ptr;
  84. }
  85. inline static void*
  86. clean_prefix(char* ptr) {
  87. size_t size = je_malloc_usable_size(ptr);
  88. struct mem_cookie *p = (struct mem_cookie *)(ptr + size - sizeof(struct mem_cookie));
  89. uint32_t handle;
  90. memcpy(&handle, &p->handle, sizeof(handle));
  91. #ifdef MEMORY_CHECK
  92. uint32_t dogtag;
  93. memcpy(&dogtag, &p->dogtag, sizeof(dogtag));
  94. if (dogtag == MEMORY_FREETAG) {
  95. fprintf(stderr, "xmalloc: double free in :%08x\n", handle);
  96. }
  97. assert(dogtag == MEMORY_ALLOCTAG); // memory out of bounds
  98. dogtag = MEMORY_FREETAG;
  99. memcpy(&p->dogtag, &dogtag, sizeof(dogtag));
  100. #endif
  101. update_xmalloc_stat_free(handle, size);
  102. return ptr;
  103. }
  104. static void malloc_oom(size_t size) {
  105. fprintf(stderr, "xmalloc: Out of memory trying to allocate %zu bytes\n",
  106. size);
  107. fflush(stderr);
  108. abort();
  109. }
  110. void
  111. memory_info_dump(const char* opts) {
  112. je_malloc_stats_print(0,0, opts);
  113. }
  114. bool
  115. mallctl_bool(const char* name, bool* newval) {
  116. bool v = 0;
  117. size_t len = sizeof(v);
  118. if(newval) {
  119. je_mallctl(name, &v, &len, newval, sizeof(bool));
  120. } else {
  121. je_mallctl(name, &v, &len, NULL, 0);
  122. }
  123. return v;
  124. }
  125. int
  126. mallctl_cmd(const char* name) {
  127. return je_mallctl(name, NULL, NULL, NULL, 0);
  128. }
  129. size_t
  130. mallctl_int64(const char* name, size_t* newval) {
  131. size_t v = 0;
  132. size_t len = sizeof(v);
  133. if(newval) {
  134. je_mallctl(name, &v, &len, newval, sizeof(size_t));
  135. } else {
  136. je_mallctl(name, &v, &len, NULL, 0);
  137. }
  138. // skynet_error(NULL, "name: %s, value: %zd\n", name, v);
  139. return v;
  140. }
  141. int
  142. mallctl_opt(const char* name, int* newval) {
  143. int v = 0;
  144. size_t len = sizeof(v);
  145. if(newval) {
  146. int ret = je_mallctl(name, &v, &len, newval, sizeof(int));
  147. if(ret == 0) {
  148. skynet_error(NULL, "set new value(%d) for (%s) succeed\n", *newval, name);
  149. } else {
  150. skynet_error(NULL, "set new value(%d) for (%s) failed: error -> %d\n", *newval, name, ret);
  151. }
  152. } else {
  153. je_mallctl(name, &v, &len, NULL, 0);
  154. }
  155. return v;
  156. }
  157. // hook : malloc, realloc, free, calloc
  158. void *
  159. skynet_malloc(size_t size) {
  160. void* ptr = je_malloc(size + PREFIX_SIZE);
  161. if(!ptr) malloc_oom(size);
  162. return fill_prefix(ptr);
  163. }
  164. void *
  165. skynet_realloc(void *ptr, size_t size) {
  166. if (ptr == NULL) return skynet_malloc(size);
  167. void* rawptr = clean_prefix(ptr);
  168. void *newptr = je_realloc(rawptr, size+PREFIX_SIZE);
  169. if(!newptr) malloc_oom(size);
  170. return fill_prefix(newptr);
  171. }
  172. void
  173. skynet_free(void *ptr) {
  174. if (ptr == NULL) return;
  175. void* rawptr = clean_prefix(ptr);
  176. je_free(rawptr);
  177. }
  178. void *
  179. skynet_calloc(size_t nmemb,size_t size) {
  180. void* ptr = je_calloc(nmemb + ((PREFIX_SIZE+size-1)/size), size );
  181. if(!ptr) malloc_oom(size);
  182. return fill_prefix(ptr);
  183. }
  184. void *
  185. skynet_memalign(size_t alignment, size_t size) {
  186. void* ptr = je_memalign(alignment, size + PREFIX_SIZE);
  187. if(!ptr) malloc_oom(size);
  188. return fill_prefix(ptr);
  189. }
  190. void *
  191. skynet_aligned_alloc(size_t alignment, size_t size) {
  192. void* ptr = je_aligned_alloc(alignment, size + (size_t)((PREFIX_SIZE + alignment -1) & ~(alignment-1)));
  193. if(!ptr) malloc_oom(size);
  194. return fill_prefix(ptr);
  195. }
  196. int
  197. skynet_posix_memalign(void **memptr, size_t alignment, size_t size) {
  198. int err = je_posix_memalign(memptr, alignment, size + PREFIX_SIZE);
  199. if (err) malloc_oom(size);
  200. fill_prefix(*memptr);
  201. return err;
  202. }
  203. #else
  204. // for skynet_lalloc use
  205. #define raw_realloc realloc
  206. #define raw_free free
  207. void
  208. memory_info_dump(const char* opts) {
  209. skynet_error(NULL, "No jemalloc");
  210. }
  211. size_t
  212. mallctl_int64(const char* name, size_t* newval) {
  213. skynet_error(NULL, "No jemalloc : mallctl_int64 %s.", name);
  214. return 0;
  215. }
  216. int
  217. mallctl_opt(const char* name, int* newval) {
  218. skynet_error(NULL, "No jemalloc : mallctl_opt %s.", name);
  219. return 0;
  220. }
  221. bool
  222. mallctl_bool(const char* name, bool* newval) {
  223. skynet_error(NULL, "No jemalloc : mallctl_bool %s.", name);
  224. return 0;
  225. }
  226. int
  227. mallctl_cmd(const char* name) {
  228. skynet_error(NULL, "No jemalloc : mallctl_cmd %s.", name);
  229. return 0;
  230. }
  231. #endif
  232. size_t
  233. malloc_used_memory(void) {
  234. return ATOM_LOAD(&_used_memory);
  235. }
  236. size_t
  237. malloc_memory_block(void) {
  238. return ATOM_LOAD(&_memory_block);
  239. }
  240. void
  241. dump_c_mem() {
  242. int i;
  243. size_t total = 0;
  244. skynet_error(NULL, "dump all service mem:");
  245. for(i=0; i<SLOT_SIZE; i++) {
  246. struct mem_data* data = &mem_stats[i];
  247. if(data->handle != 0 && data->allocated != 0) {
  248. total += data->allocated;
  249. skynet_error(NULL, ":%08x -> %zdkb %db", data->handle, data->allocated >> 10, (int)(data->allocated % 1024));
  250. }
  251. }
  252. skynet_error(NULL, "+total: %zdkb",total >> 10);
  253. }
  254. char *
  255. skynet_strdup(const char *str) {
  256. size_t sz = strlen(str);
  257. char * ret = skynet_malloc(sz+1);
  258. memcpy(ret, str, sz+1);
  259. return ret;
  260. }
  261. void *
  262. skynet_lalloc(void *ptr, size_t osize, size_t nsize) {
  263. if (nsize == 0) {
  264. raw_free(ptr);
  265. return NULL;
  266. } else {
  267. return raw_realloc(ptr, nsize);
  268. }
  269. }
  270. int
  271. dump_mem_lua(lua_State *L) {
  272. int i;
  273. lua_newtable(L);
  274. for(i=0; i<SLOT_SIZE; i++) {
  275. struct mem_data* data = &mem_stats[i];
  276. if(data->handle != 0 && data->allocated != 0) {
  277. lua_pushinteger(L, data->allocated);
  278. lua_rawseti(L, -2, (lua_Integer)data->handle);
  279. }
  280. }
  281. return 1;
  282. }
  283. size_t
  284. malloc_current_memory(void) {
  285. uint32_t handle = skynet_current_handle();
  286. int i;
  287. for(i=0; i<SLOT_SIZE; i++) {
  288. struct mem_data* data = &mem_stats[i];
  289. if(data->handle == (uint32_t)handle && data->allocated != 0) {
  290. return (size_t) data->allocated;
  291. }
  292. }
  293. return 0;
  294. }
  295. void
  296. skynet_debug_memory(const char *info) {
  297. // for debug use
  298. uint32_t handle = skynet_current_handle();
  299. size_t mem = malloc_current_memory();
  300. fprintf(stderr, "[:%08x] %s %p\n", handle, info, (void *)mem);
  301. }