Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F105794428
D22829.id65903.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D22829.id65903.diff
View Options
Index: lib/libmemstat/memstat_uma.c
===================================================================
--- lib/libmemstat/memstat_uma.c
+++ lib/libmemstat/memstat_uma.c
@@ -311,10 +311,12 @@
LIST_HEAD(, uma_keg) uma_kegs;
struct memory_type *mtp;
struct uma_zone_domain uzd;
+ struct uma_domain ukd;
struct uma_bucket *ubp, ub;
struct uma_cache *ucp, *ucp_array;
struct uma_zone *uzp, uz;
struct uma_keg *kzp, kz;
+ uint64_t kegfree;
int hint_dontsearch, i, mp_maxid, ndomains, ret;
char name[MEMTYPE_MAXNAME];
cpuset_t all_cpus;
@@ -454,18 +456,29 @@
for (i = 0; i < ndomains; i++) {
ret = kread(kvm, &uz.uz_domain[i], &uzd,
sizeof(uzd), 0);
+ if (ret != 0)
+ continue;
for (ubp =
TAILQ_FIRST(&uzd.uzd_buckets);
ubp != NULL;
ubp = TAILQ_NEXT(&ub, ub_link)) {
ret = kread(kvm, ubp, &ub,
sizeof(ub), 0);
+ if (ret != 0)
+ continue;
mtp->mt_zonefree += ub.ub_cnt;
}
}
if (!((kz.uk_flags & UMA_ZONE_SECONDARY) &&
LIST_FIRST(&kz.uk_zones) != uzp)) {
- mtp->mt_kegfree = kz.uk_free;
+ kegfree = 0;
+ for (i = 0; i < ndomains; i++) {
+ ret = kread(kvm, &kzp->uk_domain[i],
+ &ukd, sizeof(ukd), 0);
+ if (ret > 0)
+ kegfree += ukd.ud_free;
+ }
+ mtp->mt_kegfree = kegfree;
mtp->mt_free += mtp->mt_kegfree;
}
mtp->mt_free += mtp->mt_zonefree;
Index: sys/vm/uma_core.c
===================================================================
--- sys/vm/uma_core.c
+++ sys/vm/uma_core.c
@@ -740,13 +740,20 @@
zone_timeout(uma_zone_t zone, void *unused)
{
uma_keg_t keg;
- u_int slabs;
+ u_int slabs, pages;
if ((zone->uz_flags & UMA_ZONE_HASH) == 0)
goto update_wss;
keg = zone->uz_keg;
- KEG_LOCK(keg);
+
+ /*
+ * Hash zones are non-numa by definition so the first domain
+ * is the only one present.
+ */
+ KEG_LOCK(keg, 0);
+ pages = keg->uk_domain[0].ud_pages;
+
/*
* Expand the keg hash table.
*
@@ -754,9 +761,7 @@
* What I'm trying to do here is completely reduce collisions. This
* may be a little aggressive. Should I allow for two collisions max?
*/
- if (keg->uk_flags & UMA_ZONE_HASH &&
- (slabs = keg->uk_pages / keg->uk_ppera) >
- keg->uk_hash.uh_hashsize) {
+ if ((slabs = pages / keg->uk_ppera) > keg->uk_hash.uh_hashsize) {
struct uma_hash newhash;
struct uma_hash oldhash;
int ret;
@@ -767,9 +772,9 @@
* I have to do everything in stages and check for
* races.
*/
- KEG_UNLOCK(keg);
+ KEG_UNLOCK(keg, 0);
ret = hash_alloc(&newhash, 1 << fls(slabs));
- KEG_LOCK(keg);
+ KEG_LOCK(keg, 0);
if (ret) {
if (hash_expand(&keg->uk_hash, &newhash)) {
oldhash = keg->uk_hash;
@@ -777,12 +782,12 @@
} else
oldhash = newhash;
- KEG_UNLOCK(keg);
+ KEG_UNLOCK(keg, 0);
hash_free(&oldhash);
- return;
+ goto update_wss;
}
}
- KEG_UNLOCK(keg);
+ KEG_UNLOCK(keg, 0);
update_wss:
ZONE_LOCK(zone);
@@ -1166,7 +1171,7 @@
struct slabhead freeslabs = { 0 };
uma_domain_t dom;
uma_slab_t slab, tmp;
- int i;
+ int i, n;
/*
* We don't want to take pages from statically allocated kegs at this
@@ -1175,33 +1180,29 @@
if (keg->uk_flags & UMA_ZONE_NOFREE || keg->uk_freef == NULL)
return;
- CTR3(KTR_UMA, "keg_drain %s(%p) free items: %u",
- keg->uk_name, keg, keg->uk_free);
- KEG_LOCK(keg);
- if (keg->uk_free == 0)
- goto finished;
-
for (i = 0; i < vm_ndomains; i++) {
+ CTR4(KTR_UMA, "keg_drain %s(%p) domain %d free items: %u",
+ keg->uk_name, keg, i, dom->ud_free);
+ n = 0;
dom = &keg->uk_domain[i];
+ KEG_LOCK(keg, i);
LIST_FOREACH_SAFE(slab, &dom->ud_free_slab, us_link, tmp) {
/* We have nowhere to free these to. */
if (slab->us_flags & UMA_SLAB_BOOT)
continue;
-
- LIST_REMOVE(slab, us_link);
- keg->uk_pages -= keg->uk_ppera;
- keg->uk_free -= keg->uk_ipers;
-
if (keg->uk_flags & UMA_ZONE_HASH)
UMA_HASH_REMOVE(&keg->uk_hash, slab);
-
+ n++;
+ LIST_REMOVE(slab, us_link);
LIST_INSERT_HEAD(&freeslabs, slab, us_link);
}
+ dom->ud_pages -= n * keg->uk_ppera;
+ dom->ud_free -= n * keg->uk_ipers;
+ KEG_UNLOCK(keg, i);
+ if ((keg->uk_flags & UMA_ZONE_NUMA) == 0)
+ break;
}
-finished:
- KEG_UNLOCK(keg);
-
while ((slab = LIST_FIRST(&freeslabs)) != NULL) {
LIST_REMOVE(slab, us_link);
keg_free_slab(keg, slab, keg->uk_ipers);
@@ -1258,8 +1259,8 @@
/*
* Allocate a new slab for a keg. This does not insert the slab onto a list.
- * The keg should be locked on entry and will be dropped and reacquired on
- * return.
+ * The keg should be unlocked on entry. If the allocation succeeds it will
+ * be locked on return.
*
* Arguments:
* flags Wait flags for the item initialization routine
@@ -1273,6 +1274,7 @@
keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int flags,
int aflags)
{
+ uma_domain_t dom;
uma_alloc allocf;
uma_slab_t slab;
unsigned long size;
@@ -1282,10 +1284,8 @@
KASSERT(domain >= 0 && domain < vm_ndomains,
("keg_alloc_slab: domain %d out of range", domain));
- KEG_LOCK_ASSERT(keg);
- allocf = keg->uk_allocf;
- KEG_UNLOCK(keg);
+ allocf = keg->uk_allocf;
slab = NULL;
mem = NULL;
if (keg->uk_flags & UMA_ZONE_OFFPAGE) {
@@ -1332,7 +1332,12 @@
slab->us_freecount = keg->uk_ipers;
slab->us_flags = sflags;
- slab->us_domain = domain;
+
+ /* For non-numa zones all pages go to the same uma_domain. */
+ if ((keg->uk_flags & UMA_ZONE_NUMA) != 0)
+ slab->us_domain = domain;
+ else
+ slab->us_domain = 0;
BIT_FILL(keg->uk_ipers, &slab->us_free);
#ifdef INVARIANTS
BIT_ZERO(keg->uk_ipers, slab_dbg_bits(slab, keg));
@@ -1348,7 +1353,7 @@
goto fail;
}
}
- KEG_LOCK(keg);
+ KEG_LOCK(keg, slab->us_domain);
CTR3(KTR_UMA, "keg_alloc_slab: allocated slab %p for %s(%p)",
slab, keg->uk_name, keg);
@@ -1356,13 +1361,19 @@
if (keg->uk_flags & UMA_ZONE_HASH)
UMA_HASH_INSERT(&keg->uk_hash, slab, mem);
- keg->uk_pages += keg->uk_ppera;
- keg->uk_free += keg->uk_ipers;
+ /*
+ * If we got a slab here it's safe to mark it partially used
+ * and return. We assume that the caller is going to remove
+ * at least one item.
+ */
+ dom = &keg->uk_domain[slab->us_domain];
+ LIST_INSERT_HEAD(&dom->ud_part_slab, slab, us_link);
+ dom->ud_pages += keg->uk_ppera;
+ dom->ud_free += keg->uk_ipers;
return (slab);
fail:
- KEG_LOCK(keg);
return (NULL);
}
@@ -1875,15 +1886,14 @@
struct uma_kctor_args *arg = udata;
uma_keg_t keg = mem;
uma_zone_t zone;
+ int i;
bzero(keg, size);
keg->uk_size = arg->size;
keg->uk_init = arg->uminit;
keg->uk_fini = arg->fini;
keg->uk_align = arg->align;
- keg->uk_free = 0;
keg->uk_reserve = 0;
- keg->uk_pages = 0;
keg->uk_flags = arg->flags;
keg->uk_slabzone = NULL;
@@ -1926,6 +1936,15 @@
keg_small_init(keg);
}
+ /*
+ * Sets all kegs with memory that comes from the page array to a
+ * first-touch domain policy.
+ */
+#ifdef UMA_FIRSTTOUCH
+ if ((keg->uk_flags & UMA_ZONE_HASH) == 0)
+ keg->uk_flags |= UMA_ZONE_NUMA;
+#endif
+
if (keg->uk_flags & UMA_ZONE_OFFPAGE)
keg->uk_slabzone = slabzone;
@@ -1954,9 +1973,10 @@
keg->uk_freef = page_free;
/*
- * Initialize keg's lock
+ * Initialize keg's locks.
*/
- KEG_LOCK_INIT(keg, (arg->flags & UMA_ZONE_MTXCLASS));
+ for (i = 0; i < vm_ndomains; i++)
+ KEG_LOCK_INIT(keg, i, (arg->flags & UMA_ZONE_MTXCLASS));
/*
* If we're putting the slab header in the actual page we need to
@@ -1983,10 +2003,7 @@
if (keg->uk_flags & UMA_ZONE_HASH)
hash_alloc(&keg->uk_hash, 0);
- CTR5(KTR_UMA, "keg_ctor %p zone %s(%p) out %d free %d\n",
- keg, zone->uz_name, zone,
- (keg->uk_pages / keg->uk_ppera) * keg->uk_ipers - keg->uk_free,
- keg->uk_free);
+ CTR3(KTR_UMA, "keg_ctor %p zone %s(%p)\n", keg, zone->uz_name, zone);
LIST_INSERT_HEAD(&keg->uk_zones, zone, uz_link);
@@ -2009,6 +2026,7 @@
zone_alloc_sysctl(uma_zone_t zone, void *unused)
{
uma_zone_domain_t zdom;
+ uma_domain_t dom;
uma_keg_t keg;
struct sysctl_oid *oid, *domainoid;
int domains, i, cnt;
@@ -2056,6 +2074,10 @@
/*
* keg if present.
*/
+ if ((zone->uz_flags & UMA_ZONE_NUMA) != 0)
+ domains = vm_ndomains;
+ else
+ domains = 1;
oid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(zone->uz_oid), OID_AUTO,
"keg", CTLFLAG_RD, NULL, "");
keg = zone->uz_keg;
@@ -2074,16 +2096,24 @@
SYSCTL_ADD_U32(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
"align", CTLFLAG_RD, &keg->uk_align, 0,
"item alignment mask");
- SYSCTL_ADD_U32(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
- "pages", CTLFLAG_RD, &keg->uk_pages, 0,
- "Total pages currently allocated from VM");
- SYSCTL_ADD_U32(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
- "free", CTLFLAG_RD, &keg->uk_free, 0,
- "items free in the slab layer");
SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
"efficiency", CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
keg, 0, sysctl_handle_uma_slab_efficiency, "I",
"Slab utilization (100 - internal fragmentation %)");
+ domainoid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(oid),
+ OID_AUTO, "domain", CTLFLAG_RD, NULL, "");
+ for (i = 0; i < domains; i++) {
+ dom = &keg->uk_domain[i];
+ oid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(domainoid),
+ OID_AUTO, VM_DOMAIN(i)->vmd_name, CTLFLAG_RD,
+ NULL, "");
+ SYSCTL_ADD_U32(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pages", CTLFLAG_RD, &dom->ud_pages, 0,
+ "Total pages currently allocated from VM");
+ SYSCTL_ADD_U32(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "free", CTLFLAG_RD, &dom->ud_free, 0,
+ "items free in the slab layer");
+ }
} else
SYSCTL_ADD_CONST_STRING(NULL, SYSCTL_CHILDREN(oid), OID_AUTO,
"name", CTLFLAG_RD, nokeg, "Keg name");
@@ -2114,12 +2144,8 @@
"Number of items in the bucket cache");
/*
- * Per-domain information.
+ * Per-domain zone information.
*/
- if ((zone->uz_flags & UMA_ZONE_NUMA) != 0)
- domains = vm_ndomains;
- else
- domains = 1;
domainoid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(zone->uz_oid),
OID_AUTO, "domain", CTLFLAG_RD, NULL, "");
for (i = 0; i < domains; i++) {
@@ -2359,20 +2385,23 @@
keg_dtor(void *arg, int size, void *udata)
{
uma_keg_t keg;
+ uint32_t free, pages;
+ int i;
keg = (uma_keg_t)arg;
- KEG_LOCK(keg);
- if (keg->uk_free != 0) {
- printf("Freed UMA keg (%s) was not empty (%d items). "
- " Lost %d pages of memory.\n",
- keg->uk_name ? keg->uk_name : "",
- keg->uk_free, keg->uk_pages);
+ free = pages = 0;
+ for (i = 0; i < vm_ndomains; i++) {
+ free += keg->uk_domain[i].ud_free;
+ pages += keg->uk_domain[i].ud_pages;
+ KEG_LOCK_FINI(keg, i);
}
- KEG_UNLOCK(keg);
+ if (free != 0)
+ printf("Freed UMA keg (%s) was not empty (%ud items). "
+ " Lost %ud pages of memory.\n",
+ keg->uk_name ? keg->uk_name : "",
+ free, pages);
hash_free(&keg->uk_hash);
-
- KEG_LOCK_FINI(keg);
}
/*
@@ -2659,11 +2688,6 @@
KASSERT(powerof2(align + 1), ("invalid zone alignment %d for \"%s\"",
align, name));
- /* Sets all zones to a first-touch domain policy. */
-#ifdef UMA_FIRSTTOUCH
- flags |= UMA_ZONE_NUMA;
-#endif
-
/* This stuff is essential for the zone ctor */
memset(&args, 0, sizeof(args));
args.name = name;
@@ -3135,7 +3159,7 @@
KASSERT(domain >= 0 && domain < vm_ndomains,
("keg_first_slab: domain %d out of range", domain));
- KEG_LOCK_ASSERT(keg);
+ KEG_LOCK_ASSERT(keg, domain);
slab = NULL;
start = domain;
@@ -3156,31 +3180,39 @@
return (NULL);
}
+/*
+ * Fetch an existing slab from a free or partial list. Returns with the
+ * keg domain lock held if a slab was found or unlocked if not.
+ */
static uma_slab_t
keg_fetch_free_slab(uma_keg_t keg, int domain, bool rr, int flags)
{
+ uma_slab_t slab;
uint32_t reserve;
- KEG_LOCK_ASSERT(keg);
+ /* !NUMA has a single free list. */
+ if ((keg->uk_flags & UMA_ZONE_NUMA) == 0)
+ domain = 0;
+ KEG_LOCK(keg, domain);
reserve = (flags & M_USE_RESERVE) != 0 ? 0 : keg->uk_reserve;
- if (keg->uk_free <= reserve)
+ if (keg->uk_domain[domain].ud_free <= reserve ||
+ (slab = keg_first_slab(keg, domain, rr)) == NULL) {
+ KEG_UNLOCK(keg, domain);
return (NULL);
- return (keg_first_slab(keg, domain, rr));
+ }
+ return (slab);
}
static uma_slab_t
keg_fetch_slab(uma_keg_t keg, uma_zone_t zone, int rdomain, const int flags)
{
struct vm_domainset_iter di;
- uma_domain_t dom;
uma_slab_t slab;
int aflags, domain;
bool rr;
restart:
- KEG_LOCK_ASSERT(keg);
-
/*
* Use the keg's policy if upper layers haven't already specified a
* domain (as happens with first-touch zones).
@@ -3211,21 +3243,11 @@
break;
slab = keg_alloc_slab(keg, zone, domain, flags, aflags);
- /*
- * If we got a slab here it's safe to mark it partially used
- * and return. We assume that the caller is going to remove
- * at least one item.
- */
- if (slab) {
- dom = &keg->uk_domain[slab->us_domain];
- LIST_INSERT_HEAD(&dom->ud_part_slab, slab, us_link);
+ if (slab != NULL)
return (slab);
- }
if (rr && vm_domainset_iter_policy(&di, &domain) != 0) {
if ((flags & M_WAITOK) != 0) {
- KEG_UNLOCK(keg);
vm_wait_doms(&keg->uk_dr.dr_policy->ds_mask);
- KEG_LOCK(keg);
goto restart;
}
break;
@@ -3237,9 +3259,9 @@
* could have while we were unlocked. Check again before we
* fail.
*/
- if ((slab = keg_fetch_free_slab(keg, domain, rr, flags)) != NULL) {
+ if ((slab = keg_fetch_free_slab(keg, domain, rr, flags)) != NULL)
return (slab);
- }
+
return (NULL);
}
@@ -3250,18 +3272,18 @@
void *item;
uint8_t freei;
- KEG_LOCK_ASSERT(keg);
+ KEG_LOCK_ASSERT(keg, slab->us_domain);
+ dom = &keg->uk_domain[slab->us_domain];
freei = BIT_FFS(keg->uk_ipers, &slab->us_free) - 1;
BIT_CLR(keg->uk_ipers, freei, &slab->us_free);
item = slab_item(slab, keg, freei);
slab->us_freecount--;
- keg->uk_free--;
+ dom->ud_free--;
/* Move this slab to the full list */
if (slab->us_freecount == 0) {
LIST_REMOVE(slab, us_link);
- dom = &keg->uk_domain[slab->us_domain];
LIST_INSERT_HEAD(&dom->ud_full_slab, slab, us_link);
}
@@ -3271,6 +3293,7 @@
static int
zone_import(void *arg, void **bucket, int max, int domain, int flags)
{
+ uma_domain_t dom;
uma_zone_t zone;
uma_slab_t slab;
uma_keg_t keg;
@@ -3282,7 +3305,6 @@
zone = arg;
slab = NULL;
keg = zone->uz_keg;
- KEG_LOCK(keg);
/* Try to keep the buckets totally full */
for (i = 0; i < max; ) {
if ((slab = keg_fetch_slab(keg, zone, domain, flags)) == NULL)
@@ -3290,9 +3312,10 @@
#ifdef NUMA
stripe = howmany(max, vm_ndomains);
#endif
+ dom = &keg->uk_domain[slab->us_domain];
while (slab->us_freecount && i < max) {
bucket[i++] = slab_alloc_item(keg, slab);
- if (keg->uk_free <= keg->uk_reserve)
+ if (dom->ud_free <= keg->uk_reserve)
break;
#ifdef NUMA
/*
@@ -3308,11 +3331,11 @@
break;
#endif
}
+ KEG_UNLOCK(keg, slab->us_domain);
/* Don't block if we allocated any successfully. */
flags &= ~M_WAITOK;
flags |= M_NOWAIT;
}
- KEG_UNLOCK(keg);
return i;
}
@@ -3863,11 +3886,10 @@
uint8_t freei;
keg = zone->uz_keg;
- KEG_LOCK_ASSERT(keg);
-
- dom = &keg->uk_domain[slab->us_domain];
+ KEG_LOCK_ASSERT(keg, slab->us_domain);
/* Do we need to remove from any lists? */
+ dom = &keg->uk_domain[slab->us_domain];
if (slab->us_freecount+1 == keg->uk_ipers) {
LIST_REMOVE(slab, us_link);
LIST_INSERT_HEAD(&dom->ud_free_slab, slab, us_link);
@@ -3882,37 +3904,45 @@
slab->us_freecount++;
/* Keg statistics. */
- keg->uk_free++;
+ dom->ud_free++;
}
static void
zone_release(void *arg, void **bucket, int cnt)
{
+ struct mtx *lock;
uma_zone_t zone;
- void *item;
uma_slab_t slab;
uma_keg_t keg;
uint8_t *mem;
+ void *item;
int i;
zone = arg;
keg = zone->uz_keg;
- KEG_LOCK(keg);
+ lock = NULL;
+ if (__predict_false((zone->uz_flags & UMA_ZONE_HASH) != 0))
+ lock = KEG_LOCK(keg, 0);
for (i = 0; i < cnt; i++) {
item = bucket[i];
- if (!(zone->uz_flags & UMA_ZONE_VTOSLAB)) {
+ if (__predict_true((zone->uz_flags & UMA_ZONE_VTOSLAB) != 0)) {
+ slab = vtoslab((vm_offset_t)item);
+ } else {
mem = (uint8_t *)((uintptr_t)item & (~UMA_SLAB_MASK));
- if (zone->uz_flags & UMA_ZONE_HASH) {
+ if ((zone->uz_flags & UMA_ZONE_HASH) != 0)
slab = hash_sfind(&keg->uk_hash, mem);
- } else {
- mem += keg->uk_pgoff;
- slab = (uma_slab_t)mem;
- }
- } else
- slab = vtoslab((vm_offset_t)item);
+ else
+ slab = (uma_slab_t)(mem + keg->uk_pgoff);
+ }
+ if (lock != KEG_LOCKPTR(keg, slab->us_domain)) {
+ if (lock != NULL)
+ mtx_unlock(lock);
+ lock = KEG_LOCK(keg, slab->us_domain);
+ }
slab_free_item(zone, slab, item);
}
- KEG_UNLOCK(keg);
+ if (lock != NULL)
+ mtx_unlock(lock);
}
/*
@@ -4196,7 +4226,6 @@
int aflags, domain, slabs;
KEG_GET(zone, keg);
- KEG_LOCK(keg);
slabs = items / keg->uk_ipers;
if (slabs * keg->uk_ipers < items)
slabs++;
@@ -4209,18 +4238,16 @@
aflags);
if (slab != NULL) {
dom = &keg->uk_domain[slab->us_domain];
+ LIST_REMOVE(slab, us_link);
LIST_INSERT_HEAD(&dom->ud_free_slab, slab,
us_link);
+ KEG_UNLOCK(keg, slab->us_domain);
break;
}
- if (vm_domainset_iter_policy(&di, &domain) != 0) {
- KEG_UNLOCK(keg);
+ if (vm_domainset_iter_policy(&di, &domain) != 0)
vm_wait_doms(&keg->uk_dr.dr_policy->ds_mask);
- KEG_LOCK(keg);
- }
}
}
- KEG_UNLOCK(keg);
}
/* See uma.h */
@@ -4458,6 +4485,7 @@
uma_keg_t kz;
uma_zone_t z;
uint64_t items;
+ uint32_t kfree, pages;
int count, error, i;
error = sysctl_wire_old_buffer(req, 0);
@@ -4487,6 +4515,11 @@
(void)sbuf_bcat(&sbuf, &ush, sizeof(ush));
LIST_FOREACH(kz, &uma_kegs, uk_link) {
+ kfree = pages = 0;
+ for (i = 0; i < vm_ndomains; i++) {
+ kfree += kz->uk_domain[i].ud_free;
+ pages += kz->uk_domain[i].ud_pages;
+ }
LIST_FOREACH(z, &kz->uk_zones, uz_link) {
bzero(&uth, sizeof(uth));
ZONE_LOCK(z);
@@ -4499,11 +4532,11 @@
uth.uth_pages = (items / kz->uk_ipers) *
kz->uk_ppera;
} else
- uth.uth_pages = kz->uk_pages;
+ uth.uth_pages = pages;
uth.uth_maxpages = (z->uz_max_items / kz->uk_ipers) *
kz->uk_ppera;
uth.uth_limit = z->uz_max_items;
- uth.uth_keg_free = z->uz_keg->uk_free;
+ uth.uth_keg_free = kfree;
/*
* A zone is secondary is it is not the first entry
@@ -4663,9 +4696,9 @@
keg = zone->uz_keg;
if ((keg->uk_flags & UMA_ZONE_HASH) == 0)
return ((uma_slab_t)(mem + keg->uk_pgoff));
- KEG_LOCK(keg);
+ KEG_LOCK(keg, 0);
slab = hash_sfind(&keg->uk_hash, mem);
- KEG_UNLOCK(keg);
+ KEG_UNLOCK(keg, 0);
return (slab);
}
@@ -4784,11 +4817,12 @@
} else
uma_zone_sumstat(z, cachefree, allocs, &frees, sleeps,
xdomain);
- if (!((z->uz_flags & UMA_ZONE_SECONDARY) &&
- (LIST_FIRST(&kz->uk_zones) != z)))
- *cachefree += kz->uk_free;
- for (i = 0; i < vm_ndomains; i++)
+ for (i = 0; i < vm_ndomains; i++) {
*cachefree += z->uz_domain[i].uzd_nitems;
+ if (!((z->uz_flags & UMA_ZONE_SECONDARY) &&
+ (LIST_FIRST(&kz->uk_zones) != z)))
+ *cachefree += kz->uk_domain[i].ud_free;
+ }
*used = *allocs - frees;
return (((int64_t)*used + *cachefree) * kz->uk_size);
}
Index: sys/vm/uma_int.h
===================================================================
--- sys/vm/uma_int.h
+++ sys/vm/uma_int.h
@@ -254,9 +254,12 @@
* Per-domain slab lists. Embedded in the kegs.
*/
struct uma_domain {
+ struct mtx_padalign ud_lock; /* Lock for the domain lists. */
struct slabhead ud_part_slab; /* partially allocated slabs */
struct slabhead ud_free_slab; /* completely unallocated slabs */
struct slabhead ud_full_slab; /* fully allocated slabs */
+ uint32_t ud_pages; /* Total page count */
+ uint32_t ud_free; /* Count of items free in slabs */
} __aligned(CACHE_LINE_SIZE);
typedef struct uma_domain * uma_domain_t;
@@ -268,14 +271,11 @@
*
*/
struct uma_keg {
- struct mtx uk_lock; /* Lock for the keg. */
struct uma_hash uk_hash;
LIST_HEAD(,uma_zone) uk_zones; /* Keg's zones */
struct domainset_ref uk_dr; /* Domain selection policy. */
uint32_t uk_align; /* Alignment mask */
- uint32_t uk_pages; /* Total page count */
- uint32_t uk_free; /* Count of items free in slabs */
uint32_t uk_reserve; /* Number of reserved items. */
uint32_t uk_size; /* Requested size of each item */
uint32_t uk_rsize; /* Real size of each item */
@@ -305,8 +305,8 @@
#ifdef _KERNEL
#define KEG_ASSERT_COLD(k) \
- KASSERT((k)->uk_pages == 0, ("keg %s initialization after use.",\
- (k)->uk_name))
+ KASSERT((k)->uk_domain[0].ud_pages == 0, \
+ ("keg %s initialization after use.", (k)->uk_name))
/*
* Free bits per-slab.
@@ -536,20 +536,22 @@
/* Lock Macros */
-#define KEG_LOCK_INIT(k, lc) \
- do { \
- if ((lc)) \
- mtx_init(&(k)->uk_lock, (k)->uk_name, \
- (k)->uk_name, MTX_DEF | MTX_DUPOK); \
- else \
- mtx_init(&(k)->uk_lock, (k)->uk_name, \
- "UMA zone", MTX_DEF | MTX_DUPOK); \
+#define KEG_LOCKPTR(k, d) (struct mtx *)&(k)->uk_domain[(d)].ud_lock
+#define KEG_LOCK_INIT(k, d, lc) \
+ do { \
+ if ((lc)) \
+ mtx_init(KEG_LOCKPTR(k, d), (k)->uk_name, \
+ (k)->uk_name, MTX_DEF | MTX_DUPOK); \
+ else \
+ mtx_init(KEG_LOCKPTR(k, d), (k)->uk_name, \
+ "UMA zone", MTX_DEF | MTX_DUPOK); \
} while (0)
-#define KEG_LOCK_FINI(k) mtx_destroy(&(k)->uk_lock)
-#define KEG_LOCK(k) mtx_lock(&(k)->uk_lock)
-#define KEG_UNLOCK(k) mtx_unlock(&(k)->uk_lock)
-#define KEG_LOCK_ASSERT(k) mtx_assert(&(k)->uk_lock, MA_OWNED)
+#define KEG_LOCK_FINI(k, d) mtx_destroy(KEG_LOCKPTR(k, d))
+#define KEG_LOCK(k, d) \
+ ({ mtx_lock(KEG_LOCKPTR(k, d)); KEG_LOCKPTR(k, d); })
+#define KEG_UNLOCK(k, d) mtx_unlock(KEG_LOCKPTR(k, d))
+#define KEG_LOCK_ASSERT(k, d) mtx_assert(KEG_LOCKPTR(k, d), MA_OWNED)
#define KEG_GET(zone, keg) do { \
(keg) = (zone)->uz_keg; \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 21, 7:20 PM (18 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15545454
Default Alt Text
D22829.id65903.diff (21 KB)
Attached To
Mode
D22829: (umaperf 5/7) Use per-domain keg locks.
Attached
Detach File
Event Timeline
Log In to Comment