diff options
author | alc <alc@FreeBSD.org> | 2017-07-22 17:49:18 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2017-07-22 17:49:18 +0000 |
commit | 489524556a040851deed9aeb609a670c3d77003a (patch) | |
tree | b3b85cdfecffb1cbacfda68c8e89d0dc1ef8b9e3 /sys/kern/subr_blist.c | |
parent | 590babdb53fc6427ee30eb966930c02d72ad4d9d (diff) | |
download | FreeBSD-src-489524556a040851deed9aeb609a670c3d77003a.zip FreeBSD-src-489524556a040851deed9aeb609a670c3d77003a.tar.gz |
MFC r319905
Reduce the frequency of hint updates on allocation without incurring
additional allocation overhead. Previously, blst_meta_alloc() updated the
hint after every successful allocation. However, these "eager" hint
updates are of no actual benefit if, instead, the "lazy" hint update at
the start of blst_meta_alloc() is generalized to handle all cases where
the number of available blocks is less than the requested allocation.
Previously, the lazy hint update at the start of blst_meta_alloc() only
handled the ALL-FULL case. (I would also note that this change provides
consistency between blist_alloc() and blist_fill() in that their hint
maintenance is now entirely lazy.)
Eliminate unnecessary checks for terminators in blst_meta_alloc() and
blst_meta_fill() when handling ALL-FREE meta nodes.
Eliminate the field "bl_free" from struct blist. It is redundant. Unless
the entire radix tree is a single leaf, the count of free blocks is stored
in the root node. Instead, provide a function blist_avail() for obtaining
the number of free blocks.
In blst_meta_alloc(), perform a sanity check on the allocation once rather
than repeating it in a loop over the meta node's children.
In blst_leaf_fill(), use the optimized bitcount*() function instead of a
loop to count the blocks being allocated.
Add or improve several comments.
Address some nearby style errors.
Diffstat (limited to 'sys/kern/subr_blist.c')
-rw-r--r-- | sys/kern/subr_blist.c | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/sys/kern/subr_blist.c b/sys/kern/subr_blist.c index d223cd5..267a6a7 100644 --- a/sys/kern/subr_blist.c +++ b/sys/kern/subr_blist.c @@ -106,6 +106,7 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <stdarg.h> +#define bitcount64(x) __bitcount64((uint64_t)(x)) #define malloc(a,b,c) calloc(a, 1) #define free(a,b) free(a) @@ -169,7 +170,7 @@ blist_create(daddr_t blocks, int flags) skip = (skip + 1) * BLIST_META_RADIX; } - bl = malloc(sizeof(struct blist), M_SWAP, flags | M_ZERO); + bl = malloc(sizeof(struct blist), M_SWAP, flags); if (bl == NULL) return (NULL); @@ -207,7 +208,7 @@ blist_destroy(blist_t bl) } /* - * blist_alloc() - reserve space in the block bitmap. Return the base + * blist_alloc() - reserve space in the block bitmap. Return the base * of a contiguous region or SWAPBLK_NONE if space could * not be allocated. */ @@ -215,17 +216,31 @@ blist_destroy(blist_t bl) daddr_t blist_alloc(blist_t bl, daddr_t count) { - daddr_t blk = SWAPBLK_NONE; + daddr_t blk; - if (bl) { + if (bl != NULL && count <= bl->bl_root->bm_bighint) { if (bl->bl_radix == BLIST_BMAP_RADIX) blk = blst_leaf_alloc(bl->bl_root, 0, count); else - blk = blst_meta_alloc(bl->bl_root, 0, count, bl->bl_radix, bl->bl_skip); - if (blk != SWAPBLK_NONE) - bl->bl_free -= count; + blk = blst_meta_alloc(bl->bl_root, 0, count, + bl->bl_radix, bl->bl_skip); + return (blk); } - return(blk); + return (SWAPBLK_NONE); +} + +/* + * blist_avail() - return the number of free blocks. + */ + +daddr_t +blist_avail(blist_t bl) +{ + + if (bl->bl_radix == BLIST_BMAP_RADIX) + return (bitcount64(bl->bl_root->u.bmu_bitmap)); + else + return (bl->bl_root->u.bmu_avail); } /* @@ -241,8 +256,8 @@ blist_free(blist_t bl, daddr_t blkno, daddr_t count) if (bl->bl_radix == BLIST_BMAP_RADIX) blst_leaf_free(bl->bl_root, blkno, count); else - blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix, bl->bl_skip, 0); - bl->bl_free += count; + blst_meta_free(bl->bl_root, blkno, count, + bl->bl_radix, bl->bl_skip, 0); } } @@ -264,10 +279,9 @@ blist_fill(blist_t bl, daddr_t blkno, daddr_t count) else filled = blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix, bl->bl_skip, 0); - bl->bl_free -= filled; - return filled; - } else - return 0; + return (filled); + } + return (0); } /* @@ -417,27 +431,32 @@ blst_meta_alloc( daddr_t radix, int skip ) { + daddr_t r; int i; int next_skip = ((u_int)skip / BLIST_META_RADIX); - if (scan->u.bmu_avail == 0) { + if (scan->u.bmu_avail < count) { /* - * ALL-ALLOCATED special case + * The meta node's hint must be too large if the allocation + * exceeds the number of free blocks. Reduce the hint, and + * return failure. */ - scan->bm_bighint = 0; - return(SWAPBLK_NONE); + scan->bm_bighint = scan->u.bmu_avail; + return (SWAPBLK_NONE); } + /* + * An ALL-FREE meta node requires special handling before allocating + * any of its blocks. + */ if (scan->u.bmu_avail == radix) { radix /= BLIST_META_RADIX; /* - * ALL-FREE special case, initialize uninitialize - * sublevel. + * Reinitialize each of the meta node's children. An ALL-FREE + * meta node cannot have a terminator in any subtree. */ for (i = 1; i <= skip; i += next_skip) { - if (scan[i].bm_bighint == (daddr_t)-1) - break; if (next_skip == 1) { scan[i].u.bmu_bitmap = (u_daddr_t)-1; scan[i].bm_bighint = BLIST_BMAP_RADIX; @@ -450,34 +469,33 @@ blst_meta_alloc( radix /= BLIST_META_RADIX; } + if (count > radix) { + /* + * The allocation exceeds the number of blocks that are + * managed by a subtree of this meta node. + */ + panic("allocation too large"); + } for (i = 1; i <= skip; i += next_skip) { if (count <= scan[i].bm_bighint) { /* - * count fits in object + * The allocation might fit in the i'th subtree. */ - daddr_t r; if (next_skip == 1) { r = blst_leaf_alloc(&scan[i], blk, count); } else { - r = blst_meta_alloc(&scan[i], blk, count, radix, next_skip - 1); + r = blst_meta_alloc(&scan[i], blk, count, + radix, next_skip - 1); } if (r != SWAPBLK_NONE) { scan->u.bmu_avail -= count; - if (scan->bm_bighint > scan->u.bmu_avail) - scan->bm_bighint = scan->u.bmu_avail; - return(r); + return (r); } } else if (scan[i].bm_bighint == (daddr_t)-1) { /* * Terminator */ break; - } else if (count > radix) { - /* - * count does not fit in object even if it were - * complete free. - */ - panic("blist_meta_alloc: allocation too large"); } blk += radix; } @@ -736,18 +754,16 @@ blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count) { int n = blk & (BLIST_BMAP_RADIX - 1); daddr_t nblks; - u_daddr_t mask, bitmap; + u_daddr_t mask; mask = ((u_daddr_t)-1 << n) & ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - count - n)); - /* Count the number of blocks we're about to allocate */ - bitmap = scan->u.bmu_bitmap & mask; - for (nblks = 0; bitmap != 0; nblks++) - bitmap &= bitmap - 1; + /* Count the number of blocks that we are allocating. */ + nblks = bitcount64(scan->u.bmu_bitmap & mask); scan->u.bmu_bitmap &= ~mask; - return nblks; + return (nblks); } /* @@ -771,8 +787,13 @@ blst_meta_fill( int next_skip = ((u_int)skip / BLIST_META_RADIX); daddr_t nblks = 0; - if (count > radix) - panic("blist_meta_fill: allocation too large"); + if (count > radix) { + /* + * The allocation exceeds the number of blocks that are + * managed by this meta node. + */ + panic("allocation too large"); + } if (count == radix || scan->u.bmu_avail == 0) { /* * ALL-ALLOCATED special case @@ -783,15 +804,18 @@ blst_meta_fill( return nblks; } + /* + * An ALL-FREE meta node requires special handling before allocating + * any of its blocks. + */ if (scan->u.bmu_avail == radix) { radix /= BLIST_META_RADIX; /* - * ALL-FREE special case, initialize sublevel + * Reinitialize each of the meta node's children. An ALL-FREE + * meta node cannot have a terminator in any subtree. */ for (i = 1; i <= skip; i += next_skip) { - if (scan[i].bm_bighint == (daddr_t)-1) - break; if (next_skip == 1) { scan[i].u.bmu_bitmap = (u_daddr_t)-1; scan[i].bm_bighint = BLIST_BMAP_RADIX; @@ -1020,7 +1044,7 @@ main(int ac, char **av) long long da = 0; long long count = 0; - printf("%lld/%lld/%lld> ", (long long)bl->bl_free, + printf("%lld/%lld/%lld> ", (long long)blist_avail(bl), (long long)size, (long long)bl->bl_radix); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) |