alloc.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124
  1. #include <unistd.h>
  2. #include <stdint.h>
  3. #include <string.h>
  4. #include <limits.h>
  5. #include <assert.h>
  6. #include <stdlib.h>
  7. #include "alloc.h"
  8. #include "build_assert/build_assert.h"
  9. #include "config.h"
  10. /* FIXME: We assume getpagesize() doesnt change. Remapping file with
  11. * different pagesize should still work. */
  12. #if HAVE_ALIGNOF
  13. #define ALIGNOF(t) __alignof__(t)
  14. #else
  15. /* Alignment by measuring structure padding. */
  16. #define ALIGNOF(t) (sizeof(struct { char c; t _h; }) - 1 - sizeof(t))
  17. #endif
  18. /* FIXME: Doesn't handle non-page-aligned poolsize. */
  19. /* FIXME: Reduce. */
  20. #define MIN_SIZE (getpagesize() * 2)
  21. /* What's the granularity of sub-page allocs? */
  22. #define BITMAP_GRANULARITY 4
  23. /* File layout:
  24. *
  25. * file := pagestates pad uniform-cache metadata
  26. * pagestates := pages * 2-bits-per-page
  27. * pad := pad to next ALIGNOF(metaheader)
  28. *
  29. * metadata := metalen next-ptr metabits
  30. * metabits := freeblock | bitblock | uniformblock
  31. * freeblock := FREE +
  32. * bitblock := BITMAP + 2-bits-per-bit-in-page + pad-to-byte
  33. * uniformblock := UNIFORM + 14-bit-byte-len + bits + pad-to-byte
  34. */
  35. #define UNIFORM_CACHE_NUM 16
  36. struct uniform_cache
  37. {
  38. uint16_t size[UNIFORM_CACHE_NUM];
  39. /* These could be u32 if we're prepared to limit size. */
  40. unsigned long page[UNIFORM_CACHE_NUM];
  41. };
  42. struct metaheader
  43. {
  44. /* Next meta header, or 0 */
  45. unsigned long next;
  46. /* Bits start here. */
  47. };
  48. /* Assumes a is a power of two. */
  49. static unsigned long align_up(unsigned long x, unsigned long a)
  50. {
  51. return (x + a - 1) & ~(a - 1);
  52. }
  53. static unsigned long align_down(unsigned long x, unsigned long a)
  54. {
  55. return x & ~(a - 1);
  56. }
  57. static unsigned long div_up(unsigned long x, unsigned long a)
  58. {
  59. return (x + a - 1) / a;
  60. }
  61. /* It turns out that we spend a lot of time dealing with bit pairs.
  62. * These routines manipulate them.
  63. */
  64. static uint8_t get_bit_pair(const uint8_t *bits, unsigned long index)
  65. {
  66. return bits[index * 2 / CHAR_BIT] >> (index * 2 % CHAR_BIT) & 3;
  67. }
  68. static void set_bit_pair(uint8_t *bits, unsigned long index, uint8_t val)
  69. {
  70. bits[index * 2 / CHAR_BIT] &= ~(3 << (index * 2 % CHAR_BIT));
  71. bits[index * 2 / CHAR_BIT] |= (val << (index * 2 % CHAR_BIT));
  72. }
  73. /* This is used for page states and subpage allocations */
  74. enum alloc_state
  75. {
  76. FREE,
  77. TAKEN,
  78. TAKEN_START,
  79. SPECIAL, /* Sub-page allocation for page states. */
  80. };
  81. /* The types for subpage metadata. */
  82. enum sub_metadata_type
  83. {
  84. /* FREE is same as alloc state */
  85. BITMAP = 1, /* bitmap allocated page */
  86. UNIFORM, /* uniform size allocated page */
  87. };
  88. /* Page states are represented by bitpairs, at the start of the pool. */
  89. #define BITS_PER_PAGE 2
  90. /* How much metadata info per byte? */
  91. #define METADATA_PER_BYTE (CHAR_BIT / 2)
  92. static uint8_t *get_page_statebits(const void *pool)
  93. {
  94. return (uint8_t *)pool + sizeof(struct uniform_cache);
  95. }
  96. static enum alloc_state get_page_state(const void *pool, unsigned long page)
  97. {
  98. return get_bit_pair(get_page_statebits(pool), page);
  99. }
  100. static void set_page_state(void *pool, unsigned long page, enum alloc_state s)
  101. {
  102. set_bit_pair(get_page_statebits(pool), page, s);
  103. }
  104. /* The offset of metadata for a subpage allocation is found at the end
  105. * of the subpage */
  106. #define SUBPAGE_METAOFF (getpagesize() - sizeof(unsigned long))
  107. /* This is the length of metadata in bits. It consists of two bits
  108. * for every BITMAP_GRANULARITY of usable bytes in the page, then two
  109. * bits for the tailer.. */
  110. #define BITMAP_METABITLEN \
  111. ((div_up(SUBPAGE_METAOFF, BITMAP_GRANULARITY) + 1) * BITS_PER_PAGE)
  112. /* This is the length in bytes. */
  113. #define BITMAP_METALEN (div_up(BITMAP_METABITLEN, CHAR_BIT))
  114. static struct metaheader *first_mheader(void *pool, unsigned long poolsize)
  115. {
  116. unsigned int pagestatelen;
  117. pagestatelen = align_up(div_up(poolsize/getpagesize() * BITS_PER_PAGE,
  118. CHAR_BIT),
  119. ALIGNOF(struct metaheader));
  120. return (struct metaheader *)(get_page_statebits(pool) + pagestatelen);
  121. }
  122. static struct metaheader *next_mheader(void *pool, struct metaheader *mh)
  123. {
  124. if (!mh->next)
  125. return NULL;
  126. return (struct metaheader *)((char *)pool + mh->next);
  127. }
  128. static unsigned long pool_offset(void *pool, void *p)
  129. {
  130. return (char *)p - (char *)pool;
  131. }
  132. void alloc_init(void *pool, unsigned long poolsize)
  133. {
  134. /* FIXME: Alignment assumptions about pool. */
  135. unsigned long len, i;
  136. struct metaheader *mh;
  137. if (poolsize < MIN_SIZE)
  138. return;
  139. mh = first_mheader(pool, poolsize);
  140. /* Mark all page states FREE, all uniform caches zero, and all of
  141. * metaheader bitmap which takes rest of first page. */
  142. len = align_up(pool_offset(pool, mh + 1), getpagesize());
  143. BUILD_ASSERT(FREE == 0);
  144. memset(pool, 0, len);
  145. /* Mark the pagestate and metadata page(s) allocated. */
  146. set_page_state(pool, 0, TAKEN_START);
  147. for (i = 1; i < div_up(len, getpagesize()); i++)
  148. set_page_state(pool, i, TAKEN);
  149. }
  150. /* Two bits per element, representing page states. Returns 0 on fail.
  151. * off is used to allocate from subpage bitmaps, which use the first 2
  152. * bits as the type, so the real bitmap is offset by 1. */
  153. static unsigned long alloc_from_bitmap(uint8_t *bits, unsigned long off,
  154. unsigned long elems,
  155. unsigned long want, unsigned long align)
  156. {
  157. long i;
  158. unsigned long free;
  159. free = 0;
  160. /* We allocate from far end, to increase ability to expand metadata. */
  161. for (i = elems - 1; i >= 0; i--) {
  162. switch (get_bit_pair(bits, off+i)) {
  163. case FREE:
  164. if (++free >= want) {
  165. unsigned long j;
  166. /* They might ask for large alignment. */
  167. if (align && i % align)
  168. continue;
  169. set_bit_pair(bits, off+i, TAKEN_START);
  170. for (j = i+1; j < i + want; j++)
  171. set_bit_pair(bits, off+j, TAKEN);
  172. return off+i;
  173. }
  174. break;
  175. case SPECIAL:
  176. case TAKEN_START:
  177. case TAKEN:
  178. free = 0;
  179. break;
  180. }
  181. }
  182. return 0;
  183. }
  184. static unsigned long alloc_get_pages(void *pool, unsigned long poolsize,
  185. unsigned long pages, unsigned long align)
  186. {
  187. return alloc_from_bitmap(get_page_statebits(pool),
  188. 0, poolsize / getpagesize(), pages,
  189. align / getpagesize());
  190. }
  191. /* Offset to metadata is at end of page. */
  192. static unsigned long *metadata_off(void *pool, unsigned long page)
  193. {
  194. return (unsigned long *)
  195. ((char *)pool + (page+1)*getpagesize() - sizeof(unsigned long));
  196. }
  197. static uint8_t *get_page_metadata(void *pool, unsigned long page)
  198. {
  199. return (uint8_t *)pool + *metadata_off(pool, page);
  200. }
  201. static void set_page_metadata(void *pool, unsigned long page, uint8_t *meta)
  202. {
  203. *metadata_off(pool, page) = meta - (uint8_t *)pool;
  204. }
  205. static unsigned long sub_page_alloc(void *pool, unsigned long page,
  206. unsigned long size, unsigned long align)
  207. {
  208. uint8_t *bits = get_page_metadata(pool, page);
  209. unsigned long i;
  210. enum sub_metadata_type type;
  211. type = get_bit_pair(bits, 0);
  212. /* If this is a uniform page, we can't allocate from it. */
  213. if (type == UNIFORM)
  214. return 0;
  215. assert(type == BITMAP);
  216. /* We use a standart bitmap, but offset because of that BITMAP
  217. * header. */
  218. i = alloc_from_bitmap(bits, 1, SUBPAGE_METAOFF/BITMAP_GRANULARITY,
  219. div_up(size, BITMAP_GRANULARITY),
  220. align / BITMAP_GRANULARITY);
  221. /* Can't allocate? */
  222. if (i == 0)
  223. return 0;
  224. /* i-1 because of the header. */
  225. return page*getpagesize() + (i-1)*BITMAP_GRANULARITY;
  226. }
  227. /* We look at the page states to figure out where the allocation for this
  228. * metadata ends. */
  229. static unsigned long get_metalen(void *pool, unsigned long poolsize,
  230. struct metaheader *mh)
  231. {
  232. unsigned long i, first, pages = poolsize / getpagesize();
  233. first = pool_offset(pool, mh + 1)/getpagesize();
  234. for (i = first + 1; i < pages && get_page_state(pool,i) == TAKEN; i++);
  235. return i * getpagesize() - pool_offset(pool, mh + 1);
  236. }
  237. static unsigned int uniform_metalen(unsigned int usize)
  238. {
  239. unsigned int metalen;
  240. assert(usize < (1 << 14));
  241. /* Two bits for the header, 14 bits for size, then one bit for each
  242. * element the page can hold. Round up to number of bytes. */
  243. metalen = div_up(2 + 14 + SUBPAGE_METAOFF / usize, CHAR_BIT);
  244. /* To ensure metaheader is always aligned, round bytes up. */
  245. metalen = align_up(metalen, ALIGNOF(struct metaheader));
  246. return metalen;
  247. }
  248. static unsigned int decode_usize(uint8_t *meta)
  249. {
  250. return ((unsigned)meta[1] << (CHAR_BIT-2)) | (meta[0] >> 2);
  251. }
  252. static void encode_usize(uint8_t *meta, unsigned int usize)
  253. {
  254. meta[0] = (UNIFORM | (usize << 2));
  255. meta[1] = (usize >> (CHAR_BIT - 2));
  256. }
  257. static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
  258. struct metaheader *mh, unsigned long bytes,
  259. enum sub_metadata_type type)
  260. {
  261. uint8_t *meta = (uint8_t *)(mh + 1);
  262. unsigned long free = 0, len, i, metalen;
  263. metalen = get_metalen(pool, poolsize, mh);
  264. /* Walk through metadata looking for free. */
  265. for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
  266. switch (get_bit_pair(meta, i)) {
  267. case FREE:
  268. len = 1;
  269. free++;
  270. if (free == bytes * METADATA_PER_BYTE) {
  271. /* Mark this as a bitmap. */
  272. set_bit_pair(meta, i - free + 1, type);
  273. return meta + (i - free + 1)/METADATA_PER_BYTE;
  274. }
  275. break;
  276. case BITMAP:
  277. /* Skip over this allocated part. */
  278. len = BITMAP_METALEN * METADATA_PER_BYTE;
  279. free = 0;
  280. break;
  281. case UNIFORM:
  282. /* Figure metalen given usize. */
  283. len = decode_usize(meta + i / METADATA_PER_BYTE);
  284. len = uniform_metalen(len) * METADATA_PER_BYTE;
  285. free = 0;
  286. break;
  287. default:
  288. assert(0);
  289. return NULL;
  290. }
  291. }
  292. return NULL;
  293. }
  294. /* We need this many bytes of metadata. */
  295. static uint8_t *new_metadata(void *pool, unsigned long poolsize,
  296. unsigned long bytes, enum sub_metadata_type type)
  297. {
  298. struct metaheader *mh, *newmh;
  299. unsigned long page;
  300. uint8_t *meta;
  301. for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh))
  302. if ((meta = alloc_metaspace(pool, poolsize, mh, bytes, type)))
  303. return meta;
  304. /* No room for metadata? Can we expand an existing one? */
  305. for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
  306. unsigned long nextpage;
  307. /* We start on this page. */
  308. nextpage = pool_offset(pool, (char *)(mh+1))/getpagesize();
  309. /* Iterate through any other pages we own. */
  310. while (get_page_state(pool, ++nextpage) == TAKEN);
  311. /* Now, can we grab that page? */
  312. if (get_page_state(pool, nextpage) != FREE)
  313. continue;
  314. /* OK, expand metadata, do it again. */
  315. set_page_state(pool, nextpage, TAKEN);
  316. BUILD_ASSERT(FREE == 0);
  317. memset((char *)pool + nextpage*getpagesize(), 0, getpagesize());
  318. return alloc_metaspace(pool, poolsize, mh, bytes, type);
  319. }
  320. /* No metadata left at all? */
  321. page = alloc_get_pages(pool, poolsize, div_up(bytes, getpagesize()), 1);
  322. if (!page)
  323. return NULL;
  324. newmh = (struct metaheader *)((char *)pool + page * getpagesize());
  325. BUILD_ASSERT(FREE == 0);
  326. memset(newmh + 1, 0, getpagesize() - sizeof(*mh));
  327. /* Sew it into linked list */
  328. mh = first_mheader(pool,poolsize);
  329. newmh->next = mh->next;
  330. mh->next = pool_offset(pool, newmh);
  331. return alloc_metaspace(pool, poolsize, newmh, bytes, type);
  332. }
  333. static void alloc_free_pages(void *pool, unsigned long pagenum)
  334. {
  335. assert(get_page_state(pool, pagenum) == TAKEN_START);
  336. set_page_state(pool, pagenum, FREE);
  337. while (get_page_state(pool, ++pagenum) == TAKEN)
  338. set_page_state(pool, pagenum, FREE);
  339. }
  340. static void maybe_transform_uniform_page(void *pool, unsigned long offset)
  341. {
  342. /* FIXME: If possible and page isn't full, change to a bitmap */
  343. }
  344. /* Returns 0 or the size of the uniform alloc to use */
  345. static unsigned long suitable_for_uc(unsigned long size, unsigned long align)
  346. {
  347. unsigned long num_elems, wastage, usize;
  348. unsigned long bitmap_cost;
  349. if (size == 0)
  350. size = 1;
  351. /* Fix up silly alignments. */
  352. usize = align_up(size, align);
  353. /* How many can fit in this page? */
  354. num_elems = SUBPAGE_METAOFF / usize;
  355. /* Can happen with bigger alignments. */
  356. if (!num_elems)
  357. return 0;
  358. /* Usize maxes out at 14 bits. */
  359. if (usize >= (1 << 14))
  360. return 0;
  361. /* How many bytes would be left at the end? */
  362. wastage = SUBPAGE_METAOFF % usize;
  363. /* If we can get a larger allocation within alignment constraints, we
  364. * should do it, otherwise might as well leave wastage at the end. */
  365. usize += align_down(wastage / num_elems, align);
  366. /* Bitmap allocation costs 2 bits per BITMAP_GRANULARITY bytes, plus
  367. * however much we waste in rounding up to BITMAP_GRANULARITY. */
  368. bitmap_cost = 2 * div_up(size, BITMAP_GRANULARITY)
  369. + CHAR_BIT * (align_up(size, BITMAP_GRANULARITY) - size);
  370. /* Our cost is 1 bit, plus usize overhead */
  371. if (bitmap_cost < 1 + (usize - size) * CHAR_BIT)
  372. return 0;
  373. return usize;
  374. }
  375. static unsigned long uniform_alloc(void *pool, unsigned long poolsize,
  376. struct uniform_cache *uc,
  377. unsigned long ucnum)
  378. {
  379. uint8_t *metadata = get_page_metadata(pool, uc->page[ucnum]) + 2;
  380. unsigned long i, max;
  381. /* Simple one-bit-per-object bitmap. */
  382. max = SUBPAGE_METAOFF / uc->size[ucnum];
  383. for (i = 0; i < max; i++) {
  384. if (!(metadata[i / CHAR_BIT] & (1 << (i % CHAR_BIT)))) {
  385. metadata[i / CHAR_BIT] |= (1 << (i % CHAR_BIT));
  386. return uc->page[ucnum] * getpagesize()
  387. + i * uc->size[ucnum];
  388. }
  389. }
  390. return 0;
  391. }
  392. static unsigned long new_uniform_page(void *pool, unsigned long poolsize,
  393. unsigned long usize)
  394. {
  395. unsigned long page, metalen;
  396. uint8_t *metadata;
  397. page = alloc_get_pages(pool, poolsize, 1, 1);
  398. if (page == 0)
  399. return 0;
  400. metalen = uniform_metalen(usize);
  401. /* Get metadata for page. */
  402. metadata = new_metadata(pool, poolsize, metalen, UNIFORM);
  403. if (!metadata) {
  404. alloc_free_pages(pool, page);
  405. return 0;
  406. }
  407. encode_usize(metadata, usize);
  408. BUILD_ASSERT(FREE == 0);
  409. memset(metadata + 2, 0, metalen - 2);
  410. /* Actually, this is a subpage page now. */
  411. set_page_state(pool, page, SPECIAL);
  412. /* Set metadata pointer for page. */
  413. set_page_metadata(pool, page, metadata);
  414. return page;
  415. }
  416. static unsigned long alloc_sub_page(void *pool, unsigned long poolsize,
  417. unsigned long size, unsigned long align)
  418. {
  419. unsigned long i, usize;
  420. uint8_t *metadata;
  421. struct uniform_cache *uc = pool;
  422. usize = suitable_for_uc(size, align);
  423. if (usize) {
  424. /* Look for a uniform page. */
  425. for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
  426. if (uc->size[i] == usize) {
  427. unsigned long ret;
  428. ret = uniform_alloc(pool, poolsize, uc, i);
  429. if (ret != 0)
  430. return ret;
  431. /* OK, that one is full, remove from cache. */
  432. uc->size[i] = 0;
  433. break;
  434. }
  435. }
  436. /* OK, try a new uniform page. Use random discard for now. */
  437. i = random() % UNIFORM_CACHE_NUM;
  438. maybe_transform_uniform_page(pool, uc->page[i]);
  439. uc->page[i] = new_uniform_page(pool, poolsize, usize);
  440. if (uc->page[i]) {
  441. uc->size[i] = usize;
  442. return uniform_alloc(pool, poolsize, uc, i);
  443. }
  444. uc->size[i] = 0;
  445. }
  446. /* Look for partial page. */
  447. for (i = 0; i < poolsize / getpagesize(); i++) {
  448. unsigned long ret;
  449. if (get_page_state(pool, i) != SPECIAL)
  450. continue;
  451. ret = sub_page_alloc(pool, i, size, align);
  452. if (ret)
  453. return ret;
  454. }
  455. /* Create new SUBPAGE page. */
  456. i = alloc_get_pages(pool, poolsize, 1, 1);
  457. if (i == 0)
  458. return 0;
  459. /* Get metadata for page. */
  460. metadata = new_metadata(pool, poolsize, BITMAP_METALEN, BITMAP);
  461. if (!metadata) {
  462. alloc_free_pages(pool, i);
  463. return 0;
  464. }
  465. /* Actually, this is a subpage page now. */
  466. set_page_state(pool, i, SPECIAL);
  467. /* Set metadata pointer for page. */
  468. set_page_metadata(pool, i, metadata);
  469. /* Do allocation like normal */
  470. return sub_page_alloc(pool, i, size, align);
  471. }
  472. static bool bitmap_page_is_empty(uint8_t *meta)
  473. {
  474. unsigned int i;
  475. /* Skip the header (first bit of metadata). */
  476. for (i = 1; i < SUBPAGE_METAOFF/BITMAP_GRANULARITY+1; i++)
  477. if (get_bit_pair(meta, i) != FREE)
  478. return false;
  479. return true;
  480. }
  481. static bool uniform_page_is_empty(uint8_t *meta)
  482. {
  483. unsigned int i, metalen;
  484. metalen = uniform_metalen(decode_usize(meta));
  485. /* Skip the header (first two bytes of metadata). */
  486. for (i = 2; i < metalen + 2; i++) {
  487. BUILD_ASSERT(FREE == 0);
  488. if (meta[i])
  489. return false;
  490. }
  491. return true;
  492. }
  493. static bool special_page_is_empty(void *pool, unsigned long page)
  494. {
  495. uint8_t *meta;
  496. enum sub_metadata_type type;
  497. meta = get_page_metadata(pool, page);
  498. type = get_bit_pair(meta, 0);
  499. switch (type) {
  500. case UNIFORM:
  501. return uniform_page_is_empty(meta);
  502. case BITMAP:
  503. return bitmap_page_is_empty(meta);
  504. default:
  505. assert(0);
  506. }
  507. }
  508. static void clear_special_metadata(void *pool, unsigned long page)
  509. {
  510. uint8_t *meta;
  511. enum sub_metadata_type type;
  512. meta = get_page_metadata(pool, page);
  513. type = get_bit_pair(meta, 0);
  514. switch (type) {
  515. case UNIFORM:
  516. /* First two bytes are the header, rest is already FREE */
  517. BUILD_ASSERT(FREE == 0);
  518. memset(meta, 0, 2);
  519. break;
  520. case BITMAP:
  521. /* First two bits is the header. */
  522. BUILD_ASSERT(BITMAP_METALEN > 1);
  523. meta[0] = 0;
  524. break;
  525. default:
  526. assert(0);
  527. }
  528. }
  529. /* Returns true if we cleaned any pages. */
  530. static bool clean_empty_subpages(void *pool, unsigned long poolsize)
  531. {
  532. unsigned long i;
  533. bool progress = false;
  534. for (i = 0; i < poolsize/getpagesize(); i++) {
  535. if (get_page_state(pool, i) != SPECIAL)
  536. continue;
  537. if (special_page_is_empty(pool, i)) {
  538. clear_special_metadata(pool, i);
  539. set_page_state(pool, i, FREE);
  540. progress = true;
  541. }
  542. }
  543. return progress;
  544. }
  545. /* Returns true if we cleaned any pages. */
  546. static bool clean_metadata(void *pool, unsigned long poolsize)
  547. {
  548. struct metaheader *mh, *prev_mh = NULL;
  549. bool progress = false;
  550. for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
  551. uint8_t *meta;
  552. long i;
  553. unsigned long metalen = get_metalen(pool, poolsize, mh);
  554. meta = (uint8_t *)(mh + 1);
  555. BUILD_ASSERT(FREE == 0);
  556. for (i = metalen - 1; i > 0; i--)
  557. if (meta[i] != 0)
  558. break;
  559. /* Completely empty? */
  560. if (prev_mh && i == metalen) {
  561. alloc_free_pages(pool,
  562. pool_offset(pool, mh)/getpagesize());
  563. prev_mh->next = mh->next;
  564. mh = prev_mh;
  565. progress = true;
  566. } else {
  567. uint8_t *p;
  568. /* Some pages at end are free? */
  569. for (p = (uint8_t *)(mh+1) + metalen - getpagesize();
  570. p > meta + i;
  571. p -= getpagesize()) {
  572. set_page_state(pool,
  573. pool_offset(pool, p)
  574. / getpagesize(),
  575. FREE);
  576. progress = true;
  577. }
  578. }
  579. }
  580. return progress;
  581. }
  582. void *alloc_get(void *pool, unsigned long poolsize,
  583. unsigned long size, unsigned long align)
  584. {
  585. bool subpage_clean = false, metadata_clean = false;
  586. unsigned long ret;
  587. if (poolsize < MIN_SIZE)
  588. return NULL;
  589. again:
  590. /* Sub-page allocations have an overhead of ~12%. */
  591. if (size + size/8 >= getpagesize() || align >= getpagesize()) {
  592. unsigned long pages = div_up(size, getpagesize());
  593. ret = alloc_get_pages(pool, poolsize, pages, align)
  594. * getpagesize();
  595. } else
  596. ret = alloc_sub_page(pool, poolsize, size, align);
  597. if (ret != 0)
  598. return (char *)pool + ret;
  599. /* Allocation failed: garbage collection. */
  600. if (!subpage_clean) {
  601. subpage_clean = true;
  602. if (clean_empty_subpages(pool, poolsize))
  603. goto again;
  604. }
  605. if (!metadata_clean) {
  606. metadata_clean = true;
  607. if (clean_metadata(pool, poolsize))
  608. goto again;
  609. }
  610. /* FIXME: Compact metadata? */
  611. return NULL;
  612. }
  613. static void bitmap_free(void *pool, unsigned long pagenum, unsigned long off,
  614. uint8_t *metadata)
  615. {
  616. assert(off % BITMAP_GRANULARITY == 0);
  617. off /= BITMAP_GRANULARITY;
  618. /* Offset by one because first bit is used for header. */
  619. off++;
  620. set_bit_pair(metadata, off++, FREE);
  621. while (off < SUBPAGE_METAOFF / BITMAP_GRANULARITY
  622. && get_bit_pair(metadata, off) == TAKEN)
  623. set_bit_pair(metadata, off++, FREE);
  624. }
  625. static void uniform_free(void *pool, unsigned long pagenum, unsigned long off,
  626. uint8_t *metadata)
  627. {
  628. unsigned int usize, bit;
  629. usize = decode_usize(metadata);
  630. /* Must have been this size. */
  631. assert(off % usize == 0);
  632. bit = off / usize;
  633. /* Skip header. */
  634. metadata += 2;
  635. /* Must have been allocated. */
  636. assert(metadata[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT)));
  637. metadata[bit / CHAR_BIT] &= ~(1 << (bit % CHAR_BIT));
  638. }
  639. static void subpage_free(void *pool, unsigned long pagenum, void *free)
  640. {
  641. unsigned long off = (unsigned long)free % getpagesize();
  642. uint8_t *metadata = get_page_metadata(pool, pagenum);
  643. enum sub_metadata_type type;
  644. type = get_bit_pair(metadata, 0);
  645. assert(off < SUBPAGE_METAOFF);
  646. switch (type) {
  647. case BITMAP:
  648. bitmap_free(pool, pagenum, off, metadata);
  649. break;
  650. case UNIFORM:
  651. uniform_free(pool, pagenum, off, metadata);
  652. break;
  653. default:
  654. assert(0);
  655. }
  656. }
  657. void alloc_free(void *pool, unsigned long poolsize, void *free)
  658. {
  659. unsigned long pagenum;
  660. struct metaheader *mh;
  661. if (!free)
  662. return;
  663. assert(poolsize >= MIN_SIZE);
  664. mh = first_mheader(pool, poolsize);
  665. assert((char *)free >= (char *)(mh + 1));
  666. assert((char *)pool + poolsize > (char *)free);
  667. pagenum = pool_offset(pool, free) / getpagesize();
  668. if (get_page_state(pool, pagenum) == SPECIAL)
  669. subpage_free(pool, pagenum, free);
  670. else {
  671. assert((unsigned long)free % getpagesize() == 0);
  672. alloc_free_pages(pool, pagenum);
  673. }
  674. }
  675. static bool is_metadata_page(void *pool, unsigned long poolsize,
  676. unsigned long page)
  677. {
  678. struct metaheader *mh;
  679. for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
  680. unsigned long start, end;
  681. start = pool_offset(pool, mh);
  682. end = pool_offset(pool, (char *)(mh+1)
  683. + get_metalen(pool, poolsize, mh));
  684. if (page >= start/getpagesize() && page < end/getpagesize())
  685. return true;
  686. }
  687. return false;
  688. }
  689. static bool check_bitmap_metadata(void *pool, unsigned long *mhoff)
  690. {
  691. enum alloc_state last_state = FREE;
  692. unsigned int i;
  693. for (i = 0; i < SUBPAGE_METAOFF / BITMAP_GRANULARITY; i++) {
  694. enum alloc_state state;
  695. /* +1 because header is the first byte. */
  696. state = get_bit_pair((uint8_t *)pool + *mhoff, i+1);
  697. switch (state) {
  698. case SPECIAL:
  699. return false;
  700. case TAKEN:
  701. if (last_state == FREE)
  702. return false;
  703. break;
  704. default:
  705. break;
  706. }
  707. last_state = state;
  708. }
  709. return true;
  710. }
  711. static bool check_uniform_metadata(void *pool, unsigned long *mhoff)
  712. {
  713. uint8_t *meta = (uint8_t *)pool + *mhoff;
  714. unsigned int i, usize;
  715. struct uniform_cache *uc = pool;
  716. usize = decode_usize(meta);
  717. if (usize == 0 || suitable_for_uc(usize, 1) != usize)
  718. return false;
  719. /* If it's in uniform cache, make sure that agrees on size. */
  720. for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
  721. uint8_t *ucm;
  722. if (!uc->size[i])
  723. continue;
  724. ucm = get_page_metadata(pool, uc->page[i]);
  725. if (ucm != meta)
  726. continue;
  727. if (usize != uc->size[i])
  728. return false;
  729. }
  730. return true;
  731. }
  732. static bool check_subpage(void *pool, unsigned long poolsize,
  733. unsigned long page)
  734. {
  735. unsigned long *mhoff = metadata_off(pool, page);
  736. if (*mhoff + sizeof(struct metaheader) > poolsize)
  737. return false;
  738. if (*mhoff % ALIGNOF(struct metaheader) != 0)
  739. return false;
  740. /* It must point to a metadata page. */
  741. if (!is_metadata_page(pool, poolsize, *mhoff / getpagesize()))
  742. return false;
  743. /* Header at start of subpage allocation */
  744. switch (get_bit_pair((uint8_t *)pool + *mhoff, 0)) {
  745. case BITMAP:
  746. return check_bitmap_metadata(pool, mhoff);
  747. case UNIFORM:
  748. return check_uniform_metadata(pool, mhoff);
  749. default:
  750. return false;
  751. }
  752. }
  753. bool alloc_check(void *pool, unsigned long poolsize)
  754. {
  755. unsigned long i;
  756. struct metaheader *mh;
  757. enum alloc_state last_state = FREE;
  758. bool was_metadata = false;
  759. if (poolsize < MIN_SIZE)
  760. return true;
  761. if (get_page_state(pool, 0) != TAKEN_START)
  762. return false;
  763. /* First check metadata pages. */
  764. /* Metadata pages will be marked TAKEN. */
  765. for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
  766. unsigned long start, end;
  767. start = pool_offset(pool, mh);
  768. if (start + sizeof(*mh) > poolsize)
  769. return false;
  770. end = pool_offset(pool, (char *)(mh+1)
  771. + get_metalen(pool, poolsize, mh));
  772. if (end > poolsize)
  773. return false;
  774. /* Non-first pages should start on a page boundary. */
  775. if (mh != first_mheader(pool, poolsize)
  776. && start % getpagesize() != 0)
  777. return false;
  778. /* It should end on a page boundary. */
  779. if (end % getpagesize() != 0)
  780. return false;
  781. }
  782. for (i = 0; i < poolsize / getpagesize(); i++) {
  783. enum alloc_state state = get_page_state(pool, i);
  784. bool is_metadata = is_metadata_page(pool, poolsize,i);
  785. switch (state) {
  786. case FREE:
  787. /* metadata pages are never free. */
  788. if (is_metadata)
  789. return false;
  790. case TAKEN_START:
  791. break;
  792. case TAKEN:
  793. /* This should continue a previous block. */
  794. if (last_state == FREE)
  795. return false;
  796. if (is_metadata != was_metadata)
  797. return false;
  798. break;
  799. case SPECIAL:
  800. /* Check metadata pointer etc. */
  801. if (!check_subpage(pool, poolsize, i))
  802. return false;
  803. }
  804. last_state = state;
  805. was_metadata = is_metadata;
  806. }
  807. return true;
  808. }
  809. void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
  810. {
  811. struct metaheader *mh;
  812. struct uniform_cache *uc = pool;
  813. unsigned long pagebitlen, metadata_pages, count[1<<BITS_PER_PAGE], tot;
  814. long i;
  815. if (poolsize < MIN_SIZE) {
  816. fprintf(out, "Pool smaller than %u: no content\n", MIN_SIZE);
  817. return;
  818. }
  819. tot = 0;
  820. for (i = 0; i < UNIFORM_CACHE_NUM; i++)
  821. tot += (uc->size[i] != 0);
  822. fprintf(out, "Uniform cache (%lu entries):\n", tot);
  823. for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
  824. unsigned int j, total = 0;
  825. uint8_t *meta;
  826. if (!uc->size[i])
  827. continue;
  828. /* First two bytes are header. */
  829. meta = get_page_metadata(pool, uc->page[i]) + 2;
  830. for (j = 0; j < SUBPAGE_METAOFF / uc->size[i]; j++)
  831. if (meta[j / 8] & (1 << (j % 8)))
  832. total++;
  833. printf(" %u: %u/%u (%u%% density)\n",
  834. uc->size[j], total, SUBPAGE_METAOFF / uc->size[i],
  835. (total * 100) / (SUBPAGE_METAOFF / uc->size[i]));
  836. }
  837. memset(count, 0, sizeof(count));
  838. for (i = 0; i < poolsize / getpagesize(); i++)
  839. count[get_page_state(pool, i)]++;
  840. mh = first_mheader(pool, poolsize);
  841. pagebitlen = (uint8_t *)mh - get_page_statebits(pool);
  842. fprintf(out, "%lu bytes of page bits: FREE/TAKEN/TAKEN_START/SUBPAGE = %lu/%lu/%lu/%lu\n",
  843. pagebitlen, count[0], count[1], count[2], count[3]);
  844. /* One metadata page for every page of page bits. */
  845. metadata_pages = div_up(pagebitlen, getpagesize());
  846. /* Now do each metadata page. */
  847. for (; mh; mh = next_mheader(pool,mh)) {
  848. unsigned long free = 0, bitmapblocks = 0, uniformblocks = 0,
  849. len = 0, uniformlen = 0, bitmaplen = 0, metalen;
  850. uint8_t *meta = (uint8_t *)(mh + 1);
  851. metalen = get_metalen(pool, poolsize, mh);
  852. metadata_pages += (sizeof(*mh) + metalen) / getpagesize();
  853. for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
  854. switch (get_bit_pair(meta, i)) {
  855. case FREE:
  856. len = 1;
  857. free++;
  858. break;
  859. case BITMAP:
  860. /* Skip over this allocated part. */
  861. len = BITMAP_METALEN * CHAR_BIT;
  862. bitmapblocks++;
  863. bitmaplen += len;
  864. break;
  865. case UNIFORM:
  866. /* Skip over this part. */
  867. len = decode_usize(meta + i/METADATA_PER_BYTE);
  868. len = uniform_metalen(len) * METADATA_PER_BYTE;
  869. uniformblocks++;
  870. uniformlen += len;
  871. break;
  872. default:
  873. assert(0);
  874. }
  875. }
  876. fprintf(out, "Metadata %lu-%lu: %lu free, %lu bitmapblocks, %lu uniformblocks, %lu%% density\n",
  877. pool_offset(pool, mh),
  878. pool_offset(pool, (char *)(mh+1) + metalen),
  879. free, bitmapblocks, uniformblocks,
  880. (bitmaplen + uniformlen) * 100
  881. / (free + bitmaplen + uniformlen));
  882. }
  883. /* Account for total pages allocated. */
  884. tot = (count[1] + count[2] - metadata_pages) * getpagesize();
  885. fprintf(out, "Total metadata bytes = %lu\n",
  886. metadata_pages * getpagesize());
  887. /* Now do every subpage. */
  888. for (i = 0; i < poolsize / getpagesize(); i++) {
  889. uint8_t *meta;
  890. unsigned int j, allocated;
  891. enum sub_metadata_type type;
  892. if (get_page_state(pool, i) != SPECIAL)
  893. continue;
  894. memset(count, 0, sizeof(count));
  895. meta = get_page_metadata(pool, i);
  896. type = get_bit_pair(meta, 0);
  897. if (type == BITMAP) {
  898. for (j = 0; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY; j++)
  899. count[get_page_state(meta, j)]++;
  900. allocated = (count[1] + count[2]) * BITMAP_GRANULARITY;
  901. fprintf(out, "Subpage bitmap ");
  902. } else {
  903. unsigned int usize = decode_usize(meta);
  904. assert(type == UNIFORM);
  905. fprintf(out, "Subpage uniform (%u) ", usize);
  906. meta += 2;
  907. for (j = 0; j < SUBPAGE_METAOFF / usize; j++)
  908. count[!!(meta[j / 8] & (1 << (j % 8)))]++;
  909. allocated = count[1] * usize;
  910. }
  911. fprintf(out, "%lu: FREE/TAKEN/TAKEN_START = %lu/%lu/%lu %u%% density\n",
  912. i, count[0], count[1], count[2],
  913. allocated * 100 / getpagesize());
  914. tot += allocated;
  915. }
  916. /* This is optimistic, since we overalloc in several cases. */
  917. fprintf(out, "Best possible allocation density = %lu%%\n",
  918. tot * 100 / poolsize);
  919. }