> On 14 Jun 2017, at 13:50, David Gwynne <da...@gwynne.id.au> wrote:
> 
> i have a few things left to do in the pools per cpu caches, one of
> which is make their activity visibile. to that end, here's a diff
> provides a way for userland to request stats from the per cpu caches,
> and uses that in systat so you can watch them.
> 
> there are two added pool sysctls. one copies an array of stats from
> each cpus cache. the interesting bits in those stats are how many
> items each cpu handled, and how many list operations the cpu did
> against the global pool cache.
> 
> the second sysctl reports stats about the global pool cache. currently
> this is the target for the list length the cpus build is, how many
> lists its holding, and how many times the gc has moved a list of
> items back into the pool for recovery.
> 
> these are used by sysctl for a new view which ive called pcaches,
> short for pool caches.
> 
> ksh: Fmt: not found

har. this was supposed to say that an example of the output is below. this is 
an 8 way box after running tcpbench for a bit.

> 
>   2 users Load 1.42 0.78 0.35 (1-88 of 158)       v880.embarrassm.net 13:48:40
> 
> NAME             LEN   NL  NGC  CPU         REQ        REL       LREQ       
> LREL
> mbufpl             8   72    0    0      955967    2622839        794     
> 209151
>                                  1      907108     362300      88367      
> 20266
>                                  2      915933     356927      90031      
> 20155
>                                  3      878324     339160      86646      
> 19250
>                                  4       30620       7851       3301        
> 454
>                                  5        1401        885        117         
> 52
>                                  6          56         57          0          > 0
>                                  7          37         45          0          > 0
> mtagpl             8    0    0    0           0          0          0         
>  0
>                                  1           0          0          0          > 0
>                                  2           0          0          0          > 0
>                                  3           0          0          0          > 0
>                                  4           0          0          0          > 0
>                                  5           0          0          0          > 0
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl2k              8   32    0    0      944634       7776     117605        
> 497
>                                  1         122     318421          0      
> 39786
>                                  2         114     313498          0      
> 39171
>                                  3         105     298051          0      
> 37242
>                                  4          22       6834          0        
> 850
>                                  5           0        744          0         
> 91
>                                  6           0          1          0          > 0
>                                  7           1          3          0          > 0
> mcl2k2             8    0    0    0           0          0          0         
>  0
>                                  1           0          0          0          > 0
>                                  2           0          0          0          > 0
>                                  3           0          0          0          > 0
>                                  4           0          0          0          > 0
>                                  5           0          0          0          > 0
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl4k              8    2    0    0          20         44          1         
>  2
>                                  1        1978       2072         85         
> 96
>                                  2        2100       1988         97         
> 83
>                                  3        1910       1986         83         
> 91
>                                  4          87         61          6          
> 2
>                                  5           1          9          0          > 0
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl8k              8   17    0    0          97        956         11        
> 117
>                                  1       19517      20418       2254       
> 2366
>                                  2       20934      20704       2441       
> 2412
>                                  3       20294      19734       2347       
> 2275
>                                  4        1234        399        150         
> 45
>                                  5           0         54          0          
> 5
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl9k              8    0    0    0           1          5          0         
>  0
>                                  1         145        176          2          
> 4
>                                  2         156        162          2          
> 2
>                                  3         159        154          1          > 0
>                                  4           3          2          1          > 0
>                                  5           0          1          0          > 0
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl12k             8    2    0    0           2          8          0         
>  0
>                                  1         271        294          6          
> 8
>                                  2         302        256          8          
> 2
>                                  3         223        294          1          
> 9
>                                  4          20          4          2          > 0
>                                  5           0          2          0          > 0
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl16k             8    2    0    0           7         34          0         
>  2
>                                  1        1108       1137         39         
> 42
>                                  2        1095       1141         40         
> 45
>                                  3        1021        998         39         
> 35
>                                  4          51         27          4          > 0
>                                  5           1          3          0          > 0
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> mcl64k             8    3    0    0          68        327          3         
> 34
>                                  1       17492      18495       1694       
> 1819
>                                  2       18369      18135       1842       
> 1812
>                                  3       18017      17252       1808       
> 1711
>                                  4         618        409         69         
> 41
>                                  5          22         41          1          
> 3
>                                  6           0          0          0          > 0
>                                  7           0          0          0          > 0
> 
> 
> the systat view could be improved, but id prefer to do that in tree.
> 
> ok?
> 
> Index: sys/kern/subr_pool.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/subr_pool.c,v
> retrieving revision 1.209
> diff -u -p -r1.209 subr_pool.c
> --- sys/kern/subr_pool.c      13 Jun 2017 11:41:11 -0000      1.209
> +++ sys/kern/subr_pool.c      14 Jun 2017 03:13:47 -0000
> @@ -122,9 +122,12 @@ struct pool_cache {
>       struct pool_cache_item  *pc_prev;       /* previous list of items */
> 
>       uint64_t                 pc_gen;        /* generation number */
> -     uint64_t                 pc_gets;
> -     uint64_t                 pc_puts;
> -     uint64_t                 pc_fails;
> +     uint64_t                 pc_nget;       /* # of successful requests */
> +     uint64_t                 pc_nfail;      /* # of unsuccessful reqs */
> +     uint64_t                 pc_nput;       /* # of releases */
> +     uint64_t                 pc_nlget;      /* # of list requests */
> +     uint64_t                 pc_nlfail;     /* # of fails getting a list */
> +     uint64_t                 pc_nlput;      /* # of list releases */
> 
>       int                      pc_nout;
> };
> @@ -133,7 +136,9 @@ void      *pool_cache_get(struct pool *);
> void   pool_cache_put(struct pool *, void *);
> void   pool_cache_destroy(struct pool *);
> #endif
> -void  pool_cache_info(struct pool *, struct kinfo_pool *);
> +void  pool_cache_pool_info(struct pool *, struct kinfo_pool *);
> +int   pool_cache_info(struct pool *, void *, size_t *);
> +int   pool_cache_cpus_info(struct pool *, void *, size_t *);
> 
> #ifdef POOL_DEBUG
> int   pool_debug = 1;
> @@ -1379,6 +1384,8 @@ sysctl_dopool(int *name, u_int namelen, 
> 
>       case KERN_POOL_NAME:
>       case KERN_POOL_POOL:
> +     case KERN_POOL_CACHE:
> +     case KERN_POOL_CACHE_CPUS:
>               break;
>       default:
>               return (EOPNOTSUPP);
> @@ -1423,10 +1430,18 @@ sysctl_dopool(int *name, u_int namelen, 
>               pi.pr_nidle = pp->pr_nidle;
>               mtx_leave(&pp->pr_mtx);
> 
> -             pool_cache_info(pp, &pi);
> +             pool_cache_pool_info(pp, &pi);
> 
>               rv = sysctl_rdstruct(oldp, oldlenp, NULL, &pi, sizeof(pi));
>               break;
> +
> +     case KERN_POOL_CACHE:
> +             rv = pool_cache_info(pp, oldp, oldlenp);
> +             break;
> +
> +     case KERN_POOL_CACHE_CPUS:
> +             rv = pool_cache_cpus_info(pp, oldp, oldlenp);
> +             break;
>       }
> 
> done:
> @@ -1608,7 +1623,7 @@ pool_cache_init(struct pool *pp)
>                   IPL_NONE, PR_WAITOK, "plcache", NULL);
>       }
> 
> -        /* must be able to use the pool items as cache list items */
> +     /* must be able to use the pool items as cache list entries */
>       KASSERT(pp->pr_size >= sizeof(struct pool_cache_item));
> 
>       cm = cpumem_get(&pool_caches);
> @@ -1625,9 +1640,12 @@ pool_cache_init(struct pool *pp)
>               pc->pc_nactv = 0;
>               pc->pc_prev = NULL;
> 
> -             pc->pc_gets = 0;
> -             pc->pc_puts = 0;
> -             pc->pc_fails = 0;
> +             pc->pc_nget = 0;
> +             pc->pc_nfail = 0;
> +             pc->pc_nput = 0;
> +             pc->pc_nlget = 0;
> +             pc->pc_nlfail = 0;
> +             pc->pc_nlput = 0;
>               pc->pc_nout = 0;
>       }
> 
> @@ -1694,7 +1712,10 @@ pool_cache_list_alloc(struct pool *pp, s
>               pp->pr_cache_nlist--;
> 
>               pool_cache_item_magic(pp, pl);
> -     }
> +
> +             pc->pc_nlget++;
> +     } else
> +             pc->pc_nlfail++;
> 
>       /* fold this cpus nout into the global while we have the lock */
>       pp->pr_cache_nout += pc->pc_nout;
> @@ -1712,6 +1733,8 @@ pool_cache_list_free(struct pool *pp, st
>       TAILQ_INSERT_TAIL(&pp->pr_cache_lists, ci, ci_nextl);
>       pp->pr_cache_nlist++;
> 
> +     pc->pc_nlput++;
> +
>       /* fold this cpus nout into the global while we have the lock */
>       pp->pr_cache_nout += pc->pc_nout;
>       pc->pc_nout = 0;
> @@ -1753,7 +1776,7 @@ pool_cache_get(struct pool *pp)
>               ci = pc->pc_prev;
>               pc->pc_prev = NULL;
>       } else if ((ci = pool_cache_list_alloc(pp, pc)) == NULL) {
> -             pc->pc_fails++;
> +             pc->pc_nfail++;
>               goto done;
>       }
> 
> @@ -1778,7 +1801,7 @@ pool_cache_get(struct pool *pp)
> 
>       pc->pc_actv = ci->ci_next;
>       pc->pc_nactv = POOL_CACHE_ITEM_NITEMS(ci) - 1;
> -     pc->pc_gets++;
> +     pc->pc_nget++;
>       pc->pc_nout++;
> 
> done:
> @@ -1825,7 +1848,7 @@ pool_cache_put(struct pool *pp, void *v)
>       pc->pc_actv = ci;
>       pc->pc_nactv = nitems;
> 
> -     pc->pc_puts++;
> +     pc->pc_nput++;
>       pc->pc_nout--;
> 
>       pool_cache_leave(pp, pc, s);
> @@ -1874,7 +1897,7 @@ pool_cache_destroy(struct pool *pp)
> }
> 
> void
> -pool_cache_info(struct pool *pp, struct kinfo_pool *pi)
> +pool_cache_pool_info(struct pool *pp, struct kinfo_pool *pi)
> {
>       struct pool_cache *pc;
>       struct cpumem_iter i;
> @@ -1892,8 +1915,8 @@ pool_cache_info(struct pool *pp, struct 
>                       while ((gen = pc->pc_gen) & 1)
>                               yield();
> 
> -                     nget = pc->pc_gets;
> -                     nput = pc->pc_puts;
> +                     nget = pc->pc_nget;
> +                     nput = pc->pc_nput;
>               } while (gen != pc->pc_gen);
> 
>               pi->pr_nget += nget;
> @@ -1908,6 +1931,80 @@ pool_cache_info(struct pool *pp, struct 
>       pi->pr_nout += pp->pr_cache_nout;
>       mtx_leave(&pp->pr_cache_mtx);
> }
> +
> +int
> +pool_cache_info(struct pool *pp, void *oldp, size_t *oldlenp)
> +{
> +     struct kinfo_pool_cache kpc;
> +
> +     if (pp->pr_cache == NULL)
> +             return (EOPNOTSUPP);
> +
> +     memset(&kpc, 0, sizeof(kpc)); /* don't leak padding */
> +
> +     mtx_enter(&pp->pr_cache_mtx);
> +     kpc.pr_ngc = 0; /* notyet */
> +     kpc.pr_len = pp->pr_cache_items;
> +     kpc.pr_nlist = pp->pr_cache_nlist;
> +     mtx_leave(&pp->pr_cache_mtx);
> +
> +     return (sysctl_rdstruct(oldp, oldlenp, NULL, &kpc, sizeof(kpc)));
> +}
> +
> +int
> +pool_cache_cpus_info(struct pool *pp, void *oldp, size_t *oldlenp)
> +{
> +     struct pool_cache *pc;
> +     struct kinfo_pool_cache_cpu *kpcc, *info;
> +     unsigned int cpu = 0;
> +     struct cpumem_iter i;
> +     int error = 0;
> +     size_t len;
> +
> +     if (pp->pr_cache == NULL)
> +             return (EOPNOTSUPP);
> +     if (*oldlenp % sizeof(*kpcc))
> +             return (EINVAL);
> +
> +     kpcc = mallocarray(ncpusfound, sizeof(*kpcc), M_TEMP,
> +         M_WAITOK|M_CANFAIL|M_ZERO);
> +     if (kpcc == NULL)
> +             return (EIO);
> +
> +     len = ncpusfound * sizeof(*kpcc);
> +
> +     CPUMEM_FOREACH(pc, &i, pp->pr_cache) {
> +             uint64_t gen;
> +
> +             if (cpu >= ncpusfound) {
> +                     error = EIO;
> +                     goto err;
> +             }
> +
> +             info = &kpcc[cpu];
> +             info->pr_cpu = cpu;
> +
> +             do {
> +                     while ((gen = pc->pc_gen) & 1)
> +                             yield();
> +
> +                     info->pr_nget = pc->pc_nget;
> +                     info->pr_nfail = pc->pc_nfail;
> +                     info->pr_nput = pc->pc_nput;
> +                     info->pr_nlget = pc->pc_nlget;
> +                     info->pr_nlfail = pc->pc_nlfail;
> +                     info->pr_nlput = pc->pc_nlput;
> +             } while (gen != pc->pc_gen);
> +
> +             cpu++;
> +     }
> +
> +     error = sysctl_rdstruct(oldp, oldlenp, NULL, kpcc, len);
> +err:
> +     free(kpcc, M_TEMP, len);
> +
> +     return (error);
> +}
> #else /* MULTIPROCESSOR */
> void
> pool_cache_init(struct pool *pp)
> @@ -1916,8 +2013,20 @@ pool_cache_init(struct pool *pp)
> }
> 
> void
> -pool_cache_info(struct pool *pp, struct kinfo_pool *pi)
> +pool_cache_pool_info(struct pool *pp, struct kinfo_pool *pi)
> {
>       /* nop */
> +}
> +
> +int
> +pool_cache_info(struct pool *pp, void *oldp, size_t *oldlenp)
> +{
> +     return (EOPNOTSUPP);
> +}
> +
> +int
> +pool_cache_cpus_info(struct pool *pp, void *oldp, size_t *oldlenp)
> +{
> +     return (EOPNOTSUPP);
> }
> #endif /* MULTIPROCESSOR */
> Index: sys/sys/pool.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/pool.h,v
> retrieving revision 1.69
> diff -u -p -r1.69 pool.h
> --- sys/sys/pool.h    7 Feb 2017 05:39:17 -0000       1.69
> +++ sys/sys/pool.h    14 Jun 2017 03:13:47 -0000
> @@ -43,6 +43,8 @@
> #define KERN_POOL_NPOOLS      1
> #define KERN_POOL_NAME                2
> #define KERN_POOL_POOL                3
> +#define KERN_POOL_CACHE              4       /* global pool cache info */
> +#define KERN_POOL_CACHE_CPUS 5       /* all cpus cache info */
> 
> struct kinfo_pool {
>       unsigned int    pr_size;        /* size of a pool item */
> @@ -66,6 +68,30 @@ struct kinfo_pool {
>       unsigned long   pr_nidle;       /* # of idle pages */
> };
> 
> +struct kinfo_pool_cache {
> +     uint64_t        pr_ngc;         /* # of times a list has been gc'ed */
> +     unsigned int    pr_len;         /* current target for list len */
> +     unsigned int    pr_nlist;       /* # of lists in the pool */
> +};
> +
> +/*
> + * KERN_POOL_CACHE_CPUS access to an array, not a single struct. ie, it
> + * provides struct kinfo_pool_cache_cpu kppc[ncpusfound].
> + */
> +struct kinfo_pool_cache_cpu {
> +     unsigned int    pr_cpu;         /* which cpu is this a cache on */
> +
> +     /* counters for times items were hanled by the cache */
> +     uint64_t        pr_nget;        /* # of requests */
> +     uint64_t        pr_nfail;       /* # of unsuccessful requests */
> +     uint64_t        pr_nput;        /* # of releases */
> +
> +     /* counters for times the cache interacted with the pool */
> +     uint64_t        pr_nlget;       /* # of list requests */
> +     uint64_t        pr_nlfail;      /* # of unsuccessful list requests */
> +     uint64_t        pr_nlput;       /* # of list releases */
> +};
> +
> #if defined(_KERNEL) || defined(_LIBKVM)
> 
> #include <sys/queue.h>
> @@ -159,8 +185,8 @@ struct pool {
>       struct mutex    pr_cache_mtx;
>       struct pool_cache_lists
>                       pr_cache_lists;
> -     u_int           pr_cache_nlist;
> -     u_int           pr_cache_items;
> +     u_int           pr_cache_nlist; /* # of lists */
> +     u_int           pr_cache_items; /* target list length */
>       u_int           pr_cache_contention;
>       int             pr_cache_nout;
> 
> Index: usr.bin/systat/pool.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/systat/pool.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 pool.c
> --- usr.bin/systat/pool.c     12 Mar 2016 12:45:27 -0000      1.11
> +++ usr.bin/systat/pool.c     14 Jun 2017 03:13:48 -0000
> @@ -26,6 +26,19 @@
> 
> #include "systat.h"
> 
> +#ifndef nitems
> +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
> +#endif
> +
> +static int sysctl_rdint(const int *, unsigned int);
> +static int hw_ncpusfound(void);
> +
> +static int pool_get_npools(void);
> +static int pool_get_name(int, char *, size_t);
> +static int pool_get_cache(int, struct kinfo_pool_cache *);
> +static int pool_get_cache_cpus(int, struct kinfo_pool_cache_cpu *,
> +    unsigned int);
> +
> void print_pool(void);
> int  read_pool(void);
> void  sort_pool(void);
> @@ -44,11 +57,25 @@ struct pool_info {
>       struct kinfo_pool pool;
> };
> 
> +/*
> + * the kernel gives an array of ncpusfound * kinfo_pool_cache structs, but
> + * it's idea of how big that struct is may differ from here. we fetch both
> + * ncpusfound and the size it thinks kinfo_pool_cache is from sysctl, and
> + * then allocate the memory for this here.
> + */
> +struct pool_cache_info {
> +     char name[32];
> +     struct kinfo_pool_cache cache;
> +     struct kinfo_pool_cache_cpu *cache_cpus;
> +};
> 
> int print_all = 0;
> int num_pools = 0;
> struct pool_info *pools = NULL;
> +int num_pool_caches = 0;
> +struct pool_cache_info *pool_caches = NULL;
> 
> +int ncpusfound = 0;
> 
> field_def fields_pool[] = {
>       {"NAME", 12, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
> @@ -65,7 +92,6 @@ field_def fields_pool[] = {
>       {"IDLE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}
> };
> 
> -
> #define FLD_POOL_NAME FIELD_ADDR(fields_pool,0)
> #define FLD_POOL_SIZE FIELD_ADDR(fields_pool,1)
> #define FLD_POOL_REQS FIELD_ADDR(fields_pool,2)
> @@ -100,11 +126,80 @@ struct view_manager pool_mgr = {
>       print_pool, pool_keyboard_callback, pool_order_list, pool_order_list
> };
> 
> -field_view views_pool[] = {
> -     {view_pool_0, "pool", '5', &pool_mgr},
> +field_view pool_view = {
> +     view_pool_0,
> +     "pool",
> +     '5',
> +     &pool_mgr
> +};
> +
> +void pool_cache_print(void);
> +int  pool_cache_read(void);
> +void pool_cache_sort(void);
> +void pool_cache_show(const struct pool_cache_info *);
> +int  pool_cache_kbd_cb(int);
> +
> +field_def pool_cache_fields[] = {
> +     {"NAME", 12, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
> +     {"LEN", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"NL", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"NGC", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"CPU",  4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"REQ", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"REL", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"LREQ", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +     {"LREL", 8, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
> +};
> +
> +#define FLD_POOL_CACHE_NAME  FIELD_ADDR(pool_cache_fields, 0)
> +#define FLD_POOL_CACHE_LEN   FIELD_ADDR(pool_cache_fields, 1)
> +#define FLD_POOL_CACHE_NL    FIELD_ADDR(pool_cache_fields, 2)
> +#define FLD_POOL_CACHE_NGC   FIELD_ADDR(pool_cache_fields, 3)
> +#define FLD_POOL_CACHE_CPU   FIELD_ADDR(pool_cache_fields, 4)
> +#define FLD_POOL_CACHE_GET   FIELD_ADDR(pool_cache_fields, 5)
> +#define FLD_POOL_CACHE_PUT   FIELD_ADDR(pool_cache_fields, 6)
> +#define FLD_POOL_CACHE_LGET  FIELD_ADDR(pool_cache_fields, 7)
> +#define FLD_POOL_CACHE_LPUT  FIELD_ADDR(pool_cache_fields, 8)
> +
> +field_def *view_pool_cache_0[] = {
> +     FLD_POOL_CACHE_NAME,
> +     FLD_POOL_CACHE_LEN,
> +     FLD_POOL_CACHE_NL,
> +     FLD_POOL_CACHE_NGC,
> +     FLD_POOL_CACHE_CPU,
> +     FLD_POOL_CACHE_GET,
> +     FLD_POOL_CACHE_PUT,
> +     FLD_POOL_CACHE_LGET,
> +     FLD_POOL_CACHE_LPUT,
> +     NULL,
> +};
> +
> +order_type pool_cache_order_list[] = {
> +     {"name", "name", 'N', sort_name_callback},
> +     {"requests", "requests", 'G', sort_req_callback},
> +     {"releases", "releases", 'P', sort_req_callback},
>       {NULL, NULL, 0, NULL}
> };
> 
> +/* Define view managers */
> +struct view_manager pool_cache_mgr = {
> +     "PoolCache",
> +     select_pool,
> +     pool_cache_read,
> +     pool_cache_sort,
> +     print_header,
> +     pool_cache_print,
> +     pool_keyboard_callback,
> +     pool_cache_order_list,
> +     pool_cache_order_list
> +};
> +
> +field_view pool_cache_view = {
> +     view_pool_cache_0,
> +     "pcaches",
> +     '5',
> +     &pool_cache_mgr
> +};
> 
> int
> sort_name_callback(const void *s1, const void *s2)
> @@ -200,30 +295,31 @@ select_pool(void)
> int
> read_pool(void)
> {
> -     int mib[4], np, i;
> +     int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_POOL, 0 };
> +     struct pool_info *p;
> +     int np, i;
>       size_t size;
> 
> -     mib[0] = CTL_KERN;
> -     mib[1] = KERN_POOL;
> -     mib[2] = KERN_POOL_NPOOLS;
> -     size = sizeof(np);
> -
> -     if (sysctl(mib, 3, &np, &size, NULL, 0) < 0) {
> +     np = pool_get_npools();
> +     if (np == -1) {
>               error("sysctl(npools): %s", strerror(errno));
>               return (-1);
>       }
> 
> -     if (np <= 0) {
> +     if (np == 0) {
> +             free(pools);
> +             pools = NULL;
>               num_pools = 0;
>               return (0);
>       }
> 
>       if (np > num_pools || pools == NULL) {
> -             struct pool_info *p = reallocarray(pools, np, sizeof(*pools));
> +             p = reallocarray(pools, np, sizeof(*pools));
>               if (p == NULL) {
>                       error("realloc: %s", strerror(errno));
>                       return (-1);
>               }
> +             /* commit */
>               pools = p;
>               num_pools = np;
>       }
> @@ -231,26 +327,19 @@ read_pool(void)
>       num_disp = num_pools;
> 
>       for (i = 0; i < num_pools; i++) {
> -             mib[0] = CTL_KERN;
> -             mib[1] = KERN_POOL;
> -             mib[2] = KERN_POOL_POOL;
> -             mib[3] = i + 1;
> +             p = &pools[i];
> +             np = i + 1;
> +
> +             mib[3] = np;
>               size = sizeof(pools[i].pool);
> -             if (sysctl(mib, 4, &pools[i].pool, &size, NULL, 0) < 0) {
> -                     memset(&pools[i], 0, sizeof(pools[i]));
> +             if (sysctl(mib, nitems(mib), &p->pool, &size, NULL, 0) < 0) {
> +                     p->name[0] = '\0';
>                       num_disp--;
>                       continue;
>               }
> -             mib[2] = KERN_POOL_NAME;
> -             size = sizeof(pools[i].name);
> -             if (sysctl(mib, 4, &pools[i].name, &size, NULL, 0) < 0) {
> -                     snprintf(pools[i].name, size, "#%d#", mib[3]);
> -             }
> -     }
> 
> -     if (i != num_pools) {
> -             memset(pools, 0, sizeof(*pools) * num_pools);
> -             return (-1);
> +             if (pool_get_name(np, p->name, sizeof(p->name)) < 0)
> +                     snprintf(p->name, sizeof(p->name), "#%d#", i + 1);
>       }
> 
>       return 0;
> @@ -289,11 +378,18 @@ initpool(void)
> {
>       field_view *v;
> 
> -     for (v = views_pool; v->name != NULL; v++)
> -             add_view(v);
> -
> +     add_view(&pool_view);
>       read_pool();
> 
> +     ncpusfound = hw_ncpusfound();
> +     if (ncpusfound == -1) {
> +             error("sysctl(ncpusfound): %s", strerror(errno));
> +             exit(1);
> +     }
> +
> +     add_view(&pool_cache_view);
> +     pool_cache_read();
> +
>       return(0);
> }
> 
> @@ -340,4 +436,194 @@ pool_keyboard_callback(int ch)
>       };
> 
>       return (1);
> +}
> +
> +int
> +pool_cache_read(void)
> +{
> +     struct pool_cache_info *pc;
> +     int np, i;
> +
> +     np = pool_get_npools();
> +     if (np == -1) {
> +             error("sysctl(npools): %s", strerror(errno));
> +             return (-1);
> +     }
> +
> +     if (np > num_pool_caches) {
> +             pc = reallocarray(pool_caches, np, sizeof(*pc));
> +             if (pc == NULL) {
> +                     error("realloc: %s", strerror(errno));
> +                     return (-1);
> +             }
> +             /* commit to using the new memory */
> +             pool_caches = pc;
> +
> +             for (i = num_pool_caches; i < np; i++) {
> +                     pc = &pool_caches[i];
> +                     pc->name[0] = '\0';
> +
> +                     pc->cache_cpus = reallocarray(NULL, ncpusfound,
> +                         sizeof(*pc->cache_cpus));
> +                     if (pc->cache_cpus == NULL) {
> +                             error("malloc cache cpus: %s", strerror(errno));
> +                             goto unalloc;
> +                     }
> +             }
> +
> +             /* commit to using the new cache_infos */
> +             num_pool_caches = np;
> +     }
> +
> +     for (i = 0; i < num_pool_caches; i++) {
> +             pc = &pool_caches[i];
> +             np = i + 1;
> +
> +             if (pool_get_cache(np, &pc->cache) < 0 ||
> +                 pool_get_cache_cpus(np, pc->cache_cpus, ncpusfound) < 0) {
> +                     pc->name[0] = '\0';
> +                     continue;
> +             }
> +
> +             if (pool_get_name(np, pc->name, sizeof(pc->name)) < 0)
> +                     snprintf(pc->name, sizeof(pc->name), "#%d#", i + 1);
> +     }
> +
> +     return 0;
> +
> +unalloc:
> +     while (i > num_pool_caches) {
> +             pc = &pool_caches[--i];
> +             free(pc->cache_cpus);
> +     }
> +}
> +
> +void
> +pool_cache_sort(void)
> +{
> +     /* XXX */
> +     order_type *ordering;
> +
> +     if (curr_mgr == NULL)
> +             return;
> +
> +     ordering = curr_mgr->order_curr;
> +
> +     if (ordering == NULL)
> +             return;
> +     if (ordering->func == NULL)
> +             return;
> +     if (pools == NULL)
> +             return;
> +     if (num_pools <= 0)
> +             return;
> +
> +     mergesort(pools, num_pools, sizeof(struct pool_info), ordering->func);
> +}
> +
> +void
> +pool_cache_print(void)
> +{
> +     struct pool_cache_info *pc;
> +     int i, n, count = 0;
> +
> +     if (pool_caches == NULL)
> +             return;
> +
> +     for (n = i = 0; i < num_pool_caches; i++) {
> +             pc = &pool_caches[i];
> +             if (pc->name[0] == '\0')
> +                     continue;
> +
> +             if (n++ < dispstart)
> +                     continue;
> +
> +             pool_cache_show(pc);
> +             count++;
> +             if (maxprint > 0 && count >= maxprint)
> +                     break;
> +     }
> +}
> +
> +void
> +pool_cache_show(const struct pool_cache_info *pc)
> +{
> +     const struct kinfo_pool_cache *kpc;
> +     const struct kinfo_pool_cache_cpu *kpcc;
> +     int cpu;
> +
> +     kpc = &pc->cache;
> +
> +     print_fld_str(FLD_POOL_CACHE_NAME, pc->name);
> +     print_fld_uint(FLD_POOL_CACHE_LEN, kpc->pr_len);
> +     print_fld_uint(FLD_POOL_CACHE_NL, kpc->pr_nlist);
> +     print_fld_uint(FLD_POOL_CACHE_NGC, kpc->pr_ngc);
> +
> +     for (cpu = 0; cpu < ncpusfound; cpu++) {
> +             kpcc = &pc->cache_cpus[cpu];
> +
> +             print_fld_uint(FLD_POOL_CACHE_CPU, kpcc->pr_cpu);
> +
> +             print_fld_size(FLD_POOL_CACHE_GET, kpcc->pr_nget);
> +             print_fld_size(FLD_POOL_CACHE_PUT, kpcc->pr_nput);
> +             print_fld_size(FLD_POOL_CACHE_LGET, kpcc->pr_nlget);
> +             print_fld_size(FLD_POOL_CACHE_LPUT, kpcc->pr_nlput);
> +             end_line();
> +     }
> +
> +}
> +
> +static int
> +pool_get_npools(void)
> +{
> +     int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_NPOOLS };
> +
> +     return (sysctl_rdint(mib, nitems(mib)));
> +}
> +
> +static int
> +pool_get_cache(int pool, struct kinfo_pool_cache *kpc)
> +{
> +     int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_CACHE, pool };
> +     size_t len = sizeof(*kpc);
> +
> +     return (sysctl(mib, nitems(mib), kpc, &len, NULL, 0));
> +}
> +
> +static int
> +pool_get_cache_cpus(int pool, struct kinfo_pool_cache_cpu *kpcc,
> +    unsigned int ncpus)
> +{
> +     int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_CACHE_CPUS, pool };
> +     size_t len = sizeof(*kpcc) * ncpus;
> +
> +     return (sysctl(mib, nitems(mib), kpcc, &len, NULL, 0));
> +}
> +
> +static int
> +pool_get_name(int pool, char *name, size_t len)
> +{
> +     int mib[] = { CTL_KERN, KERN_POOL, KERN_POOL_NAME, pool };
> +
> +     return (sysctl(mib, nitems(mib), name, &len, NULL, 0));
> +}
> +
> +static int
> +hw_ncpusfound(void)
> +{
> +     int mib[] = { CTL_HW, HW_NCPUFOUND };
> +
> +     return (sysctl_rdint(mib, nitems(mib)));
> +}
> +
> +static int
> +sysctl_rdint(const int *mib, unsigned int nmib)
> +{
> +     int i;
> +     size_t size = sizeof(i);
> +
> +     if (sysctl(mib, nmib, &i, &size, NULL, 0) == -1)
> +             return (-1);
> +
> +     return (i);
> }
> Index: usr.bin/systat/systat.1
> ===================================================================
> RCS file: /cvs/src/usr.bin/systat/systat.1,v
> retrieving revision 1.101
> diff -u -p -r1.101 systat.1
> --- usr.bin/systat/systat.1   12 Mar 2015 01:03:00 -0000      1.101
> +++ usr.bin/systat/systat.1   14 Jun 2017 03:13:48 -0000
> @@ -136,6 +136,7 @@ argument expects to be one of:
> .Ic queues ,
> .Ic pf ,
> .Ic pool ,
> +.Ic pcache ,
> .Ic malloc ,
> .Ic buckets ,
> .Ic nfsclient ,
> @@ -379,6 +380,10 @@ and
> By default only the statistics of active pools are displayed but pressing
> .Ic A
> changes the view to show all of them.
> +.It Ic pcache
> +Display kernel
> +.Xr pool 9
> +per CPU cache statistics.
> .It Ic queues
> Display statistics about the active queues,
> similar to the output of

Reply via email to