Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Dec 2019 20:50:53 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r356080 - in head: lib/libmemstat sys/vm
Message-ID:  <201912252050.xBPKorE2041962@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Wed Dec 25 20:50:53 2019
New Revision: 356080
URL: https://svnweb.freebsd.org/changeset/base/356080

Log:
  Optimize fast path allocations by storing bucket headers in the per-cpu
  cache area.  This allows us to check on bucket space for all per-cpu
  buckets with a single cacheline access and fewer branches.
  
  Reviewed by:	markj, rlibby
  Differential Revision:	https://reviews.freebsd.org/D22825

Modified:
  head/lib/libmemstat/memstat_uma.c
  head/sys/vm/uma_core.c
  head/sys/vm/uma_int.h

Modified: head/lib/libmemstat/memstat_uma.c
==============================================================================
--- head/lib/libmemstat/memstat_uma.c	Wed Dec 25 19:26:35 2019	(r356079)
+++ head/lib/libmemstat/memstat_uma.c	Wed Dec 25 20:50:53 2019	(r356080)
@@ -438,28 +438,9 @@ memstat_kvm_uma(struct memory_type_list *list, void *k
 				mtp->mt_numallocs += ucp->uc_allocs;
 				mtp->mt_numfrees += ucp->uc_frees;
 
-				if (ucp->uc_allocbucket != NULL) {
-					ret = kread(kvm, ucp->uc_allocbucket,
-					    &ub, sizeof(ub), 0);
-					if (ret != 0) {
-						free(ucp_array);
-						_memstat_mtl_empty(list);
-						list->mtl_error = ret;
-						return (-1);
-					}
-					mtp->mt_free += ub.ub_cnt;
-				}
-				if (ucp->uc_freebucket != NULL) {
-					ret = kread(kvm, ucp->uc_freebucket,
-					    &ub, sizeof(ub), 0);
-					if (ret != 0) {
-						free(ucp_array);
-						_memstat_mtl_empty(list);
-						list->mtl_error = ret;
-						return (-1);
-					}
-					mtp->mt_free += ub.ub_cnt;
-				}
+				mtp->mt_free += ucp->uc_allocbucket.ucb_cnt;
+				mtp->mt_free += ucp->uc_freebucket.ucb_cnt;
+				mtp->mt_free += ucp->uc_crossbucket.ucb_cnt;
 			}
 skip_percpu:
 			mtp->mt_size = kz.uk_size;

Modified: head/sys/vm/uma_core.c
==============================================================================
--- head/sys/vm/uma_core.c	Wed Dec 25 19:26:35 2019	(r356079)
+++ head/sys/vm/uma_core.c	Wed Dec 25 20:50:53 2019	(r356080)
@@ -533,6 +533,144 @@ zone_put_bucket(uma_zone_t zone, uma_zone_domain_t zdo
 	zone->uz_bkt_count += bucket->ub_cnt;
 }
 
