From e13c98351f1a6eebc83bbb96fbdb32b5aa48a3d0 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Thu, 15 Jun 2017 03:47:08 +0000 Subject: add a rough start to a pcache view, to show pool cpu cache info. ok mikeb@ millert@ --- usr.bin/systat/pool.c | 348 +++++++++++++++++++++++++++++++++++++++++++----- usr.bin/systat/systat.1 | 9 +- 2 files changed, 324 insertions(+), 33 deletions(-) (limited to 'usr.bin') diff --git a/usr.bin/systat/pool.c b/usr.bin/systat/pool.c index e43a66edc74..0f09237c68b 100644 --- a/usr.bin/systat/pool.c +++ b/usr.bin/systat/pool.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pool.c,v 1.11 2016/03/12 12:45:27 sthen Exp $ */ +/* $OpenBSD: pool.c,v 1.12 2017/06/15 03:47:07 dlg Exp $ */ /* * Copyright (c) 2008 Can Erkin Acar * @@ -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); } @@ -341,3 +437,193 @@ 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); +} diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1 index c7f8d78bdf8..fd223d3b4de 100644 --- a/usr.bin/systat/systat.1 +++ b/usr.bin/systat/systat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: systat.1,v 1.101 2015/03/12 01:03:00 claudio Exp $ +.\" $OpenBSD: systat.1,v 1.102 2017/06/15 03:47:07 dlg Exp $ .\" $NetBSD: systat.1,v 1.6 1996/05/10 23:16:39 thorpej Exp $ .\" .\" Copyright (c) 1985, 1990, 1993 @@ -30,7 +30,7 @@ .\" .\" @(#)systat.1 8.2 (Berkeley) 12/30/93 .\" -.Dd $Mdocdate: March 12 2015 $ +.Dd $Mdocdate: June 15 2017 $ .Dt SYSTAT 1 .Os .Sh NAME @@ -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 -- cgit v1.2.3