VERSION := 3
SUBVERSION := 1
-MINORVERSION := 14
-TARVERSION := 3.1.14
-LIBVERSION := 3.1.14
+MINORVERSION := 15
+TARVERSION := 3.1.15
+LIBVERSION := 3.1.15
############ vars
BINFILES := $(usr/bin)uptime $(usr/bin)tload $(usr/bin)free $(usr/bin)w \
$(usr/bin)top $(usr/bin)vmstat $(usr/bin)watch $(usr/bin)skill \
$(usr/bin)snice $(bin)kill $(sbin)sysctl $(usr/bin)pmap \
- $(usr/proc/bin)pgrep $(usr/proc/bin)pkill
+ $(usr/proc/bin)pgrep $(usr/proc/bin)pkill $(usr/bin)slabtop
MANFILES := $(man1)uptime.1 $(man1)tload.1 $(man1)free.1 $(man1)w.1 \
$(man1)top.1 $(man1)watch.1 $(man1)skill.1 $(man1)kill.1 \
$(man1)snice.1 $(man1)pgrep.1 $(man1)pkill.1 $(man1)pmap.1 \
- $(man5)sysctl.conf.5 $(man8)vmstat.8 $(man8)sysctl.8
+ $(man5)sysctl.conf.5 $(man8)vmstat.8 $(man8)sysctl.8 \
+ $(man1)slabtop.1
TARFILES := AUTHORS BUGS NEWS README TODO COPYING COPYING.LIB \
Makefile procps.lsm procps.spec v t README.top \
minimal.c $(notdir $(MANFILES)) \
uptime.c tload.c free.c w.c top.c vmstat.c watch.c skill.c \
- sysctl.c pgrep.c top.h pmap.c
+ sysctl.c pgrep.c top.h pmap.c slabtop.c
+
+# Stuff (tests, temporary hacks, etc.) left out of the standard tarball
+_TARFILES :=
CURSES := -I/usr/include/ncurses -lncurses
.SUFFIXES:
.SUFFIXES: .a .o .c .s .h
-.PHONY: all clean do_all install tar # ps
+.PHONY: all clean do_all install tar extratar
ALL := $(notdir $(BINFILES))
tar cf procps-$(TARVERSION).tar procps-$(TARVERSION)
gzip -9 procps-$(TARVERSION).tar
+extratar: $(_TARFILES)
+ mkdir extra-$(TARVERSION)
+ (tar cf - $(_TARFILES)) | (cd extra-$(TARVERSION) && tar xf -)
+ tar cf extra-$(TARVERSION).tar extra-$(TARVERSION)
+ gzip -9 extra-$(TARVERSION).tar
+
clean:
rm -f $(CLEAN)
pmap w uptime tload free sysctl vmstat utmp pgrep skill: % : %.o $(LIBPROC)
$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^
-top: % : %.o $(LIBPROC)
+slabtop top: % : %.o $(LIBPROC)
$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(CURSES)
watch: % : %.o
+procps-3.1.15 --> procps-3.1.16
+
+future-proof the tty handling (thanks to Zhou Wei)
+slabtop (Chris Rivera and Robert Love) #226778 rh114012a
+
procps-3.1.14 --> procps-3.1.15
install to /lib64 if it exists
Suppose you wanted to install stuff in strange places.
You might do something like this:
- make usr/bin=/tmp/fff/iii/ DESTDIR=/tmp/fff install="install -D" ldconfig=echo install
+ make usr/bin=/tmp/Q/iii/ DESTDIR=/tmp/Q install="install -D" ldconfig=echo install
If cross-compiling, you might need to set lib64 to
either "lib" or "lib64", like one of these examples:
#define MINOR_OF(d) ((unsigned)minor(d))
#else
#define MAJOR_OF(d) ( ((unsigned)(d)>>8u) & 0xfffu )
-#define MINOR_OF(d) ( ((unsigned)(d)&0xffu) | (((unsigned)(d)&0xfff00000u)>>20u) )
+#define MINOR_OF(d) ( ((unsigned)(d)&0xffu) | (((unsigned)(d)&0xfff00000u)>>12u) )
#undef major
#undef minor
#define major <-- do not use -->
kb_active; kb_inactive; kb_main_buffers; kb_main_cached;
kb_main_free; kb_main_total; kb_main_used; kb_swap_free;
kb_swap_total; kb_swap_used; kb_main_shared;
- vm_pgpgin; vm_pgpgout; vm_pswpin; vm_pswpout;
+ vm_pgpgin; vm_pgpgout; vm_pswpin; vm_pswpout; free_slabinfo; put_slabinfo;
+ get_slabinfo;
local: *;
};
#define LABEL_OFFSET
#endif
+#define STRINGIFY_ARG(a) #a
+#define STRINGIFY(a) STRINGIFY_ARG(a)
// marks old junk, to warn non-procps library users
#if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3
--- /dev/null
+/*
+ * slab.c - slab related functions for libproc
+ *
+ * Chris Rivera <cmrivera@ufl.edu>
+ * Robert Love <rml@tech9.net>
+ *
+ * This program is licensed under the GNU Library General Public License, v2
+ *
+ * Copyright (C) 2003 Chris Rivera
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "slab.h"
+#include "procps.h"
+
+#define SLABINFO_LINE_LEN 2048
+#define SLABINFO_VER_LEN 100
+#define SLABINFO_FILE "/proc/slabinfo"
+
+static struct slab_info *free_index;
+
+/*
+ * 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.
+ */
+static struct slab_info *get_slabnode(void)
+{
+ struct slab_info *node;
+
+ if (free_index) {
+ node = free_index;
+ free_index = free_index->next;
+ } else {
+ node = malloc(sizeof(struct slab_info));
+ if (!node)
+ perror("malloc");
+ }
+
+ return node;
+}
+
+/*
+ * put_slabinfo - return all allocated nodes to the free list
+ */
+void put_slabinfo(struct slab_info *head)
+{
+ free_index = head;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * parse_slabinfo20 - actual parse routine for slabinfo 2.0 (2.6 kernels)
+ */
+static int parse_slabinfo20(struct slab_info **list, struct slab_stat *stats,
+ FILE *f)
+{
+ 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
+ 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 = 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 += curr->nr_objs * curr->obj_size;
+ stats->active_size += 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, "error 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;
+}
+
+/*
+ * 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)
+{
+ 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
+ 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 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 = 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 += curr->nr_objs * curr->obj_size;
+ stats->active_size += 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, "error 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;
+}
+
+/*
+ * parse_slabinfo10 - actual parsing routine for slabinfo 1.0 (2.2 kernels)
+ *
+ * Not yet implemented. Please feel free.
+ */
+static int parse_slabinfo10(struct slab_info **list, struct slab_stat *stats,
+ FILE *f)
+{
+ (void) list, (void) stats, (void) f;
+ fprintf(stderr, "slabinfo version 1.0 not yet supported\n");
+ return 1;
+}
+
+/*
+ * slabinfo - parse the system's slabinfo and fill out both a linked list of
+ * slab_info structures and the slab_stat 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.
+ */
+int get_slabinfo(struct slab_info **list, struct slab_stat *stats)
+{
+ FILE *slabfile;
+ char buffer[SLABINFO_VER_LEN];
+ int major, minor, ret = 0;
+
+ slabfile = fopen(SLABINFO_FILE, "r");
+ if (!slabfile) {
+ perror("fopen");
+ return 1;
+ }
+
+ if (!fgets(buffer, SLABINFO_VER_LEN, slabfile)) {
+ fprintf(stderr, "cannot read from slabinfo\n");
+ return 1;
+ }
+
+ if (sscanf(buffer, "slabinfo - version: %d.%d", &major, &minor) != 2) {
+ fprintf(stderr, "not the good old slabinfo we know\n");
+ return 1;
+ }
+
+ if (major == 2 && minor == 0)
+ 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");
+ return 1;
+ }
+
+ fclose(slabfile);
+
+ return ret;
+}
--- /dev/null
+#ifndef _PROC_SLAB_H
+#define _PROC_SLAB_H
+
+#define SLAB_INFO_NAME_LEN 64
+
+struct slab_info {
+ char name[SLAB_INFO_NAME_LEN]; /* name of this cache */
+ int nr_objs; /* number of objects in this cache */
+ int nr_active_objs; /* number of active objects */
+ int obj_size; /* size of each object */
+ int objs_per_slab; /* number of objects per slab */
+ int pages_per_slab; /* number of pages per slab */
+ int nr_slabs; /* number of slabs in this cache */
+ int nr_active_slabs; /* number of active slabs */
+ int use; /* percent full: total / active */
+ int cache_size; /* size of entire cache */
+ struct slab_info *next;
+};
+
+struct slab_stat {
+ int nr_objs; /* number of objects, among all caches */
+ int nr_active_objs; /* number of active objects, among all caches */
+ int total_size; /* size of all objects */
+ int active_size; /* size of all active objects */
+ int nr_pages; /* number of pages consumed by all objects */
+ int nr_slabs; /* number of slabs, among all caches */
+ int nr_active_slabs; /* number of active slabs, among all caches */
+ int nr_caches; /* number of caches */
+ int nr_active_caches; /* number of active caches */
+ int avg_obj_size; /* average object size */
+ int min_obj_size; /* size of smallest object */
+ int max_obj_size; /* size of largest object */
+};
+
+extern void put_slabinfo(struct slab_info *);
+extern void free_slabinfo(struct slab_info *);
+extern int get_slabinfo(struct slab_info **, struct slab_stat *);
+
+#endif /* _PROC_SLAB_H */
Begin4
Title: procps
-Version: 3.1.14
-Entered-date: 2003-09-26
+Version: 3.1.15
+Entered-date: 2003-12-24
Description: Linux system utilities
Keywords: procps /proc libproc sysctl pmap ps uptime tload
free w top vmstat watch skill snice kill pgrep pkill
Author: Albert Cahalan, Michael K. Johnson, Jim Warner, etc.
Maintained-by: various <procps-feedback@lists.sf.net>
Primary-site: http://procps.sf.net/
- 242kB procps-3.1.14.tar.gz
+ 242kB procps-3.1.15.tar.gz
Alternate-site: http://www.debian.org/Packages/unstable/base/procps.html
- 242kB procps-3.1.14.tar.gz
+ 242kB procps-3.1.15.tar.gz
Copying-policy: mixed
End
Name: procps
%define major_version 3
%define minor_version 1
-%define revision 14
+%define revision 15
%define version %{major_version}.%{minor_version}.%{revision}
Version: %{version}
Release: 1
int fd;
// wchan file is suitable for testing
-//snprintf(filename, sizeof filename, "/proc/%d/task/%d/wchan", pp->tgid, pp->tid);
- snprintf(filename, sizeof filename, "/proc/%d/task/%d/attr/current", pp->tgid, pp->tid);
+//snprintf(filename, sizeof filename, "/proc/%d/wchan", pp->tgid);
+ snprintf(filename, sizeof filename, "/proc/%d/attr/current", pp->tgid);
fd = open(filename, O_RDONLY, 0);
if(likely(fd==-1)) goto fail;
{"cnswap", "-", pr_nop, sr_cnswap, 1, 0, LNX, AN|RIGHT},
{"comm", "COMMAND", pr_comm, sr_nop, 16, COM, U98, PO|UNLIMITED}, /*ucomm*/
{"command", "COMMAND", pr_args, sr_nop, 16, ARG, XXX, PO|UNLIMITED}, /*args*/
-{"context", "CONTEXT", pr_context, sr_nop, 40, 0, LNX, AN|LEFT},
+{"context", "CONTEXT", pr_context, sr_nop, 40, 0, LNX, PO|LEFT},
{"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/
{"cpu", "CPU", pr_nop, sr_nop, 3, 0, BSD, AN|RIGHT}, /* FIXME ... HP-UX wants this as the CPU number for SMP? */
{"cputime", "TIME", pr_time, sr_nop, 8, 0, DEC, ET|RIGHT}, /*time*/
{"jobc", "JOBC", pr_nop, sr_nop, 4, 0, XXX, AN|RIGHT},
{"ktrace", "KTRACE", pr_nop, sr_nop, 8, 0, BSD, AN|RIGHT},
{"ktracep", "KTRACEP", pr_nop, sr_nop, 8, 0, BSD, AN|RIGHT},
-{"label", "LABEL", pr_nop, sr_nop, 25, 0, SGI, AN|LEFT},
+{"label", "LABEL", pr_nop, sr_nop, 25, 0, SGI, PO|LEFT},
{"lim", "LIM", pr_lim, sr_rss_rlim, 5, 0, BSD, AN|RIGHT},
{"login", "LOGNAME", pr_nop, sr_nop, 8, 0, BSD, AN|LEFT}, /*logname*/ /* double check */
{"logname", "LOGNAME", pr_nop, sr_nop, 8, 0, XXX, AN|LEFT}, /*login*/
--- /dev/null
+.\" slabtop.1 - manpage for the slabtop(1) utility, part of procps
+.\"
+.\" Copyright (C) 2003 Chris Rivera
+.\" Licensed under the terms of the GNU Library General Public License, v2
+.TH SLABTOP 1 "13 Sep 2003" "Linux" "Linux User's Manual"
+.SH NAME
+slabtop \- display kernel slab cache information in real time
+
+.SH SYNOPSIS
+.BI "slabtop [ " options " ] "
+
+.SH DESCRIPTION
+.BR slabtop (1)
+displays detailed kernel slab cache information in real time. It displays a
+listing of the top caches sorted by one of the listed sort criterias. It also
+displays a statistics header filled with slab layer information.
+
+.SH OPTIONS
+Normal invocation of
+.BR slabtop (1)
+does not require any options. The behavior, however, can be fine-tuned by
+specifying one or more of the following flags:
+.TP
+.B \-\^\-delay=n, \-d n
+Refresh the display every n seconds. By default,
+.BR slabtop (1)
+refreshes the display every three seconds. To exit the program, hit
+.BR q.
+.TP
+.B \-\^\-sort=S, \-s S
+Sort by S, where S is one of the sort criteria.
+.TP
+.B \-\^\-once, \-o
+Display the output once and then exit.
+.TP
+.B \-\^\-version, \-V
+Display version information and exit.
+.TP
+.B \-\^\-help
+Display usage information and exit.
+
+.SH SORT CRITERIA
+The following are valid sort criteria used to sort the individual slab caches
+and thereby determine what are the "top" slab caches to display. The default
+sort criteria is to sort by the number of objects ("o").
+
+The sort criteria can also be changed while slabtop is running by pressing
+the associated character.
+.TP
+.BR a:
+sort by number of active objects
+.TP
+.BR b:
+sort by objects per slab
+.TP
+.BR c:
+sort by cache size
+.TP
+.BR l:
+sort by number of slabs
+.TP
+.BR v
+sort by number of active slabs
+.TP
+.BR n:
+sort by name
+.TP
+.BR o:
+sort by number of objects
+.TP
+.BR p:
+sort by pages per slab
+.TP
+.BR s:
+sort by object size
+.TP
+.BR u:
+sort by cache utilization
+
+.SH COMMANDS
+.BR slabtop (1)
+accepts keyboard commands from the user during use. The following are
+supported. In the case of letters, both cases are accepted.
+
+Each of the valid sort characters are also accepted, to change the sort
+routine. See the section
+.IR "SORT CRITERIA" .
+
+.TP
+.BR <SPACEBAR>
+Refresh the screen.
+.TP
+.BR Q
+Quit the program.
+
+.SH FILES
+.IR /proc/slabinfo " \-\- slab information"
+
+.SH "SEE ALSO"
+.BR free (1),
+.BR ps (1),
+.BR top (1),
+.BR vmstat (8)
+
+.SH NOTES
+Currently,
+.BR slabtop (1)
+requires a 2.4 or later kernel (specifically, a version 1.1 or later
+.IR /proc/slabinfo ).
+Kernel 2.2 should be supported in the future.
+
+.SH AUTHORS
+Written by Chris Rivera and Robert Love.
+
+.BR slabtop (1)
+was inspired by Martin Bligh's perl script,
+.BR vmtop .
+
+The procps package is maintained by Robert Love and was created by Michael
+Johnson.
+
+Send bug reports to <procps-list@redhat.com>.
--- /dev/null
+/*
+ * slabtop.c - utility to display kernel slab information.
+ *
+ * Chris Rivera <cmrivera@ufl.edu>
+ * Robert Love <rml@tech9.net>
+ *
+ * This program is licensed under the GNU Library General Public License, v2
+ *
+ * Copyright (C) 2003 Chris Rivera
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <ncurses.h>
+#include <termios.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+
+#include "proc/slab.h"
+#include "proc/version.h"
+
+#define DEF_SORT_FUNC sort_nr_objs
+#define SLAB_STAT_ZERO { nr_objs: 0 }
+
+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);
+}
+
+/*
+ * term_size - set the globals 'cols' and 'rows' to the current terminal size
+ */
+static void term_size(int unused)
+{
+ struct winsize ws;
+ (void) unused;
+
+ if ((ioctl(1, 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)
+{
+ (void) unused;
+
+ delay = 0;
+}
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr, "usage: %s [options]\n\n", cmd);
+ fprintf(stderr, "options:\n");
+ fprintf(stderr, " --delay=n, -d n "
+ "delay n seconds between updates\n");
+ fprintf(stderr, " --once, -o "
+ "only display once, then exit\n");
+ fprintf(stderr, " --sort=S, -s S "
+ "specify sort criteria S (see below)\n");
+ fprintf(stderr, " --version, -V "
+ "display version information and exit\n");
+ fprintf(stderr, " --help display this help and exit\n\n");
+ fprintf(stderr, "The following are valid sort criteria:\n");
+ fprintf(stderr, " a: sort by number of active objects\n");
+ fprintf(stderr, " b: sort by objects per slab\n");
+ fprintf(stderr, " c: sort by cache size\n");
+ fprintf(stderr, " l: sort by number of slabs\n");
+ fprintf(stderr, " v: sort by number of active slabs\n");
+ fprintf(stderr, " n: sort by name\n");
+ fprintf(stderr, " o: sort by number of objects\n");
+ fprintf(stderr, " p: sort by pages per slab\n");
+ fprintf(stderr, " s: sort by object size\n");
+ fprintf(stderr, " u: sort by cache utilization\n");
+}
+
+/*
+ * 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)
+{
+ switch (key) {
+ case 'n':
+ return sort_name;
+ case 'o':
+ return sort_nr_objs;
+ case 'a':
+ return sort_nr_active_objs;
+ case 's':
+ return sort_obj_size;
+ case 'b':
+ return sort_objs_per_slab;
+ case 'p':
+ return sort_pages_per_slab;
+ case 'l':
+ return sort_nr_slabs;
+ case 'v':
+ return sort_nr_active_slabs;
+ case 'c':
+ return sort_cache_size;
+ case 'u':
+ return sort_use;
+ default:
+ return DEF_SORT_FUNC;
+ }
+}
+
+static void parse_input(char c)
+{
+ 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;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int o;
+ unsigned short old_rows;
+ struct slab_info *slab_list = NULL;
+
+ struct option longopts[] = {
+ { "delay", 1, NULL, 'd' },
+ { "sort", 1, NULL, 's' },
+ { "once", 0, NULL, 'o' },
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ sort_func = DEF_SORT_FUNC;
+
+ while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
+ int ret = 1;
+
+ switch (o) {
+ case 'd':
+ errno = 0;
+ delay = strtol(optarg, NULL, 10);
+ if (errno) {
+ perror("strtoul");
+ return 1;
+ }
+ if (delay < 0) {
+ fprintf(stderr, "error: can't have a "\
+ "negative delay\n");
+ exit(1);
+ }
+ break;
+ case 's':
+ sort_func = set_sort_func(optarg[0]);
+ break;
+ case 'o':
+ delay = 0;
+ break;
+ case 'V':
+ display_version();
+ return 0;
+ case 'h':
+ ret = 0;
+ default:
+ usage(argv[0]);
+ return ret;
+ }
+ }
+
+ if (tcgetattr(0, &saved_tty) == -1)
+ perror("tcgetattr");
+
+ initscr();
+ term_size(0);
+ old_rows = rows;
+ resizeterm(rows, cols);
+ signal(SIGWINCH, term_size);
+ signal(SIGINT, sigint_handler);
+
+ do {
+ struct slab_info *curr;
+ struct slab_stat stats = SLAB_STAT_ZERO;
+ struct timeval tv;
+ fd_set readfds;
+ char c;
+ int i;
+
+ if (get_slabinfo(&slab_list, &stats))
+ break;
+
+ if (old_rows != rows) {
+ resizeterm(rows, cols);
+ old_rows = rows;
+ }
+
+ move(0,0);
+ printw( " Active / Total Objects (%% used) : "
+ "%d / %d (%.1f%%)\n"
+ " Active / Total Slabs (%% used) : "
+ "%d / %d (%.1f%%)\n"
+ " Active / Total Caches (%% used) : "
+ "%d / %d (%.1f%%)\n"
+ " Active / Total Size (%% used) : "
+ "%.2fK / %.2fK (%.1f%%)\n"
+ " Minimum / Average / Maximum Object : "
+ "%.2fK / %.2fK / %.2fK\n\n",
+ stats.nr_active_objs, stats.nr_objs,
+ 100.0 * stats.nr_active_objs / stats.nr_objs,
+ stats.nr_active_slabs, stats.nr_slabs,
+ 100.0 * stats.nr_active_slabs / stats.nr_slabs,
+ stats.nr_active_caches, stats.nr_caches,
+ 100.0 * stats.nr_active_caches / stats.nr_caches,
+ stats.active_size / 1024.0, stats.total_size / 1024.0,
+ 100.0 * stats.active_size / stats.total_size,
+ 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);
+ printw( "%6s %6s %4s %8s %6s %8s %10s %-23s\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++) {
+ printw("%6d %6d %3d%% %7.2fK %6d %8d %9dK %-23s\n",
+ curr->nr_objs, curr->nr_active_objs, curr->use,
+ curr->obj_size / 1024.0, curr->nr_slabs,
+ curr->objs_per_slab, curr->cache_size / 1024,
+ curr->name);
+ curr = curr->next;
+ }
+
+ refresh();
+ put_slabinfo(slab_list);
+
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+ tv.tv_sec = delay;
+ tv.tv_usec = 0;
+ if (select(1, &readfds, NULL, NULL, &tv) > 0) {
+ if (read(0, &c, 1) != 1)
+ break;
+ parse_input(c);
+ }
+ } while (delay);
+
+ tcsetattr(0, TCSAFLUSH, &saved_tty);
+ free_slabinfo(slab_list);
+ return 0;
+}
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
putp(tg2(0, Screen_rows));
putp(Cap_curs_norm);
+ putp(Cap_smam);
+ putp("\n");
fflush(stdout);
raise(SIGSTOP);
/* later, after SIGCONT... */
ZAP_TIMEOUT
if (!Batch)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);
+ putp(Cap_clr_scr);
+ putp(Cap_rmam);
}
\f