+/* Pops an item out of a per-cpu cache bucket. */
+static inline void *
+cache_bucket_pop(uma_cache_t cache, uma_cache_bucket_t bucket)
+{
+	void *item;
+
+	CRITICAL_ASSERT(curthread);
+
+	bucket->ucb_cnt--;
+	item = bucket->ucb_bucket->ub_bucket[bucket->ucb_cnt];
+#ifdef INVARIANTS
+	bucket->ucb_bucket->ub_bucket[bucket->ucb_cnt] = NULL;
+	KASSERT(item != NULL, ("uma_zalloc: Bucket pointer mangled."));
+#endif
+	cache->uc_allocs++;
+
+	return (item);
+}
+
+/* Pushes an item into a per-cpu cache bucket. */
+static inline void
+cache_bucket_push(uma_cache_t cache, uma_cache_bucket_t bucket, void *item)
+{
+
+	CRITICAL_ASSERT(curthread);
+	KASSERT(bucket->ucb_bucket->ub_bucket[bucket->ucb_cnt] == NULL,
+	    ("uma_zfree: Freeing to non free bucket index."));
+
+	bucket->ucb_bucket->ub_bucket[bucket->ucb_cnt] = item;
+	bucket->ucb_cnt++;
+	cache->uc_frees++;
+}
+
+/*
+ * Unload a UMA bucket from a per-cpu cache.
+ */
+static inline uma_bucket_t
+cache_bucket_unload(uma_cache_bucket_t bucket)
+{
+	uma_bucket_t b;
+
+	b = bucket->ucb_bucket;
+	if (b != NULL) {
+		MPASS(b->ub_entries == bucket->ucb_entries);
+		b->ub_cnt = bucket->ucb_cnt;
+		bucket->ucb_bucket = NULL;
+		bucket->ucb_entries = bucket->ucb_cnt = 0;
+	}
+
+	return (b);
+}
+
+static inline uma_bucket_t
+cache_bucket_unload_alloc(uma_cache_t cache)
+{
+
+	return (cache_bucket_unload(&cache->uc_allocbucket));
+}
+
+static inline uma_bucket_t
+cache_bucket_unload_free(uma_cache_t cache)
+{
+
+	return (cache_bucket_unload(&cache->uc_freebucket));
+}
+
+static inline uma_bucket_t
+cache_bucket_unload_cross(uma_cache_t cache)
+{
+
+	return (cache_bucket_unload(&cache->uc_crossbucket));
+}
+
+/*
+ * Load a bucket into a per-cpu cache bucket.
+ */
+static inline void
+cache_bucket_load(uma_cache_bucket_t bucket, uma_bucket_t b)
+{
+
+	CRITICAL_ASSERT(curthread);
+	MPASS(bucket->ucb_bucket == NULL);
+
+	bucket->ucb_bucket = b;
+	bucket->ucb_cnt = b->ub_cnt;
+	bucket->ucb_entries = b->ub_entries;
+}
+
+static inline void
+cache_bucket_load_alloc(uma_cache_t cache, uma_bucket_t b)
+{
+
+	cache_bucket_load(&cache->uc_allocbucket, b);
+}
+
+static inline void
+cache_bucket_load_free(uma_cache_t cache, uma_bucket_t b)
+{
+
+	cache_bucket_load(&cache->uc_freebucket, b);
+}
+
+#ifdef UMA_XDOMAIN
+static inline void 
+cache_bucket_load_cross(uma_cache_t cache, uma_bucket_t b)
+{
+
+	cache_bucket_load(&cache->uc_crossbucket, b);
+}
+#endif
+
+/*
+ * Copy and preserve ucb_spare.
+ */
+static inline void
+cache_bucket_copy(uma_cache_bucket_t b1, uma_cache_bucket_t b2)
+{
+
+	b1->ucb_bucket = b2->ucb_bucket;
+	b1->ucb_entries = b2->ucb_entries;
+	b1->ucb_cnt = b2->ucb_cnt;
+}
+
+/*
+ * Swap two cache buckets.
+ */
+static inline void
+cache_bucket_swap(uma_cache_bucket_t b1, uma_cache_bucket_t b2)
+{
+	struct uma_cache_bucket b3;
+
+	CRITICAL_ASSERT(curthread);
+
+	cache_bucket_copy(&b3, b1);
+	cache_bucket_copy(b1, b2);
+	cache_bucket_copy(b2, &b3);
+}
+
 static void
 zone_log_warning(uma_zone_t zone)
 {
@@ -801,6 +939,7 @@ static void
 cache_drain(uma_zone_t zone)
 {
 	uma_cache_t cache;
+	uma_bucket_t bucket;
 	int cpu;
 
 	/*
@@ -817,18 +956,21 @@ cache_drain(uma_zone_t zone)
 	 */
 	CPU_FOREACH(cpu) {
 		cache = &zone->uz_cpu[cpu];
-		bucket_drain(zone, cache->uc_allocbucket);
-		if (cache->uc_allocbucket != NULL)
-			bucket_free(zone, cache->uc_allocbucket, NULL);
-		cache->uc_allocbucket = NULL;
-		bucket_drain(zone, cache->uc_freebucket);
-		if (cache->uc_freebucket != NULL)
-			bucket_free(zone, cache->uc_freebucket, NULL);
-		cache->uc_freebucket = NULL;
-		bucket_drain(zone, cache->uc_crossbucket);
-		if (cache->uc_crossbucket != NULL)
-			bucket_free(zone, cache->uc_crossbucket, NULL);
-		cache->uc_crossbucket = NULL;
+		bucket = cache_bucket_unload_alloc(cache);
+		if (bucket != NULL) {
+			bucket_drain(zone, bucket);
+			bucket_free(zone, bucket, NULL);
+		}
+		bucket = cache_bucket_unload_free(cache);
+		if (bucket != NULL) {
+			bucket_drain(zone, bucket);
+			bucket_free(zone, bucket, NULL);
+		}
+		bucket = cache_bucket_unload_cross(cache);
+		if (bucket != NULL) {
+			bucket_drain(zone, bucket);
+			bucket_free(zone, bucket, NULL);
+		}
 	}
 	ZONE_LOCK(zone);
 	bucket_cache_reclaim(zone, true);
@@ -866,24 +1008,17 @@ cache_drain_safe_cpu(uma_zone_t zone, void *unused)
 	else
 		domain = 0;
 	cache = &zone->uz_cpu[curcpu];
-	if (cache->uc_allocbucket) {
-		if (cache->uc_allocbucket->ub_cnt != 0)
-			zone_put_bucket(zone, &zone->uz_domain[domain],
-			    cache->uc_allocbucket, false);
-		else
-			b1 = cache->uc_allocbucket;
-		cache->uc_allocbucket = NULL;
+	b1 = cache_bucket_unload_alloc(cache);
+	if (b1 != NULL && b1->ub_cnt != 0) {
+		zone_put_bucket(zone, &zone->uz_domain[domain], b1, false);
+		b1 = NULL;
 	}
-	if (cache->uc_freebucket) {
-		if (cache->uc_freebucket->ub_cnt != 0)
-			zone_put_bucket(zone, &zone->uz_domain[domain],
-			    cache->uc_freebucket, false);
-		else
-			b2 = cache->uc_freebucket;
-		cache->uc_freebucket = NULL;
+	b2 = cache_bucket_unload_free(cache);
+	if (b2 != NULL && b2->ub_cnt != 0) {
+		zone_put_bucket(zone, &zone->uz_domain[domain], b2, false);
+		b2 = NULL;
 	}
-	b3 = cache->uc_crossbucket;
-	cache->uc_crossbucket = NULL;
+	b3 = cache_bucket_unload_cross(cache);
 	critical_exit();
 	ZONE_UNLOCK(zone);
 	if (b1)
@@ -2666,33 +2801,6 @@ uma_zfree_pcpu_arg(uma_zone_t zone, void *item, void *
 	uma_zfree_arg(zone, item, udata);
 }
 
-static inline void *
-bucket_pop(uma_zone_t zone, uma_cache_t cache, uma_bucket_t bucket)
-{
-	void *item;
-
-	bucket->ub_cnt--;
-	item = bucket->ub_bucket[bucket->ub_cnt];
-#ifdef INVARIANTS
-	bucket->ub_bucket[bucket->ub_cnt] = NULL;
-	KASSERT(item != NULL, ("uma_zalloc: Bucket pointer mangled."));
-#endif
-	cache->uc_allocs++;
-
-	return (item);
-}
-
-static inline void
-bucket_push(uma_zone_t zone, uma_cache_t cache, uma_bucket_t bucket,
-    void *item)
-{
-	KASSERT(bucket->ub_bucket[bucket->ub_cnt] == NULL,
-	    ("uma_zfree: Freeing to non free bucket index."));
-	bucket->ub_bucket[bucket->ub_cnt] = item;
-	bucket->ub_cnt++;
-	cache->uc_frees++;
-}
-
 static void *
 item_ctor(uma_zone_t zone, void *udata, int flags, void *item)
 {
@@ -2749,7 +2857,7 @@ item_dtor(uma_zone_t zone, void *item, void *udata, en
 void *
 uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
 {
-	uma_bucket_t bucket;
+	uma_cache_bucket_t bucket;
 	uma_cache_t cache;
 	void *item;
 	int cpu, domain;
@@ -2806,9 +2914,9 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags
 	do {
 		cpu = curcpu;
 		cache = &zone->uz_cpu[cpu];
-		bucket = cache->uc_allocbucket;
-		if (__predict_true(bucket != NULL && bucket->ub_cnt != 0)) {
-			item = bucket_pop(zone, cache, bucket);
+		bucket = &cache->uc_allocbucket;
+		if (__predict_true(bucket->ucb_cnt != 0)) {
+			item = cache_bucket_pop(cache, bucket);
 			critical_exit();
 			return (item_ctor(zone, udata, flags, item));
 		}
@@ -2846,18 +2954,15 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *
 	 * If we have run out of items in our alloc bucket see
 	 * if we can switch with the free bucket.
 	 */
-	bucket = cache->uc_freebucket;
-	if (bucket != NULL && bucket->ub_cnt != 0) {
-		cache->uc_freebucket = cache->uc_allocbucket;
-		cache->uc_allocbucket = bucket;
+	if (cache->uc_freebucket.ucb_cnt != 0) {
+		cache_bucket_swap(&cache->uc_freebucket, &cache->uc_allocbucket);
 		return (true);
 	}
 
 	/*
 	 * Discard any empty allocation bucket while we hold no locks.
 	 */
-	bucket = cache->uc_allocbucket;
-	cache->uc_allocbucket = NULL;
+	bucket = cache_bucket_unload_alloc(cache);
 	critical_exit();
 	if (bucket != NULL)
 		bucket_free(zone, bucket, udata);
@@ -2887,7 +2992,7 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *
 	cache = &zone->uz_cpu[cpu];
 
 	/* See if we lost the race to fill the cache. */
-	if (cache->uc_allocbucket != NULL) {
+	if (cache->uc_allocbucket.ucb_bucket != NULL) {
 		ZONE_UNLOCK(zone);
 		return (true);
 	}
@@ -2907,7 +3012,7 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *
 		ZONE_UNLOCK(zone);
 		KASSERT(bucket->ub_cnt != 0,
 		    ("uma_zalloc_arg: Returning an empty bucket."));
-		cache->uc_allocbucket = bucket;
+		cache_bucket_load_alloc(cache, bucket);
 		return (true);
 	}
 	/* We are no longer associated with this CPU. */
@@ -2937,10 +3042,10 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *
 	 */
 	cpu = curcpu;
 	cache = &zone->uz_cpu[cpu];
-	if (cache->uc_allocbucket == NULL &&
+	if (cache->uc_allocbucket.ucb_bucket == NULL &&
 	    ((zone->uz_flags & UMA_ZONE_NUMA) == 0 ||
 	    domain == PCPU_GET(domain))) {
-		cache->uc_allocbucket = bucket;
+		cache_bucket_load_alloc(cache, bucket);
 		zdom->uzd_imax += bucket->ub_cnt;
 	} else if (zone->uz_bkt_count >= zone->uz_bkt_max) {
 		critical_exit();
@@ -3361,7 +3466,7 @@ void
 uma_zfree_arg(uma_zone_t zone, void *item, void *udata)
 {
 	uma_cache_t cache;
-	uma_bucket_t bucket;
+	uma_cache_bucket_t bucket;
 	int cpu, domain, itemdomain;
 
 	/* Enable entropy collection for RANDOM_ENABLE_UMA kernel option */
@@ -3411,7 +3516,7 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata
 	do {
 		cpu = curcpu;
 		cache = &zone->uz_cpu[cpu];
-		bucket = cache->uc_allocbucket;
+		bucket = &cache->uc_allocbucket;
 #ifdef UMA_XDOMAIN
 		if ((zone->uz_flags & UMA_ZONE_NUMA) != 0) {
 			itemdomain = _vm_phys_domain(pmap_kextract((vm_offset_t)item));
@@ -3419,7 +3524,7 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata
 		}
 		if ((zone->uz_flags & UMA_ZONE_NUMA) != 0 &&
 		    domain != itemdomain) {
-			bucket = cache->uc_crossbucket;
+			bucket = &cache->uc_crossbucket;
 		} else
 #endif
 
@@ -3428,11 +3533,10 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata
 		 * for cache-hot datastructures.  Spill over into the freebucket
 		 * if necessary.  Alloc will swap them if one runs dry.
 		 */
-		if (bucket == NULL || bucket->ub_cnt >= bucket->ub_entries)
-			bucket = cache->uc_freebucket;
-		if (__predict_true(bucket != NULL &&
-		    bucket->ub_cnt < bucket->ub_entries)) {
-			bucket_push(zone, cache, bucket, item);
+		if (__predict_false(bucket->ucb_cnt >= bucket->ucb_entries))
+			bucket = &cache->uc_freebucket;
+		if (__predict_true(bucket->ucb_cnt < bucket->ucb_entries)) {
+			cache_bucket_push(cache, bucket, item);
 			critical_exit();
 			return;
 		}
@@ -3536,16 +3640,12 @@ cache_free(uma_zone_t zone, uma_cache_t cache, void *u
 		itemdomain = domain = 0;
 #ifdef UMA_XDOMAIN
 	if (domain != itemdomain) {
-		bucket = cache->uc_crossbucket;
-		cache->uc_crossbucket = NULL;
+		bucket = cache_bucket_unload_cross(cache);
 		if (bucket != NULL)
 			atomic_add_64(&zone->uz_xdomain, bucket->ub_cnt);
 	} else
 #endif
-	{
-		bucket = cache->uc_freebucket;
-		cache->uc_freebucket = NULL;
-	}
+		bucket = cache_bucket_unload_free(cache);
 
 
 	/* We are no longer associated with this CPU. */
@@ -3570,8 +3670,9 @@ cache_free(uma_zone_t zone, uma_cache_t cache, void *u
 	 */
 	if ((zone->uz_flags & UMA_ZONE_NUMA) != 0) {
 		domain = PCPU_GET(domain);
-		if (domain != itemdomain && cache->uc_crossbucket == NULL) {
-			cache->uc_crossbucket = bucket;
+		if (domain != itemdomain &&
+		    cache->uc_crossbucket.ucb_bucket == NULL) {
+			cache_bucket_load_cross(cache, bucket);
 			return (true);
 		}
 	}
@@ -3579,12 +3680,12 @@ cache_free(uma_zone_t zone, uma_cache_t cache, void *u
 	/*
 	 * We may have lost the race to fill the bucket or switched CPUs.
 	 */
-	if (cache->uc_freebucket != NULL) {
+	if (cache->uc_freebucket.ucb_bucket != NULL) {
 		critical_exit();
 		bucket_free(zone, bucket, udata);
 		critical_enter();
 	} else
-		cache->uc_freebucket = bucket;
+		cache_bucket_load_free(cache, bucket);
 
 	return (true);
 }
@@ -4175,9 +4276,6 @@ uma_avail(void)
  * Note: does not update the zone statistics, as it can't safely clear the
  * per-CPU cache statistic.
  *
- * XXXRW: Following the uc_allocbucket and uc_freebucket pointers here isn't
- * safe from off-CPU; we should modify the caches to track this information
- * directly so that we don't have to.
  */
 static void
 uma_zone_sumstat(uma_zone_t z, long *cachefreep, uint64_t *allocsp,
@@ -4191,14 +4289,10 @@ uma_zone_sumstat(uma_zone_t z, long *cachefreep, uint6
 	cachefree = 0;
 	CPU_FOREACH(cpu) {
 		cache = &z->uz_cpu[cpu];
-		if (cache->uc_allocbucket != NULL)
-			cachefree += cache->uc_allocbucket->ub_cnt;
-		if (cache->uc_freebucket != NULL)
-			cachefree += cache->uc_freebucket->ub_cnt;
-		if (cache->uc_crossbucket != NULL) {
-			xdomain += cache->uc_crossbucket->ub_cnt;
-			cachefree += cache->uc_crossbucket->ub_cnt;
-		}
+		cachefree += cache->uc_allocbucket.ucb_cnt;
+		cachefree += cache->uc_freebucket.ucb_cnt;
+		xdomain += cache->uc_crossbucket.ucb_cnt;
+		cachefree += cache->uc_crossbucket.ucb_cnt;
 		allocs += cache->uc_allocs;
 		frees += cache->uc_frees;
 	}
@@ -4244,7 +4338,6 @@ uma_vm_zone_stats(struct uma_type_header *uth, uma_zon
     struct uma_percpu_stat *ups, bool internal)
 {
 	uma_zone_domain_t zdom;
-	uma_bucket_t bucket;
 	uma_cache_t cache;
 	int i;
 
@@ -4272,15 +4365,9 @@ uma_vm_zone_stats(struct uma_type_header *uth, uma_zon
 		if (internal || CPU_ABSENT(i))
 			continue;
 		cache = &z->uz_cpu[i];
-		bucket = (uma_bucket_t)atomic_load_ptr(&cache->uc_allocbucket);
-		if (bucket != NULL)
-			ups[i].ups_cache_free += bucket->ub_cnt;
-		bucket = (uma_bucket_t)atomic_load_ptr(&cache->uc_freebucket);
-		if (bucket != NULL)
-			ups[i].ups_cache_free += bucket->ub_cnt;
-		bucket = (uma_bucket_t)atomic_load_ptr(&cache->uc_crossbucket);
-		if (bucket != NULL)
-			ups[i].ups_cache_free += bucket->ub_cnt;
+		ups[i].ups_cache_free += cache->uc_allocbucket.ucb_cnt;
+		ups[i].ups_cache_free += cache->uc_freebucket.ucb_cnt;
+		ups[i].ups_cache_free += cache->uc_crossbucket.ucb_cnt;
 		ups[i].ups_allocs = cache->uc_allocs;
 		ups[i].ups_frees = cache->uc_frees;
 	}

Modified: head/sys/vm/uma_int.h
==============================================================================
--- head/sys/vm/uma_int.h	Wed Dec 25 19:26:35 2019	(r356079)
+++ head/sys/vm/uma_int.h	Wed Dec 25 20:50:53 2019	(r356080)
@@ -171,13 +171,14 @@ struct uma_hash {
 #if defined(__amd64__) || defined(__powerpc64__)
 #define UMA_ALIGN	__aligned(128)
 #else
-#define UMA_ALIGN
+#define UMA_ALIGN	__aligned(CACHE_LINE_SIZE)
 #endif
 
 /*
- * Structures for per cpu queues.
+ * The uma_bucket structure is used to queue and manage buckets divorced
+ * from per-cpu caches.  They are loaded into uma_cache_bucket structures
+ * for use.
  */
-
 struct uma_bucket {
 	TAILQ_ENTRY(uma_bucket)	ub_link;	/* Link into the zone */
 	int16_t	ub_cnt;				/* Count of items in bucket. */
@@ -187,12 +188,29 @@ struct uma_bucket {
 
 typedef struct uma_bucket * uma_bucket_t;
 
+/*
+ * The uma_cache_bucket structure is statically allocated on each per-cpu
+ * cache.  Its use reduces branches and cache misses in the fast path.
+ */
+struct uma_cache_bucket {
+	uma_bucket_t	ucb_bucket;
+	int16_t		ucb_cnt;
+	int16_t		ucb_entries;
+	uint32_t	ucb_spare;
+};
+
+typedef struct uma_cache_bucket * uma_cache_bucket_t;
+
+/*
+ * The uma_cache structure is allocated for each cpu for every zone
+ * type.  This optimizes synchronization out of the allocator fast path.
+ */
 struct uma_cache {
-	uma_bucket_t	uc_freebucket;	/* Bucket we're freeing to */
-	uma_bucket_t	uc_allocbucket;	/* Bucket to allocate from */
-	uma_bucket_t	uc_crossbucket;	/* cross domain bucket */
-	uint64_t	uc_allocs;	/* Count of allocations */
-	uint64_t	uc_frees;	/* Count of frees */
+	struct uma_cache_bucket	uc_freebucket;	/* Bucket we're freeing to */
+	struct uma_cache_bucket	uc_allocbucket;	/* Bucket to allocate from */
+	struct uma_cache_bucket	uc_crossbucket;	/* cross domain bucket */
+	uint64_t		uc_allocs;	/* Count of allocations */
+	uint64_t		uc_frees;	/* Count of frees */
 } UMA_ALIGN;
 
 typedef struct uma_cache * uma_cache_t;
@@ -200,7 +218,7 @@ typedef struct uma_cache * uma_cache_t;
 LIST_HEAD(slabhead, uma_slab);
 
 /*
- * Per-domain memory list.  Embedded in the kegs.
+ * Per-domain slab lists.  Embedded in the kegs.
  */
 struct uma_domain {
 	struct slabhead	ud_part_slab;	/* partially allocated slabs */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201912252050.xBPKorE2041962>