Hi there.

I wouldn't have gone into this if ant hadn't produced that 10% figure
for the speed improvement with simply reordering of increments and
dereferences (although jhb@ reported the speed-up he noticed was much
less than that).

I attach* a patch that: (i) incorporates ant's exchange of uc_freebucket
for uc_allocbucket, and (ii) throws away the uma_bucket.ub_cnt counter
of free bucket entries, in favor of a pointer -- uma_bucket.ub_last --
to the last free bucket entry. If a simple reordering is capable of
producing a 10% improvement, this change should do much better, since it
saves the 'add-' in the 'add-and-dereference' process of using arrays
and counters. The semantics of the pointer closely follow those of the
ub_cnt counter: ub_last - ub_bucket should equal the old value of
ub_cnt.

I grep'ed through the whole source repository and the uses of
uma_bucket.ub_cnt seem confined within sys/vm/uma_core.c, so this change
must be quite self-contained -- i.e. the change in the fields of
uma_bucket doesn't seem to affect any other part of the system. One
could argue that it may make the code a bit less readable, but it only
affects uma_core.c, so it may be worth the "inconvenience".

I don't have a FreeBSD box around any more, so I can't test this patch.
Heck, I can't either check it for syntax errors and such, so don't throw
things at me if this doesn't even compile. Can somebody with the time
and resources give it a try?

\n\n

* Also online at http://noth.ceid.upatras.gr/Misc/uma_bucket.diff
  to avoid being bitten by mailers auto{wrapp,indent}ing the diff
  content.
diff -urbB src.orig/sys/vm/uma_core.c src/sys/vm/uma_core.c
--- src.orig/sys/vm/uma_core.c  2005-06-30 19:09:06.777623184 +0300
+++ src/sys/vm/uma_core.c       2005-06-30 19:12:59.907182104 +0300
@@ -322,7 +322,7 @@
 #ifdef INVARIANTS
                bzero(bucket->ub_bucket, sizeof(void *) * ubz->ubz_entries);
 #endif
-               bucket->ub_cnt = 0;
+               bucket->ub_last = bucket->ub_bucket;
                bucket->ub_entries = ubz->ubz_entries;
        }
 
@@ -559,11 +559,11 @@
        if (zone->uz_keg->uk_flags & UMA_ZONE_MALLOC)
                mzone = 1;
 
