You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
6.5 KiB

  1. /*
  2. ISC License
  3. Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
  4. Permission to use, copy, modify, and/or distribute this software for any
  5. purpose with or without fee is hereby granted, provided that the above
  6. copyright notice and this permission notice appear in all copies.
  7. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. */
  15. #pragma once
  16. #include "kvec.h"
  17. #include <errno.h>
  18. #include <stdint.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/mman.h>
  22. #include <unistd.h>
  23. #define ROUND_UP(N,S) ((((N) + (S) - 1) / (S)) * (S))
  24. typedef kvec_t(void*) slab_kvec_t;
  25. typedef struct mem_stack_t mem_stack_t;
  26. struct mem_stack_t
  27. {
  28. mem_stack_t *next;
  29. };
  30. typedef struct fmp_t fmp_t;
  31. struct fmp_t
  32. {
  33. mem_stack_t *objs;
  34. slab_kvec_t slabs;
  35. uint64_t avail_objs;
  36. uint64_t obj_size;
  37. uint64_t page_size;
  38. uint64_t slab_size;
  39. };
  40. static
  41. inline
  42. uint64_t
  43. fmp_page_size()
  44. {
  45. return sysconf(_SC_PAGESIZE);
  46. }
  47. static
  48. inline
  49. void
  50. fmp_init(fmp_t *fmp_,
  51. const uint64_t obj_size_,
  52. const uint64_t page_multiple_)
  53. {
  54. kv_init(fmp_->slabs);
  55. fmp_->objs = NULL;
  56. fmp_->avail_objs = 0;
  57. fmp_->obj_size = ROUND_UP(obj_size_,sizeof(void*));
  58. fmp_->page_size = fmp_page_size();
  59. fmp_->slab_size = (fmp_->page_size * page_multiple_);
  60. }
  61. static
  62. inline
  63. uint64_t
  64. fmp_slab_count(fmp_t *fmp_)
  65. {
  66. return kv_size(fmp_->slabs);
  67. }
  68. static
  69. inline
  70. void*
  71. fmp_slab_alloc_posix_memalign(fmp_t *fmp_)
  72. {
  73. int rv;
  74. void *mem;
  75. const size_t alignment = fmp_->page_size;
  76. const size_t size = fmp_->slab_size;
  77. rv = posix_memalign(&mem,alignment,size);
  78. if(rv != 0)
  79. return NULL;
  80. return NULL;
  81. }
  82. static
  83. inline
  84. void*
  85. fmp_slab_alloc_mmap(fmp_t *fmp_)
  86. {
  87. void *mem;
  88. void *address = NULL;
  89. const size_t length = fmp_->slab_size;
  90. const int protect = PROT_READ|PROT_WRITE;
  91. const int flags = MAP_PRIVATE|MAP_ANONYMOUS;
  92. const int filedes = -1;
  93. const off_t offset = 0;
  94. mem = mmap(address,length,protect,flags,filedes,offset);
  95. if(mem == MAP_FAILED)
  96. return NULL;
  97. return mem;
  98. }
  99. static
  100. inline
  101. void
  102. fmp_slab_free_posix_memalign(fmp_t* fmp_,
  103. void *mem_)
  104. {
  105. (void)fmp_;
  106. free(mem_);
  107. }
  108. static
  109. inline
  110. void
  111. fmp_slab_free_mmap(fmp_t* fmp_,
  112. void *mem_)
  113. {
  114. void *addr = mem_;
  115. size_t length = fmp_->slab_size;
  116. (void)munmap(addr,length);
  117. }
  118. static
  119. inline
  120. int
  121. fmp_slab_alloc(fmp_t *fmp_)
  122. {
  123. char *i;
  124. void *mem;
  125. mem = fmp_slab_alloc_mmap(fmp_);
  126. if(mem == NULL)
  127. return -ENOMEM;
  128. kv_push(void*,fmp_->slabs,mem);
  129. i = ((char*)mem + fmp_->slab_size - fmp_->obj_size);
  130. while(i >= (char*)mem)
  131. {
  132. mem_stack_t *obj = (mem_stack_t*)i;
  133. obj->next = fmp_->objs;
  134. fmp_->objs = obj;
  135. fmp_->avail_objs++;
  136. i -= fmp_->obj_size;
  137. }
  138. return 0;
  139. }
  140. static
  141. inline
  142. void*
  143. fmp_alloc(fmp_t *fmp_)
  144. {
  145. void *rv;
  146. if(fmp_->objs == NULL)
  147. fmp_slab_alloc(fmp_);
  148. if(fmp_->objs == NULL)
  149. return NULL;
  150. rv = fmp_->objs;
  151. fmp_->objs = fmp_->objs->next;
  152. fmp_->avail_objs--;
  153. return rv;
  154. }
  155. static
  156. inline
  157. void*
  158. fmp_calloc(fmp_t *fmp_)
  159. {
  160. void *obj;
  161. obj = fmp_alloc(fmp_);
  162. if(obj == NULL)
  163. return NULL;
  164. memset(obj,0,fmp_->obj_size);
  165. return obj;
  166. }
  167. static
  168. inline
  169. void
  170. fmp_free(fmp_t *fmp_,
  171. void *obj_)
  172. {
  173. mem_stack_t *obj = (mem_stack_t*)obj_;
  174. obj->next = fmp_->objs;
  175. fmp_->objs = obj;
  176. fmp_->avail_objs++;
  177. }
  178. static
  179. inline
  180. void
  181. fmp_clear(fmp_t *fmp_)
  182. {
  183. while(kv_size(fmp_->slabs))
  184. {
  185. void *slab = kv_pop(fmp_->slabs);
  186. fmp_slab_free_mmap(fmp_,slab);
  187. }
  188. fmp_->objs = NULL;
  189. fmp_->avail_objs = 0;
  190. }
  191. static
  192. inline
  193. void
  194. fmp_destroy(fmp_t *fmp_)
  195. {
  196. fmp_clear(fmp_);
  197. kv_destroy(fmp_->slabs);
  198. }
  199. static
  200. inline
  201. uint64_t
  202. fmp_avail_objs(fmp_t *fmp_)
  203. {
  204. return fmp_->avail_objs;
  205. }
  206. static
  207. inline
  208. uint64_t
  209. fmp_objs_per_slab(fmp_t *fmp_)
  210. {
  211. return (fmp_->slab_size / fmp_->obj_size);
  212. }
  213. static
  214. inline
  215. uint64_t
  216. fmp_objs_in_slab(fmp_t *fmp_,
  217. void *slab_)
  218. {
  219. char *slab;
  220. uint64_t objs_per_slab;
  221. uint64_t objs_in_slab;
  222. slab = (char*)slab_;
  223. objs_in_slab = 0;
  224. objs_per_slab = fmp_objs_per_slab(fmp_);
  225. for(mem_stack_t *stack = fmp_->objs; stack != NULL; stack = stack->next)
  226. {
  227. char *obj = (char*)stack;
  228. if((obj >= slab) && (obj < (slab + fmp_->slab_size)))
  229. objs_in_slab++;
  230. if(objs_in_slab >= objs_per_slab)
  231. break;
  232. }
  233. return objs_in_slab;
  234. }
  235. static
  236. inline
  237. void
  238. fmp_remove_objs_in_slab(fmp_t *fmp_,
  239. void *slab_)
  240. {
  241. char *slab;
  242. uint64_t objs_per_slab;
  243. uint64_t objs_in_slab;
  244. mem_stack_t **p;
  245. p = &fmp_->objs;
  246. slab = (char*)slab_;
  247. objs_in_slab = 0;
  248. objs_per_slab = fmp_objs_per_slab(fmp_);
  249. while((*p) != NULL)
  250. {
  251. char *obj = (char*)*p;
  252. if((obj >= slab) && (obj < (slab + fmp_->slab_size)))
  253. {
  254. objs_in_slab++;
  255. *p = (*p)->next;
  256. fmp_->avail_objs--;
  257. if(objs_in_slab >= objs_per_slab)
  258. break;
  259. continue;
  260. }
  261. p = &(*p)->next;
  262. }
  263. }
  264. static
  265. inline
  266. int
  267. fmp_gc_slab(fmp_t *fmp_,
  268. uint64_t slab_idx_)
  269. {
  270. char *slab;
  271. uint64_t objs_in_slab;
  272. uint64_t objs_per_slab;
  273. slab_idx_ = (slab_idx_ % kv_size(fmp_->slabs));
  274. slab = kv_A(fmp_->slabs,slab_idx_);
  275. objs_per_slab = fmp_objs_per_slab(fmp_);
  276. objs_in_slab = fmp_objs_in_slab(fmp_,slab);
  277. if(objs_in_slab != objs_per_slab)
  278. return 0;
  279. fmp_remove_objs_in_slab(fmp_,slab);
  280. kv_delete(fmp_->slabs,slab_idx_);
  281. fmp_slab_free_mmap(fmp_,slab);
  282. return 1;
  283. }
  284. static
  285. inline
  286. int
  287. fmp_gc(fmp_t *fmp_)
  288. {
  289. uint64_t slab_idx;
  290. slab_idx = rand();
  291. return fmp_gc_slab(fmp_,slab_idx);
  292. }
  293. static
  294. inline
  295. double
  296. fmp_slab_usage_ratio(fmp_t *fmp_)
  297. {
  298. double avail_objs;
  299. double objs_per_slab;
  300. double nums_of_slabs;
  301. avail_objs = fmp_->avail_objs;
  302. objs_per_slab = fmp_objs_per_slab(fmp_);
  303. nums_of_slabs = kv_size(fmp_->slabs);
  304. return (avail_objs / (objs_per_slab * nums_of_slabs));
  305. }
  306. static
  307. inline
  308. uint64_t
  309. fmp_total_allocated_memory(fmp_t *fmp_)
  310. {
  311. return (fmp_->slab_size * kv_size(fmp_->slabs));
  312. }