> 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