add slabtop, fix top ^Z terminal handling
This commit is contained in:
parent
c36c11c6b2
commit
efd8648fc7
26
Makefile
26
Makefile
@ -18,9 +18,9 @@
|
||||
|
||||
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
|
||||
|
||||
@ -51,18 +51,22 @@ usr/include := $(DESTDIR)/usr/include/
|
||||
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
|
||||
|
||||
@ -98,7 +102,7 @@ ALL_LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
|
||||
.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))
|
||||
|
||||
@ -141,6 +145,12 @@ tar: $(TARFILES)
|
||||
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)
|
||||
|
||||
@ -171,7 +181,7 @@ w.o: w.c
|
||||
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
|
||||
|
5
NEWS
5
NEWS
@ -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
|
||||
|
||||
install to /lib64 if it exists
|
||||
|
2
README
2
README
@ -29,7 +29,7 @@ INSTALLATION
|
||||
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:
|
||||
|
@ -36,7 +36,7 @@
|
||||
#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 -->
|
||||
|
@ -14,6 +14,7 @@ global:
|
||||
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: *;
|
||||
};
|
||||
|
@ -68,6 +68,8 @@
|
||||
#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
|
||||
|
290
proc/slab.c
Normal file
290
proc/slab.c
Normal 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
39
proc/slab.h
Normal 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 */
|
@ -1,15 +1,15 @@
|
||||
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
|
||||
|
@ -3,7 +3,7 @@ Summary: System and process monitoring utilities
|
||||
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
|
||||
|
@ -943,8 +943,8 @@ static int pr_context(char *restrict const outbuf, const proc_t *restrict const
|
||||
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;
|
||||
@ -1052,7 +1052,7 @@ static const format_struct format_array[] = {
|
||||
{"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*/
|
||||
@ -1092,7 +1092,7 @@ static const format_struct format_array[] = {
|
||||
{"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*/
|
||||
|
122
slabtop.1
Normal file
122
slabtop.1
Normal 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
403
slabtop.c
Normal 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
4
top.c
@ -446,12 +446,16 @@ static void suspend (int dont_care_sig)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user