alloc.c 28 KB

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