fe75e26ab6
The entire tree's polluted with inappropriate trailing whitespace. This commit rids our environment of all of those useless keystrokes. Unfortunately, it sure ain't a permanent solution and requires every contributor to instruct their editor(s) to prevent or eliminate them. Plus it's strongly recommended we all insert something like what's shown below to our '.gitconfig' file so as to provide at least some warnings when we try to apply any patches (git am) that do contain the #@!%& things! References(s): ~/.gitconfig excerpt --------------------------------- [core] whitespace = trailing-space, space-before-tab, blank-at-eof [apply] whitespace = warn --------------------------------- ~/.gitconfig excerpt Signed-off-by: Jim Warner <james.warner@comcast.net>
354 lines
9.5 KiB
C
354 lines
9.5 KiB
C
/*
|
|
* slab.c - slab related functions for libproc
|
|
*
|
|
* Chris Rivera <cmrivera@ufl.edu>
|
|
* Robert Love <rml@tech9.net>
|
|
*
|
|
* Copyright (C) 2003 Chris Rivera
|
|
* Copyright 2004, Albert Cahalan
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <ctype.h>
|
|
|
|
#include "slab.h"
|
|
#include "procps.h"
|
|
#include "alloc.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 = xmalloc(sizeof(struct slab_info));
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* slab_badname_detect - return true if current slab was declared with
|
|
* whitespaces for instance
|
|
* FIXME :Other cases ?
|
|
*/
|
|
|
|
static int slab_badname_detect(const char *restrict buffer)
|
|
{
|
|
int numberarea=0;
|
|
while (*buffer){
|
|
if((*buffer)==' ')
|
|
numberarea=1;
|
|
if(isalpha(*buffer)&&numberarea)
|
|
return 1;
|
|
buffer++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 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.x (2.6 kernels)
|
|
// Note: difference between 2.0 and 2.1 is in the ": globalstat" part where version 2.1
|
|
// has extra column <nodeallocs>. We don't use ": globalstat" part in both versions.
|
|
//
|
|
// Formats (we don't use "statistics" extensions)
|
|
//
|
|
// slabinfo - version: 2.1
|
|
// # name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
|
|
// : tunables <batchcount> <limit> <sharedfactor> \
|
|
// : slabdata <active_slabs> <num_slabs> <sharedavail>
|
|
//
|
|
// slabinfo - version: 2.1 (statistics)
|
|
// # name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
|
|
// : tunables <batchcount> <limit> <sharedfactor> \
|
|
// : slabdata <active_slabs> <num_slabs> <sharedavail> \
|
|
// : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit> <nodeallocs> \
|
|
// : cpustat <allochit> <allocmiss> <freehit> <freemiss>
|
|
//
|
|
// slabinfo - version: 2.0
|
|
// # name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
|
|
// : tunables <batchcount> <limit> <sharedfactor> \
|
|
// : slabdata <active_slabs> <num_slabs> <sharedavail>
|
|
//
|
|
// slabinfo - version: 2.0 (statistics)
|
|
// # name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
|
|
// : tunables <batchcount> <limit> <sharedfactor> \
|
|
// : slabdata <active_slabs> <num_slabs> <sharedavail> \
|
|
// : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit> \
|
|
// : cpustat <allochit> <allocmiss> <freehit> <freemiss>
|
|
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
|
|
if (prev)
|
|
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 = (unsigned long)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 += (unsigned long)curr->nr_objs * curr->obj_size;
|
|
stats->active_size += (unsigned long)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, "\rerror 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
|
|
if (prev)
|
|
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 your slabinfo version 1.1\n\r");
|
|
if(slab_badname_detect(buffer))
|
|
fprintf(stderr, "Found an error in cache name at line %s\n", buffer);
|
|
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 = (unsigned long)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 += (unsigned long)curr->nr_objs * curr->obj_size;
|
|
stats->active_size += (unsigned long)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, "\rerror 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 " SLABINFO_FILE);
|
|
return 1;
|
|
}
|
|
|
|
if (!fgets(buffer, SLABINFO_VER_LEN, slabfile)) {
|
|
fprintf(stderr, "cannot read from slabinfo\n");
|
|
fclose(slabfile);
|
|
return 1;
|
|
}
|
|
|
|
if (sscanf(buffer, "slabinfo - version: %d.%d", &major, &minor) != 2) {
|
|
fprintf(stderr, "not the good old slabinfo we know\n");
|
|
fclose(slabfile);
|
|
return 1;
|
|
}
|
|
|
|
if (major == 2)
|
|
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");
|
|
fclose(slabfile);
|
|
return 1;
|
|
}
|
|
|
|
fclose(slabfile);
|
|
|
|
return ret;
|
|
}
|