-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Am Tue, 11 Feb 2020 20:06:33 +0000 (UTC)
Mark Johnston <ma...@freebsd.org> schrieb:

> Author: markj
> Date: Tue Feb 11 20:06:33 2020
> New Revision: 357776
> URL: https://svnweb.freebsd.org/changeset/base/357776
> 
> Log:
>   Reduce lock hold time in keg_drain().
>   
>   Maintain a count of free slabs in the per-domain keg structure and use
>   that to clear the free slab list in constant time for most cases.  This
>   helps minimize lock contention induced by reclamation, in preparation
>   for proactive trimming of excesses of free memory.
>   
>   Reviewed by:        jeff, rlibby
>   Tested by:  pho
>   Differential Revision:      https://reviews.freebsd.org/D23532
> 
> 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    Tue Feb 11 20:02:20 2020        (r357775)
> +++ head/sys/vm/uma_core.c    Tue Feb 11 20:06:33 2020        (r357776)
> @@ -1258,39 +1258,34 @@ keg_free_slab(uma_keg_t keg, uma_slab_t slab, int star
>  static void
>  keg_drain(uma_keg_t keg)
>  {
> -     struct slabhead freeslabs = { 0 };
> +     struct slabhead freeslabs;
>       uma_domain_t dom;
>       uma_slab_t slab, tmp;
>       int i, n;
>  
> -     /*
> -      * We don't want to take pages from statically allocated kegs at this
> -      * time
> -      */
>       if (keg->uk_flags & UMA_ZONE_NOFREE || keg->uk_freef == NULL)
>               return;
>  
>       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;
> +                 keg->uk_name, keg, i, dom->ud_free_items);
>               dom = &keg->uk_domain[i];
> +             LIST_INIT(&freeslabs);
> +
>               KEG_LOCK(keg, i);
> -             LIST_FOREACH_SAFE(slab, &dom->ud_free_slab, us_link, tmp) {
> -                     if (keg->uk_flags & UMA_ZFLAG_HASH)
> +             if ((keg->uk_flags & UMA_ZFLAG_HASH) != 0) {
> +                     LIST_FOREACH(slab, &dom->ud_free_slab, us_link)
>                               UMA_HASH_REMOVE(&keg->uk_hash, slab);
> -                     n++;
> -                     LIST_REMOVE(slab, us_link);
> -                     LIST_INSERT_HEAD(&freeslabs, slab, us_link);
>               }
> +             n = dom->ud_free_slabs;
> +             LIST_SWAP(&freeslabs, &dom->ud_free_slab, uma_slab, us_link);
> +             dom->ud_free_slabs = 0;
> +             dom->ud_free_items -= n * keg->uk_ipers;
>               dom->ud_pages -= n * keg->uk_ppera;
> -             dom->ud_free -= n * keg->uk_ipers;
>               KEG_UNLOCK(keg, i);
> -     }
>  
> -     while ((slab = LIST_FIRST(&freeslabs)) != NULL) {
> -             LIST_REMOVE(slab, us_link);
> -             keg_free_slab(keg, slab, keg->uk_ipers);
> +             LIST_FOREACH_SAFE(slab, &freeslabs, us_link, tmp)
> +                     keg_free_slab(keg, slab, keg->uk_ipers);
>       }
>  }
>  
> @@ -1458,7 +1453,7 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int dom
>       dom = &keg->uk_domain[domain];
>       LIST_INSERT_HEAD(&dom->ud_part_slab, slab, us_link);
>       dom->ud_pages += keg->uk_ppera;
> -     dom->ud_free += keg->uk_ipers;
> +     dom->ud_free_items += keg->uk_ipers;
>  
>       return (slab);
>  
> @@ -2286,7 +2281,7 @@ zone_alloc_sysctl(uma_zone_t zone, void *unused)
>                           "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,
> +                         "free_items", CTLFLAG_RD, &dom->ud_free_items, 0,
>                           "items free in the slab layer");
>               }
>       } else
> @@ -2572,7 +2567,7 @@ keg_dtor(void *arg, int size, void *udata)
>       keg = (uma_keg_t)arg;
>       free = pages = 0;
>       for (i = 0; i < vm_ndomains; i++) {
> -             free += keg->uk_domain[i].ud_free;
> +             free += keg->uk_domain[i].ud_free_items;
>               pages += keg->uk_domain[i].ud_pages;
>               KEG_LOCK_FINI(keg, i);
>       }
> @@ -3386,11 +3381,11 @@ keg_first_slab(uma_keg_t keg, int domain, bool rr)
>       start = domain;
>       do {
>               dom = &keg->uk_domain[domain];
> -             if (!LIST_EMPTY(&dom->ud_part_slab))
> -                     return (LIST_FIRST(&dom->ud_part_slab));
> -             if (!LIST_EMPTY(&dom->ud_free_slab)) {
> -                     slab = LIST_FIRST(&dom->ud_free_slab);
> +             if ((slab = LIST_FIRST(&dom->ud_part_slab)) != NULL)
> +                     return (slab);
> +             if ((slab = LIST_FIRST(&dom->ud_free_slab)) != NULL) {
>                       LIST_REMOVE(slab, us_link);
> +                     dom->ud_free_slabs--;
>                       LIST_INSERT_HEAD(&dom->ud_part_slab, slab, us_link);
>                       return (slab);
>               }
> @@ -3417,7 +3412,7 @@ keg_fetch_free_slab(uma_keg_t keg, int domain, bool rr
>  
>       KEG_LOCK(keg, domain);
>       reserve = (flags & M_USE_RESERVE) != 0 ? 0 : keg->uk_reserve;
> -     if (keg->uk_domain[domain].ud_free <= reserve ||
> +     if (keg->uk_domain[domain].ud_free_items <= reserve ||
>           (slab = keg_first_slab(keg, domain, rr)) == NULL) {
>               KEG_UNLOCK(keg, domain);
>               return (NULL);
> @@ -3502,9 +3497,13 @@ slab_alloc_item(uma_keg_t keg, uma_slab_t slab)
>       BIT_CLR(keg->uk_ipers, freei, &slab->us_free);
>       item = slab_item(slab, keg, freei);
>       slab->us_freecount--;
> -     dom->ud_free--;
> +     dom->ud_free_items--;
>  
> -     /* Move this slab to the full list */
> +     /*
> +      * Move this slab to the full list.  It must be on the partial list, so
> +      * we do not need to update the free slab count.  In particular,
> +      * keg_fetch_slab() always returns slabs on the partial list.
> +      */
>       if (slab->us_freecount == 0) {
>               LIST_REMOVE(slab, us_link);
>               LIST_INSERT_HEAD(&dom->ud_full_slab, slab, us_link);
> @@ -3538,7 +3537,7 @@ zone_import(void *arg, void **bucket, int max, int dom
>               dom = &keg->uk_domain[slab->us_domain];
>               while (slab->us_freecount && i < max) { 
>                       bucket[i++] = slab_alloc_item(keg, slab);
> -                     if (dom->ud_free <= keg->uk_reserve)
> +                     if (dom->ud_free_items <= keg->uk_reserve)
>                               break;
>  #ifdef NUMA
>                       /*
> @@ -4240,9 +4239,10 @@ slab_free_item(uma_zone_t zone, uma_slab_t slab, void 
>  
>       /* Do we need to remove from any lists? */
>       dom = &keg->uk_domain[slab->us_domain];
> -     if (slab->us_freecount+1 == keg->uk_ipers) {
> +     if (slab->us_freecount + 1 == keg->uk_ipers) {
>               LIST_REMOVE(slab, us_link);
>               LIST_INSERT_HEAD(&dom->ud_free_slab, slab, us_link);
> +             dom->ud_free_slabs++;
>       } else if (slab->us_freecount == 0) {
>               LIST_REMOVE(slab, us_link);
>               LIST_INSERT_HEAD(&dom->ud_part_slab, slab, us_link);
> @@ -4254,7 +4254,7 @@ slab_free_item(uma_zone_t zone, uma_slab_t slab, void 
>       slab->us_freecount++;
>  
>       /* Keg statistics. */
> -     dom->ud_free++;
> +     dom->ud_free_items++;
>  }
>  
>  static void
> @@ -4635,9 +4635,14 @@ uma_prealloc(uma_zone_t zone, int items)
>                           aflags);
>                       if (slab != NULL) {
>                               dom = &keg->uk_domain[slab->us_domain];
> +                             /*
> +                              * keg_alloc_slab() always returns a slab on the
> +                              * partial list.
> +                              */
>                               LIST_REMOVE(slab, us_link);
>                               LIST_INSERT_HEAD(&dom->ud_free_slab, slab,
>                                   us_link);
> +                             dom->ud_free_slabs++;
>                               KEG_UNLOCK(keg, slab->us_domain);
>                               break;
>                       }
> @@ -4915,7 +4920,7 @@ sysctl_vm_zone_stats(SYSCTL_HANDLER_ARGS)
>       LIST_FOREACH(kz, &uma_kegs, uk_link) {
>               kfree = pages = 0;
>               for (i = 0; i < vm_ndomains; i++) {
> -                     kfree += kz->uk_domain[i].ud_free;
> +                     kfree += kz->uk_domain[i].ud_free_items;
>                       pages += kz->uk_domain[i].ud_pages;
>               }
>               LIST_FOREACH(z, &kz->uk_zones, uz_link) {
> @@ -5219,7 +5224,7 @@ get_uma_stats(uma_keg_t kz, uma_zone_t z, uint64_t *al
>               *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;
> +                     *cachefree += kz->uk_domain[i].ud_free_items;
>       }
>       *used = *allocs - frees;
>       return (((int64_t)*used + *cachefree) * kz->uk_size);
> 
> Modified: head/sys/vm/uma_int.h
> ==============================================================================
> --- head/sys/vm/uma_int.h     Tue Feb 11 20:02:20 2020        (r357775)
> +++ head/sys/vm/uma_int.h     Tue Feb 11 20:06:33 2020        (r357776)
> @@ -324,7 +324,8 @@ struct uma_domain {
>       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 */
> +     uint32_t        ud_free_items;  /* Count of items free in all slabs */
> +     uint32_t        ud_free_slabs;  /* Count of free slabs */
>  } __aligned(CACHE_LINE_SIZE);
>  
>  typedef struct uma_domain * uma_domain_t;
> _______________________________________________
> svn-src-h...@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/svn-src-head
> To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

This commit breaks buildworld:


[...]
===> lib/libcasper/services/cap_fileargs (all)
- --- all_subdir_lib/libmemstat ---
- --- memstat_uma.o ---
/usr/src/lib/libmemstat/memstat_uma.c:479:22: error: no member named 'ud_free' 
in 'struct
uma_domain' kegfree += ukd.ud_free;
                                                           ~~~ ^
1 error generated.
- --- all_subdir_lib/libiconv_modules ---
- --- all_subdir_lib/libiconv_modules/VIQR ---
===> lib/libiconv_modules/VIQR (all)


- -- 
O. Hartmann

Ich widerspreche der Nutzung oder Übermittlung meiner Daten für
Werbezwecke oder für die Markt- oder Meinungsforschung (§ 28 Abs. 4 BDSG).
-----BEGIN PGP SIGNATURE-----

iHUEARYIAB0WIQSy8IBxAPDkqVBaTJ44N1ZZPba5RwUCXkMKvQAKCRA4N1ZZPba5
R8tOAP0ZiRf9EKhz/QUBNoUfXjlfjCd3WuXilQKFMqNbOstaVgD/SkxfBxLE+C/P
m0jmz7Al5AGai9Lia1X6y15McuqoHgc=
=PPFe
-----END PGP SIGNATURE-----
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to