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
|
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
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
|
procps-3.1.14 --> procps-3.1.15
|
||||||
|
|
||||||
install to /lib64 if it exists
|
install to /lib64 if it exists
|
||||||
|
2
README
2
README
@ -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:
|
||||||
|
@ -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 -->
|
||||||
|
@ -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: *;
|
||||||
};
|
};
|
||||||
|
@ -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
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
|
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
|
||||||
|
@ -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
|
||||||
|
@ -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
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user