From 6aa36717c46156740add4b0cbfb5fb2350ddd6dd Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Tue, 21 Jul 2015 00:00:00 -0500 Subject: [PATCH] library: slab is redesigned to use 'stack' vs. 'chain' In addition to that text shown below the line which is common to several commit messages, this patch contains several minor changes with lessor impact upon the API: . A 'read' was added to function procps_slabnode_count (but only when necessary, i.e. info->nodes_used == 0). . The #include header files are ordered alphabetically now, with all those types separately grouped. ------------------------------------------------------ . The former 'chains' have now become 'stacks' without the 'next' pointer in each result struct. The pointers initially seemed to offer some flexibility with memory allocations and benefits for the library access logic. However, user access was always via displacement and a a statically allocated chain was cumbersome to define. . An enumerator ending in '_noop' will no longer serve as a fencepost delimiter. Rather, it has become a much more important and flexible user oriented tool. Adding one or more such 'items' in any items list passed into the library becomes the means of extending the 'stack' to also include user (not just library) data. Any such data is guaranteed to never be altered by the library. . Anticipating PID support, where many different types must be represented in a result structure, we'll adopt a common naming standard. And, while not every results structure currently needs to reflect disparate types a union will be employed so the same dot qualifier ('.') can be used consistently when accessing all such data. Signed-off-by: Jim Warner --- proc/libprocps.sym | 14 +- proc/slab.c | 443 ++++++++++++++++++++++++--------------------- proc/slab.h | 102 +++++------ slabtop.c | 103 +++++------ vmstat.c | 26 ++- 5 files changed, 357 insertions(+), 331 deletions(-) diff --git a/proc/libprocps.sym b/proc/libprocps.sym index 16d0bcbd..655e8eec 100644 --- a/proc/libprocps.sym +++ b/proc/libprocps.sym @@ -47,16 +47,16 @@ global: procps_slabinfo_ref; procps_slabinfo_unref; procps_slabs_get; - procps_slabs_getchain; + procps_slabs_getstack; procps_slabnode_count; procps_slabnode_getname; procps_slabnode_get; - procps_slabnode_getchain; - procps_slabnode_chain_fill; - procps_slabnode_chain_alloc; - procps_slabnode_chains_fill; - procps_slabnode_chains_sort; - procps_slabnode_chains_alloc; + procps_slabnode_getstack; + procps_slabnode_stack_fill; + procps_slabnode_stack_alloc; + procps_slabnode_stacks_fill; + procps_slabnode_stacks_sort; + procps_slabnode_stacks_alloc; procps_stat_new; procps_stat_read; procps_stat_read_jiffs; diff --git a/proc/slab.c b/proc/slab.c index aae81645..a400a469 100644 --- a/proc/slab.c +++ b/proc/slab.c @@ -23,16 +23,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include #include #include -#include -#include -#include #include +#include +#include +#include +#include +#include + +#include +#include #include #include "procps-private.h" @@ -41,32 +42,32 @@ #define SLABINFO_LINE_LEN 2048 #define SLAB_INFO_NAME_LEN 128 -struct slabinfo_node { - char name[SLAB_INFO_NAME_LEN]; /* name of this cache */ - unsigned long cache_size; /* size of entire cache */ - unsigned nr_objs; /* number of objects in this cache */ - unsigned nr_active_objs; /* number of active objects */ - unsigned obj_size; /* size of each object */ - unsigned objs_per_slab; /* number of objects per slab */ - unsigned pages_per_slab; /* number of pages per slab */ - unsigned nr_slabs; /* number of slabs in this cache */ - unsigned nr_active_slabs; /* number of active slabs */ - unsigned use; /* percent full: total / active */ -}; - struct slabinfo_stats { unsigned long total_size; /* size of all objects */ unsigned long active_size; /* size of all active objects */ - unsigned nr_objs; /* number of objects, among all caches */ - unsigned nr_active_objs; /* number of active objects, among all caches */ - unsigned nr_pages; /* number of pages consumed by all objects */ - unsigned nr_slabs; /* number of slabs, among all caches */ - unsigned nr_active_slabs; /* number of active slabs, among all caches */ - unsigned nr_caches; /* number of caches */ - unsigned nr_active_caches; /* number of active caches */ - unsigned avg_obj_size; /* average object size */ - unsigned min_obj_size; /* size of smallest object */ - unsigned max_obj_size; /* size of largest object */ + unsigned int nr_objs; /* number of objects, among all caches */ + unsigned int nr_active_objs; /* number of active objects, among all caches */ + unsigned int nr_pages; /* number of pages consumed by all objects */ + unsigned int nr_slabs; /* number of slabs, among all caches */ + unsigned int nr_active_slabs; /* number of active slabs, among all caches */ + unsigned int nr_caches; /* number of caches */ + unsigned int nr_active_caches; /* number of active caches */ + unsigned int avg_obj_size; /* average object size */ + unsigned int min_obj_size; /* size of smallest object */ + unsigned int max_obj_size; /* size of largest object */ +}; + +struct slabinfo_node { + char name[SLAB_INFO_NAME_LEN]; /* name of this cache */ + unsigned long cache_size; /* size of entire cache */ + unsigned int nr_objs; /* number of objects in this cache */ + unsigned int nr_active_objs; /* number of active objects */ + unsigned int obj_size; /* size of each object */ + unsigned int objs_per_slab; /* number of objects per slab */ + unsigned int pages_per_slab; /* number of pages per slab */ + unsigned int nr_slabs; /* number of slabs in this cache */ + unsigned int nr_active_slabs; /* number of active slabs */ + unsigned int use; /* percent full: total / active */ }; struct procps_slabinfo { @@ -76,21 +77,21 @@ struct procps_slabinfo { struct slabinfo_node *nodes; /* first slabnode of this list */ int nodes_alloc; /* nodes alloc()ed */ int nodes_used; /* nodes using alloced memory */ - struct chains_anchor *chained; + struct stacks_anchor *stacked; }; -struct chain_vectors { - struct chains_anchor *owner; - struct slabnode_chain **heads; +struct stack_vectors { + struct stacks_anchor *owner; + struct slabnode_stack **heads; }; -struct chains_anchor { +struct stacks_anchor { int depth; int inuse; int header_size; - struct chain_vectors *vectors; - struct chains_anchor *self; - struct chains_anchor *next; + struct stack_vectors *vectors; + struct stacks_anchor *self; + struct stacks_anchor *next; }; @@ -207,9 +208,9 @@ static int parse_slabinfo20 ( return retval; if (sscanf(buffer, - "%" STRINGIFY(SLAB_INFO_NAME_LEN) - "s %d %d %d %d %d : tunables %*d %*d %*d : \ - slabdata %d %d %*d", node->name, + "%" STRINGIFY(SLAB_INFO_NAME_LEN) "s" \ + "%u %u %u %u %u : tunables %*u %*u %*u : slabdata %u %u %*u", + node->name, &node->nr_active_objs, &node->nr_objs, &node->obj_size, &node->objs_per_slab, &node->pages_per_slab, &node->nr_active_slabs, @@ -231,7 +232,7 @@ static int parse_slabinfo20 ( * page_size; if (node->nr_objs) { - node->use = 100 * node->nr_active_objs / node->nr_objs; + node->use = (unsigned int)100 * node->nr_active_objs / node->nr_objs; stats->nr_active_caches++; } else node->use = 0; @@ -283,7 +284,7 @@ PROCPS_EXPORT int procps_slabinfo_new ( /* procps_slabinfo_read(): * * Read the data out of /proc/slabinfo putting the information - * into the supplie info container + * into the supplied info container * * Returns: 0 on success, negative on error */ @@ -329,6 +330,7 @@ PROCPS_EXPORT int procps_slabinfo_ref ( { if (info == NULL) return -EINVAL; + info->refcount++; return info->refcount; } @@ -338,18 +340,19 @@ PROCPS_EXPORT int procps_slabinfo_unref ( { if (info == NULL || *info == NULL) return -EINVAL; + (*info)->refcount--; if ((*info)->refcount == 0) { if ((*info)->slabinfo_fp) { fclose((*info)->slabinfo_fp); (*info)->slabinfo_fp = NULL; } - if ((*info)->chained) { + if ((*info)->stacked) { do { - struct chains_anchor *p = (*info)->chained; - (*info)->chained = (*info)->chained->next; + struct stacks_anchor *p = (*info)->stacked; + (*info)->stacked = (*info)->stacked->next; free(p); - } while((*info)->chained); + } while((*info)->stacked); } free((*info)->nodes); free(*info); @@ -363,6 +366,9 @@ PROCPS_EXPORT unsigned long procps_slabs_get ( struct procps_slabinfo *info, enum slabs_item item) { + /* note: most of the results we might return are actually just + unsigned int, but we must accommodate the largest potential + result and so return an unsigned long */ if (info == NULL) return -EINVAL; @@ -391,68 +397,66 @@ PROCPS_EXPORT unsigned long procps_slabs_get ( return info->stats.total_size; case PROCPS_SLABS_SIZE_ACTIVE: return info->stats.active_size; - case PROCPS_SLABS_noop: - return 0; default: - return -EINVAL; + return 0; } - return 0; } -PROCPS_EXPORT int procps_slabs_getchain ( +PROCPS_EXPORT int procps_slabs_getstack ( struct procps_slabinfo *info, - struct slabs_result *these) + struct slab_result *these) { if (info == NULL || these == NULL) return -EINVAL; - do { + for (;;) { switch (these->item) { case PROCPS_SLABS_OBJS: - these->result = info->stats.nr_objs; + these->result.u_int = info->stats.nr_objs; break; case PROCPS_SLABS_AOBJS: - these->result = info->stats.nr_active_objs; + these->result.u_int = info->stats.nr_active_objs; break; case PROCPS_SLABS_PAGES: - these->result = info->stats.nr_pages; + these->result.u_int = info->stats.nr_pages; break; case PROCPS_SLABS_SLABS: - these->result = info->stats.nr_slabs; + these->result.u_int = info->stats.nr_slabs; break; case PROCPS_SLABS_ASLABS: - these->result = info->stats.nr_active_slabs; + these->result.u_int = info->stats.nr_active_slabs; break; case PROCPS_SLABS_CACHES: - these->result = info->stats.nr_caches; + these->result.u_int = info->stats.nr_caches; break; case PROCPS_SLABS_ACACHES: - these->result = info->stats.nr_active_caches; + these->result.u_int = info->stats.nr_active_caches; break; case PROCPS_SLABS_SIZE_AVG: - these->result = info->stats.avg_obj_size; + these->result.u_int = info->stats.avg_obj_size; break; case PROCPS_SLABS_SIZE_MIN: - these->result = info->stats.min_obj_size; + these->result.u_int = info->stats.min_obj_size; break; case PROCPS_SLABS_SIZE_MAX: - these->result = info->stats.max_obj_size; + these->result.u_int = info->stats.max_obj_size; break; case PROCPS_SLABS_SIZE_TOTAL: - these->result = info->stats.total_size; + these->result.ul_int = info->stats.total_size; break; case PROCPS_SLABS_SIZE_ACTIVE: - these->result = info->stats.active_size; + these->result.ul_int = info->stats.active_size; break; case PROCPS_SLABS_noop: - these->result = 0; + // don't disturb potential user data in the result struct break; + case PROCPS_SLABS_stack_end: + return 0; default: return -EINVAL; } - these = these->next; - } while(these); - return 0; + ++these; + } } /* @@ -481,6 +485,9 @@ PROCPS_EXPORT unsigned long procps_slabnode_get ( enum slabnode_item item, int nodeid) { + /* note: most of the results we might return are actually just + unsigned int, but we must accommodate the largest potential + result and so return an unsigned long */ if (info == NULL) return -EINVAL; @@ -503,18 +510,14 @@ PROCPS_EXPORT unsigned long procps_slabnode_get ( return info->nodes[nodeid].nr_active_slabs; case PROCPS_SLABNODE_USE: return info->nodes[nodeid].use; - case PROCPS_SLABNODE_noop: - return 0; - // PROCPS_SLABNODE_NAME also invalid in this context default: - return -EINVAL; + return 0; } - return 0; } -PROCPS_EXPORT int procps_slabnode_getchain ( +PROCPS_EXPORT int procps_slabnode_getstack ( struct procps_slabinfo *info, - struct slabnode_result *these, + struct slab_result *these, int nodeid) { if (info == NULL || these == NULL) @@ -522,64 +525,65 @@ PROCPS_EXPORT int procps_slabnode_getchain ( if (nodeid > info->nodes_used) return -EINVAL; - do { + for (;;) { switch (these->item) { case PROCPS_SLABNODE_SIZE: - these->result.num = info->nodes[nodeid].cache_size; + these->result.ul_int = info->nodes[nodeid].cache_size; break; case PROCPS_SLABNODE_OBJS: - these->result.num = info->nodes[nodeid].nr_objs; + these->result.u_int = info->nodes[nodeid].nr_objs; break; case PROCPS_SLABNODE_AOBJS: - these->result.num = info->nodes[nodeid].nr_active_objs; + these->result.u_int = info->nodes[nodeid].nr_active_objs; break; case PROCPS_SLABNODE_OBJ_SIZE: - these->result.num = info->nodes[nodeid].obj_size; + these->result.u_int = info->nodes[nodeid].obj_size; break; case PROCPS_SLABNODE_OBJS_PER_SLAB: - these->result.num = info->nodes[nodeid].objs_per_slab; + these->result.u_int = info->nodes[nodeid].objs_per_slab; break; case PROCPS_SLABNODE_PAGES_PER_SLAB: - these->result.num = info->nodes[nodeid].pages_per_slab; + these->result.u_int = info->nodes[nodeid].pages_per_slab; break; case PROCPS_SLABNODE_SLABS: - these->result.num = info->nodes[nodeid].nr_slabs; + these->result.u_int = info->nodes[nodeid].nr_slabs; break; case PROCPS_SLABNODE_ASLABS: - these->result.num = info->nodes[nodeid].nr_active_slabs; + these->result.u_int = info->nodes[nodeid].nr_active_slabs; break; case PROCPS_SLABNODE_USE: - these->result.num = info->nodes[nodeid].use; + these->result.u_int = info->nodes[nodeid].use; break; case PROCPS_SLABNODE_NAME: these->result.str = info->nodes[nodeid].name; break; case PROCPS_SLABNODE_noop: - these->result.num = 0; + // don't disturb potential user data in the result struct break; + case PROCPS_SLABNODE_stack_end: + return 0; default: return -EINVAL; } - these = these->next; - } while(these); - return 0; + ++these; + } } -PROCPS_EXPORT int procps_slabnode_chain_fill ( +PROCPS_EXPORT int procps_slabnode_stack_fill ( struct procps_slabinfo *info, - struct slabnode_chain *chain, + struct slabnode_stack *stack, int nodeid) { int rc; - if (info == NULL || chain == NULL || chain->head == NULL) + if (info == NULL || stack == NULL || stack->head == NULL) return -EINVAL; if ((rc = procps_slabinfo_read(info)) < 0) return rc; - return procps_slabnode_getchain(info, chain->head, nodeid); + return procps_slabnode_getstack(info, stack->head, nodeid); } /* @@ -590,245 +594,276 @@ PROCPS_EXPORT int procps_slabnode_chain_fill ( * Returns: number of nodes in @info or <0 on error */ PROCPS_EXPORT int procps_slabnode_count ( - const struct procps_slabinfo *info) + struct procps_slabinfo *info) { + int rc = 0; + if (!info) return -EINVAL; + if (!info->nodes_used) + rc = procps_slabinfo_read(info); + if (rc < 0) + return rc; return info->nodes_used; } -PROCPS_EXPORT int procps_slabnode_chains_fill ( +PROCPS_EXPORT int procps_slabnode_stacks_fill ( struct procps_slabinfo *info, - struct slabnode_chain **chains, - int maxchains) + struct slabnode_stack **stacks, + int maxstacks) { int i, rc; - if (info == NULL || *chains == NULL) + if (info == NULL || *stacks == NULL) return -EINVAL; - if (maxchains < 1) + if (maxstacks < 1) return -EINVAL; if ((rc = procps_slabinfo_read(info)) < 0) return rc; - if (maxchains > info->chained->depth) - maxchains = info->chained->depth; - if (maxchains > info->nodes_used) - maxchains = info->nodes_used; + if (maxstacks > info->stacked->depth) + maxstacks = info->stacked->depth; + if (maxstacks > info->nodes_used) + maxstacks = info->nodes_used; - for (i = 0; i < maxchains; i++) { - if (chains[i] == NULL) + for (i = 0; i < maxstacks; i++) { + if (stacks[i] == NULL) break; - if ((rc = procps_slabnode_getchain(info, chains[i]->head, i) < 0)) + if ((rc = procps_slabnode_getstack(info, stacks[i]->head, i) < 0)) return rc; } - info->chained->inuse = i; - return info->chained->inuse; + info->stacked->inuse = i; + return info->stacked->inuse; } -static void chains_validate (struct slabnode_chain **v, const char *who) +static void stacks_validate (struct slabnode_stack **v, const char *who) { #if 0 #include - int i, x, n = 0; - struct chain_vectors *p = (struct chain_vectors *)v - 1; + int i, t, x, n = 0; + struct stack_vectors *p = (struct stack_vectors *)v - 1; fprintf(stderr, "%s: called by '%s'\n", __func__, who); fprintf(stderr, "%s: owned by %p (whose self = %p)\n", __func__, p->owner, p->owner->self); for (x = 0; v[x]; x++) { - struct slabnode_chain *h = v[x]; - struct slabnode_result *r = h->head; + struct slabnode_stack *h = v[x]; + struct slab_result *r = h->head; fprintf(stderr, "%s: vector[%02d] = %p", __func__, x, h); - i = 0; - do { - i++; - r = r->next; - } while (r); - fprintf(stderr, ", chain %d found %d elements\n", n, i); + for (i = 0; r->item < PROCPS_SLABNODE_stack_end; i++, r++) + ; + t = i + 1; + fprintf(stderr, ", stack %d found %d elements\n", n, i); ++n; } - fprintf(stderr, "%s: found %d chain(s)\n", __func__, x); + fprintf(stderr, "%s: found %d stack(s), each %d bytes (including eos)\n", __func__, x, (int)sizeof(struct slab_result) * t); + fprintf(stderr, "%s: found %d stack(s)\n", __func__, x); fprintf(stderr, "%s: this header size = %2d\n", __func__, (int)p->owner->header_size); - fprintf(stderr, "%s: sizeof(struct slabnode_chain) = %2d\n", __func__, (int)sizeof(struct slabnode_chain)); - fprintf(stderr, "%s: sizeof(struct slabnode_result) = %2d\n", __func__, (int)sizeof(struct slabnode_result)); + fprintf(stderr, "%s: sizeof(struct slabnode_stack) = %2d\n", __func__, (int)sizeof(struct slabnode_stack)); + fprintf(stderr, "%s: sizeof(struct slab_result) = %2d\n", __func__, (int)sizeof(struct slab_result)); fputc('\n', stderr); return; #endif } -static struct slabnode_result *chain_make ( - struct slabnode_result *p, +static struct slab_result *stack_make ( + struct slab_result *p, int maxitems, enum slabnode_item *items) { - struct slabnode_result *p_sav = p; + struct slab_result *p_sav = p; int i; for (i = 0; i < maxitems; i++) { - if (i > PROCPS_SLABNODE_noop) - p->item = PROCPS_SLABNODE_noop; - else - p->item = items[i]; - p->result.num = 0; - p->next = p + 1; + p->item = items[i]; + // note: we rely on calloc to initialize actual result ++p; } - (--p)->next = NULL; return p_sav; } -/* - * procps_slabnode_chains_alloc(): - * - * Allocate and initialize one or more chains each of which is anchored in an - * associated meminfo_chain structure (which may include extra user space). - * - * All such chains will will have their result structures properly primed with - * 'items' and 'next' pointers, while the result itself will be zeroed. - * - * Returns an array of pointers representing the 'heads' of each new chain. - */ -PROCPS_EXPORT struct slabnode_chain **procps_slabnode_chains_alloc ( - struct procps_slabinfo *info, - int maxchains, - int chain_extra, +static int stack_items_valid ( int maxitems, enum slabnode_item *items) { - struct chains_anchor *p_blob; - struct chain_vectors *p_vect; - struct slabnode_chain *p_head; + int i; + + for (i = 0; i < maxitems; i++) { + if (items[i] < PROCPS_SLABNODE_SIZE) + return 0; + if (items[i] > PROCPS_SLABNODE_stack_end) + return 0; + } + if (items[maxitems -1] != PROCPS_SLABNODE_stack_end) + return 0; + return 1; +} + +/* + * procps_slabnode_stacks_alloc(): + * + * Allocate and initialize one or more stacks each of which is anchored in an + * associated slabnode_stack structure (which may include extra user space). + * + * All such stacks will will have their result structures properly primed with + * 'items', while the result itself will be zeroed. + * + * Returns an array of pointers representing the 'heads' of each new stack. + */ +PROCPS_EXPORT struct slabnode_stack **procps_slabnode_stacks_alloc ( + struct procps_slabinfo *info, + int maxstacks, + int stack_extra, + int maxitems, + enum slabnode_item *items) +{ + struct stacks_anchor *p_blob; + struct stack_vectors *p_vect; + struct slabnode_stack *p_head; size_t vect_size, head_size, list_size, blob_size; void *v_head, *v_list; int i; if (info == NULL || items == NULL) return NULL; - if (maxchains < 1 || maxitems < 1) + if (maxstacks < 1 || maxitems < 1) + return NULL; + if (!stack_items_valid(maxitems, items)) return NULL; - vect_size = sizeof(struct chain_vectors); // address vector struct - vect_size += sizeof(void *) * maxchains; // plus vectors themselves + vect_size = sizeof(struct stack_vectors); // address vector struct + vect_size += sizeof(void *) * maxstacks; // plus vectors themselves vect_size += sizeof(void *); // plus NULL delimiter - head_size = sizeof(struct slabnode_chain) + chain_extra; // a head struct + user stuff - list_size = sizeof(struct slabnode_result) * maxitems; // a results chain - blob_size = sizeof(struct chains_anchor); // the anchor itself + head_size = sizeof(struct slabnode_stack) + stack_extra; // a head struct + user stuff + list_size = sizeof(struct slab_result) * maxitems; // a results stack + blob_size = sizeof(struct stacks_anchor); // the anchor itself blob_size += vect_size; // all vectors + delims - blob_size += head_size * maxchains; // all head structs + user stuff - blob_size += list_size * maxchains; // all results chains + blob_size += head_size * maxstacks; // all head structs + user stuff + blob_size += list_size * maxstacks; // all results stacks /* note: all memory is allocated in a single blob, facilitating a later free(). as a minimum, it's important that the result structures themselves always be - contiguous for any given chain (just as they are when defined statically). */ + contiguous for any given stack (just as they are when defined statically). */ if (NULL == (p_blob = calloc(1, blob_size))) return NULL; - p_blob->next = info->chained; - info->chained = p_blob; + p_blob->next = info->stacked; + info->stacked = p_blob; p_blob->self = p_blob; p_blob->header_size = head_size; - p_blob->vectors = (void *)p_blob + sizeof(struct chains_anchor); + p_blob->vectors = (void *)p_blob + sizeof(struct stacks_anchor); p_vect = p_blob->vectors; p_vect->owner = p_blob->self; - p_vect->heads = (void *)p_vect + sizeof(struct chain_vectors); + p_vect->heads = (void *)p_vect + sizeof(struct stack_vectors); v_head = (void *)p_vect + vect_size; - v_list = v_head + (head_size * maxchains); + v_list = v_head + (head_size * maxstacks); - for (i = 0; i < maxchains; i++) { - p_head = (struct slabnode_chain *)v_head; - p_head->head = chain_make((struct slabnode_result *)v_list, maxitems, items); + for (i = 0; i < maxstacks; i++) { + p_head = (struct slabnode_stack *)v_head; + p_head->head = stack_make((struct slab_result *)v_list, maxitems, items); p_blob->vectors->heads[i] = p_head; v_list += list_size; v_head += head_size; } - p_blob->depth = maxchains; - chains_validate(p_blob->vectors->heads, __func__); + p_blob->depth = maxstacks; + stacks_validate(p_blob->vectors->heads, __func__); return p_blob->vectors->heads; } /* - * procps_slabnode_chain_alloc(): + * procps_slabnode_stack_alloc(): * - * Allocate and initialize a single result chain under a simplified interface. + * Allocate and initialize a single result stack under a simplified interface. * - * Such a chain will will have its result structures properly primed with - * 'items' and 'next' pointers, while the result itself will be zeroed. + * Such a stack will will have its result structures properly primed with + * 'items', while the result itself will be zeroed. * */ -PROCPS_EXPORT struct slabnode_chain *procps_slabnode_chain_alloc ( +PROCPS_EXPORT struct slabnode_stack *procps_slabnode_stack_alloc ( struct procps_slabinfo *info, int maxitems, enum slabnode_item *items) { - struct slabnode_chain **v; + struct slabnode_stack **v; if (info == NULL || items == NULL || maxitems < 1) return NULL; - v = procps_slabnode_chains_alloc(info, 1, 0, maxitems, items); + v = procps_slabnode_stacks_alloc(info, 1, 0, maxitems, items); if (!v) return NULL; - chains_validate(v, __func__); + stacks_validate(v, __func__); return v[0]; } -static int chains_sort ( - const struct slabnode_chain **A, - const struct slabnode_chain **B, +static int stacks_sort ( + const struct slabnode_stack **A, + const struct slabnode_stack **B, enum slabnode_item *offset) { - const struct slabnode_result *a = (*A)->head + *offset; - const struct slabnode_result *b = (*B)->head + *offset; + const struct slab_result *a = (*A)->head + *offset; + const struct slab_result *b = (*B)->head + *offset; // note: everything will be sorted high-to-low - if (a->item == PROCPS_SLABNODE_NAME) - return strcoll(a->result.str, b->result.str); - if ( a->result.num > b->result.num ) return -1; - if ( a->result.num < b->result.num ) return +1; + switch (a->item) { + case PROCPS_SLABNODE_noop: + case PROCPS_SLABNODE_stack_end: + break; + case PROCPS_SLABNODE_NAME: + return strcoll(a->result.str, b->result.str); + case PROCPS_SLABNODE_SIZE: + if ( a->result.ul_int > b->result.ul_int ) return -1; + if ( a->result.ul_int < b->result.ul_int ) return +1; + break; + default: + if ( a->result.u_int > b->result.u_int ) return -1; + if ( a->result.u_int < b->result.u_int ) return +1; + break; + } return 0; } /* - * procps_slabnode_chains_sort(): + * procps_slabnode_stacks_sort(): * - * Sort chains anchored as 'heads' in the passed slabnode_chain pointers + * Sort stacks anchored as 'heads' in the passed slabnode_stack pointers * array based on the designated sort enumerator. * * Returns those same addresses sorted. * - * Note: all of the chains must be homogeneous (of equal length and content). + * Note: all of the stacks must be homogeneous (of equal length and content). */ -PROCPS_EXPORT struct slabnode_chain **procps_slabnode_chains_sort ( +PROCPS_EXPORT struct slabnode_stack **procps_slabnode_stacks_sort ( struct procps_slabinfo *info, - struct slabnode_chain **chains, - int numchained, + struct slabnode_stack **stacks, + int numstacked, enum slabnode_item sort) { #define QSORT_r int (*)(const void *, const void *, void *) - struct slabnode_result *p = chains[0]->head; + struct slab_result *p = stacks[0]->head; int offset = 0;; - if (info == NULL || chains == NULL) + if (info == NULL || stacks == NULL) return NULL; if (sort < 0 || sort > PROCPS_SLABNODE_noop) return NULL; - if (numchained > info->chained->depth) + if (numstacked > info->stacked->depth) return NULL; - if (numchained < 2) - return chains; + if (numstacked < 2) + return stacks; - if (numchained > info->chained->inuse) - numchained = info->chained->inuse; + if (numstacked > info->stacked->inuse) + numstacked = info->stacked->inuse; for (;;) { if (p->item == sort) break; ++offset; - if (!(p = p->next)) + if (p->item == PROCPS_SLABNODE_stack_end) return NULL; + ++p; } - qsort_r(chains, numchained, sizeof(void *), (QSORT_r)chains_sort, &offset); - return chains; + qsort_r(stacks, numstacked, sizeof(void *), (QSORT_r)stacks_sort, &offset); + return stacks; #undef QSORT_r } diff --git a/proc/slab.h b/proc/slab.h index 8e2b6a0d..a41460c0 100644 --- a/proc/slab.h +++ b/proc/slab.h @@ -25,54 +25,50 @@ __BEGIN_DECLS enum slabs_item { - PROCPS_SLABS_OBJS, - PROCPS_SLABS_AOBJS, - PROCPS_SLABS_PAGES, - PROCPS_SLABS_SLABS, - PROCPS_SLABS_ASLABS, - PROCPS_SLABS_CACHES, - PROCPS_SLABS_ACACHES, - PROCPS_SLABS_SIZE_AVG, - PROCPS_SLABS_SIZE_MIN, - PROCPS_SLABS_SIZE_MAX, - PROCPS_SLABS_SIZE_TOTAL, - PROCPS_SLABS_SIZE_ACTIVE, - PROCPS_SLABS_noop + PROCPS_SLABS_OBJS, // u_int + PROCPS_SLABS_AOBJS, // u_int + PROCPS_SLABS_PAGES, // u_int + PROCPS_SLABS_SLABS, // u_int + PROCPS_SLABS_ASLABS, // u_int + PROCPS_SLABS_CACHES, // u_int + PROCPS_SLABS_ACACHES, // u_int + PROCPS_SLABS_SIZE_AVG, // u_int + PROCPS_SLABS_SIZE_MIN, // u_int + PROCPS_SLABS_SIZE_MAX, // u_int + PROCPS_SLABS_SIZE_TOTAL, // ul_int + PROCPS_SLABS_SIZE_ACTIVE, // ul_int + PROCPS_SLABS_noop, // n/a + PROCPS_SLABS_stack_end // n/a }; enum slabnode_item { - PROCPS_SLABNODE_SIZE, - PROCPS_SLABNODE_OBJS, - PROCPS_SLABNODE_AOBJS, - PROCPS_SLABNODE_OBJ_SIZE, - PROCPS_SLABNODE_OBJS_PER_SLAB, - PROCPS_SLABNODE_PAGES_PER_SLAB, - PROCPS_SLABNODE_SLABS, - PROCPS_SLABNODE_ASLABS, - PROCPS_SLABNODE_USE, - PROCPS_SLABNODE_NAME, - PROCPS_SLABNODE_noop + PROCPS_SLABNODE_SIZE, // ul_int + PROCPS_SLABNODE_OBJS, // u_int + PROCPS_SLABNODE_AOBJS, // u_int + PROCPS_SLABNODE_OBJ_SIZE, // u_int + PROCPS_SLABNODE_OBJS_PER_SLAB, // u_int + PROCPS_SLABNODE_PAGES_PER_SLAB, // u_int + PROCPS_SLABNODE_SLABS, // u_int + PROCPS_SLABNODE_ASLABS, // u_int + PROCPS_SLABNODE_USE, // u_int + PROCPS_SLABNODE_NAME, // str + PROCPS_SLABNODE_noop, // n/a + PROCPS_SLABNODE_stack_end // n/a }; struct procps_slabinfo; -struct slabs_result { - enum slabs_item item; - unsigned long result; - struct slabs_result *next; +struct slabnode_stack { + struct slab_result *head; }; -struct slabnode_chain { - struct slabnode_result *head; -}; - -struct slabnode_result { - enum slabnode_item item; +struct slab_result { + int item; union { - unsigned long num; + unsigned int u_int; + unsigned long ul_int; char *str; } result; - struct slabnode_result *next; }; int procps_slabinfo_new (struct procps_slabinfo **info); @@ -85,11 +81,11 @@ unsigned long procps_slabs_get ( struct procps_slabinfo *info, enum slabs_item item); -int procps_slabs_getchain ( +int procps_slabs_getstack ( struct procps_slabinfo *info, - struct slabs_result *these); + struct slab_result *these); -int procps_slabnode_count (const struct procps_slabinfo *info); +int procps_slabnode_count (struct procps_slabinfo *info); const char *procps_slabnode_getname ( struct procps_slabinfo *info, @@ -100,37 +96,37 @@ unsigned long procps_slabnode_get ( enum slabnode_item item, int nodeid); -int procps_slabnode_getchain ( +int procps_slabnode_getstack ( struct procps_slabinfo *info, - struct slabnode_result *these, + struct slab_result *these, int nodeid); -int procps_slabnode_chain_fill ( +int procps_slabnode_stack_fill ( struct procps_slabinfo *info, - struct slabnode_chain *chain, + struct slabnode_stack *stack, int nodeid); -int procps_slabnode_chains_fill ( +int procps_slabnode_stacks_fill ( struct procps_slabinfo *info, - struct slabnode_chain **chains, - int maxchains); + struct slabnode_stack **stacks, + int maxstacks); -struct slabnode_chain *procps_slabnode_chain_alloc ( +struct slabnode_stack *procps_slabnode_stack_alloc ( struct procps_slabinfo *info, int maxitems, enum slabnode_item *items); -struct slabnode_chain **procps_slabnode_chains_alloc ( +struct slabnode_stack **procps_slabnode_stacks_alloc ( struct procps_slabinfo *info, - int maxchains, - int chain_extra, + int maxstacks, + int stack_extra, int maxitems, enum slabnode_item *items); -struct slabnode_chain **procps_slabnode_chains_sort ( +struct slabnode_stack **procps_slabnode_stacks_sort ( struct procps_slabinfo *info, - struct slabnode_chain **chains, - int numchained, + struct slabnode_stack **stacks, + int numstacked, enum slabnode_item sort); __END_DECLS diff --git a/slabtop.c b/slabtop.c index f197d447..36d7c536 100644 --- a/slabtop.c +++ b/slabtop.c @@ -60,10 +60,10 @@ enum slabnode_item Node_items[] = { PROCPS_SLABNODE_OBJS, PROCPS_SLABNODE_AOBJS, PROCPS_SLABNODE_USE, PROCPS_SLABNODE_OBJ_SIZE, PROCPS_SLABNODE_SLABS, PROCPS_SLABNODE_OBJS_PER_SLAB, PROCPS_SLABNODE_SIZE, PROCPS_SLABNODE_NAME, - /* last 2 are sortable but are not displayable, + /* next 2 are sortable but are not displayable, thus they need not be represented in the Relative_enums */ - PROCPS_SLABNODE_PAGES_PER_SLAB, - PROCPS_SLABNODE_ASLABS }; + PROCPS_SLABNODE_PAGES_PER_SLAB, PROCPS_SLABNODE_ASLABS, + PROCPS_SLABNODE_stack_end }; enum Relative_enums { my_OBJS, my_AOBJS, my_USE, my_OSIZE, @@ -195,61 +195,60 @@ static void parse_opts (int argc, char **argv) static void print_summary (void) { - #define STAT_VAL(e) (int)stats[e].result enum slabs_enums { stat_AOBJS, stat_OBJS, stat_ASLABS, stat_SLABS, stat_ACACHES, stat_CACHES, stat_ACTIVE, stat_TOTAL, - stat_MIN, stat_AVG, stat_MAX, + stat_MIN, stat_AVG, stat_MAX }; - static struct slabs_result stats[] = { - { PROCPS_SLABS_AOBJS, 0, &stats[1] }, - { PROCPS_SLABS_OBJS, 0, &stats[2] }, - { PROCPS_SLABS_ASLABS, 0, &stats[3] }, - { PROCPS_SLABS_SLABS, 0, &stats[4] }, - { PROCPS_SLABS_ACACHES, 0, &stats[5] }, - { PROCPS_SLABS_CACHES, 0, &stats[6] }, - { PROCPS_SLABS_SIZE_ACTIVE, 0, &stats[7] }, - { PROCPS_SLABS_SIZE_TOTAL, 0, &stats[8] }, - { PROCPS_SLABS_SIZE_MIN, 0, &stats[9] }, - { PROCPS_SLABS_SIZE_AVG, 0, &stats[10] }, - { PROCPS_SLABS_SIZE_MAX, 0, NULL }, + static struct slab_result stats[] = { + { PROCPS_SLABS_AOBJS, 0 }, + { PROCPS_SLABS_OBJS, 0 }, + { PROCPS_SLABS_ASLABS, 0 }, + { PROCPS_SLABS_SLABS, 0 }, + { PROCPS_SLABS_ACACHES, 0 }, + { PROCPS_SLABS_CACHES, 0 }, + { PROCPS_SLABS_SIZE_ACTIVE, 0 }, + { PROCPS_SLABS_SIZE_TOTAL, 0 }, + { PROCPS_SLABS_SIZE_MIN, 0 }, + { PROCPS_SLABS_SIZE_AVG, 0 }, + { PROCPS_SLABS_SIZE_MAX, 0 }, + { PROCPS_SLABS_stack_end, 0 } }; - if (procps_slabs_getchain(Slab_info, stats) < 0) \ + if (procps_slabs_getstack(Slab_info, stats) < 0) \ xerrx(EXIT_FAILURE, _("Error getting slab summary results")); - PRINT_line(" %-35s: %d / %d (%.1f%%)\n" + PRINT_line(" %-35s: %u / %u (%.1f%%)\n" , /* Translation Hint: Next five strings must not * exceed a length of 35 characters. */ /* xgettext:no-c-format */ _("Active / Total Objects (% used)") - , STAT_VAL(stat_AOBJS) - , STAT_VAL(stat_OBJS) - , 100.0 * STAT_VAL(stat_AOBJS) / STAT_VAL(stat_OBJS)); - PRINT_line(" %-35s: %d / %d (%.1f%%)\n" + , stats[stat_AOBJS].result.u_int + , stats[stat_OBJS ].result.u_int + , 100.0 * stats[stat_AOBJS].result.u_int / stats[stat_OBJS].result.u_int); + PRINT_line(" %-35s: %u / %u (%.1f%%)\n" , /* xgettext:no-c-format */ _("Active / Total Slabs (% used)") - , STAT_VAL(stat_ASLABS) - , STAT_VAL(stat_SLABS) - , 100.0 * STAT_VAL(stat_ASLABS) / STAT_VAL(stat_SLABS)); - PRINT_line(" %-35s: %d / %d (%.1f%%)\n" + , stats[stat_ASLABS].result.u_int + , stats[stat_SLABS ].result.u_int + , 100.0 * stats[stat_ASLABS].result.u_int / stats[stat_SLABS].result.u_int); + PRINT_line(" %-35s: %u / %u (%.1f%%)\n" , /* xgettext:no-c-format */ _("Active / Total Caches (% used)") - , STAT_VAL(stat_ACACHES) - , STAT_VAL(stat_CACHES) - , 100.0 * STAT_VAL(stat_ACACHES) / STAT_VAL(stat_CACHES)); + , stats[stat_ACACHES].result.u_int + , stats[stat_CACHES ].result.u_int + , 100.0 * stats[stat_ACACHES].result.u_int / stats[stat_CACHES].result.u_int); PRINT_line(" %-35s: %.2fK / %.2fK (%.1f%%)\n" , /* xgettext:no-c-format */ _("Active / Total Size (% used)") - , STAT_VAL(stat_ACTIVE) / 1024.0 - , STAT_VAL(stat_TOTAL) / 1024.0 - , 100.0 * STAT_VAL(stat_ACTIVE) / STAT_VAL(stat_TOTAL)); + , stats[stat_ACTIVE].result.ul_int / 1024.0 + , stats[stat_TOTAL ].result.ul_int / 1024.0 + , 100.0 * stats[stat_ACTIVE].result.ul_int / stats[stat_TOTAL].result.ul_int); PRINT_line(" %-35s: %.2fK / %.2fK / %.2fK\n\n" , _("Minimum / Average / Maximum Object") - , STAT_VAL(stat_MIN) / 1024.0 - , STAT_VAL(stat_AVG) / 1024.0 - , STAT_VAL(stat_MAX) / 1024.0); - #undef STAT_VAL + , stats[stat_MIN].result.u_int / 1024.0 + , stats[stat_AVG].result.u_int / 1024.0 + , stats[stat_MAX].result.u_int / 1024.0); } static void print_headings (void) @@ -259,21 +258,19 @@ static void print_headings (void) PRINT_line("%-78s\n", _(" OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME")); } -static void print_details (struct slabnode_chain *chain) +static void print_details (struct slabnode_stack *stack) { - #define my_NUM(c,e) (unsigned)c->head[e].result.num - #define my_STR(c,e) c->head[e].result.str - - PRINT_line("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n" - , my_NUM(chain, my_OBJS), my_NUM(chain, my_AOBJS) - , my_NUM(chain, my_USE), my_NUM(chain, my_OSIZE) / 1024.0 - , my_NUM(chain, my_SLABS), my_NUM(chain, my_OPS) - , my_NUM(chain, my_SIZE) / 1024 - , my_STR(chain, my_NAME)); + PRINT_line("%6u %6u %3u%% %7.2fK %6u %8u %9luK %-23s\n" + , stack->head[my_OBJS ].result.u_int + , stack->head[my_AOBJS].result.u_int + , stack->head[my_USE ].result.u_int + , stack->head[my_OSIZE].result.u_int / 1024.0 + , stack->head[my_SLABS].result.u_int + , stack->head[my_OPS ].result.u_int + , stack->head[my_SIZE ].result.ul_int / 1024 + , stack->head[my_NAME ].result.str); return; - #undef my_NUM - #undef my_STR } @@ -281,7 +278,7 @@ int main(int argc, char *argv[]) { int is_tty, nr_slabs, rc = EXIT_SUCCESS; unsigned short old_rows; - struct slabnode_chain **v; + struct slabnode_stack **v; #ifdef HAVE_PROGRAM_INVOCATION_NAME program_invocation_name = program_invocation_short_name; @@ -296,7 +293,7 @@ int main(int argc, char *argv[]) if (procps_slabinfo_new(&Slab_info) < 0) xerrx(EXIT_FAILURE, _("Unable to create slabinfo structure")); - if (!(v = procps_slabnode_chains_alloc(Slab_info, CHAINS_ALLOC, 0, MAX_ITEMS, Node_items))) + if (!(v = procps_slabnode_stacks_alloc(Slab_info, CHAINS_ALLOC, 0, MAX_ITEMS, Node_items))) xerrx(EXIT_FAILURE, _("Unable to allocate slabinfo nodes")); if (!Run_once) { @@ -317,12 +314,12 @@ int main(int argc, char *argv[]) int i; // this next guy also performs the procps_slabnode_read() call - if ((nr_slabs = procps_slabnode_chains_fill(Slab_info, v, CHAINS_ALLOC)) < 0) { + if ((nr_slabs = procps_slabnode_stacks_fill(Slab_info, v, CHAINS_ALLOC)) < 0) { xwarn(_("Unable to get slabinfo node data")); rc = EXIT_FAILURE; break; } - if (!(v = procps_slabnode_chains_sort(Slab_info, v, nr_slabs, Sort_item))) { + if (!(v = procps_slabnode_stacks_sort(Slab_info, v, nr_slabs, Sort_item))) { xwarn(_("Unable to sort slab nodes")); rc = EXIT_FAILURE; break; diff --git a/vmstat.c b/vmstat.c index 57b27617..919076e6 100644 --- a/vmstat.c +++ b/vmstat.c @@ -612,22 +612,19 @@ static void slabformat (void) { #define CHAINS_ALLOC 150 #define MAX_ITEMS (int)(sizeof(node_items) / sizeof(node_items[0])) - #define SLAB_NUM(c,e) (unsigned)c->head[e].result.num - #define SLAB_STR(c,e) c->head[e].result.str struct procps_slabinfo *slab_info; - struct slabnode_chain **v; + struct slabnode_stack **v, *p; int i, j, nr_slabs; - const char format[] = "%-24.24s %6u %6u %6u %6u\n"; enum slabnode_item node_items[] = { PROCPS_SLABNODE_AOBJS, PROCPS_SLABNODE_OBJS, PROCPS_SLABNODE_OBJ_SIZE, PROCPS_SLABNODE_OBJS_PER_SLAB, - PROCPS_SLABNODE_NAME }; + PROCPS_SLABNODE_NAME, PROCPS_SLABNODE_stack_end }; enum rel_enums { slab_AOBJS, slab_OBJS, slab_OSIZE, slab_OPS, slab_NAME }; if (procps_slabinfo_new(&slab_info) < 0) xerrx(EXIT_FAILURE, _("Unable to create slabinfo structure")); - if (!(v = procps_slabnode_chains_alloc(slab_info, CHAINS_ALLOC, 0, MAX_ITEMS, node_items))) + if (!(v = procps_slabnode_stacks_alloc(slab_info, CHAINS_ALLOC, 0, MAX_ITEMS, node_items))) xerrx(EXIT_FAILURE, _("Unable to allocate slabinfo nodes")); if (!moreheaders) @@ -635,18 +632,21 @@ static void slabformat (void) for (i = 0; infinite_updates || i < num_updates; i++) { // this next guy also performs the procps_slabnode_read() call - if ((nr_slabs = procps_slabnode_chains_fill(slab_info, v, CHAINS_ALLOC)) < 0) + if ((nr_slabs = procps_slabnode_stacks_fill(slab_info, v, CHAINS_ALLOC)) < 0) xerrx(EXIT_FAILURE, _("Unable to get slabinfo node data, requires root permission")); - if (!(v = procps_slabnode_chains_sort(slab_info, v, nr_slabs, PROCPS_SLABNODE_NAME))) + if (!(v = procps_slabnode_stacks_sort(slab_info, v, nr_slabs, PROCPS_SLABNODE_NAME))) xerrx(EXIT_FAILURE, _("Unable to sort slab nodes")); for (j = 0; j < nr_slabs; j++) { + p = v[j]; if (moreheaders && ((j % height) == 0)) slabheader(); - printf(format, - SLAB_STR(v[j], slab_NAME), - SLAB_NUM(v[j], slab_AOBJS), SLAB_NUM(v[j], slab_OBJS), - SLAB_NUM(v[j], slab_OSIZE), SLAB_NUM(v[j], slab_OPS)); + printf("%-24.24s %6u %6u %6u %6u\n", + p->head[slab_NAME ].result.str, + p->head[slab_AOBJS].result.u_int, + p->head[slab_OBJS ].result.u_int, + p->head[slab_OSIZE].result.u_int, + p->head[slab_OPS ].result.u_int); } if (infinite_updates || i+1 < num_updates) sleep(sleep_time); @@ -654,8 +654,6 @@ static void slabformat (void) procps_slabinfo_unref(&slab_info); #undef CHAINS_ALLOC #undef MAX_ITEMS - #undef SLAB_NUM - #undef SLAB_STR } static void disksum_format(void)