add slabtop, fix top ^Z terminal handling
This commit is contained in:
@@ -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 */
|
Reference in New Issue
Block a user