-       while (bucket->ub_cnt > 0)  {
-               bucket->ub_cnt--;
-               item = bucket->ub_bucket[bucket->ub_cnt];
+       while (bucket->ub_last != bucket->ub_bucket)  {
+               bucket->ub_last--;
+               item = *(bucket->ub_last);
 #ifdef INVARIANTS
-               bucket->ub_bucket[bucket->ub_cnt] = NULL;
+               *(bucket->ub_last) = NULL;
                KASSERT(item != NULL,
                    ("bucket_drain: botched ptr, item is NULL"));
 #endif
@@ -1820,11 +1820,11 @@
        bucket = cache->uc_allocbucket;
 
        if (bucket) {
-               if (bucket->ub_cnt > 0) {
-                       bucket->ub_cnt--;
-                       item = bucket->ub_bucket[bucket->ub_cnt];
+               if (bucket->ub_last != bucket->ub_bucket) {
+                       bucket->ub_last--;
+                       item = *(bucket->ub_last);
 #ifdef INVARIANTS
-                       bucket->ub_bucket[bucket->ub_cnt] = NULL;
+                       *(bucket->ub_last) = NULL;
 #endif
                        KASSERT(item != NULL,
                            ("uma_zalloc: Bucket pointer mangled."));
@@ -1851,7 +1851,7 @@
                         * We have run out of items in our allocbucket.
                         * See if we can switch with our free bucket.
                         */
-                       if (cache->uc_freebucket->ub_cnt > 0) {
+                       if (cache->uc_freebucket->ub_last != 
cache->uc_freebucket->ub_bucket) {
 #ifdef UMA_DEBUG_ALLOC
                                printf("uma_zalloc: Swapping empty with"
                                    " alloc.\n");
@@ -1880,12 +1880,12 @@
        cache = &zone->uz_cpu[cpu];
        bucket = cache->uc_allocbucket;
        if (bucket != NULL) {
-               if (bucket->ub_cnt > 0) {
+               if (bucket->ub_last != bucket->ub_bucket) {
                        ZONE_UNLOCK(zone);
                        goto zalloc_start;
                }
                bucket = cache->uc_freebucket;
-               if (bucket != NULL && bucket->ub_cnt > 0) {
+               if (bucket != NULL && bucket->ub_last != bucket->ub_bucket) {
                        ZONE_UNLOCK(zone);
                        goto zalloc_start;
                }
@@ -1897,7 +1897,7 @@
 
        /* Our old one is now a free bucket */
        if (cache->uc_allocbucket) {
-               KASSERT(cache->uc_allocbucket->ub_cnt == 0,
+               KASSERT(cache->uc_allocbucket->ub_last == 
cache->uc_allocbucket->ub_backet,
                    ("uma_zalloc_arg: Freeing a non free bucket."));
                LIST_INSERT_HEAD(&zone->uz_free_bucket,
                    cache->uc_allocbucket, ub_link);
@@ -1906,7 +1906,7 @@
 
        /* Check the free list for a new alloc bucket */
        if ((bucket = LIST_FIRST(&zone->uz_full_bucket)) != NULL) {
-               KASSERT(bucket->ub_cnt != 0,
+               KASSERT(bucket->ub_last != bucket->ub_bucket,
                    ("uma_zalloc_arg: Returning an empty bucket."));
 
                LIST_REMOVE(bucket, ub_link);
@@ -2069,14 +2069,14 @@
 {
        uma_bucket_t bucket;
        uma_slab_t slab;
-       int16_t saved;
+       void ** saved;
        int max, origflags = flags;
 
        /*
         * Try this zone's free list first so we don't allocate extra buckets.
         */
        if ((bucket = LIST_FIRST(&zone->uz_free_bucket)) != NULL) {
-               KASSERT(bucket->ub_cnt == 0,
+               KASSERT(bucket->ub_last == bucket->ub_bucket,
                    ("uma_zalloc_bucket: Bucket on free list is not empty."));
                LIST_REMOVE(bucket, ub_link);
        } else {
@@ -2106,14 +2106,13 @@
 #endif
        zone->uz_fills++;
 
-       max = MIN(bucket->ub_entries, zone->uz_count);
+  max = bucket->ub_bucket + MIN(bucket->ub_entries, zone->uz_count);
        /* Try to keep the buckets totally full */
-       saved = bucket->ub_cnt;
-       while (bucket->ub_cnt < max &&
+       saved = bucket->ub_last;
+       while (bucket->ub_last < max &&
            (slab = uma_zone_slab(zone, flags)) != NULL) {
-               while (slab->us_freecount && bucket->ub_cnt < max) {
-                       bucket->ub_bucket[bucket->ub_cnt++] =
-                           uma_slab_alloc(zone, slab);
+               while (slab->us_freecount && bucket->ub_last < max) {
+                       *(bucket->ub_last++) = uma_slab_alloc(zone, slab);
                }
 
                /* Don't block on the next fill */
@@ -2128,34 +2127,34 @@
         * own it.
         */
        if (zone->uz_init != NULL) {
-               int i;
+               void ** i;
 
                ZONE_UNLOCK(zone);
-               for (i = saved; i < bucket->ub_cnt; i++)
-                       if (zone->uz_init(bucket->ub_bucket[i],
+               for (i = saved; i < bucket->ub_last; i++)
+                       if (zone->uz_init(*i,
                            zone->uz_keg->uk_size, origflags) != 0)
                                break;
                /*
                 * If we couldn't initialize the whole bucket, put the
                 * rest back onto the freelist.
                 */
-               if (i != bucket->ub_cnt) {
-                       int j;
+               if (i != bucket->ub_last) {
+                       void ** j;
 
-                       for (j = i; j < bucket->ub_cnt; j++) {
-                               uma_zfree_internal(zone, bucket->ub_bucket[j],
+                       for (j = i; j < bucket->ub_last; j++) {
+                               uma_zfree_internal(zone, *j,
                                    NULL, SKIP_FINI);
 #ifdef INVARIANTS
-                               bucket->ub_bucket[j] = NULL;
+                               (*j) = NULL;
 #endif
                        }
-                       bucket->ub_cnt = i;
+                       bucket->ub_last = i;
                }
                ZONE_LOCK(zone);
        }
 
        zone->uz_fills--;
-       if (bucket->ub_cnt != 0) {
+       if (bucket->ub_last != bucket->ub_bucket) {
                LIST_INSERT_HEAD(&zone->uz_full_bucket,
                    bucket, ub_link);
                return (1);
@@ -2281,7 +2280,7 @@
        cache = &zone->uz_cpu[cpu];
 
 zfree_start:
-       bucket = cache->uc_freebucket;
+       bucket = cache->uc_allocbucket;
 
        if (bucket) {
                /*
@@ -2289,14 +2288,14 @@
                 * check to be slightly out of sync.
                 */
 
-               if (bucket->ub_cnt < bucket->ub_entries) {
-                       KASSERT(bucket->ub_bucket[bucket->ub_cnt] == NULL,
+               if (bucket->ub_last < (bucket->ub_bucket + bucket->ub_entries)) 
{
+                       KASSERT(*(bucket->ub_last) == NULL,
                            ("uma_zfree: Freeing to non free bucket index."));
-                       bucket->ub_bucket[bucket->ub_cnt] = item;
-                       bucket->ub_cnt++;
+                       *(bucket->ub_last) = item;
+                       bucket->ub_last++;
                        critical_exit();
                        return;
-               } else if (cache->uc_allocbucket) {
+               } else if (cache->uc_freebucket) {
 #ifdef UMA_DEBUG_ALLOC
                        printf("uma_zfree: Swapping buckets.\n");
 #endif
@@ -2304,8 +2303,7 @@
                         * We have run out of space in our freebucket.
                         * See if we can switch with our alloc bucket.
                         */
-                       if (cache->uc_allocbucket->ub_cnt <
-                           cache->uc_freebucket->ub_cnt) {
+                       if (cache->uc_freebucket->ub_last == 
cache->uc_freebucket->ub_bucket) {
                                bucket = cache->uc_freebucket;
                                cache->uc_freebucket = cache->uc_allocbucket;
                                cache->uc_allocbucket = bucket;
@@ -2332,14 +2330,14 @@
        cpu = curcpu;
        cache = &zone->uz_cpu[cpu];
        if (cache->uc_freebucket != NULL) {
-               if (cache->uc_freebucket->ub_cnt <
+               if ((cache->uc_freebucket->ub_last - 
cache->uc_freebucket->ub_bucket) <
                    cache->uc_freebucket->ub_entries) {
                        ZONE_UNLOCK(zone);
                        goto zfree_start;
                }
                if (cache->uc_allocbucket != NULL &&
-                   (cache->uc_allocbucket->ub_cnt <
-                   cache->uc_freebucket->ub_cnt)) {
+                               ((cache->uc_allocbucket->ub_last - 
cache->uc_allocbucket->ub_bucket) <
+                                (cache->uc_freebucket->ub_last - 
cache->uc_freebucket->ub_bucket))) {
                        ZONE_UNLOCK(zone);
                        goto zfree_start;
                }
@@ -2353,8 +2351,8 @@
 #ifdef UMA_DEBUG_ALLOC
                printf("uma_zfree: Putting old bucket on the free list.\n");
 #endif
-               /* ub_cnt is pointing to the last free item */
-               KASSERT(bucket->ub_cnt != 0,
+               /* ub_last is pointing to the last free item */
+               KASSERT(bucket->ub_last != bucket->ub_bucket,
                    ("uma_zfree: Attempting to insert an empty bucket onto the 
full list.\n"));
                LIST_INSERT_HEAD(&zone->uz_full_bucket,
                    bucket, ub_link);
@@ -2707,9 +2705,9 @@
 {
        printf("alloc: %p(%d), free: %p(%d)\n",
                cache->uc_allocbucket,
-               cache->uc_allocbucket?cache->uc_allocbucket->ub_cnt:0,
+               cache->uc_allocbucket?(cache->uc_allocbucket->ub_last - 
cache->uc_allocbucket->ub_bucket):0,
                cache->uc_freebucket,
-               cache->uc_freebucket?cache->uc_freebucket->ub_cnt:0);
+               cache->uc_freebucket?(cache->uc_freebucket->ub_last - 
cache->uc_freebucket->ub_bucket):0);
 }
 
 void
@@ -2795,9 +2793,9 @@
                                        continue;
                                cache = &z->uz_cpu[cpu];
                                if (cache->uc_allocbucket != NULL)
-                                       cachefree += 
cache->uc_allocbucket->ub_cnt;
+                                       cachefree += 
(cache->uc_allocbucket->ub_last - cache->uc_allocbucket->ub_bucket);
                                if (cache->uc_freebucket != NULL)
-                                       cachefree += 
cache->uc_freebucket->ub_cnt;
+                                       cachefree += 
(cache->uc_freebucket->ub_last - cache->uc_freebucket->ub_bucket);
                                alloc += cache->uc_allocs;
                                cache->uc_allocs = 0;
                        }
@@ -2805,7 +2803,7 @@
                alloc += z->uz_allocs;
 
                LIST_FOREACH(bucket, &z->uz_full_bucket, ub_link) {
-                       cachefree += bucket->ub_cnt;
+                       cachefree += (bucket->ub_last - bucket->ub_bucket);
                }
                totalfree = zk->uk_free + cachefree;
                len = snprintf(offset, linesize,
diff -urbB src.orig/sys/vm/uma_int.h src/sys/vm/uma_int.h
--- src.orig/sys/vm/uma_int.h   2005-06-30 19:09:00.625558440 +0300
+++ src/sys/vm/uma_int.h        2005-06-30 18:41:16.515541616 +0300
@@ -166,7 +166,7 @@
 
 struct uma_bucket {
        LIST_ENTRY(uma_bucket)  ub_link;        /* Link into the zone */
-       int16_t ub_cnt;                         /* Count of free items. */
+       void    **ub_last;                              /* Pointer to last free 
item */
        int16_t ub_entries;                     /* Max items. */
        void    *ub_bucket[];                   /* actual allocation storage */
 };

Attachment: signature.asc
Description: Digital signature

Reply via email to