escape_str;
escape_strlist;
escaped_copy;
- free_slabinfo;
freeproc;
get_ns_id;
get_ns_name;
get_pid_digits;
- get_slabinfo;
- getslabinfo;
look_up_our_self;
lookup_wchan;
openproc;
- put_slabinfo;
readeither;
readproc;
readproctab2;
procps_meminfo_unref;
procps_meminfo_get;
procps_meminfo_get_chain;
+ procps_slabinfo_new;
+ procps_slabinfo_read;
+ procps_slabinfo_ref;
+ procps_slabinfo_unref;
+ procps_slabinfo_stat_get;
+ procps_slabinfo_stat_getchain;
+ procps_slabinfo_sort;
+ procps_slabinfo_node_count;
+ procps_slabinfo_node_get;
+ procps_slabinfo_node_getchain;
+ procps_slabinfo_node_getname;
procps_stat_new;
procps_stat_read;
procps_stat_read_jiffs;
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include "slab.h"
-#include "procps.h"
-#include "alloc.h"
-
-#define SLABINFO_LINE_LEN 2048
-#define SLABINFO_VER_LEN 100
-#define SLABINFO_FILE "/proc/slabinfo"
-
-static struct slab_info *free_index;
+#include "procps-private.h"
+
+#define SLABINFO_LINE_LEN 2048
+#define SLABINFO_VER_LEN 100
+#define SLAB_INFO_NAME_LEN 128
+#define SLABINFO_FILE "/proc/slabinfo"
+#define INITIAL_NODES 30
+
+struct procps_slabnode {
+ 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 */
+};
+
+struct procps_slabinfo {
+ int refcount;
+ FILE *slabinfo_fp;
+ struct slabinfo_stats stats;
+ struct procps_slabnode *nodes; /* first slabnode of this list */
+ int nodes_alloc; /* nodes alloc()ed */
+ int nodes_used; /* nodes using alloced memory */
+};
/*
- * get_slabnode - allocate slab_info structures using a free list
- *
- * In the fast path, we simply return a node off the free list. In the slow
- * list, we malloc() a new node. The free list is never automatically reaped,
- * both for simplicity and because the number of slab caches is fairly
- * constant.
+ * Zero out the slabnode data, keeping the memory allocated.
*/
-static struct slab_info *get_slabnode(void)
+static void slabnodes_clear(
+ struct procps_slabinfo *info)
{
- struct slab_info *node;
-
- if (free_index) {
- node = free_index;
- free_index = free_index->next;
- } else {
- node = xmalloc(sizeof(struct slab_info));
- }
-
- return node;
+ if (info == NULL || info->nodes == NULL || info->nodes_alloc < 1)
+ return;
+ memset(info->nodes, 0, sizeof(struct procps_slabnode)*info->nodes_alloc);
+ info->nodes_used = 0;
}
-/*
- * slab_badname_detect - return true if current slab was declared with
- * whitespaces for instance
- * FIXME :Other cases ?
+/* Alloc up more slabnode memory, if required
*/
-
-static int slab_badname_detect(const char *restrict buffer)
+static int slabnodes_alloc(
+ struct procps_slabinfo *info)
{
- int numberarea=0;
- while (*buffer){
- if((*buffer)==' ')
- numberarea=1;
- if(isalpha(*buffer)&&numberarea)
- return 1;
- buffer++;
- }
- return 0;
+ struct procps_slabnode *new_nodes;
+ int new_count;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ if (info->nodes_used < info->nodes_alloc)
+ return 0;
+ /* Increment the allocated number of slabs */
+ new_count = info->nodes_alloc * 5/4+30;
+
+ if ((new_nodes = realloc(info->nodes,
+ sizeof(struct procps_slabnode)*new_count)) == NULL)
+ return -ENOMEM;
+ info->nodes = new_nodes;
+ info->nodes_alloc = new_count;
+ return 0;
}
/*
- * put_slabinfo - return all allocated nodes to the free list
+ * get_slabnode - allocate slab_info structures using a free list
+ *
+ * In the fast path, we simply return a node off the free list. In the slow
+ * list, we malloc() a new node. The free list is never automatically reaped,
+ * both for simplicity and because the number of slab caches is fairly
+ * constant.
*/
-void put_slabinfo(struct slab_info *head)
+static int get_slabnode(
+ struct procps_slabinfo *info,
+ struct procps_slabnode **node)
{
- free_index = head;
-}
+ int retval;
-/*
- * free_slabinfo - deallocate the memory associated with each node in the
- * slab_info linked list
- */
-void free_slabinfo(struct slab_info *list)
-{
- while (list) {
- struct slab_info *temp = list->next;
- free(list);
- list = temp;
- }
+ if (!info)
+ return -EINVAL;
+
+ if (info->nodes_used == info->nodes_alloc) {
+ if ((retval = slabnodes_alloc(info)) < 0)
+ return retval;
+ }
+ *node = &(info->nodes[info->nodes_used++]);
+ return 0;
}
-/* parse_slabinfo20 - actual parse routine for slabinfo 2.x (2.6 kernels)
+/* parse_slabinfo20:
+ *
+ * sactual parse routine for slabinfo 2.x (2.6 kernels)
* Note: difference between 2.0 and 2.1 is in the ": globalstat" part where version 2.1
* has extra column <nodeallocs>. We don't use ": globalstat" part in both versions.
*
* : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit> \
* : cpustat <allochit> <allocmiss> <freehit> <freemiss>
*/
-static int parse_slabinfo20(struct slab_info **list, struct slab_stat *stats,
- FILE *f)
+static int parse_slabinfo20(
+ struct procps_slabinfo *info)
{
- struct slab_info *curr = NULL, *prev = NULL;
- char buffer[SLABINFO_LINE_LEN];
- int entries = 0;
- int page_size = getpagesize();
-
- stats->min_obj_size = INT_MAX;
- stats->max_obj_size = 0;
-
- while (fgets(buffer, SLABINFO_LINE_LEN, f)) {
- int assigned;
-
- if (buffer[0] == '#')
- continue;
-
- curr = get_slabnode();
- if (!curr)
- break;
-
- if (entries++ == 0)
- *list = curr;
- else
- if (prev)
- prev->next = curr;
-
- assigned = sscanf(buffer, "%" STRINGIFY(SLAB_INFO_NAME_LEN)
- "s %d %d %d %d %d : tunables %*d %*d %*d : \
- slabdata %d %d %*d", curr->name,
- &curr->nr_active_objs, &curr->nr_objs,
- &curr->obj_size, &curr->objs_per_slab,
- &curr->pages_per_slab, &curr->nr_active_slabs,
- &curr->nr_slabs);
-
- if (assigned < 8) {
- fprintf(stderr, "unrecognizable data in slabinfo!\n");
- curr = NULL;
- break;
- }
-
- if (curr->obj_size < stats->min_obj_size)
- stats->min_obj_size = curr->obj_size;
- if (curr->obj_size > stats->max_obj_size)
- stats->max_obj_size = curr->obj_size;
-
- curr->cache_size = (unsigned long)curr->nr_slabs * curr->pages_per_slab * page_size;
-
- if (curr->nr_objs) {
- curr->use = 100 * curr->nr_active_objs / curr->nr_objs;
- stats->nr_active_caches++;
- } else
- curr->use = 0;
-
- stats->nr_objs += curr->nr_objs;
- stats->nr_active_objs += curr->nr_active_objs;
- stats->total_size += (unsigned long)curr->nr_objs * curr->obj_size;
- stats->active_size += (unsigned long)curr->nr_active_objs * curr->obj_size;
- stats->nr_pages += curr->nr_slabs * curr->pages_per_slab;
- stats->nr_slabs += curr->nr_slabs;
- stats->nr_active_slabs += curr->nr_active_slabs;
-
- prev = curr;
- }
-
- if (!curr) {
- fprintf(stderr, "\rerror reading slabinfo!\n");
- return 1;
- }
-
- curr->next = NULL;
- stats->nr_caches = entries;
- if (stats->nr_objs)
- stats->avg_obj_size = stats->total_size / stats->nr_objs;
-
- return 0;
+ struct procps_slabnode *node;
+ char buffer[SLABINFO_LINE_LEN];
+ int retval;
+ int page_size = getpagesize();
+ struct slabinfo_stats *stats = &(info->stats);
+
+ stats->min_obj_size = INT_MAX;
+ stats->max_obj_size = 0;
+
+ while (fgets(buffer, SLABINFO_LINE_LEN, info->slabinfo_fp )) {
+ if (buffer[0] == '#')
+ continue;
+
+ if ((retval = get_slabnode(info, &node)) < 0)
+ 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,
+ &node->nr_active_objs, &node->nr_objs,
+ &node->obj_size, &node->objs_per_slab,
+ &node->pages_per_slab, &node->nr_active_slabs,
+ &node->nr_slabs) < 8) {
+ if (errno != 0)
+ return -errno;
+ return -EINVAL;
+ }
+
+ if (node->obj_size < stats->min_obj_size)
+ stats->min_obj_size = node->obj_size;
+ if (node->obj_size > stats->max_obj_size)
+ stats->max_obj_size = node->obj_size;
+
+ node->cache_size = (unsigned long)node->nr_slabs * node->pages_per_slab
+ * page_size;
+
+ if (node->nr_objs) {
+ node->use = 100 * node->nr_active_objs / node->nr_objs;
+ stats->nr_active_caches++;
+ } else
+ node->use = 0;
+
+ stats->nr_objs += node->nr_objs;
+ stats->nr_active_objs += node->nr_active_objs;
+ stats->total_size += (unsigned long)node->nr_objs * node->obj_size;
+ stats->active_size += (unsigned long)node->nr_active_objs * node->obj_size;
+ stats->nr_pages += node->nr_slabs * node->pages_per_slab;
+ stats->nr_slabs += node->nr_slabs;
+ stats->nr_active_slabs += node->nr_active_slabs;
+ stats->nr_caches++;
+ }
+
+ if (stats->nr_objs)
+ stats->avg_obj_size = stats->total_size / stats->nr_objs;
+
+ return 0;
}
/*
* parse_slabinfo11 - actual parsing routine for slabinfo 1.1 (2.4 kernels)
*/
-static int parse_slabinfo11(struct slab_info **list, struct slab_stat *stats,
- FILE *f)
+static int parse_slabinfo11(
+ struct procps_slabinfo *info)
{
- struct slab_info *curr = NULL, *prev = NULL;
- char buffer[SLABINFO_LINE_LEN];
- int entries = 0;
- int page_size = getpagesize();
-
- stats->min_obj_size = INT_MAX;
- stats->max_obj_size = 0;
-
- while (fgets(buffer, SLABINFO_LINE_LEN, f)) {
- int assigned;
-
- curr = get_slabnode();
- if (!curr)
- break;
-
- if (entries++ == 0)
- *list = curr;
- else
- if (prev)
- prev->next = curr;
-
- assigned = sscanf(buffer, "%" STRINGIFY(SLAB_INFO_NAME_LEN)
- "s %d %d %d %d %d %d",
- curr->name, &curr->nr_active_objs,
- &curr->nr_objs, &curr->obj_size,
- &curr->nr_active_slabs, &curr->nr_slabs,
- &curr->pages_per_slab);
-
- if (assigned < 6) {
- fprintf(stderr, "unrecognizable data in your slabinfo version 1.1\n\r");
- if(slab_badname_detect(buffer))
- fprintf(stderr, "Found an error in cache name at line %s\n", buffer);
- curr = NULL;
- break;
- }
-
- if (curr->obj_size < stats->min_obj_size)
- stats->min_obj_size = curr->obj_size;
- if (curr->obj_size > stats->max_obj_size)
- stats->max_obj_size = curr->obj_size;
-
- curr->cache_size = (unsigned long)curr->nr_slabs * curr->pages_per_slab * page_size;
-
- if (curr->nr_objs) {
- curr->use = 100 * curr->nr_active_objs / curr->nr_objs;
- stats->nr_active_caches++;
- } else
- curr->use = 0;
-
- if (curr->obj_size)
- curr->objs_per_slab = curr->pages_per_slab *
- page_size / curr->obj_size;
-
- stats->nr_objs += curr->nr_objs;
- stats->nr_active_objs += curr->nr_active_objs;
- stats->total_size += (unsigned long)curr->nr_objs * curr->obj_size;
- stats->active_size += (unsigned long)curr->nr_active_objs * curr->obj_size;
- stats->nr_pages += curr->nr_slabs * curr->pages_per_slab;
- stats->nr_slabs += curr->nr_slabs;
- stats->nr_active_slabs += curr->nr_active_slabs;
-
- prev = curr;
- }
-
- if (!curr) {
- fprintf(stderr, "\rerror reading slabinfo!\n");
- return 1;
- }
-
- curr->next = NULL;
- stats->nr_caches = entries;
- if (stats->nr_objs)
- stats->avg_obj_size = stats->total_size / stats->nr_objs;
-
- return 0;
+ struct procps_slabnode *node;
+ char buffer[SLABINFO_LINE_LEN];
+ int retval;
+ int page_size = getpagesize();
+ struct slabinfo_stats *stats = &(info->stats);
+
+ stats->min_obj_size = INT_MAX;
+ stats->max_obj_size = 0;
+
+ while (fgets(buffer, SLABINFO_LINE_LEN, info->slabinfo_fp )) {
+ if (buffer[0] == '#')
+ continue;
+
+ if ((retval = get_slabnode(info, &node)) < 0)
+ return retval;
+
+ if (sscanf(buffer,
+ "%" STRINGIFY(SLAB_INFO_NAME_LEN)
+ "s %d %d %d %d %d %d",
+ node->name, &node->nr_active_objs,
+ &node->nr_objs, &node->obj_size,
+ &node->nr_active_slabs, &node->nr_slabs,
+ &node->pages_per_slab) < 6) {
+ if (errno != 0)
+ return -errno;
+ return -EINVAL;
+ }
+
+ if (node->obj_size < stats->min_obj_size)
+ stats->min_obj_size = node->obj_size;
+ if (node->obj_size > stats->max_obj_size)
+ stats->max_obj_size = node->obj_size;
+
+ node->cache_size = (unsigned long)node->nr_slabs *
+ node->pages_per_slab * page_size;
+
+ if (node->nr_objs) {
+ node->use = 100 * node->nr_active_objs / node->nr_objs;
+ stats->nr_active_caches++;
+ } else
+ node->use = 0;
+
+ if (node->obj_size)
+ node->objs_per_slab = node->pages_per_slab *
+ page_size / node->obj_size;
+
+ stats->nr_objs += node->nr_objs;
+ stats->nr_active_objs += node->nr_active_objs;
+ stats->total_size += (unsigned long)node->nr_objs * node->obj_size;
+ stats->active_size += (unsigned long)node->nr_active_objs * node->obj_size;
+ stats->nr_pages += node->nr_slabs * node->pages_per_slab;
+ stats->nr_slabs += node->nr_slabs;
+ stats->nr_active_slabs += node->nr_active_slabs;
+ stats->nr_caches++;
+ }
+
+ if (stats->nr_objs)
+ stats->avg_obj_size = stats->total_size / stats->nr_objs;
+
+ return 0;
}
/*
- * parse_slabinfo10 - actual parsing routine for slabinfo 1.0 (2.2 kernels)
+ * procps_slabinfo_new:
*
- * Not yet implemented. Please feel free.
+ * @info: location of returned new structure
+ *
+ * Returns: 0 on success <0 on failure
+ */
+PROCPS_EXPORT int procps_slabinfo_new(
+ struct procps_slabinfo **info)
+{
+ struct procps_slabinfo *si;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ si = calloc(1, sizeof(struct procps_slabinfo));
+ if (!si)
+ return -ENOMEM;
+
+ si->refcount = 1;
+ si->slabinfo_fp = NULL;
+ si->nodes_alloc = 0;
+ si->nodes_used = 0;
+ si->nodes = NULL;
+ *info = si;
+ return 0;
+}
+
+/* procps_slabinfo_read:
+ *
+ * Read the data out of /proc/slabinfo putting the information
+ * into the supplie info container
+ *
+ * Returns: 0 on success, negative on error
*/
-static int parse_slabinfo10(struct slab_info **list, struct slab_stat *stats,
- FILE *f)
+PROCPS_EXPORT int procps_slabinfo_read (
+ struct procps_slabinfo *info)
+{
+ char line[SLABINFO_LINE_LEN];
+ int retval, size, major, minor;
+
+ if (info == NULL)
+ return -1;
+
+ memset(&(info->stats), 0, sizeof(struct slabinfo_stats));
+ if ((retval = slabnodes_alloc(info)) < 0)
+ return retval;
+ slabnodes_clear(info);
+
+ if (NULL == info->slabinfo_fp &&
+ (info->slabinfo_fp = fopen(SLABINFO_FILE, "r")) == NULL)
+ return -errno;
+ if (fseek(info->slabinfo_fp, 0L, SEEK_SET) < 0)
+ return -errno;
+
+ /* Parse the version string */
+ if (!fgets(line, SLABINFO_LINE_LEN, info->slabinfo_fp))
+ return -errno;
+
+ if (sscanf(line, "slabinfo - version: %d.%d", &major, &minor) != 2)
+ return -EINVAL;
+
+ if (major == 2)
+ retval = parse_slabinfo20(info);
+ else if (major == 1 && minor == 1)
+ retval = parse_slabinfo11(info);
+ else
+ return -ERANGE;
+ return retval;
+}
+
+PROCPS_EXPORT int procps_slabinfo_ref (
+ struct procps_slabinfo *info)
{
- (void) list, (void) stats, (void) f;
- fprintf(stderr, "slabinfo version 1.0 not yet supported\n");
- return 1;
+ if (info == NULL)
+ return -EINVAL;
+ info->refcount++;
+ return info->refcount;
+}
+
+PROCPS_EXPORT int procps_slabinfo_unref (
+ struct procps_slabinfo **info)
+{
+ 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;
+ }
+ free(*info);
+ *info = NULL;
+ return 0;
+ }
+ return (*info)->refcount;
+}
+
+PROCPS_EXPORT unsigned long procps_slabinfo_stat_get(
+ struct procps_slabinfo *info,
+ enum procps_slabinfo_stat item)
+{
+ if (!item)
+ return 0;
+ switch (item) {
+ case PROCPS_SLABINFO_OBJS:
+ return info->stats.nr_objs;
+ case PROCPS_SLABINFO_AOBJS:
+ return info->stats.nr_active_objs;
+ case PROCPS_SLABINFO_PAGES:
+ return info->stats.nr_pages;
+ case PROCPS_SLABINFO_SLABS:
+ return info->stats.nr_slabs;
+ case PROCPS_SLABINFO_ASLABS:
+ return info->stats.nr_active_slabs;
+ case PROCPS_SLABINFO_CACHES:
+ return info->stats.nr_caches;
+ case PROCPS_SLABINFO_ACACHES:
+ return info->stats.nr_active_caches;
+ case PROCPS_SLABINFO_SIZE_AVG:
+ return info->stats.avg_obj_size;
+ case PROCPS_SLABINFO_SIZE_MIN:
+ return info->stats.min_obj_size;
+ case PROCPS_SLABINFO_SIZE_MAX:
+ return info->stats.max_obj_size;
+ case PROCPS_SLABINFO_SIZE_TOTAL:
+ return info->stats.total_size;
+ case PROCPS_SLABINFO_SIZE_ACTIVE:
+ return info->stats.active_size;
+ }
+ return 0;
+}
+
+PROCPS_EXPORT int procps_slabinfo_stat_getchain(
+ struct procps_slabinfo *info,
+ struct procps_slabinfo_result *result)
+{
+ if (!info || !result)
+ return -EINVAL;
+
+ do {
+ switch (result->item) {
+ case PROCPS_SLABINFO_OBJS:
+ result->result = info->stats.nr_objs;
+ break;
+ case PROCPS_SLABINFO_AOBJS:
+ result->result = info->stats.nr_active_objs;
+ break;
+ case PROCPS_SLABINFO_PAGES:
+ result->result = info->stats.nr_pages;
+ break;
+ case PROCPS_SLABINFO_SLABS:
+ result->result = info->stats.nr_slabs;
+ break;
+ case PROCPS_SLABINFO_ASLABS:
+ result->result = info->stats.nr_active_slabs;
+ break;
+ case PROCPS_SLABINFO_CACHES:
+ result->result = info->stats.nr_caches;
+ break;
+ case PROCPS_SLABINFO_ACACHES:
+ result->result = info->stats.nr_active_caches;
+ break;
+ case PROCPS_SLABINFO_SIZE_AVG:
+ result->result = info->stats.avg_obj_size;
+ break;
+ case PROCPS_SLABINFO_SIZE_MIN:
+ result->result = info->stats.min_obj_size;
+ break;
+ case PROCPS_SLABINFO_SIZE_MAX:
+ result->result = info->stats.max_obj_size;
+ break;
+ case PROCPS_SLABINFO_SIZE_TOTAL:
+ result->result = info->stats.total_size;
+ break;
+ case PROCPS_SLABINFO_SIZE_ACTIVE:
+ result->result = info->stats.active_size;
+ break;
+ default:
+ return -EINVAL;
+ }
+ result = result->next;
+ } while(result);
+ return 0;
}
/*
- * slabinfo - parse the system's slabinfo and fill out both a linked list of
- * slab_info structures and the slab_stat structure
+ * procps_slabinfo_node_getname():
+ *
+ * @info: slabinfo structure with data read in
+ * @nodeid: number of node we want the name for
+ *
+ * Find the name of the given node
+ *
+ * Returns: name or NULL on error
+ */
+PROCPS_EXPORT char *procps_slabinfo_node_getname(
+ struct procps_slabinfo *info,
+ int nodeid)
+{
+ if (info == NULL)
+ return NULL;
+ if (nodeid > info->nodes_used)
+ return NULL;
+ return info->nodes[nodeid].name;
+}
+
+PROCPS_EXPORT int procps_slabinfo_node_getchain (
+ struct procps_slabinfo *info,
+ struct procps_slabnode_result *result,
+ int nodeid)
+{
+ if (info == NULL || result == NULL)
+ return -EINVAL;
+ if (nodeid > info->nodes_used)
+ return -EINVAL;
+
+ do {
+ switch (result->item) {
+ case PROCPS_SLABNODE_SIZE:
+ result->result = info->nodes[nodeid].cache_size;
+ break;
+ case PROCPS_SLABNODE_OBJS:
+ result->result = info->nodes[nodeid].nr_objs;
+ break;
+ case PROCPS_SLABNODE_AOBJS:
+ result->result = info->nodes[nodeid].nr_active_objs;
+ break;
+ case PROCPS_SLABNODE_OBJ_SIZE:
+ result->result = info->nodes[nodeid].obj_size;
+ break;
+ case PROCPS_SLABNODE_OBJS_PER_SLAB:
+ result->result = info->nodes[nodeid].objs_per_slab;
+ break;
+ case PROCPS_SLABNODE_PAGES_PER_SLAB:
+ result->result = info->nodes[nodeid].pages_per_slab;
+ break;
+ case PROCPS_SLABNODE_SLABS:
+ result->result = info->nodes[nodeid].nr_slabs;
+ break;
+ case PROCPS_SLABNODE_ASLABS:
+ result->result = info->nodes[nodeid].nr_active_slabs;
+ break;
+ case PROCPS_SLABNODE_USE:
+ result->result = info->nodes[nodeid].use;
+ break;
+ default:
+ return -EINVAL;
+ }
+ result = result->next;
+ } while(result);
+ return 0;
+}
+
+/*
+ * Sorting functions
+ *
+ * These functions sort the slabnodes. The sort type is
+ * the same as the get enum
+ */
+static int sort_name(const void *a, const void *b)
+{
+ return strcmp(
+ ((struct procps_slabnode*)a)->name,
+ ((struct procps_slabnode*)b)->name);
+}
+
+static int sort_objs(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->nr_objs -
+ ((struct procps_slabnode*)a)->nr_objs;
+}
+
+static int sort_aobjs(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->nr_active_objs -
+ ((struct procps_slabnode*)a)->nr_active_objs;
+}
+
+static int sort_size(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->obj_size -
+ ((struct procps_slabnode*)a)->obj_size;
+}
+
+static int sort_objsperslab(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->objs_per_slab -
+ ((struct procps_slabnode*)a)->objs_per_slab;
+}
+
+static int sort_pagesperslab(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->pages_per_slab -
+ ((struct procps_slabnode*)a)->pages_per_slab;
+}
+
+static int sort_slabs(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->nr_slabs -
+ ((struct procps_slabnode*)a)->nr_slabs;
+}
+
+static int sort_use(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->use -
+ ((struct procps_slabnode*)a)->use;
+}
+
+static int sort_aslabs(const void *a, const void *b)
+{
+ return ((struct procps_slabnode*)b)->nr_active_slabs -
+ ((struct procps_slabnode*)a)->nr_active_slabs;
+}
+
+/*
+ * procps_slabinfo_sort:
+ *
+ * @info: the slabinfo that has the read data
+ * @item: slabnode item to sort by
+ *
+ * Sort the slabnodes contained in @info based
+ * upon the criteria @item
+ *
+ * Returns: 0 on success < on error
+ */
+PROCPS_EXPORT int procps_slabinfo_sort(
+ struct procps_slabinfo *info,
+ const enum procps_slabinfo_nodeitem item)
+{
+ void * sort_func = NULL;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ switch (item) {
+ case PROCPS_SLABNODE_NAME:
+ sort_func = sort_name;
+ break;
+ case PROCPS_SLABNODE_OBJS:
+ sort_func = sort_objs;
+ break;
+ case PROCPS_SLABNODE_AOBJS:
+ sort_func = sort_aobjs;
+ break;
+ case PROCPS_SLABNODE_SIZE:
+ sort_func = sort_size;
+ break;
+ case PROCPS_SLABNODE_OBJS_PER_SLAB:
+ sort_func = sort_objsperslab;
+ break;
+ case PROCPS_SLABNODE_PAGES_PER_SLAB:
+ sort_func = sort_pagesperslab;
+ break;
+ case PROCPS_SLABNODE_SLABS:
+ sort_func = sort_slabs;
+ break;
+ case PROCPS_SLABNODE_ASLABS:
+ sort_func = sort_aslabs;
+ break;
+ case PROCPS_SLABNODE_USE:
+ sort_func = sort_use;
+ break;
+ default:
+ return -EINVAL;
+ }
+ qsort(info->nodes, info->nodes_used,
+ sizeof(struct procps_slabnode), sort_func);
+ return 0;
+}
+
+/*
+ * procps_slabinfo_node_count():
+ *
+ * @info: read in slabinfo structure
*
- * The function returns zero on success, in which case 'list' and 'stats' are
- * valid. Nonzero is returned on failure and the state of 'list' and 'stats'
- * are undefined.
+ * Returns: number of nodes in @info or <0 on error
*/
-int get_slabinfo(struct slab_info **list, struct slab_stat *stats)
+PROCPS_EXPORT int procps_slabinfo_node_count(
+ const struct procps_slabinfo *info)
{
- FILE *slabfile;
- char buffer[SLABINFO_VER_LEN];
- int major, minor, ret = 0;
-
- slabfile = fopen(SLABINFO_FILE, "r");
- if (!slabfile) {
- perror("fopen " SLABINFO_FILE);
- return 1;
- }
-
- if (!fgets(buffer, SLABINFO_VER_LEN, slabfile)) {
- fprintf(stderr, "cannot read from slabinfo\n");
- fclose(slabfile);
- return 1;
- }
-
- if (sscanf(buffer, "slabinfo - version: %d.%d", &major, &minor) != 2) {
- fprintf(stderr, "not the good old slabinfo we know\n");
- fclose(slabfile);
- return 1;
- }
-
- if (major == 2)
- ret = parse_slabinfo20(list, stats, slabfile);
- else if (major == 1 && minor == 1)
- ret = parse_slabinfo11(list, stats, slabfile);
- else if (major == 1 && minor == 0)
- ret = parse_slabinfo10(list, stats, slabfile);
- else {
- fprintf(stderr, "unrecognizable slabinfo version\n");
- fclose(slabfile);
- return 1;
- }
-
- fclose(slabfile);
-
- return ret;
+ if (!info)
+ return -EINVAL;
+ return info->nodes_used;
}
#ifndef _PROC_SLAB_H
#define _PROC_SLAB_H
-#define SLAB_INFO_NAME_LEN 128
-
-struct slab_info {
- char name[SLAB_INFO_NAME_LEN]; /* name of this cache */
- struct slab_info *next;
- 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 */
+__BEGIN_DECLS
+
+enum procps_slabinfo_stat {
+ PROCPS_SLABINFO_OBJS,
+ PROCPS_SLABINFO_AOBJS,
+ PROCPS_SLABINFO_PAGES,
+ PROCPS_SLABINFO_SLABS,
+ PROCPS_SLABINFO_ASLABS,
+ PROCPS_SLABINFO_CACHES,
+ PROCPS_SLABINFO_ACACHES,
+ PROCPS_SLABINFO_SIZE_AVG,
+ PROCPS_SLABINFO_SIZE_MIN,
+ PROCPS_SLABINFO_SIZE_MAX,
+ PROCPS_SLABINFO_SIZE_TOTAL,
+ PROCPS_SLABINFO_SIZE_ACTIVE,
+};
+
+enum procps_slabinfo_nodeitem {
+ PROCPS_SLABNODE_NAME,
+ 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
};
-struct slab_stat {
- 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 */
+struct procps_slabinfo;
+struct procps_slabnode;
+
+struct procps_slabinfo_result {
+ enum procps_slabinfo_stat item;
+ unsigned long result;
+ struct procps_slabinfo_result *next;
};
-extern void put_slabinfo(struct slab_info *);
-extern void free_slabinfo(struct slab_info *);
-extern int get_slabinfo(struct slab_info **, struct slab_stat *);
+struct procps_slabnode_result {
+ enum procps_slabinfo_nodeitem item;
+ unsigned long result;
+ struct procps_slabnode_result *next;
+};
+
+int procps_slabinfo_new (struct procps_slabinfo **info);
+int procps_slabinfo_read (struct procps_slabinfo *info);
+
+int procps_slabinfo_ref (struct procps_slabinfo *info);
+int procps_slabinfo_unref (struct procps_slabinfo **info);
+
+unsigned long procps_slabinfo_stat_get (struct procps_slabinfo *info,
+ enum procps_slabinfo_stat item);
+
+int procps_slabinfo_stat_getchain (struct procps_slabinfo *info,
+ struct procps_slabinfo_result *result);
+
+int procps_slabinfo_sort( struct procps_slabinfo *info,
+ const enum procps_slabinfo_nodeitem item);
+
+int procps_slabinfo_node_count(const struct procps_slabinfo *info);
+
+int procps_slabinfo_node_get (struct procps_slabinfo *info,
+ struct procps_slabnode **node);
+int procps_slabinfo_node_getchain (struct procps_slabinfo *info,
+ struct procps_slabnode_result *result,
+ int nodeid);
+
+char *procps_slabinfo_node_getname(struct procps_slabinfo *info,
+ int nodeid);
+__END_DECLS
+
#endif /* _PROC_SLAB_H */
#include "fileutils.h"
#include "nls.h"
#include "strutils.h"
-#include "proc/slab.h"
-#include "proc/version.h"
+#include <proc/slab.h>
-#define DEF_SORT_FUNC sort_nr_objs
+#define DEFAULT_SORT_ITEM PROCPS_SLABNODE_OBJS
static unsigned short cols, rows;
static struct termios saved_tty;
static long delay = 3;
-static int (*sort_func)(const struct slab_info *, const struct slab_info *);
-
-static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
-{
- struct slab_info sorted_list;
- struct slab_info *curr = &sorted_list;
-
- while ((a != NULL) && (b != NULL)) {
- if (sort_func(a, b)) {
- curr->next = a;
- curr = a;
- a = a->next;
- } else {
- curr->next = b;
- curr = b;
- b = b->next;
- }
- }
-
- curr->next = (a == NULL) ? b : a;
- return sorted_list.next;
-}
-
-/*
- * slabsort - merge sort the slab_info linked list based on sort_func
- */
-static struct slab_info *slabsort(struct slab_info *list)
-{
- struct slab_info *a, *b;
-
- if ((list == NULL) || (list->next == NULL))
- return list;
-
- a = list;
- b = list->next;
-
- while ((b != NULL) && (b->next != NULL)) {
- list = list->next;
- b = b->next->next;
- }
-
- b = list->next;
- list->next = NULL;
-
- return merge_objs(slabsort(a), slabsort(b));
-}
-
-/*
- * Sort Routines. Each of these should be associated with a command-line
- * search option. The functions should fit the prototype:
- *
- * int sort_foo(const struct slab_info *a, const struct slab_info *b)
- *
- * They return one if the first parameter is larger than the second
- * Otherwise, they return zero.
- */
-
-static int sort_name(const struct slab_info *a, const struct slab_info *b)
-{
- return (strcmp(a->name, b->name) < 0) ? 1 : 0;
-}
-
-static int sort_nr_objs(const struct slab_info *a, const struct slab_info *b)
-{
- return (a->nr_objs > b->nr_objs);
-}
-
-static int sort_nr_active_objs(const struct slab_info *a,
- const struct slab_info *b)
-{
- return (a->nr_active_objs > b->nr_active_objs);
-}
-
-static int sort_obj_size(const struct slab_info *a, const struct slab_info *b)
-{
- return (a->obj_size > b->obj_size);
-}
-
-static int sort_objs_per_slab(const struct slab_info *a,
- const struct slab_info *b)
-{
- return (a->objs_per_slab > b->objs_per_slab);
-}
-
-static int sort_pages_per_slab(const struct slab_info *a,
- const struct slab_info *b)
-{
- return (a->pages_per_slab > b->pages_per_slab);
-}
-
-static int sort_nr_slabs(const struct slab_info *a, const struct slab_info *b)
-{
- return (a->nr_slabs > b->nr_slabs);
-}
-
-static int sort_nr_active_slabs(const struct slab_info *a,
- const struct slab_info *b)
-{
- return (a->nr_active_slabs > b->nr_active_slabs);
-}
-
-
-static int sort_use(const struct slab_info *a, const struct slab_info *b)
-{
- return (a->use > b->use);
-}
-
-static int sort_cache_size(const struct slab_info *a, const struct slab_info *b)
-{
- return (a->cache_size > b->cache_size);
-}
+static int run_once = 0;
+#define print_line(fmt, ...) if (run_once) printf(fmt, __VA_ARGS__); else printw(fmt, __VA_ARGS__)
/*
* term_size - set the globals 'cols' and 'rows' to the current terminal size
*/
static void term_size(int unusused __attribute__ ((__unused__)))
{
- struct winsize ws;
-
- if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) && ws.ws_row > 10) {
- cols = ws.ws_col;
- rows = ws.ws_row;
- } else {
- cols = 80;
- rows = 24;
- }
+ struct winsize ws;
+
+ if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) && ws.ws_row > 10) {
+ cols = ws.ws_col;
+ rows = ws.ws_row;
+ } else {
+ cols = 80;
+ rows = 24;
+ }
}
static void sigint_handler(int unused __attribute__ ((__unused__)))
{
- delay = 0;
+ delay = 0;
}
static void __attribute__((__noreturn__)) usage(FILE *out)
{
- fputs(USAGE_HEADER, out);
- fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
- fputs(USAGE_OPTIONS, out);
- fputs(_(" -d, --delay <secs> delay updates\n"), out);
- fputs(_(" -o, --once only display once, then exit\n"), out);
- fputs(_(" -s, --sort <char> specify sort criteria by character (see below)\n"), out);
- fputs(USAGE_SEPARATOR, out);
- fputs(USAGE_HELP, out);
- fputs(USAGE_VERSION, out);
-
- fputs(_("\nThe following are valid sort criteria:\n"), out);
- fputs(_(" a: sort by number of active objects\n"), out);
- fputs(_(" b: sort by objects per slab\n"), out);
- fputs(_(" c: sort by cache size\n"), out);
- fputs(_(" l: sort by number of slabs\n"), out);
- fputs(_(" v: sort by number of active slabs\n"), out);
- fputs(_(" n: sort by name\n"), out);
- fputs(_(" o: sort by number of objects (the default)\n"), out);
- fputs(_(" p: sort by pages per slab\n"), out);
- fputs(_(" s: sort by object size\n"), out);
- fputs(_(" u: sort by cache utilization\n"), out);
- fprintf(out, USAGE_MAN_TAIL("slabtop(1)"));
-
- exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ fputs(USAGE_HEADER, out);
+ fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
+ fputs(USAGE_OPTIONS, out);
+ fputs(_(" -d, --delay <secs> delay updates\n"), out);
+ fputs(_(" -o, --once only display once, then exit\n"), out);
+ fputs(_(" -s, --sort <char> specify sort criteria by character (see below)\n"), out);
+ fputs(USAGE_SEPARATOR, out);
+ fputs(USAGE_HELP, out);
+ fputs(USAGE_VERSION, out);
+
+ fputs(_("\nThe following are valid sort criteria:\n"), out);
+ fputs(_(" a: sort by number of active objects\n"), out);
+ fputs(_(" b: sort by objects per slab\n"), out);
+ fputs(_(" c: sort by cache size\n"), out);
+ fputs(_(" l: sort by number of slabs\n"), out);
+ fputs(_(" v: sort by number of active slabs\n"), out);
+ fputs(_(" n: sort by name\n"), out);
+ fputs(_(" o: sort by number of objects (the default)\n"), out);
+ fputs(_(" p: sort by pages per slab\n"), out);
+ fputs(_(" s: sort by object size\n"), out);
+ fputs(_(" u: sort by cache utilization\n"), out);
+ fprintf(out, USAGE_MAN_TAIL("slabtop(1)"));
+
+ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}
/*
* set_sort_func - return the slab_sort_func that matches the given key.
* On unrecognizable key, DEF_SORT_FUNC is returned.
*/
-static void * set_sort_func(char key)
+static enum procps_slabinfo_nodeitem get_sort_item(
+ const char key,
+ enum procps_slabinfo_nodeitem old_sort)
+{
+ switch (tolower(key)) {
+ case 'n':
+ return PROCPS_SLABNODE_NAME;
+ case 'o':
+ return PROCPS_SLABNODE_OBJS;
+ case 'a':
+ return PROCPS_SLABNODE_AOBJS;
+ case 's':
+ return PROCPS_SLABNODE_SIZE;
+ case 'b':
+ return PROCPS_SLABNODE_OBJS_PER_SLAB;
+ case 'p':
+ return PROCPS_SLABNODE_PAGES_PER_SLAB;
+ case 'l':
+ return PROCPS_SLABNODE_SLABS;
+ case 'v':
+ return PROCPS_SLABNODE_ASLABS;
+ case 'c':
+ return PROCPS_SLABNODE_SIZE;
+ case 'u':
+ return PROCPS_SLABNODE_USE;
+ default:
+ return old_sort;
+ }
+}
+
+#if 0
+ case 'Q':
+ delay = 0;
+ break;
+ }
+}
+#endif
+
+static void print_stats(struct procps_slabinfo *info)
{
- switch (key) {
- case 'n':
- return (void *) sort_name;
- case 'o':
- return (void *) sort_nr_objs;
- case 'a':
- return (void *) sort_nr_active_objs;
- case 's':
- return (void *) sort_obj_size;
- case 'b':
- return (void *) sort_objs_per_slab;
- case 'p':
- return (void *) sort_pages_per_slab;
- case 'l':
- return (void *) sort_nr_slabs;
- case 'v':
- return (void *) sort_nr_active_slabs;
- case 'c':
- return (void *) sort_cache_size;
- case 'u':
- return (void *) sort_use;
- default:
- return (void *) DEF_SORT_FUNC;
- }
+#define STAT_VAL(e) stats[e].result
+ enum stat_enums {
+ stat_AOBJS, stat_OBJS, stat_ASLABS, stat_SLABS,
+ stat_ACACHES, stat_CACHES, stat_ACTIVE, stat_TOTAL,
+ stat_MIN, stat_AVG, stat_MAX,
+ };
+ static struct procps_slabinfo_result stats[] = {
+ { PROCPS_SLABINFO_AOBJS, 0, &stats[1] },
+ { PROCPS_SLABINFO_OBJS, 0, &stats[2] },
+ { PROCPS_SLABINFO_ASLABS, 0, &stats[3] },
+ { PROCPS_SLABINFO_SLABS, 0, &stats[4] },
+ { PROCPS_SLABINFO_ACACHES, 0, &stats[5] },
+ { PROCPS_SLABINFO_CACHES, 0, &stats[6] },
+ { PROCPS_SLABINFO_SIZE_ACTIVE, 0, &stats[7] },
+ { PROCPS_SLABINFO_SIZE_TOTAL, 0, &stats[8] },
+ { PROCPS_SLABINFO_SIZE_MIN, 0, &stats[9] },
+ { PROCPS_SLABINFO_SIZE_AVG, 0, &stats[10] },
+ { PROCPS_SLABINFO_SIZE_MAX, 0, NULL },
+ };
+
+ if (procps_slabinfo_stat_getchain(info, stats) < 0)
+ xerrx(EXIT_FAILURE,
+ _("Error getting slabinfo results"));
+
+ print_line(" %-35s: %d / %d (%.1f%%)\n"
+ " %-35s: %d / %d (%.1f%%)\n"
+ " %-35s: %d / %d (%.1f%%)\n"
+ " %-35s: %.2fK / %.2fK (%.1f%%)\n"
+ " %-35s: %.2fK / %.2fK / %.2fK\n\n",
+ /* Translation Hint: Next five strings must not
+ * exceed 35 length in 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),
+ /* 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),
+ /* 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),
+ /* 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),
+ _("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
}
-static void parse_input(char c)
+static void cleanup(const int is_tty, struct procps_slabinfo **slab_info)
{
- c = toupper(c);
- switch(c) {
- case 'A':
- sort_func = sort_nr_active_objs;
- break;
- case 'B':
- sort_func = sort_objs_per_slab;
- break;
- case 'C':
- sort_func = sort_cache_size;
- break;
- case 'L':
- sort_func = sort_nr_slabs;
- break;
- case 'V':
- sort_func = sort_nr_active_slabs;
- break;
- case 'N':
- sort_func = sort_name;
- break;
- case 'O':
- sort_func = sort_nr_objs;
- break;
- case 'P':
- sort_func = sort_pages_per_slab;
- break;
- case 'S':
- sort_func = sort_obj_size;
- break;
- case 'U':
- sort_func = sort_use;
- break;
- case 'Q':
- delay = 0;
- break;
- }
+ if (is_tty)
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
+ if (!run_once)
+ endwin();
+ procps_slabinfo_unref(slab_info);
}
-#define print_line(fmt, ...) if (run_once) printf(fmt, __VA_ARGS__); else printw(fmt, __VA_ARGS__)
int main(int argc, char *argv[])
{
- int is_tty, o;
- unsigned short old_rows;
- struct slab_info *slab_list = NULL;
- int run_once = 0, retval = EXIT_SUCCESS;
-
- static const struct option longopts[] = {
- { "delay", required_argument, NULL, 'd' },
- { "sort", required_argument, NULL, 's' },
- { "once", no_argument, NULL, 'o' },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'V' },
- { NULL, 0, NULL, 0 }
- };
+ int is_tty, o;
+ int nr_slabs;
+ unsigned short old_rows;
+ int retval = EXIT_SUCCESS;
+ struct procps_slabinfo *slab_info;
+ enum procps_slabinfo_nodeitem sort_item = DEFAULT_SORT_ITEM;
+
+ static const struct option longopts[] = {
+ { "delay", required_argument, NULL, 'd' },
+ { "sort", required_argument, NULL, 's' },
+ { "once", no_argument, NULL, 'o' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ struct procps_slabnode_result result[] = {
+ { PROCPS_SLABNODE_OBJS, 0, &result[1] },
+ { PROCPS_SLABNODE_AOBJS, 0, &result[2] },
+ { PROCPS_SLABNODE_USE, 0, &result[3] },
+ { PROCPS_SLABNODE_OBJ_SIZE, 0, &result[4] },
+ { PROCPS_SLABNODE_SLABS, 0, &result[5] },
+ { PROCPS_SLABNODE_OBJS_PER_SLAB, 0, &result[6] },
+ { PROCPS_SLABNODE_SIZE, 0, NULL } };
+ enum result_enums {
+ stat_OBJS, stat_AOBJS, stat_USE, stat_OSIZE, stat_SLABS,
+ stat_OPS, stat_SIZE };
#ifdef HAVE_PROGRAM_INVOCATION_NAME
- program_invocation_name = program_invocation_short_name;
+ program_invocation_name = program_invocation_short_name;
#endif
- setlocale (LC_ALL, "");
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
- atexit(close_stdout);
-
- sort_func = DEF_SORT_FUNC;
-
- while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
- switch (o) {
- case 'd':
- errno = 0;
- delay = strtol_or_err(optarg, _("illegal delay"));
- if (delay < 1)
- xerrx(EXIT_FAILURE,
- _("delay must be positive integer"));
- break;
- case 's':
- sort_func = (int (*)(const struct slab_info*,
- const struct slab_info *)) set_sort_func(optarg[0]);
- break;
- case 'o':
- run_once=1;
- delay = 0;
- break;
- case 'V':
- printf(PROCPS_NG_VERSION);
- return EXIT_SUCCESS;
- case 'h':
- usage(stdout);
- default:
- usage(stderr);
- }
- }
-
- is_tty = isatty(STDIN_FILENO);
- if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
- xwarn(_("terminal setting retrieval"));
-
- old_rows = rows;
- term_size(0);
- if (!run_once) {
- initscr();
- resizeterm(rows, cols);
- signal(SIGWINCH, term_size);
- }
- signal(SIGINT, sigint_handler);
-
- do {
- struct slab_info *curr;
- struct slab_stat stats;
- struct timeval tv;
- fd_set readfds;
- char c;
- int i;
- memset(&stats, 0, sizeof(struct slab_stat));
-
- if (get_slabinfo(&slab_list, &stats)) {
- retval = EXIT_FAILURE;
- break;
- }
-
- if (!run_once && old_rows != rows) {
- resizeterm(rows, cols);
- old_rows = rows;
- }
-
- move(0, 0);
- print_line(" %-35s: %d / %d (%.1f%%)\n"
- " %-35s: %d / %d (%.1f%%)\n"
- " %-35s: %d / %d (%.1f%%)\n"
- " %-35s: %.2fK / %.2fK (%.1f%%)\n"
- " %-35s: %.2fK / %.2fK / %.2fK\n\n",
- /* Translation Hint: Next five strings must not
- * exceed 35 length in characters. */
- /* xgettext:no-c-format */
- _("Active / Total Objects (% used)"),
- stats.nr_active_objs, stats.nr_objs,
- 100.0 * stats.nr_active_objs / stats.nr_objs,
- /* xgettext:no-c-format */
- _("Active / Total Slabs (% used)"),
- stats.nr_active_slabs, stats.nr_slabs,
- 100.0 * stats.nr_active_slabs / stats.nr_slabs,
- /* xgettext:no-c-format */
- _("Active / Total Caches (% used)"),
- stats.nr_active_caches, stats.nr_caches,
- 100.0 * stats.nr_active_caches / stats.nr_caches,
- /* xgettext:no-c-format */
- _("Active / Total Size (% used)"),
- stats.active_size / 1024.0, stats.total_size / 1024.0,
- 100.0 * stats.active_size / stats.total_size,
- _("Minimum / Average / Maximum Object"),
- stats.min_obj_size / 1024.0, stats.avg_obj_size / 1024.0,
- stats.max_obj_size / 1024.0);
-
- slab_list = slabsort(slab_list);
-
- attron(A_REVERSE);
- /* Translation Hint: Please keep alignment of the
- * following intact. */
- print_line("%-78s\n", _(" OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME"));
- attroff(A_REVERSE);
-
- curr = slab_list;
- for (i = 0; i < rows - 8 && curr->next; i++) {
- print_line("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n",
- curr->nr_objs, curr->nr_active_objs, curr->use,
- curr->obj_size / 1024.0, curr->nr_slabs,
- curr->objs_per_slab, (unsigned)(curr->cache_size / 1024),
- curr->name);
- curr = curr->next;
- }
-
- put_slabinfo(slab_list);
- if (!run_once) {
- refresh();
- FD_ZERO(&readfds);
- FD_SET(STDIN_FILENO, &readfds);
- tv.tv_sec = delay;
- tv.tv_usec = 0;
- if (select(STDOUT_FILENO, &readfds, NULL, NULL, &tv) > 0) {
- if (read(STDIN_FILENO, &c, 1) != 1)
- break;
- parse_input(c);
- }
- }
- } while (delay);
-
- if (is_tty)
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
- free_slabinfo(slab_list);
- if (!run_once)
- endwin();
- return retval;
+ setlocale (LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ atexit(close_stdout);
+
+ while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
+ switch (o) {
+ case 'd':
+ errno = 0;
+ delay = strtol_or_err(optarg, _("illegal delay"));
+ if (delay < 1)
+ xerrx(EXIT_FAILURE,
+ _("delay must be positive integer"));
+ break;
+ case 's':
+ sort_item = get_sort_item(optarg[0], sort_item);
+ break;
+ case 'o':
+ run_once=1;
+ delay = 0;
+ break;
+ case 'V':
+ printf(PROCPS_NG_VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage(stdout);
+ default:
+ usage(stderr);
+ }
+ }
+
+ if (procps_slabinfo_new(&slab_info) < 0)
+ xerrx(EXIT_FAILURE,
+ _("Unable to create slabinfo structure"));
+
+
+ is_tty = isatty(STDIN_FILENO);
+ if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
+ xwarn(_("terminal setting retrieval"));
+
+ old_rows = rows;
+ term_size(0);
+ if (!run_once) {
+ initscr();
+ resizeterm(rows, cols);
+ signal(SIGWINCH, term_size);
+ }
+ signal(SIGINT, sigint_handler);
+
+#define STAT_VAL(e) result[e].result
+ do {
+ char *slab_name;
+ struct timeval tv;
+ fd_set readfds;
+ char c;
+ int i, myerrno;
+
+ if (procps_slabinfo_read(slab_info) < 0) {
+ xwarn(_("Unable to read slabinfo"));
+ retval = EXIT_FAILURE;
+ break;
+ }
+
+ if (!run_once && old_rows != rows) {
+ resizeterm(rows, cols);
+ old_rows = rows;
+ }
+
+ move(0, 0);
+ print_stats(slab_info);
+
+ if (procps_slabinfo_sort(slab_info, sort_item) < 0) {
+ xwarn(_("Unable to sort slabnodes"));
+ retval= EXIT_FAILURE;
+ break;
+ }
+
+ attron(A_REVERSE);
+ /* Translation Hint: Please keep alignment of the
+ * following intact. */
+ print_line("%-78s\n", _(" OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME"));
+ attroff(A_REVERSE);
+
+ if ((nr_slabs = procps_slabinfo_node_count(slab_info)) < 0) {
+ xwarn(_("Unable to count slabinfo nodes"));
+ retval = EXIT_FAILURE;
+ break;
+ }
+
+ for (i=0 ; i < rows - 8 && i < nr_slabs; i++) {
+ if (procps_slabinfo_node_getchain(slab_info, result, i) < 0) {
+ xwarn(_("Unable to get slabinfo node data"));
+ retval = EXIT_FAILURE;
+ break;
+ }
+ slab_name= procps_slabinfo_node_getname(slab_info, i);
+ print_line("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n",
+ STAT_VAL(stat_OBJS), STAT_VAL(stat_AOBJS),
+ STAT_VAL(stat_USE),
+ STAT_VAL(stat_OSIZE) / 1024.0, STAT_VAL(stat_SLABS),
+ STAT_VAL(stat_OPS),
+ (unsigned)(STAT_VAL(stat_SIZE) / 1024),
+ slab_name?slab_name:"(unknown)");
+ }
+ if (!run_once) {
+ refresh();
+ FD_ZERO(&readfds);
+ FD_SET(STDIN_FILENO, &readfds);
+ tv.tv_sec = delay;
+ tv.tv_usec = 0;
+ if (select(STDOUT_FILENO, &readfds, NULL, NULL, &tv) > 0) {
+ if (read(STDIN_FILENO, &c, 1) != 1)
+ break;
+ if (c == 'Q' || c == 'q')
+ delay = 0;
+ else
+ sort_item = get_sort_item(c, sort_item);
+ }
+ }
+ } while (delay);
+ cleanup(is_tty, &slab_info);
+
}
#include <proc/vmstat.h>
#include <proc/readstat.h>
#include <proc/meminfo.h>
+#include <proc/slab.h>
#include <proc/diskstat.h>
#define UNIT_B 1
static void slabformat(void)
{
- FILE *fSlab;
- struct slab_cache *slabs;
- unsigned long nSlab, i, j, k;
- const char format[] = "%-24s %6u %6u %6u %6u\n";
-
- fSlab = fopen("/proc/slabinfo", "rb");
- if (!fSlab) {
- xwarnx(_("your kernel does not support slabinfo or your permissions are insufficient"));
- return;
- }
+ struct procps_slabinfo *slab_info;
+ int i, nodeid, nr_slabs;
+ const char format[] = "%-24s %6u %6u %6u %6u\n";
+ char *slab_name;
+ struct procps_slabnode_result result[] = {
+ { PROCPS_SLABNODE_AOBJS, 0, &result[1] },
+ { PROCPS_SLABNODE_OBJS, 0, &result[2] },
+ { PROCPS_SLABNODE_OBJ_SIZE, 0, &result[3] },
+ { PROCPS_SLABNODE_OBJS_PER_SLAB, 0, NULL }};
+ enum result_enums {
+ stat_AOBJS, stat_OBJS, stat_OSIZE, stat_OPS};
+#define SLAB_VAL(e) result[e].result
- if (!moreheaders)
- slabheader();
- nSlab = getslabinfo(&slabs);
- for (k = 0; k < nSlab; k++) {
- if (moreheaders && ((k % height) == 0))
- slabheader();
- printf(format,
- slabs[k].name,
- slabs[k].active_objs,
- slabs[k].num_objs,
- slabs[k].objsize, slabs[k].objperslab);
- }
- free(slabs);
- for (j = 1, k = 1; infinite_updates || j < num_updates; j++) {
- sleep(sleep_time);
- nSlab = getslabinfo(&slabs);
- for (i = 0; i < nSlab; i++, k++) {
- if (moreheaders && ((k % height) == 0))
- slabheader();
- printf(format,
- slabs[i].name,
- slabs[i].active_objs,
- slabs[i].num_objs,
- slabs[i].objsize, slabs[i].objperslab);
- }
- free(slabs);
- }
- fclose(fSlab);
+
+ if (procps_slabinfo_new(&slab_info) < 0)
+ xerrx(EXIT_FAILURE,
+ _("Unable to create slabinfo structure"));
+
+
+ if (!moreheaders)
+ slabheader();
+
+ for (i = 0; infinite_updates || i < num_updates; i++) {
+ if (procps_slabinfo_read(slab_info) < 0)
+ xerrx(EXIT_FAILURE,
+ _("Unable to read slabinfo structure"));
+ if ((nr_slabs = procps_slabinfo_node_count(slab_info)) < 0)
+ xerrx(EXIT_FAILURE,
+ _("Unable to count number of slabinfo nodes"));
+
+ for (nodeid = 0; nodeid < nr_slabs; nodeid++) {
+ if (moreheaders && ((nodeid % height) == 0))
+ slabheader();
+ if (procps_slabinfo_node_getchain(slab_info, result, nodeid) < 0)
+ xerrx(EXIT_FAILURE,
+ _("Error getting slabinfo results"));
+ slab_name = procps_slabinfo_node_getname(slab_info, nodeid);
+
+ printf(format,
+ slab_name?slab_name:"(unknown)",
+ SLAB_VAL(stat_AOBJS), SLAB_VAL(stat_OBJS),
+ SLAB_VAL(stat_OSIZE), SLAB_VAL(stat_OPS));
+ }
+ if (infinite_updates || i+1 < num_updates)
+ sleep(sleep_time);
+ }
}
static void disksum_format(void)
sleep_time = tmp;
infinite_updates = 1;
}
+ num_updates = 1;
if (optind < argc) {
num_updates = strtol_or_err(argv[optind++], _("failed to parse argument"));
infinite_updates = 0;