add slabtop, fix top ^Z terminal handling

This commit is contained in:
albert 2004-01-24 22:33:56 +00:00
parent c36c11c6b2
commit efd8648fc7
14 changed files with 896 additions and 20 deletions

View File

@ -18,9 +18,9 @@
VERSION := 3 VERSION := 3
SUBVERSION := 1 SUBVERSION := 1
MINORVERSION := 14 MINORVERSION := 15
TARVERSION := 3.1.14 TARVERSION := 3.1.15
LIBVERSION := 3.1.14 LIBVERSION := 3.1.15
############ vars ############ vars
@ -51,18 +51,22 @@ usr/include := $(DESTDIR)/usr/include/
BINFILES := $(usr/bin)uptime $(usr/bin)tload $(usr/bin)free $(usr/bin)w \ 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)top $(usr/bin)vmstat $(usr/bin)watch $(usr/bin)skill \
$(usr/bin)snice $(bin)kill $(sbin)sysctl $(usr/bin)pmap \ $(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 \ 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)top.1 $(man1)watch.1 $(man1)skill.1 $(man1)kill.1 \
$(man1)snice.1 $(man1)pgrep.1 $(man1)pkill.1 $(man1)pmap.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 \ TARFILES := AUTHORS BUGS NEWS README TODO COPYING COPYING.LIB \
Makefile procps.lsm procps.spec v t README.top \ Makefile procps.lsm procps.spec v t README.top \
minimal.c $(notdir $(MANFILES)) \ minimal.c $(notdir $(MANFILES)) \
uptime.c tload.c free.c w.c top.c vmstat.c watch.c skill.c \ 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 CURSES := -I/usr/include/ncurses -lncurses
@ -98,7 +102,7 @@ ALL_LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .a .o .c .s .h .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)) ALL := $(notdir $(BINFILES))
@ -141,6 +145,12 @@ tar: $(TARFILES)
tar cf procps-$(TARVERSION).tar procps-$(TARVERSION) tar cf procps-$(TARVERSION).tar procps-$(TARVERSION)
gzip -9 procps-$(TARVERSION).tar 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: clean:
rm -f $(CLEAN) rm -f $(CLEAN)
@ -171,7 +181,7 @@ w.o: w.c
pmap w uptime tload free sysctl vmstat utmp pgrep skill: % : %.o $(LIBPROC) pmap w uptime tload free sysctl vmstat utmp pgrep skill: % : %.o $(LIBPROC)
$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^
top: % : %.o $(LIBPROC) slabtop top: % : %.o $(LIBPROC)
$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(CURSES) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(CURSES)
watch: % : %.o watch: % : %.o

5
NEWS
View File

@ -1,3 +1,8 @@
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 procps-3.1.14 --> procps-3.1.15
install to /lib64 if it exists install to /lib64 if it exists

2
README
View File

@ -29,7 +29,7 @@ INSTALLATION
Suppose you wanted to install stuff in strange places. Suppose you wanted to install stuff in strange places.
You might do something like this: 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 If cross-compiling, you might need to set lib64 to
either "lib" or "lib64", like one of these examples: either "lib" or "lib64", like one of these examples:

View File

@ -36,7 +36,7 @@
#define MINOR_OF(d) ((unsigned)minor(d)) #define MINOR_OF(d) ((unsigned)minor(d))
#else #else
#define MAJOR_OF(d) ( ((unsigned)(d)>>8u) & 0xfffu ) #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 major
#undef minor #undef minor
#define major <-- do not use --> #define major <-- do not use -->

View File

@ -14,6 +14,7 @@ global:
kb_active; kb_inactive; kb_main_buffers; kb_main_cached; kb_active; kb_inactive; kb_main_buffers; kb_main_cached;
kb_main_free; kb_main_total; kb_main_used; kb_swap_free; kb_main_free; kb_main_total; kb_main_used; kb_swap_free;
kb_swap_total; kb_swap_used; kb_main_shared; 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: *; local: *;
}; };

View File

@ -68,6 +68,8 @@
#define LABEL_OFFSET #define LABEL_OFFSET
#endif #endif
#define STRINGIFY_ARG(a) #a
#define STRINGIFY(a) STRINGIFY_ARG(a)
// marks old junk, to warn non-procps library users // marks old junk, to warn non-procps library users
#if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 #if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3

290
proc/slab.c Normal file
View File

@ -0,0 +1,290 @@
/*
* 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;
}

39
proc/slab.h Normal file
View File

@ -0,0 +1,39 @@
#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 */

