crn_mem.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. // File: crn_mem.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_console.h"
  5. #include "../inc/crnlib.h"
  6. #include <malloc.h>
  7. #if CRNLIB_USE_WIN32_API
  8. #include "crn_winhdr.h"
  9. #endif
  10. #define CRNLIB_MEM_STATS 0
  11. #if !CRNLIB_USE_WIN32_API
  12. #define _msize malloc_usable_size
  13. #endif
  14. namespace crnlib
  15. {
  16. #if CRNLIB_MEM_STATS
  17. #if CRNLIB_64BIT_POINTERS
  18. typedef LONGLONG mem_stat_t;
  19. #define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange64
  20. #else
  21. typedef LONG mem_stat_t;
  22. #define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange
  23. #endif
  24. static volatile mem_stat_t g_total_blocks;
  25. static volatile mem_stat_t g_total_allocated;
  26. static volatile mem_stat_t g_max_allocated;
  27. static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta)
  28. {
  29. mem_stat_t cur_total_blocks;
  30. for ( ; ; )
  31. {
  32. cur_total_blocks = (mem_stat_t)g_total_blocks;
  33. mem_stat_t new_total_blocks = static_cast<mem_stat_t>(cur_total_blocks + block_delta);
  34. CRNLIB_ASSERT(new_total_blocks >= 0);
  35. if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_blocks, new_total_blocks, cur_total_blocks) == cur_total_blocks)
  36. break;
  37. }
  38. mem_stat_t cur_total_allocated, new_total_allocated;
  39. for ( ; ; )
  40. {
  41. cur_total_allocated = g_total_allocated;
  42. new_total_allocated = static_cast<mem_stat_t>(cur_total_allocated + byte_delta);
  43. CRNLIB_ASSERT(new_total_allocated >= 0);
  44. if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_allocated, new_total_allocated, cur_total_allocated) == cur_total_allocated)
  45. break;
  46. }
  47. for ( ; ; )
  48. {
  49. mem_stat_t cur_max_allocated = g_max_allocated;
  50. mem_stat_t new_max_allocated = CRNLIB_MAX(new_total_allocated, cur_max_allocated);
  51. if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_max_allocated, new_max_allocated, cur_max_allocated) == cur_max_allocated)
  52. break;
  53. }
  54. return new_total_allocated;
  55. }
  56. #endif // CRNLIB_MEM_STATS
  57. static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
  58. {
  59. pUser_data;
  60. void* p_new;
  61. if (!p)
  62. {
  63. p_new = ::malloc(size);
  64. CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
  65. if (!p_new)
  66. {
  67. printf("WARNING: ::malloc() of size %u failed!\n", (uint)size);
  68. }
  69. if (pActual_size)
  70. *pActual_size = p_new ? ::_msize(p_new) : 0;
  71. }
  72. else if (!size)
  73. {
  74. ::free(p);
  75. p_new = NULL;
  76. if (pActual_size)
  77. *pActual_size = 0;
  78. }
  79. else
  80. {
  81. void* p_final_block = p;
  82. #ifdef WIN32
  83. p_new = ::_expand(p, size);
  84. #else
  85. p_new = NULL;
  86. #endif
  87. if (p_new)
  88. {
  89. CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
  90. p_final_block = p_new;
  91. }
  92. else if (movable)
  93. {
  94. p_new = ::realloc(p, size);
  95. if (p_new)
  96. {
  97. CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
  98. p_final_block = p_new;
  99. }
  100. else
  101. {
  102. printf("WARNING: ::realloc() of size %u failed!\n", (uint)size);
  103. }
  104. }
  105. if (pActual_size)
  106. *pActual_size = ::_msize(p_final_block);
  107. }
  108. return p_new;
  109. }
  110. static size_t crnlib_default_msize(void* p, void* pUser_data)
  111. {
  112. pUser_data;
  113. return p ? _msize(p) : 0;
  114. }
  115. #if 0
  116. static __declspec(thread) void *g_pBuf;
  117. static __declspec(thread) size_t g_buf_size;
  118. static __declspec(thread) size_t g_buf_ofs;
  119. static size_t crnlib_nofree_msize(void* p, void* pUser_data)
  120. {
  121. pUser_data;
  122. return p ? ((const size_t*)p)[-1] : 0;
  123. }
  124. static void* crnlib_nofree_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
  125. {
  126. pUser_data;
  127. void* p_new;
  128. if (!p)
  129. {
  130. size = math::align_up_value(size, CRNLIB_MIN_ALLOC_ALIGNMENT);
  131. size_t actual_size = sizeof(size_t)*2 + size;
  132. size_t num_remaining = g_buf_size - g_buf_ofs;
  133. if (num_remaining < actual_size)
  134. {
  135. g_buf_size = CRNLIB_MAX(actual_size, 32*1024*1024);
  136. g_buf_ofs = 0;
  137. g_pBuf = malloc(g_buf_size);
  138. if (!g_pBuf)
  139. return NULL;
  140. }
  141. p_new = (uint8*)g_pBuf + g_buf_ofs;
  142. ((size_t*)p_new)[1] = size;
  143. p_new = (size_t*)p_new + 2;
  144. g_buf_ofs += actual_size;
  145. if (pActual_size)
  146. *pActual_size = size;
  147. CRNLIB_ASSERT(crnlib_nofree_msize(p_new, NULL) == size);
  148. }
  149. else if (!size)
  150. {
  151. if (pActual_size)
  152. *pActual_size = 0;
  153. p_new = NULL;
  154. }
  155. else
  156. {
  157. size_t cur_size = crnlib_nofree_msize(p, NULL);
  158. p_new = p;
  159. if (!movable)
  160. return NULL;
  161. if (size > cur_size)
  162. {
  163. p_new = crnlib_nofree_realloc(NULL, size, NULL, true, NULL);
  164. if (!p_new)
  165. return NULL;
  166. memcpy(p_new, p, cur_size);
  167. cur_size = size;
  168. }
  169. if (pActual_size)
  170. *pActual_size = cur_size;
  171. }
  172. return p_new;
  173. }
  174. static crn_realloc_func g_pRealloc = crnlib_nofree_realloc;
  175. static crn_msize_func g_pMSize = crnlib_nofree_msize;
  176. #else
  177. static crn_realloc_func g_pRealloc = crnlib_default_realloc;
  178. static crn_msize_func g_pMSize = crnlib_default_msize;
  179. #endif
  180. static void* g_pUser_data;
  181. void crnlib_mem_error(const char* p_msg)
  182. {
  183. crnlib_assert(p_msg, __FILE__, __LINE__);
  184. }
  185. void* crnlib_malloc(size_t size)
  186. {
  187. return crnlib_malloc(size, NULL);
  188. }
  189. void* crnlib_malloc(size_t size, size_t* pActual_size)
  190. {
  191. size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U);
  192. if (!size)
  193. size = sizeof(uint32);
  194. if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
  195. {
  196. crnlib_mem_error("crnlib_malloc: size too big");
  197. return NULL;
  198. }
  199. size_t actual_size = size;
  200. uint8* p_new = static_cast<uint8*>((*g_pRealloc)(NULL, size, &actual_size, true, g_pUser_data));
  201. if (pActual_size)
  202. *pActual_size = actual_size;
  203. if ((!p_new) || (actual_size < size))
  204. {
  205. crnlib_mem_error("crnlib_malloc: out of memory");
  206. return NULL;
  207. }
  208. CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
  209. #if CRNLIB_MEM_STATS
  210. CRNLIB_ASSERT((*g_pMSize)(p_new, g_pUser_data) == actual_size);
  211. update_total_allocated(1, static_cast<mem_stat_t>(actual_size));
  212. #endif
  213. return p_new;
  214. }
  215. void* crnlib_realloc(void* p, size_t size, size_t* pActual_size, bool movable)
  216. {
  217. if ((ptr_bits_t)p & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
  218. {
  219. crnlib_mem_error("crnlib_realloc: bad ptr");
  220. return NULL;
  221. }
  222. if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
  223. {
  224. crnlib_mem_error("crnlib_malloc: size too big");
  225. return NULL;
  226. }
  227. #if CRNLIB_MEM_STATS
  228. size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0;
  229. CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32)));
  230. #endif
  231. if ((size) && (size < sizeof(uint32)))
  232. size = sizeof(uint32);
  233. size_t actual_size = size;
  234. void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data);
  235. if (pActual_size)
  236. *pActual_size = actual_size;
  237. CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
  238. #if CRNLIB_MEM_STATS
  239. CRNLIB_ASSERT(!p_new || ((*g_pMSize)(p_new, g_pUser_data) == actual_size));
  240. int num_new_blocks = 0;
  241. if (p)
  242. {
  243. if (!p_new)
  244. num_new_blocks = -1;
  245. }
  246. else if (p_new)
  247. {
  248. num_new_blocks = 1;
  249. }
  250. update_total_allocated(num_new_blocks, static_cast<mem_stat_t>(actual_size) - static_cast<mem_stat_t>(cur_size));
  251. #endif
  252. return p_new;
  253. }
  254. void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size)
  255. {
  256. size_t total = count * size;
  257. void *p = crnlib_malloc(total, pActual_size);
  258. if (p) memset(p, 0, total);
  259. return p;
  260. }
  261. void crnlib_free(void* p)
  262. {
  263. if (!p)
  264. return;
  265. if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
  266. {
  267. crnlib_mem_error("crnlib_free: bad ptr");
  268. return;
  269. }
  270. #if CRNLIB_MEM_STATS
  271. size_t cur_size = (*g_pMSize)(p, g_pUser_data);
  272. CRNLIB_ASSERT(cur_size >= sizeof(uint32));
  273. update_total_allocated(-1, -static_cast<mem_stat_t>(cur_size));
  274. #endif
  275. (*g_pRealloc)(p, 0, NULL, true, g_pUser_data);
  276. }
  277. size_t crnlib_msize(void* p)
  278. {
  279. if (!p)
  280. return 0;
  281. if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
  282. {
  283. crnlib_mem_error("crnlib_msize: bad ptr");
  284. return 0;
  285. }
  286. return (*g_pMSize)(p, g_pUser_data);
  287. }
  288. void crnlib_print_mem_stats()
  289. {
  290. #if CRNLIB_MEM_STATS
  291. if (console::is_initialized())
  292. {
  293. console::debug("crnlib_print_mem_stats:");
  294. console::debug("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER, g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
  295. }
  296. else
  297. {
  298. printf("crnlib_print_mem_stats:\n");
  299. printf("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER "\n", g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
  300. }
  301. #endif
  302. }
  303. } // namespace crnlib
  304. void crn_set_memory_callbacks(crn_realloc_func pRealloc, crn_msize_func pMSize, void* pUser_data)
  305. {
  306. if ((!pRealloc) || (!pMSize))
  307. {
  308. crnlib::g_pRealloc = crnlib::crnlib_default_realloc;
  309. crnlib::g_pMSize = crnlib::crnlib_default_msize;
  310. crnlib::g_pUser_data = NULL;
  311. }
  312. else
  313. {
  314. crnlib::g_pRealloc = pRealloc;
  315. crnlib::g_pMSize = pMSize;
  316. crnlib::g_pUser_data = pUser_data;
  317. }
  318. }