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 @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_pool.c,v 1.209 2017/06/13 11:41:11 dlg Exp $ */ +/* $OpenBSD: subr_pool.c,v 1.208 2017/04/20 14:13:00 visa Exp $ */ /* $NetBSD: subr_pool.c,v 1.61 2001/09/26 07:14:56 chs Exp $ */ /*- @@ -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 @@ -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