svn commit: r355510 - head/sys/vm
Jeff Roberson
jeff at FreeBSD.org
Sun Dec 8 01:15:07 UTC 2019
Author: jeff
Date: Sun Dec 8 01:15:06 2019
New Revision: 355510
URL: https://svnweb.freebsd.org/changeset/base/355510
Log:
Use a variant slab structure for offpage zones. This saves space in
embedded slabs but also is an opportunity to tidy up code and add
accessor inlines.
Reviewed by: markj, rlibby
Differential Revision: https://reviews.freebsd.org/D22609
Modified:
head/sys/vm/uma_core.c
head/sys/vm/uma_int.h
Modified: head/sys/vm/uma_core.c
==============================================================================
--- head/sys/vm/uma_core.c Sun Dec 8 00:06:00 2019 (r355509)
+++ head/sys/vm/uma_core.c Sun Dec 8 01:15:06 2019 (r355510)
@@ -664,8 +664,7 @@ hash_alloc(struct uma_hash *hash, u_int size)
if (size > UMA_HASH_SIZE_INIT) {
hash->uh_hashsize = size;
alloc = sizeof(hash->uh_slab_hash[0]) * hash->uh_hashsize;
- hash->uh_slab_hash = (struct slabhead *)malloc(alloc,
- M_UMAHASH, M_NOWAIT);
+ hash->uh_slab_hash = malloc(alloc, M_UMAHASH, M_NOWAIT);
} else {
alloc = sizeof(hash->uh_slab_hash[0]) * UMA_HASH_SIZE_INIT;
hash->uh_slab_hash = zone_alloc_item(hashzone, NULL,
@@ -698,7 +697,7 @@ hash_alloc(struct uma_hash *hash, u_int size)
static int
hash_expand(struct uma_hash *oldhash, struct uma_hash *newhash)
{
- uma_slab_t slab;
+ uma_hash_slab_t slab;
u_int hval;
u_int idx;
@@ -714,12 +713,12 @@ hash_expand(struct uma_hash *oldhash, struct uma_hash
*/
for (idx = 0; idx < oldhash->uh_hashsize; idx++)
- while (!SLIST_EMPTY(&oldhash->uh_slab_hash[idx])) {
- slab = SLIST_FIRST(&oldhash->uh_slab_hash[idx]);
- SLIST_REMOVE_HEAD(&oldhash->uh_slab_hash[idx], us_hlink);
- hval = UMA_HASH(newhash, slab->us_data);
- SLIST_INSERT_HEAD(&newhash->uh_slab_hash[hval],
- slab, us_hlink);
+ while (!LIST_EMPTY(&oldhash->uh_slab_hash[idx])) {
+ slab = LIST_FIRST(&oldhash->uh_slab_hash[idx]);
+ LIST_REMOVE(slab, uhs_hlink);
+ hval = UMA_HASH(newhash, slab->uhs_data);
+ LIST_INSERT_HEAD(&newhash->uh_slab_hash[hval],
+ slab, uhs_hlink);
}
return (1);
@@ -992,7 +991,7 @@ keg_free_slab(uma_keg_t keg, uma_slab_t slab, int star
CTR4(KTR_UMA, "keg_free_slab keg %s(%p) slab %p, returning %d bytes",
keg->uk_name, keg, slab, PAGE_SIZE * keg->uk_ppera);
- mem = slab->us_data;
+ mem = slab_data(slab, keg);
flags = slab->us_flags;
i = start;
if (keg->uk_fini != NULL) {
@@ -1006,11 +1005,10 @@ keg_free_slab(uma_keg_t keg, uma_slab_t slab, int star
* albeit we don't make skip check for other init/fini
* invocations.
*/
- if (!uma_dbg_kskip(keg, slab->us_data + (keg->uk_rsize * i)) ||
+ if (!uma_dbg_kskip(keg, slab_item(slab, keg, i)) ||
keg->uk_fini != trash_fini)
#endif
- keg->uk_fini(slab->us_data + (keg->uk_rsize * i),
- keg->uk_size);
+ keg->uk_fini(slab_item(slab, keg, i), keg->uk_size);
}
if (keg->uk_flags & UMA_ZONE_OFFPAGE)
zone_free_item(keg->uk_slabzone, slab, NULL, SKIP_NONE);
@@ -1057,18 +1055,17 @@ keg_drain(uma_keg_t keg)
keg->uk_free -= keg->uk_ipers;
if (keg->uk_flags & UMA_ZONE_HASH)
- UMA_HASH_REMOVE(&keg->uk_hash, slab,
- slab->us_data);
+ UMA_HASH_REMOVE(&keg->uk_hash, slab);
- SLIST_INSERT_HEAD(&freeslabs, slab, us_hlink);
+ LIST_INSERT_HEAD(&freeslabs, slab, us_link);
}
}
finished:
KEG_UNLOCK(keg);
- while ((slab = SLIST_FIRST(&freeslabs)) != NULL) {
- SLIST_REMOVE(&freeslabs, slab, uma_slab, us_hlink);
+ while ((slab = LIST_FIRST(&freeslabs)) != NULL) {
+ LIST_REMOVE(slab, us_link);
keg_free_slab(keg, slab, keg->uk_ipers);
}
}
@@ -1190,13 +1187,14 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int dom
/* Point the slab into the allocated memory */
if (!(keg->uk_flags & UMA_ZONE_OFFPAGE))
slab = (uma_slab_t )(mem + keg->uk_pgoff);
+ else
+ ((uma_hash_slab_t)slab)->uhs_data = mem;
if (keg->uk_flags & UMA_ZONE_VTOSLAB)
for (i = 0; i < keg->uk_ppera; i++)
vsetzoneslab((vm_offset_t)mem + (i * PAGE_SIZE),
zone, slab);
- slab->us_data = mem;
slab->us_freecount = keg->uk_ipers;
slab->us_flags = sflags;
slab->us_domain = domain;
@@ -1207,7 +1205,7 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int dom
if (keg->uk_init != NULL) {
for (i = 0; i < keg->uk_ipers; i++)
- if (keg->uk_init(slab->us_data + (keg->uk_rsize * i),
+ if (keg->uk_init(slab_item(slab, keg, i),
keg->uk_size, flags) != 0)
break;
if (i != keg->uk_ipers) {
@@ -2393,15 +2391,12 @@ uma_startup(void *mem, int npages)
zone_ctor(zones, zsize, &args, M_WAITOK);
/* Now make a zone for slab headers */
- slabzone = uma_zcreate("UMA Slabs",
- slab_sizeof(SLAB_MAX_SETSIZE),
- NULL, NULL, NULL, NULL,
- UMA_ALIGN_PTR, UMA_ZFLAG_INTERNAL);
+ slabzone = uma_zcreate("UMA Slabs", sizeof(struct uma_hash_slab),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZFLAG_INTERNAL);
hashzone = uma_zcreate("UMA Hash",
sizeof(struct slabhead *) * UMA_HASH_SIZE_INIT,
- NULL, NULL, NULL, NULL,
- UMA_ALIGN_PTR, UMA_ZFLAG_INTERNAL);
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZFLAG_INTERNAL);
bucket_init();
@@ -3097,7 +3092,7 @@ slab_alloc_item(uma_keg_t keg, uma_slab_t slab)
freei = BIT_FFS(keg->uk_ipers, &slab->us_free) - 1;
BIT_CLR(keg->uk_ipers, freei, &slab->us_free);
- item = slab->us_data + (keg->uk_rsize * freei);
+ item = slab_item(slab, keg, freei);
slab->us_freecount--;
keg->uk_free--;
@@ -3609,7 +3604,7 @@ slab_free_item(uma_zone_t zone, uma_slab_t slab, void
}
/* Slab management. */
- freei = ((uintptr_t)item - (uintptr_t)slab->us_data) / keg->uk_rsize;
+ freei = slab_item_index(slab, keg, item);
BIT_SET(keg->uk_ipers, freei, &slab->us_free);
slab->us_freecount++;
@@ -4491,7 +4486,7 @@ uma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *
item, zone->uz_name);
}
keg = zone->uz_keg;
- freei = ((uintptr_t)item - (uintptr_t)slab->us_data) / keg->uk_rsize;
+ freei = slab_item_index(slab, keg, item);
if (BIT_ISSET(SLAB_MAX_SETSIZE, freei, &slab->us_debugfree))
panic("Duplicate alloc of %p from zone %p(%s) slab %p(%d)\n",
@@ -4519,13 +4514,13 @@ uma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *i
item, zone->uz_name);
}
keg = zone->uz_keg;
- freei = ((uintptr_t)item - (uintptr_t)slab->us_data) / keg->uk_rsize;
+ freei = slab_item_index(slab, keg, item);
if (freei >= keg->uk_ipers)
panic("Invalid free of %p from zone %p(%s) slab %p(%d)\n",
item, zone, zone->uz_name, slab, freei);
- if (((freei * keg->uk_rsize) + slab->us_data) != item)
+ if (slab_item(slab, keg, freei) != item)
panic("Unaligned free of %p from zone %p(%s) slab %p(%d)\n",
item, zone, zone->uz_name, slab, freei);
Modified: head/sys/vm/uma_int.h
==============================================================================
--- head/sys/vm/uma_int.h Sun Dec 8 00:06:00 2019 (r355509)
+++ head/sys/vm/uma_int.h Sun Dec 8 01:15:06 2019 (r355510)
@@ -139,33 +139,28 @@
/* Max waste percentage before going to off page slab management */
#define UMA_MAX_WASTE 10
+
/*
- * I doubt there will be many cases where this is exceeded. This is the initial
- * size of the hash table for uma_slabs that are managed off page. This hash
- * does expand by powers of two. Currently it doesn't get smaller.
+ * Hash table for freed address -> slab translation.
+ *
+ * Only zones with memory not touchable by the allocator use the
+ * hash table. Otherwise slabs are found with vtoslab().
*/
#define UMA_HASH_SIZE_INIT 32
-/*
- * I should investigate other hashing algorithms. This should yield a low
- * number of collisions if the pages are relatively contiguous.
- */
-
#define UMA_HASH(h, s) ((((uintptr_t)s) >> UMA_SLAB_SHIFT) & (h)->uh_hashmask)
#define UMA_HASH_INSERT(h, s, mem) \
- SLIST_INSERT_HEAD(&(h)->uh_slab_hash[UMA_HASH((h), \
- (mem))], (s), us_hlink)
-#define UMA_HASH_REMOVE(h, s, mem) \
- SLIST_REMOVE(&(h)->uh_slab_hash[UMA_HASH((h), \
- (mem))], (s), uma_slab, us_hlink)
+ LIST_INSERT_HEAD(&(h)->uh_slab_hash[UMA_HASH((h), \
+ (mem))], (uma_hash_slab_t)(s), uhs_hlink)
-/* Hash table for freed address -> slab translation */
+#define UMA_HASH_REMOVE(h, s) \
+ LIST_REMOVE((uma_hash_slab_t)(s), uhs_hlink)
-SLIST_HEAD(slabhead, uma_slab);
+LIST_HEAD(slabhashhead, uma_hash_slab);
struct uma_hash {
- struct slabhead *uh_slab_hash; /* Hash table for slabs */
+ struct slabhashhead *uh_slab_hash; /* Hash table for slabs */
u_int uh_hashsize; /* Current size of the hash table */
u_int uh_hashmask; /* Mask used during hashing */
};
@@ -202,13 +197,15 @@ struct uma_cache {
typedef struct uma_cache * uma_cache_t;
+LIST_HEAD(slabhead, uma_slab);
+
/*
* Per-domain memory list. Embedded in the kegs.
*/
struct uma_domain {
- LIST_HEAD(,uma_slab) ud_part_slab; /* partially allocated slabs */
- LIST_HEAD(,uma_slab) ud_free_slab; /* empty slab list */
- LIST_HEAD(,uma_slab) ud_full_slab; /* full slabs */
+ struct slabhead ud_part_slab; /* partially allocated slabs */
+ struct slabhead ud_free_slab; /* completely unallocated slabs */
+ struct slabhead ud_full_slab; /* fully allocated slabs */
};
typedef struct uma_domain * uma_domain_t;
@@ -271,8 +268,6 @@ BITSET_DEFINE(noslabbits, 0);
*/
struct uma_slab {
LIST_ENTRY(uma_slab) us_link; /* slabs in zone */
- SLIST_ENTRY(uma_slab) us_hlink; /* Link for hash table */
- uint8_t *us_data; /* First item */
uint16_t us_freecount; /* How many are free? */
uint8_t us_flags; /* Page flags see uma.h */
uint8_t us_domain; /* Backing NUMA domain. */
@@ -281,7 +276,6 @@ struct uma_slab {
#endif
struct noslabbits us_free; /* Free bitmask. */
};
-
#if MAXMEMDOM >= 255
#error "Slab domain type insufficient"
#endif
@@ -293,6 +287,47 @@ size_t slab_sizeof(int nitems);
size_t slab_space(int nitems);
int slab_ipers(size_t size, int align);
+/*
+ * Slab structure with a full sized bitset and hash link for both
+ * HASH and OFFPAGE zones.
+ */
+struct uma_hash_slab {
+ struct uma_slab uhs_slab; /* Must be first. */
+ struct slabbits uhs_bits; /* Must be second. */
+ LIST_ENTRY(uma_hash_slab) uhs_hlink; /* Link for hash table */
+ uint8_t *uhs_data; /* First item */
+};
+
+typedef struct uma_hash_slab * uma_hash_slab_t;
+
+static inline void *
+slab_data(uma_slab_t slab, uma_keg_t keg)
+{
+
+ if ((keg->uk_flags & UMA_ZONE_OFFPAGE) == 0)
+ return ((void *)((uintptr_t)slab - keg->uk_pgoff));
+ else
+ return (((uma_hash_slab_t)slab)->uhs_data);
+}
+
+static inline void *
+slab_item(uma_slab_t slab, uma_keg_t keg, int index)
+{
+ uintptr_t data;
+
+ data = (uintptr_t)slab_data(slab, keg);
+ return ((void *)(data + keg->uk_rsize * index));
+}
+
+static inline int
+slab_item_index(uma_slab_t slab, uma_keg_t keg, void *item)
+{
+ uintptr_t data;
+
+ data = (uintptr_t)slab_data(slab, keg);
+ return (((uintptr_t)item - data) / keg->uk_rsize);
+}
+
TAILQ_HEAD(uma_bucketlist, uma_bucket);
struct uma_zone_domain {
@@ -444,14 +479,14 @@ static __inline uma_slab_t hash_sfind(struct uma_hash
static __inline uma_slab_t
hash_sfind(struct uma_hash *hash, uint8_t *data)
{
- uma_slab_t slab;
+ uma_hash_slab_t slab;
u_int hval;
hval = UMA_HASH(hash, data);
- SLIST_FOREACH(slab, &hash->uh_slab_hash[hval], us_hlink) {
- if ((uint8_t *)slab->us_data == data)
- return (slab);
+ LIST_FOREACH(slab, &hash->uh_slab_hash[hval], uhs_hlink) {
+ if ((uint8_t *)slab->uhs_data == data)
+ return (&slab->uhs_slab);
}
return (NULL);
}
More information about the svn-src-head
mailing list