View File

@ -1,15 +1,15 @@
Begin4 Begin4
Title: procps Title: procps
Version: 3.1.14 Version: 3.1.15
Entered-date: 2003-09-26 Entered-date: 2003-12-24
Description: Linux system utilities Description: Linux system utilities
Keywords: procps /proc libproc sysctl pmap ps uptime tload Keywords: procps /proc libproc sysctl pmap ps uptime tload
free w top vmstat watch skill snice kill pgrep pkill free w top vmstat watch skill snice kill pgrep pkill
Author: Albert Cahalan, Michael K. Johnson, Jim Warner, etc. Author: Albert Cahalan, Michael K. Johnson, Jim Warner, etc.
Maintained-by: various <procps-feedback@lists.sf.net> Maintained-by: various <procps-feedback@lists.sf.net>
Primary-site: http://procps.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 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 Copying-policy: mixed
End End

View File

@ -3,7 +3,7 @@ Summary: System and process monitoring utilities
Name: procps Name: procps
%define major_version 3 %define major_version 3
%define minor_version 1 %define minor_version 1
%define revision 14 %define revision 15
%define version %{major_version}.%{minor_version}.%{revision} %define version %{major_version}.%{minor_version}.%{revision}
Version: %{version} Version: %{version}
Release: 1 Release: 1

View File

@ -943,8 +943,8 @@ static int pr_context(char *restrict const outbuf, const proc_t *restrict const
int fd; int fd;
// wchan file is suitable for testing // 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/wchan", pp->tgid);
snprintf(filename, sizeof filename, "/proc/%d/task/%d/attr/current", pp->tgid, pp->tid); snprintf(filename, sizeof filename, "/proc/%d/attr/current", pp->tgid);
fd = open(filename, O_RDONLY, 0); fd = open(filename, O_RDONLY, 0);
if(likely(fd==-1)) goto fail; if(likely(fd==-1)) goto fail;
@ -1052,7 +1052,7 @@ static const format_struct format_array[] = {
{"cnswap", "-", pr_nop, sr_cnswap, 1, 0, LNX, AN|RIGHT}, {"cnswap", "-", pr_nop, sr_cnswap, 1, 0, LNX, AN|RIGHT},
{"comm", "COMMAND", pr_comm, sr_nop, 16, COM, U98, PO|UNLIMITED}, /*ucomm*/ {"comm", "COMMAND", pr_comm, sr_nop, 16, COM, U98, PO|UNLIMITED}, /*ucomm*/
{"command", "COMMAND", pr_args, sr_nop, 16, ARG, XXX, PO|UNLIMITED}, /*args*/ {"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*/ {"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? */ {"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*/ {"cputime", "TIME", pr_time, sr_nop, 8, 0, DEC, ET|RIGHT}, /*time*/
@ -1092,7 +1092,7 @@ static const format_struct format_array[] = {
{"jobc", "JOBC", pr_nop, sr_nop, 4, 0, XXX, AN|RIGHT}, {"jobc", "JOBC", pr_nop, sr_nop, 4, 0, XXX, AN|RIGHT},
{"ktrace", "KTRACE", pr_nop, sr_nop, 8, 0, BSD, AN|RIGHT}, {"ktrace", "KTRACE", pr_nop, sr_nop, 8, 0, BSD, AN|RIGHT},
{"ktracep", "KTRACEP", 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}, {"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 */ {"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*/ {"logname", "LOGNAME", pr_nop, sr_nop, 8, 0, XXX, AN|LEFT}, /*login*/

122
slabtop.1 Normal file
View File

@ -0,0 +1,122 @@
.\" 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>.

403
slabtop.c Normal file
View File

@ -0,0 +1,403 @@
/*
* 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;
}

4
top.c
View File

@ -446,12 +446,16 @@ static void suspend (int dont_care_sig)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty); tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
putp(tg2(0, Screen_rows)); putp(tg2(0, Screen_rows));
putp(Cap_curs_norm); putp(Cap_curs_norm);
putp(Cap_smam);
putp("\n");
fflush(stdout); fflush(stdout);
raise(SIGSTOP); raise(SIGSTOP);
/* later, after SIGCONT... */ /* later, after SIGCONT... */
ZAP_TIMEOUT ZAP_TIMEOUT
if (!Batch) if (!Batch)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty); tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);
putp(Cap_clr_scr);
putp(Cap_rmam);
} }