+
+void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
+{
+ struct metaheader *mh;
+ struct uniform_cache *uc = pool;
+ unsigned long pagebitlen, metadata_pages, count[1<<BITS_PER_PAGE], tot;
+ long i;
+
+ if (poolsize < MIN_SIZE) {
+ fprintf(out, "Pool smaller than %u: no content\n", MIN_SIZE);
+ return;
+ }
+
+ tot = 0;
+ for (i = 0; i < UNIFORM_CACHE_NUM; i++)
+ tot += (uc->size[i] != 0);
+ fprintf(out, "Uniform cache (%lu entries):\n", tot);
+ for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
+ unsigned int j, total = 0;
+ uint8_t *meta;
+
+ if (!uc->size[i])
+ continue;
+
+ /* First two bytes are header. */
+ meta = get_page_metadata(pool, uc->page[i]) + 2;
+
+ for (j = 0; j < SUBPAGE_METAOFF / uc->size[i]; j++)
+ if (meta[j / 8] & (1 << (j % 8)))
+ total++;
+
+ printf(" %u: %u/%u (%u%% density)\n",
+ uc->size[j], total, SUBPAGE_METAOFF / uc->size[i],
+ (total * 100) / (SUBPAGE_METAOFF / uc->size[i]));
+ }
+
+ memset(count, 0, sizeof(count));
+ for (i = 0; i < poolsize / getpagesize(); i++)
+ count[get_page_state(pool, i)]++;
+
+ mh = first_mheader(pool, poolsize);
+ pagebitlen = (uint8_t *)mh - get_page_statebits(pool);
+ fprintf(out, "%lu bytes of page bits: FREE/TAKEN/TAKEN_START/SUBPAGE = %lu/%lu/%lu/%lu\n",
+ pagebitlen, count[0], count[1], count[2], count[3]);
+
+ /* One metadata page for every page of page bits. */
+ metadata_pages = div_up(pagebitlen, getpagesize());
+
+ /* Now do each metadata page. */
+ for (; mh; mh = next_mheader(pool,mh)) {
+ unsigned long free = 0, bitmapblocks = 0, uniformblocks = 0,
+ len = 0, uniformlen = 0, bitmaplen = 0, metalen;
+ uint8_t *meta = (uint8_t *)(mh + 1);
+
+ metalen = get_metalen(pool, poolsize, mh);
+ metadata_pages += (sizeof(*mh) + metalen) / getpagesize();
+
+ for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
+ switch (get_bit_pair(meta, i)) {
+ case FREE:
+ len = 1;
+ free++;
+ break;
+ case BITMAP:
+ /* Skip over this allocated part. */
+ len = BITMAP_METALEN * CHAR_BIT;
+ bitmapblocks++;
+ bitmaplen += len;
+ break;
+ case UNIFORM:
+ /* Skip over this part. */
+ len = decode_usize(meta + i/METADATA_PER_BYTE);
+ len = uniform_metalen(len) * METADATA_PER_BYTE;
+ uniformblocks++;
+ uniformlen += len;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ fprintf(out, "Metadata %lu-%lu: %lu free, %lu bitmapblocks, %lu uniformblocks, %lu%% density\n",
+ pool_offset(pool, mh),
+ pool_offset(pool, (char *)(mh+1) + metalen),
+ free, bitmapblocks, uniformblocks,
+ (bitmaplen + uniformlen) * 100
+ / (free + bitmaplen + uniformlen));
+ }
+
+ /* Account for total pages allocated. */
+ tot = (count[1] + count[2] - metadata_pages) * getpagesize();
+
+ fprintf(out, "Total metadata bytes = %lu\n",
+ metadata_pages * getpagesize());
+
+ /* Now do every subpage. */
+ for (i = 0; i < poolsize / getpagesize(); i++) {
+ uint8_t *meta;
+ unsigned int j, allocated;
+ enum sub_metadata_type type;
+
+ if (get_page_state(pool, i) != SPECIAL)
+ continue;
+
+ memset(count, 0, sizeof(count));
+
+ meta = get_page_metadata(pool, i);
+ type = get_bit_pair(meta, 0);
+
+ if (type == BITMAP) {
+ for (j = 0; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY; j++)
+ count[get_page_state(meta, j)]++;
+ allocated = (count[1] + count[2]) * BITMAP_GRANULARITY;
+ fprintf(out, "Subpage bitmap ");
+ } else {
+ unsigned int usize = decode_usize(meta);
+
+ assert(type == UNIFORM);
+ fprintf(out, "Subpage uniform (%u) ", usize);
+ meta += 2;
+ for (j = 0; j < SUBPAGE_METAOFF / usize; j++)
+ count[!!(meta[j / 8] & (1 << (j % 8)))]++;
+ allocated = count[1] * usize;
+ }
+ fprintf(out, "%lu: FREE/TAKEN/TAKEN_START = %lu/%lu/%lu %u%% density\n",
+ i, count[0], count[1], count[2],
+ allocated * 100 / getpagesize());
+ tot += allocated;
+ }
+
+ /* This is optimistic, since we overalloc in several cases. */
+ fprintf(out, "Best possible allocation density = %lu%%\n",
+ tot * 100 / poolsize);
+}