2007-05-07 01:49:48 +04:00
/*
* Slabinfo : Tool to get reports about slabs
*
2008-07-04 20:59:22 +04:00
* ( C ) 2007 sgi , Christoph Lameter
2011-06-01 21:26:00 +04:00
* ( C ) 2011 Linux Foundation , Christoph Lameter
2007-05-07 01:49:48 +04:00
*
2011-06-01 21:26:00 +04:00
* Compile with :
2007-05-07 01:49:48 +04:00
*
* gcc - o slabinfo slabinfo . c
*/
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <dirent.h>
2007-10-17 10:31:29 +04:00
# include <strings.h>
2007-05-07 01:49:48 +04:00
# include <string.h>
# include <unistd.h>
# include <stdarg.h>
# include <getopt.h>
# include <regex.h>
2007-05-09 13:32:37 +04:00
# include <errno.h>
2007-05-07 01:49:48 +04:00
# define MAX_SLABS 500
# define MAX_ALIASES 500
# define MAX_NODES 1024
struct slabinfo {
char * name ;
int alias ;
int refs ;
int aliases , align , cache_dma , cpu_slabs , destroy_by_rcu ;
int hwcache_align , object_size , objs_per_slab ;
int sanity_checks , slab_size , store_user , trace ;
int order , poison , reclaim_account , red_zone ;
2008-04-14 20:11:40 +04:00
unsigned long partial , objects , slabs , objects_partial , objects_total ;
2008-02-08 04:47:41 +03:00
unsigned long alloc_fastpath , alloc_slowpath ;
unsigned long free_fastpath , free_slowpath ;
unsigned long free_frozen , free_add_partial , free_remove_partial ;
unsigned long alloc_from_partial , alloc_slab , free_slab , alloc_refill ;
unsigned long cpuslab_flush , deactivate_full , deactivate_empty ;
unsigned long deactivate_to_head , deactivate_to_tail ;
2008-04-30 03:14:46 +04:00
unsigned long deactivate_remote_frees , order_fallback ;
2011-06-01 21:26:00 +04:00
unsigned long cmpxchg_double_cpu_fail , cmpxchg_double_fail ;
unsigned long alloc_node_mismatch , deactivate_bypass ;
2011-08-10 01:12:28 +04:00
unsigned long cpu_partial_alloc , cpu_partial_free ;
2007-05-07 01:49:48 +04:00
int numa [ MAX_NODES ] ;
int numa_partial [ MAX_NODES ] ;
} slabinfo [ MAX_SLABS ] ;
struct aliasinfo {
char * name ;
char * ref ;
struct slabinfo * slab ;
} aliasinfo [ MAX_ALIASES ] ;
2015-11-06 05:45:34 +03:00
int slabs ;
int actual_slabs ;
int aliases ;
int alias_targets ;
int highest_node ;
2007-05-07 01:49:48 +04:00
char buffer [ 4096 ] ;
2015-11-06 05:45:34 +03:00
int show_empty ;
int show_report ;
int show_alias ;
int show_slab ;
2007-05-07 01:49:48 +04:00
int skip_zero = 1 ;
2015-11-06 05:45:34 +03:00
int show_numa ;
int show_track ;
int show_first_alias ;
int validate ;
int shrink ;
int show_inverted ;
int show_single_ref ;
int show_totals ;
int sort_size ;
int sort_active ;
int set_debug ;
int show_ops ;
int show_activity ;
2015-11-06 05:45:20 +03:00
int output_lines = - 1 ;
2015-11-06 05:45:22 +03:00
int sort_loss ;
2015-11-06 05:45:28 +03:00
int extended_totals ;
2015-11-06 05:45:31 +03:00
int show_bytes ;
2007-05-09 13:32:37 +04:00
/* Debug options */
2015-11-06 05:45:34 +03:00
int sanity ;
int redzone ;
int poison ;
int tracking ;
int tracing ;
2007-05-07 01:49:48 +04:00
int page_size ;
regex_t pattern ;
2009-09-23 03:43:42 +04:00
static void fatal ( const char * x , . . . )
2007-05-07 01:49:48 +04:00
{
va_list ap ;
va_start ( ap , x ) ;
vfprintf ( stderr , x , ap ) ;
va_end ( ap ) ;
2007-10-17 10:31:29 +04:00
exit ( EXIT_FAILURE ) ;
2007-05-07 01:49:48 +04:00
}
2009-09-23 03:43:42 +04:00
static void usage ( void )
2007-05-07 01:49:48 +04:00
{
2011-06-01 21:26:00 +04:00
printf ( " slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation. \n \n "
2007-05-09 13:32:37 +04:00
" slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp] \n "
2007-05-07 01:49:48 +04:00
" -a|--aliases Show aliases \n "
2008-02-08 04:47:41 +03:00
" -A|--activity Most active slabs first \n "
2007-05-09 13:32:37 +04:00
" -d<options>|--debug=<options> Set/Clear Debug options \n "
2008-02-08 04:47:41 +03:00
" -D|--display-active Switch line format to activity \n "
" -e|--empty Show empty slabs \n "
2007-05-09 13:32:37 +04:00
" -f|--first-alias Show first alias \n "
2007-05-07 01:49:48 +04:00
" -h|--help Show usage information \n "
2007-05-09 13:32:37 +04:00
" -i|--inverted Inverted list \n "
" -l|--slabs Show slabs \n "
2007-05-07 01:49:48 +04:00
" -n|--numa Show NUMA information \n "
2007-05-09 13:32:37 +04:00
" -o|--ops Show kmem_cache_ops \n "
2007-05-07 01:49:48 +04:00
" -s|--shrink Shrink slabs \n "
2007-05-09 13:32:37 +04:00
" -r|--report Detailed report on single slabs \n "
" -S|--Size Sort by size \n "
2007-05-07 01:49:48 +04:00
" -t|--tracking Show alloc/free information \n "
" -T|--Totals Show summary information \n "
2007-05-09 13:32:37 +04:00
" -v|--validate Validate slabs \n "
2007-05-07 01:49:48 +04:00
" -z|--zero Include empty slabs \n "
" -1|--1ref Single reference \n "
2015-11-06 05:45:20 +03:00
" -N|--lines=K Show the first K slabs \n "
2015-11-06 05:45:22 +03:00
" -L|--Loss Sort by loss \n "
2015-11-06 05:45:28 +03:00
" -X|--Xtotals Show extended summary information \n "
2015-11-06 05:45:31 +03:00
" -B|--Bytes Show size in bytes \n "
2007-05-09 13:32:37 +04:00
" \n Valid debug options (FZPUT may be combined) \n "
" a / A Switch on all debug options (=FZUP) \n "
" - Switch off all debug options \n "
2016-03-16 00:55:06 +03:00
" f / F Sanity Checks (SLAB_CONSISTENCY_CHECKS) \n "
2007-05-09 13:32:37 +04:00
" z / Z Redzoning \n "
" p / P Poisoning \n "
" u / U Tracking \n "
" t / T Tracing \n "
2007-05-07 01:49:48 +04:00
) ;
}
2009-09-23 03:43:42 +04:00
static unsigned long read_obj ( const char * name )
2007-05-07 01:49:48 +04:00
{
FILE * f = fopen ( name , " r " ) ;
if ( ! f )
buffer [ 0 ] = 0 ;
else {
2007-10-17 10:31:29 +04:00
if ( ! fgets ( buffer , sizeof ( buffer ) , f ) )
2007-05-07 01:49:48 +04:00
buffer [ 0 ] = 0 ;
fclose ( f ) ;
if ( buffer [ strlen ( buffer ) ] = = ' \n ' )
buffer [ strlen ( buffer ) ] = 0 ;
}
return strlen ( buffer ) ;
}
/*
* Get the contents of an attribute
*/
2009-09-23 03:43:42 +04:00
static unsigned long get_obj ( const char * name )
2007-05-07 01:49:48 +04:00
{
if ( ! read_obj ( name ) )
return 0 ;
return atol ( buffer ) ;
}
2009-09-23 03:43:42 +04:00
static unsigned long get_obj_and_str ( const char * name , char * * x )
2007-05-07 01:49:48 +04:00
{
unsigned long result = 0 ;
char * p ;
* x = NULL ;
if ( ! read_obj ( name ) ) {
x = NULL ;
return 0 ;
}
result = strtoul ( buffer , & p , 10 ) ;
while ( * p = = ' ' )
p + + ;
if ( * p )
* x = strdup ( p ) ;
return result ;
}
2009-09-23 03:43:42 +04:00
static void set_obj ( struct slabinfo * s , const char * name , int n )
2007-05-07 01:49:48 +04:00
{
char x [ 100 ] ;
2007-05-09 13:32:37 +04:00
FILE * f ;
2007-05-07 01:49:48 +04:00
2007-10-17 10:31:29 +04:00
snprintf ( x , 100 , " %s/%s " , s - > name , name ) ;
2007-05-09 13:32:37 +04:00
f = fopen ( x , " w " ) ;
2007-05-07 01:49:48 +04:00
if ( ! f )
fatal ( " Cannot write to %s \n " , x ) ;
fprintf ( f , " %d \n " , n ) ;
fclose ( f ) ;
}
2009-09-23 03:43:42 +04:00
static unsigned long read_slab_obj ( struct slabinfo * s , const char * name )
2007-05-09 13:32:37 +04:00
{
char x [ 100 ] ;
FILE * f ;
2007-10-17 10:31:29 +04:00
size_t l ;
2007-05-09 13:32:37 +04:00
2007-10-17 10:31:29 +04:00
snprintf ( x , 100 , " %s/%s " , s - > name , name ) ;
2007-05-09 13:32:37 +04:00
f = fopen ( x , " r " ) ;
if ( ! f ) {
buffer [ 0 ] = 0 ;
l = 0 ;
} else {
l = fread ( buffer , 1 , sizeof ( buffer ) , f ) ;
buffer [ l ] = 0 ;
fclose ( f ) ;
}
return l ;
}
2007-05-07 01:49:48 +04:00
/*
* Put a size string together
*/
2009-09-23 03:43:42 +04:00
static int store_size ( char * buffer , unsigned long value )
2007-05-07 01:49:48 +04:00
{
unsigned long divisor = 1 ;
char trailer = 0 ;
int n ;
2015-11-06 05:45:31 +03:00
if ( ! show_bytes ) {
if ( value > 1000000000UL ) {
divisor = 100000000UL ;
trailer = ' G ' ;
} else if ( value > 1000000UL ) {
divisor = 100000UL ;
trailer = ' M ' ;
} else if ( value > 1000UL ) {
divisor = 100 ;
trailer = ' K ' ;
}
2007-05-07 01:49:48 +04:00
}
value / = divisor ;
n = sprintf ( buffer , " %ld " , value ) ;
if ( trailer ) {
buffer [ n ] = trailer ;
n + + ;
buffer [ n ] = 0 ;
}
if ( divisor ! = 1 ) {
memmove ( buffer + n - 2 , buffer + n - 3 , 4 ) ;
buffer [ n - 2 ] = ' . ' ;
n + + ;
}
return n ;
}
2009-09-23 03:43:42 +04:00
static void decode_numa_list ( int * numa , char * t )
2007-05-07 01:49:48 +04:00
{
int node ;
int nr ;
memset ( numa , 0 , MAX_NODES * sizeof ( int ) ) ;
2007-05-17 09:10:55 +04:00
if ( ! t )
return ;
2007-05-07 01:49:48 +04:00
while ( * t = = ' N ' ) {
t + + ;
node = strtoul ( t , & t , 10 ) ;
if ( * t = = ' = ' ) {
t + + ;
nr = strtoul ( t , & t , 10 ) ;
numa [ node ] = nr ;
if ( node > highest_node )
highest_node = node ;
}
while ( * t = = ' ' )
t + + ;
}
}
2009-09-23 03:43:42 +04:00
static void slab_validate ( struct slabinfo * s )
2007-05-07 01:49:48 +04:00
{
2007-05-18 11:36:43 +04:00
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
2007-05-07 01:49:48 +04:00
set_obj ( s , " validate " , 1 ) ;
}
2009-09-23 03:43:42 +04:00
static void slab_shrink ( struct slabinfo * s )
2007-05-07 01:49:48 +04:00
{
2007-05-18 11:36:43 +04:00
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
2007-05-07 01:49:48 +04:00
set_obj ( s , " shrink " , 1 ) ;
}
int line = 0 ;
2009-09-23 03:43:42 +04:00
static void first_line ( void )
2007-05-07 01:49:48 +04:00
{
2008-02-08 04:47:41 +03:00
if ( show_activity )
2015-11-06 05:45:31 +03:00
printf ( " Name Objects Alloc Free "
" %%Fast Fallb O CmpX UL \n " ) ;
2008-02-08 04:47:41 +03:00
else
2015-11-06 05:45:31 +03:00
printf ( " Name Objects Objsize %s "
2015-11-06 05:45:22 +03:00
" Slabs/Part/Cpu O/S O %%Fr %%Ef Flg \n " ,
2015-11-06 05:45:31 +03:00
sort_loss ? " Loss " : " Space " ) ;
2007-05-07 01:49:48 +04:00
}
/*
* Find the shortest alias of a slab
*/
2009-09-23 03:43:42 +04:00
static struct aliasinfo * find_one_alias ( struct slabinfo * find )
2007-05-07 01:49:48 +04:00
{
struct aliasinfo * a ;
struct aliasinfo * best = NULL ;
for ( a = aliasinfo ; a < aliasinfo + aliases ; a + + ) {
if ( a - > slab = = find & &
( ! best | | strlen ( best - > name ) < strlen ( a - > name ) ) ) {
best = a ;
if ( strncmp ( a - > name , " kmall " , 5 ) = = 0 )
return best ;
}
}
2007-05-09 13:32:37 +04:00
return best ;
2007-05-07 01:49:48 +04:00
}
2009-09-23 03:43:42 +04:00
static unsigned long slab_size ( struct slabinfo * s )
2007-05-07 01:49:48 +04:00
{
return s - > slabs * ( page_size < < s - > order ) ;
}
2009-09-23 03:43:42 +04:00
static unsigned long slab_activity ( struct slabinfo * s )
2008-02-08 04:47:41 +03:00
{
return s - > alloc_fastpath + s - > free_fastpath +
s - > alloc_slowpath + s - > free_slowpath ;
}
2015-11-06 05:45:22 +03:00
static unsigned long slab_waste ( struct slabinfo * s )
{
return slab_size ( s ) - s - > objects * s - > object_size ;
}
2009-09-23 03:43:42 +04:00
static void slab_numa ( struct slabinfo * s , int mode )
2007-05-09 13:32:37 +04:00
{
int node ;
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
if ( ! highest_node ) {
printf ( " \n %s: No NUMA information available. \n " , s - > name ) ;
return ;
}
if ( skip_zero & & ! s - > slabs )
return ;
if ( ! line ) {
printf ( " \n %-21s: " , mode ? " NUMA nodes " : " Slab " ) ;
for ( node = 0 ; node < = highest_node ; node + + )
printf ( " %4d " , node ) ;
printf ( " \n ---------------------- " ) ;
for ( node = 0 ; node < = highest_node ; node + + )
printf ( " ----- " ) ;
printf ( " \n " ) ;
}
printf ( " %-21s " , mode ? " All slabs " : s - > name ) ;
for ( node = 0 ; node < = highest_node ; node + + ) {
char b [ 20 ] ;
store_size ( b , s - > numa [ node ] ) ;
printf ( " %4s " , b ) ;
}
printf ( " \n " ) ;
if ( mode ) {
printf ( " %-21s " , " Partial slabs " ) ;
for ( node = 0 ; node < = highest_node ; node + + ) {
char b [ 20 ] ;
store_size ( b , s - > numa_partial [ node ] ) ;
printf ( " %4s " , b ) ;
}
printf ( " \n " ) ;
}
line + + ;
}
2009-09-23 03:43:42 +04:00
static void show_tracking ( struct slabinfo * s )
2007-05-09 13:32:37 +04:00
{
printf ( " \n %s: Kernel object allocation \n " , s - > name ) ;
printf ( " ----------------------------------------------------------------------- \n " ) ;
if ( read_slab_obj ( s , " alloc_calls " ) )
2011-06-01 21:26:00 +04:00
printf ( " %s " , buffer ) ;
2007-05-09 13:32:37 +04:00
else
printf ( " No Data \n " ) ;
printf ( " \n %s: Kernel object freeing \n " , s - > name ) ;
printf ( " ------------------------------------------------------------------------ \n " ) ;
if ( read_slab_obj ( s , " free_calls " ) )
2011-06-01 21:26:00 +04:00
printf ( " %s " , buffer ) ;
2007-05-09 13:32:37 +04:00
else
printf ( " No Data \n " ) ;
}
2009-09-23 03:43:42 +04:00
static void ops ( struct slabinfo * s )
2007-05-09 13:32:37 +04:00
{
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
if ( read_slab_obj ( s , " ops " ) ) {
printf ( " \n %s: kmem_cache operations \n " , s - > name ) ;
printf ( " -------------------------------------------- \n " ) ;
2011-06-01 21:26:00 +04:00
printf ( " %s " , buffer ) ;
2007-05-09 13:32:37 +04:00
} else
printf ( " \n %s has no kmem_cache operations \n " , s - > name ) ;
}
2009-09-23 03:43:42 +04:00
static const char * onoff ( int x )
2007-05-09 13:32:37 +04:00
{
if ( x )
return " On " ;
return " Off " ;
}
2009-09-23 03:43:42 +04:00
static void slab_stats ( struct slabinfo * s )
2008-02-08 04:47:41 +03:00
{
unsigned long total_alloc ;
unsigned long total_free ;
unsigned long total ;
if ( ! s - > alloc_slab )
return ;
total_alloc = s - > alloc_fastpath + s - > alloc_slowpath ;
total_free = s - > free_fastpath + s - > free_slowpath ;
if ( ! total_alloc )
return ;
printf ( " \n " ) ;
printf ( " Slab Perf Counter Alloc Free %%Al %%Fr \n " ) ;
printf ( " -------------------------------------------------- \n " ) ;
printf ( " Fastpath %8lu %8lu %3lu %3lu \n " ,
s - > alloc_fastpath , s - > free_fastpath ,
s - > alloc_fastpath * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > free_fastpath * 100 / total_free : 0 ) ;
2008-02-08 04:47:41 +03:00
printf ( " Slowpath %8lu %8lu %3lu %3lu \n " ,
total_alloc - s - > alloc_fastpath , s - > free_slowpath ,
( total_alloc - s - > alloc_fastpath ) * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > free_slowpath * 100 / total_free : 0 ) ;
2008-02-08 04:47:41 +03:00
printf ( " Page Alloc %8lu %8lu %3lu %3lu \n " ,
s - > alloc_slab , s - > free_slab ,
s - > alloc_slab * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > free_slab * 100 / total_free : 0 ) ;
2008-02-08 04:47:41 +03:00
printf ( " Add partial %8lu %8lu %3lu %3lu \n " ,
s - > deactivate_to_head + s - > deactivate_to_tail ,
s - > free_add_partial ,
( s - > deactivate_to_head + s - > deactivate_to_tail ) * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > free_add_partial * 100 / total_free : 0 ) ;
2008-02-08 04:47:41 +03:00
printf ( " Remove partial %8lu %8lu %3lu %3lu \n " ,
s - > alloc_from_partial , s - > free_remove_partial ,
s - > alloc_from_partial * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > free_remove_partial * 100 / total_free : 0 ) ;
2008-02-08 04:47:41 +03:00
2011-08-10 01:12:28 +04:00
printf ( " Cpu partial list %8lu %8lu %3lu %3lu \n " ,
s - > cpu_partial_alloc , s - > cpu_partial_free ,
s - > cpu_partial_alloc * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > cpu_partial_free * 100 / total_free : 0 ) ;
2011-08-10 01:12:28 +04:00
2008-02-08 04:47:41 +03:00
printf ( " RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu \n " ,
s - > deactivate_remote_frees , s - > free_frozen ,
s - > deactivate_remote_frees * 100 / total_alloc ,
2012-06-26 05:30:31 +04:00
total_free ? s - > free_frozen * 100 / total_free : 0 ) ;
2008-02-08 04:47:41 +03:00
printf ( " Total %8lu %8lu \n \n " , total_alloc , total_free ) ;
if ( s - > cpuslab_flush )
printf ( " Flushes %8lu \n " , s - > cpuslab_flush ) ;
total = s - > deactivate_full + s - > deactivate_empty +
2011-06-01 21:26:00 +04:00
s - > deactivate_to_head + s - > deactivate_to_tail + s - > deactivate_bypass ;
if ( total ) {
2016-06-25 00:50:21 +03:00
printf ( " \n Slab Deactivation Occurrences %% \n " ) ;
2011-06-01 21:26:00 +04:00
printf ( " ------------------------------------------------- \n " ) ;
printf ( " Slab full %7lu %3lu%% \n " ,
s - > deactivate_full , ( s - > deactivate_full * 100 ) / total ) ;
printf ( " Slab empty %7lu %3lu%% \n " ,
s - > deactivate_empty , ( s - > deactivate_empty * 100 ) / total ) ;
printf ( " Moved to head of partial list %7lu %3lu%% \n " ,
s - > deactivate_to_head , ( s - > deactivate_to_head * 100 ) / total ) ;
printf ( " Moved to tail of partial list %7lu %3lu%% \n " ,
2008-02-08 04:47:41 +03:00
s - > deactivate_to_tail , ( s - > deactivate_to_tail * 100 ) / total ) ;
2011-06-01 21:26:00 +04:00
printf ( " Deactivation bypass %7lu %3lu%% \n " ,
s - > deactivate_bypass , ( s - > deactivate_bypass * 100 ) / total ) ;
printf ( " Refilled from foreign frees %7lu %3lu%% \n " ,
s - > alloc_refill , ( s - > alloc_refill * 100 ) / total ) ;
printf ( " Node mismatch %7lu %3lu%% \n " ,
s - > alloc_node_mismatch , ( s - > alloc_node_mismatch * 100 ) / total ) ;
}
2016-07-21 01:45:05 +03:00
if ( s - > cmpxchg_double_fail | | s - > cmpxchg_double_cpu_fail ) {
2011-06-01 21:26:00 +04:00
printf ( " \n Cmpxchg_double Looping \n ------------------------ \n " ) ;
printf ( " Locked Cmpxchg Double redos %lu \n Unlocked Cmpxchg Double redos %lu \n " ,
s - > cmpxchg_double_fail , s - > cmpxchg_double_cpu_fail ) ;
2016-07-21 01:45:05 +03:00
}
2008-02-08 04:47:41 +03:00
}
2009-09-23 03:43:42 +04:00
static void report ( struct slabinfo * s )
2007-05-09 13:32:37 +04:00
{
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
2007-05-17 09:10:55 +04:00
2015-11-06 05:45:31 +03:00
printf ( " \n Slabcache: %-15s Aliases: %2d Order : %2d Objects: %lu \n " ,
2007-05-17 09:10:55 +04:00
s - > name , s - > aliases , s - > order , s - > objects ) ;
2007-05-09 13:32:37 +04:00
if ( s - > hwcache_align )
printf ( " ** Hardware cacheline aligned \n " ) ;
if ( s - > cache_dma )
printf ( " ** Memory is allocated in a special DMA zone \n " ) ;
if ( s - > destroy_by_rcu )
printf ( " ** Slabs are destroyed via RCU \n " ) ;
if ( s - > reclaim_account )
printf ( " ** Reclaim accounting active \n " ) ;
printf ( " \n Sizes (bytes) Slabs Debug Memory \n " ) ;
printf ( " ------------------------------------------------------------------------ \n " ) ;
printf ( " Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld \n " ,
s - > object_size , s - > slabs , onoff ( s - > sanity_checks ) ,
s - > slabs * ( page_size < < s - > order ) ) ;
printf ( " SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld \n " ,
s - > slab_size , s - > slabs - s - > partial - s - > cpu_slabs ,
onoff ( s - > red_zone ) , s - > objects * s - > object_size ) ;
printf ( " SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld \n " ,
page_size < < s - > order , s - > partial , onoff ( s - > poison ) ,
s - > slabs * ( page_size < < s - > order ) - s - > objects * s - > object_size ) ;
printf ( " Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld \n " ,
s - > slab_size - s - > object_size , s - > cpu_slabs , onoff ( s - > store_user ) ,
( s - > slab_size - s - > object_size ) * s - > objects ) ;
printf ( " Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld \n " ,
s - > align , s - > objs_per_slab , onoff ( s - > trace ) ,
( ( page_size < < s - > order ) - s - > objs_per_slab * s - > slab_size ) *
s - > slabs ) ;
ops ( s ) ;
show_tracking ( s ) ;
slab_numa ( s , 1 ) ;
2008-02-08 04:47:41 +03:00
slab_stats ( s ) ;
2007-05-09 13:32:37 +04:00
}
2007-05-07 01:49:48 +04:00
2009-09-23 03:43:42 +04:00
static void slabcache ( struct slabinfo * s )
2007-05-07 01:49:48 +04:00
{
char size_str [ 20 ] ;
char dist_str [ 40 ] ;
char flags [ 20 ] ;
char * p = flags ;
2007-05-09 13:32:37 +04:00
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
if ( actual_slabs = = 1 ) {
report ( s ) ;
return ;
}
if ( skip_zero & & ! show_empty & & ! s - > slabs )
return ;
if ( show_empty & & s - > slabs )
2007-05-07 01:49:48 +04:00
return ;
2015-11-06 05:45:22 +03:00
if ( sort_loss = = 0 )
store_size ( size_str , slab_size ( s ) ) ;
else
store_size ( size_str , slab_waste ( s ) ) ;
2008-04-14 20:11:40 +04:00
snprintf ( dist_str , 40 , " %lu/%lu/%d " , s - > slabs - s - > cpu_slabs ,
s - > partial , s - > cpu_slabs ) ;
2007-05-07 01:49:48 +04:00
if ( ! line + + )
first_line ( ) ;
if ( s - > aliases )
* p + + = ' * ' ;
if ( s - > cache_dma )
* p + + = ' d ' ;
if ( s - > hwcache_align )
* p + + = ' A ' ;
if ( s - > poison )
* p + + = ' P ' ;
if ( s - > reclaim_account )
* p + + = ' a ' ;
if ( s - > red_zone )
* p + + = ' Z ' ;
if ( s - > sanity_checks )
* p + + = ' F ' ;
if ( s - > store_user )
* p + + = ' U ' ;
if ( s - > trace )
* p + + = ' T ' ;
* p = 0 ;
2008-02-08 04:47:41 +03:00
if ( show_activity ) {
unsigned long total_alloc ;
unsigned long total_free ;
total_alloc = s - > alloc_fastpath + s - > alloc_slowpath ;
total_free = s - > free_fastpath + s - > free_slowpath ;
2011-06-01 21:26:00 +04:00
printf ( " %-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld \n " ,
2008-02-08 04:47:41 +03:00
s - > name , s - > objects ,
total_alloc , total_free ,
total_alloc ? ( s - > alloc_fastpath * 100 / total_alloc ) : 0 ,
2008-04-30 03:14:46 +04:00
total_free ? ( s - > free_fastpath * 100 / total_free ) : 0 ,
2011-06-01 21:26:00 +04:00
s - > order_fallback , s - > order , s - > cmpxchg_double_fail ,
s - > cmpxchg_double_cpu_fail ) ;
2015-11-06 05:45:28 +03:00
} else {
2015-11-06 05:45:31 +03:00
printf ( " %-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s \n " ,
2008-02-08 04:47:41 +03:00
s - > name , s - > objects , s - > object_size , size_str , dist_str ,
s - > objs_per_slab , s - > order ,
s - > slabs ? ( s - > partial * 100 ) / s - > slabs : 100 ,
s - > slabs ? ( s - > objects * s - > object_size * 100 ) /
( s - > slabs * ( page_size < < s - > order ) ) : 100 ,
flags ) ;
2015-11-06 05:45:28 +03:00
}
2007-05-07 01:49:48 +04:00
}
2007-05-09 13:32:37 +04:00
/*
* Analyze debug options . Return false if something is amiss .
*/
2009-09-23 03:43:42 +04:00
static int debug_opt_scan ( char * opt )
2007-05-07 01:49:48 +04:00
{
2007-05-09 13:32:37 +04:00
if ( ! opt | | ! opt [ 0 ] | | strcmp ( opt , " - " ) = = 0 )
return 1 ;
if ( strcasecmp ( opt , " a " ) = = 0 ) {
sanity = 1 ;
poison = 1 ;
redzone = 1 ;
tracking = 1 ;
return 1 ;
}
2007-05-07 01:49:48 +04:00
2007-05-09 13:32:37 +04:00
for ( ; * opt ; opt + + )
2010-10-21 22:01:56 +04:00
switch ( * opt ) {
2007-05-09 13:32:37 +04:00
case ' F ' : case ' f ' :
if ( sanity )
return 0 ;
sanity = 1 ;
break ;
case ' P ' : case ' p ' :
if ( poison )
return 0 ;
poison = 1 ;
break ;
2007-05-07 01:49:48 +04:00
2007-05-09 13:32:37 +04:00
case ' Z ' : case ' z ' :
if ( redzone )
return 0 ;
redzone = 1 ;
break ;
2007-05-07 01:49:48 +04:00
2007-05-09 13:32:37 +04:00
case ' U ' : case ' u ' :
if ( tracking )
return 0 ;
tracking = 1 ;
break ;
2007-05-07 01:49:48 +04:00
2007-05-09 13:32:37 +04:00
case ' T ' : case ' t ' :
if ( tracing )
return 0 ;
tracing = 1 ;
break ;
default :
return 0 ;
}
return 1 ;
2007-05-07 01:49:48 +04:00
}
2009-09-23 03:43:42 +04:00
static int slab_empty ( struct slabinfo * s )
2007-05-07 01:49:48 +04:00
{
2007-05-09 13:32:37 +04:00
if ( s - > objects > 0 )
return 0 ;
2007-05-07 01:49:48 +04:00
2007-05-09 13:32:37 +04:00
/*
* We may still have slabs even if there are no objects . Shrinking will
* remove them .
*/
if ( s - > slabs ! = 0 )
set_obj ( s , " shrink " , 1 ) ;
2007-05-07 01:49:48 +04:00
2007-05-09 13:32:37 +04:00
return 1 ;
}
2009-09-23 03:43:42 +04:00
static void slab_debug ( struct slabinfo * s )
2007-05-09 13:32:37 +04:00
{
2007-05-18 11:36:43 +04:00
if ( strcmp ( s - > name , " * " ) = = 0 )
return ;
2007-05-09 13:32:37 +04:00
if ( sanity & & ! s - > sanity_checks ) {
set_obj ( s , " sanity " , 1 ) ;
}
if ( ! sanity & & s - > sanity_checks ) {
if ( slab_empty ( s ) )
set_obj ( s , " sanity " , 0 ) ;
else
fprintf ( stderr , " %s not empty cannot disable sanity checks \n " , s - > name ) ;
}
if ( redzone & & ! s - > red_zone ) {
if ( slab_empty ( s ) )
set_obj ( s , " red_zone " , 1 ) ;
else
fprintf ( stderr , " %s not empty cannot enable redzoning \n " , s - > name ) ;
}
if ( ! redzone & & s - > red_zone ) {
if ( slab_empty ( s ) )
set_obj ( s , " red_zone " , 0 ) ;
else
fprintf ( stderr , " %s not empty cannot disable redzoning \n " , s - > name ) ;
}
if ( poison & & ! s - > poison ) {
if ( slab_empty ( s ) )
set_obj ( s , " poison " , 1 ) ;
else
fprintf ( stderr , " %s not empty cannot enable poisoning \n " , s - > name ) ;
}
if ( ! poison & & s - > poison ) {
if ( slab_empty ( s ) )
set_obj ( s , " poison " , 0 ) ;
else
fprintf ( stderr , " %s not empty cannot disable poisoning \n " , s - > name ) ;
}
if ( tracking & & ! s - > store_user ) {
if ( slab_empty ( s ) )
set_obj ( s , " store_user " , 1 ) ;
else
fprintf ( stderr , " %s not empty cannot enable tracking \n " , s - > name ) ;
}
if ( ! tracking & & s - > store_user ) {
if ( slab_empty ( s ) )
set_obj ( s , " store_user " , 0 ) ;
else
fprintf ( stderr , " %s not empty cannot disable tracking \n " , s - > name ) ;
}
if ( tracing & & ! s - > trace ) {
if ( slabs = = 1 )
set_obj ( s , " trace " , 1 ) ;
else
fprintf ( stderr , " %s can only enable trace for one slab at a time \n " , s - > name ) ;
}
if ( ! tracing & & s - > trace )
set_obj ( s , " trace " , 1 ) ;
2007-05-07 01:49:48 +04:00
}
2009-09-23 03:43:42 +04:00
static void totals ( void )
2007-05-07 01:49:48 +04:00
{
struct slabinfo * s ;
int used_slabs = 0 ;
char b1 [ 20 ] , b2 [ 20 ] , b3 [ 20 ] , b4 [ 20 ] ;
unsigned long long max = 1ULL < < 63 ;
/* Object size */
unsigned long long min_objsize = max , max_objsize = 0 , avg_objsize ;
/* Number of partial slabs in a slabcache */
unsigned long long min_partial = max , max_partial = 0 ,
avg_partial , total_partial = 0 ;
/* Number of slabs in a slab cache */
unsigned long long min_slabs = max , max_slabs = 0 ,
avg_slabs , total_slabs = 0 ;
/* Size of the whole slab */
unsigned long long min_size = max , max_size = 0 ,
avg_size , total_size = 0 ;
/* Bytes used for object storage in a slab */
unsigned long long min_used = max , max_used = 0 ,
avg_used , total_used = 0 ;
/* Waste: Bytes used for alignment and padding */
unsigned long long min_waste = max , max_waste = 0 ,
avg_waste , total_waste = 0 ;
/* Number of objects in a slab */
unsigned long long min_objects = max , max_objects = 0 ,
avg_objects , total_objects = 0 ;
/* Waste per object */
unsigned long long min_objwaste = max ,
max_objwaste = 0 , avg_objwaste ,
total_objwaste = 0 ;
/* Memory per object */
unsigned long long min_memobj = max ,
max_memobj = 0 , avg_memobj ,
total_objsize = 0 ;
/* Percentage of partial slabs per slab */
unsigned long min_ppart = 100 , max_ppart = 0 ,
avg_ppart , total_ppart = 0 ;
/* Number of objects in partial slabs */
unsigned long min_partobj = max , max_partobj = 0 ,
avg_partobj , total_partobj = 0 ;
/* Percentage of partial objects of all objects in a slab */
unsigned long min_ppartobj = 100 , max_ppartobj = 0 ,
avg_ppartobj , total_ppartobj = 0 ;
for ( s = slabinfo ; s < slabinfo + slabs ; s + + ) {
unsigned long long size ;
unsigned long used ;
unsigned long long wasted ;
unsigned long long objwaste ;
unsigned long percentage_partial_slabs ;
unsigned long percentage_partial_objs ;
if ( ! s - > slabs | | ! s - > objects )
continue ;
used_slabs + + ;
size = slab_size ( s ) ;
used = s - > objects * s - > object_size ;
wasted = size - used ;
objwaste = s - > slab_size - s - > object_size ;
percentage_partial_slabs = s - > partial * 100 / s - > slabs ;
if ( percentage_partial_slabs > 100 )
percentage_partial_slabs = 100 ;
2008-04-14 20:11:40 +04:00
percentage_partial_objs = s - > objects_partial * 100
2007-05-07 01:49:48 +04:00
/ s - > objects ;
if ( percentage_partial_objs > 100 )
percentage_partial_objs = 100 ;
if ( s - > object_size < min_objsize )
min_objsize = s - > object_size ;
if ( s - > partial < min_partial )
min_partial = s - > partial ;
if ( s - > slabs < min_slabs )
min_slabs = s - > slabs ;
if ( size < min_size )
min_size = size ;
if ( wasted < min_waste )
min_waste = wasted ;
if ( objwaste < min_objwaste )
min_objwaste = objwaste ;
if ( s - > objects < min_objects )
min_objects = s - > objects ;
if ( used < min_used )
min_used = used ;
2008-04-14 20:11:40 +04:00
if ( s - > objects_partial < min_partobj )
min_partobj = s - > objects_partial ;
2007-05-07 01:49:48 +04:00
if ( percentage_partial_slabs < min_ppart )
min_ppart = percentage_partial_slabs ;
if ( percentage_partial_objs < min_ppartobj )
min_ppartobj = percentage_partial_objs ;
if ( s - > slab_size < min_memobj )
min_memobj = s - > slab_size ;
if ( s - > object_size > max_objsize )
max_objsize = s - > object_size ;
if ( s - > partial > max_partial )
max_partial = s - > partial ;
if ( s - > slabs > max_slabs )
max_slabs = s - > slabs ;
if ( size > max_size )
max_size = size ;
if ( wasted > max_waste )
max_waste = wasted ;
if ( objwaste > max_objwaste )
max_objwaste = objwaste ;
if ( s - > objects > max_objects )
max_objects = s - > objects ;
if ( used > max_used )
max_used = used ;
2008-04-14 20:11:40 +04:00
if ( s - > objects_partial > max_partobj )
max_partobj = s - > objects_partial ;
2007-05-07 01:49:48 +04:00
if ( percentage_partial_slabs > max_ppart )
max_ppart = percentage_partial_slabs ;
if ( percentage_partial_objs > max_ppartobj )
max_ppartobj = percentage_partial_objs ;
if ( s - > slab_size > max_memobj )
max_memobj = s - > slab_size ;
total_partial + = s - > partial ;
total_slabs + = s - > slabs ;
total_size + = size ;
total_waste + = wasted ;
total_objects + = s - > objects ;
total_used + = used ;
2008-04-14 20:11:40 +04:00
total_partobj + = s - > objects_partial ;
2007-05-07 01:49:48 +04:00
total_ppart + = percentage_partial_slabs ;
total_ppartobj + = percentage_partial_objs ;
total_objwaste + = s - > objects * objwaste ;
total_objsize + = s - > objects * s - > slab_size ;
}
if ( ! total_objects ) {
printf ( " No objects \n " ) ;
return ;
}
if ( ! used_slabs ) {
printf ( " No slabs \n " ) ;
return ;
}
/* Per slab averages */
avg_partial = total_partial / used_slabs ;
avg_slabs = total_slabs / used_slabs ;
avg_size = total_size / used_slabs ;
avg_waste = total_waste / used_slabs ;
avg_objects = total_objects / used_slabs ;
avg_used = total_used / used_slabs ;
avg_partobj = total_partobj / used_slabs ;
avg_ppart = total_ppart / used_slabs ;
avg_ppartobj = total_ppartobj / used_slabs ;
/* Per object object sizes */
avg_objsize = total_used / total_objects ;
avg_objwaste = total_objwaste / total_objects ;
avg_partobj = total_partobj * 100 / total_objects ;
avg_memobj = total_objsize / total_objects ;
printf ( " Slabcache Totals \n " ) ;
printf ( " ---------------- \n " ) ;
2015-11-06 05:45:31 +03:00
printf ( " Slabcaches : %15d Aliases : %11d->%-3d Active: %3d \n " ,
2007-05-07 01:49:48 +04:00
slabs , aliases , alias_targets , used_slabs ) ;
store_size ( b1 , total_size ) ; store_size ( b2 , total_waste ) ;
store_size ( b3 , total_waste * 100 / total_used ) ;
2015-11-06 05:45:31 +03:00
printf ( " Memory used: %15s # Loss : %15s MRatio:%6s%% \n " , b1 , b2 , b3 ) ;
2007-05-07 01:49:48 +04:00
store_size ( b1 , total_objects ) ; store_size ( b2 , total_partobj ) ;
store_size ( b3 , total_partobj * 100 / total_objects ) ;
2015-11-06 05:45:31 +03:00
printf ( " # Objects : %15s # PartObj: %15s ORatio:%6s%% \n " , b1 , b2 , b3 ) ;
2007-05-07 01:49:48 +04:00
printf ( " \n " ) ;
2015-11-06 05:45:31 +03:00
printf ( " Per Cache Average "
" Min Max Total \n " ) ;
printf ( " --------------------------------------- "
" ------------------------------------- \n " ) ;
2007-05-07 01:49:48 +04:00
store_size ( b1 , avg_objects ) ; store_size ( b2 , min_objects ) ;
store_size ( b3 , max_objects ) ; store_size ( b4 , total_objects ) ;
2015-11-06 05:45:31 +03:00
printf ( " #Objects %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_slabs ) ; store_size ( b2 , min_slabs ) ;
store_size ( b3 , max_slabs ) ; store_size ( b4 , total_slabs ) ;
2015-11-06 05:45:31 +03:00
printf ( " #Slabs %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_partial ) ; store_size ( b2 , min_partial ) ;
store_size ( b3 , max_partial ) ; store_size ( b4 , total_partial ) ;
2015-11-06 05:45:31 +03:00
printf ( " #PartSlab %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_ppart ) ; store_size ( b2 , min_ppart ) ;
store_size ( b3 , max_ppart ) ;
store_size ( b4 , total_partial * 100 / total_slabs ) ;
2015-11-06 05:45:31 +03:00
printf ( " %%PartSlab%15s%% %15s%% %15s%% %15s%% \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_partobj ) ; store_size ( b2 , min_partobj ) ;
store_size ( b3 , max_partobj ) ;
store_size ( b4 , total_partobj ) ;
2015-11-06 05:45:31 +03:00
printf ( " PartObjs %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_ppartobj ) ; store_size ( b2 , min_ppartobj ) ;
store_size ( b3 , max_ppartobj ) ;
store_size ( b4 , total_partobj * 100 / total_objects ) ;
2015-11-06 05:45:31 +03:00
printf ( " %% PartObj%15s%% %15s%% %15s%% %15s%% \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_size ) ; store_size ( b2 , min_size ) ;
store_size ( b3 , max_size ) ; store_size ( b4 , total_size ) ;
2015-11-06 05:45:31 +03:00
printf ( " Memory %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_used ) ; store_size ( b2 , min_used ) ;
store_size ( b3 , max_used ) ; store_size ( b4 , total_used ) ;
2015-11-06 05:45:31 +03:00
printf ( " Used %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
store_size ( b1 , avg_waste ) ; store_size ( b2 , min_waste ) ;
store_size ( b3 , max_waste ) ; store_size ( b4 , total_waste ) ;
2015-11-06 05:45:31 +03:00
printf ( " Loss %15s %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 , b4 ) ;
printf ( " \n " ) ;
2015-11-06 05:45:31 +03:00
printf ( " Per Object Average "
" Min Max \n " ) ;
printf ( " --------------------------------------- "
" -------------------- \n " ) ;
2007-05-07 01:49:48 +04:00
store_size ( b1 , avg_memobj ) ; store_size ( b2 , min_memobj ) ;
store_size ( b3 , max_memobj ) ;
2015-11-06 05:45:31 +03:00
printf ( " Memory %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 ) ;
store_size ( b1 , avg_objsize ) ; store_size ( b2 , min_objsize ) ;
store_size ( b3 , max_objsize ) ;
2015-11-06 05:45:31 +03:00
printf ( " User %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 ) ;
store_size ( b1 , avg_objwaste ) ; store_size ( b2 , min_objwaste ) ;
store_size ( b3 , max_objwaste ) ;
2015-11-06 05:45:31 +03:00
printf ( " Loss %15s %15s %15s \n " ,
2007-05-07 01:49:48 +04:00
b1 , b2 , b3 ) ;
}
2009-09-23 03:43:42 +04:00
static void sort_slabs ( void )
2007-05-07 01:49:48 +04:00
{
struct slabinfo * s1 , * s2 ;
for ( s1 = slabinfo ; s1 < slabinfo + slabs ; s1 + + ) {
for ( s2 = s1 + 1 ; s2 < slabinfo + slabs ; s2 + + ) {
int result ;
if ( sort_size )
result = slab_size ( s1 ) < slab_size ( s2 ) ;
2008-02-08 04:47:41 +03:00
else if ( sort_active )
result = slab_activity ( s1 ) < slab_activity ( s2 ) ;
2015-11-06 05:45:22 +03:00
else if ( sort_loss )
result = slab_waste ( s1 ) < slab_waste ( s2 ) ;
2007-05-07 01:49:48 +04:00
else
result = strcasecmp ( s1 - > name , s2 - > name ) ;
if ( show_inverted )
result = - result ;
if ( result > 0 ) {
struct slabinfo t ;
memcpy ( & t , s1 , sizeof ( struct slabinfo ) ) ;
memcpy ( s1 , s2 , sizeof ( struct slabinfo ) ) ;
memcpy ( s2 , & t , sizeof ( struct slabinfo ) ) ;
}
}
}
}
2009-09-23 03:43:42 +04:00
static void sort_aliases ( void )
2007-05-07 01:49:48 +04:00
{
struct aliasinfo * a1 , * a2 ;
for ( a1 = aliasinfo ; a1 < aliasinfo + aliases ; a1 + + ) {
for ( a2 = a1 + 1 ; a2 < aliasinfo + aliases ; a2 + + ) {
char * n1 , * n2 ;
n1 = a1 - > name ;
n2 = a2 - > name ;
if ( show_alias & & ! show_inverted ) {
n1 = a1 - > ref ;
n2 = a2 - > ref ;
}
if ( strcasecmp ( n1 , n2 ) > 0 ) {
struct aliasinfo t ;
memcpy ( & t , a1 , sizeof ( struct aliasinfo ) ) ;
memcpy ( a1 , a2 , sizeof ( struct aliasinfo ) ) ;
memcpy ( a2 , & t , sizeof ( struct aliasinfo ) ) ;
}
}
}
}
2009-09-23 03:43:42 +04:00
static void link_slabs ( void )
2007-05-07 01:49:48 +04:00
{
struct aliasinfo * a ;
struct slabinfo * s ;
for ( a = aliasinfo ; a < aliasinfo + aliases ; a + + ) {
2007-05-09 13:32:37 +04:00
for ( s = slabinfo ; s < slabinfo + slabs ; s + + )
2007-05-07 01:49:48 +04:00
if ( strcmp ( a - > ref , s - > name ) = = 0 ) {
a - > slab = s ;
s - > refs + + ;
break ;
}
if ( s = = slabinfo + slabs )
fatal ( " Unresolved alias %s \n " , a - > ref ) ;
}
}
2009-09-23 03:43:42 +04:00
static void alias ( void )
2007-05-07 01:49:48 +04:00
{
struct aliasinfo * a ;
char * active = NULL ;
sort_aliases ( ) ;
link_slabs ( ) ;
for ( a = aliasinfo ; a < aliasinfo + aliases ; a + + ) {
if ( ! show_single_ref & & a - > slab - > refs = = 1 )
continue ;
if ( ! show_inverted ) {
if ( active ) {
if ( strcmp ( a - > slab - > name , active ) = = 0 ) {
printf ( " %s " , a - > name ) ;
continue ;
}
}
2007-05-09 13:32:37 +04:00
printf ( " \n %-12s <- %s " , a - > slab - > name , a - > name ) ;
2007-05-07 01:49:48 +04:00
active = a - > slab - > name ;
}
else
2015-11-06 05:45:31 +03:00
printf ( " %-15s -> %s \n " , a - > name , a - > slab - > name ) ;
2007-05-07 01:49:48 +04:00
}
if ( active )
printf ( " \n " ) ;
}
2009-09-23 03:43:42 +04:00
static void rename_slabs ( void )
2007-05-07 01:49:48 +04:00
{
struct slabinfo * s ;
struct aliasinfo * a ;
for ( s = slabinfo ; s < slabinfo + slabs ; s + + ) {
if ( * s - > name ! = ' : ' )
continue ;
if ( s - > refs > 1 & & ! show_first_alias )
continue ;
a = find_one_alias ( s ) ;
2007-05-09 13:32:37 +04:00
if ( a )
s - > name = a - > name ;
else {
s - > name = " * " ;
actual_slabs - - ;
}
2007-05-07 01:49:48 +04:00
}
}
2009-09-23 03:43:42 +04:00
static int slab_mismatch ( char * slab )
2007-05-07 01:49:48 +04:00
{
return regexec ( & pattern , slab , 0 , NULL , 0 ) ;
}
2009-09-23 03:43:42 +04:00
static void read_slab_dir ( void )
2007-05-07 01:49:48 +04:00
{
DIR * dir ;
struct dirent * de ;
struct slabinfo * slab = slabinfo ;
struct aliasinfo * alias = aliasinfo ;
char * p ;
char * t ;
int count ;
2008-02-05 10:35:48 +03:00
if ( chdir ( " /sys/kernel/slab " ) & & chdir ( " /sys/slab " ) )
2007-05-09 13:32:37 +04:00
fatal ( " SYSFS support for SLUB not active \n " ) ;
2007-05-07 01:49:48 +04:00
dir = opendir ( " . " ) ;
while ( ( de = readdir ( dir ) ) ) {
if ( de - > d_name [ 0 ] = = ' . ' | |
2007-05-09 13:32:37 +04:00
( de - > d_name [ 0 ] ! = ' : ' & & slab_mismatch ( de - > d_name ) ) )
continue ;
2007-05-07 01:49:48 +04:00
switch ( de - > d_type ) {
case DT_LNK :
2010-10-21 22:01:56 +04:00
alias - > name = strdup ( de - > d_name ) ;
2011-10-17 18:48:10 +04:00
count = readlink ( de - > d_name , buffer , sizeof ( buffer ) - 1 ) ;
2007-05-07 01:49:48 +04:00
if ( count < 0 )
fatal ( " Cannot read symlink %s \n " , de - > d_name ) ;
buffer [ count ] = 0 ;
p = buffer + count ;
while ( p > buffer & & p [ - 1 ] ! = ' / ' )
p - - ;
alias - > ref = strdup ( p ) ;
alias + + ;
break ;
case DT_DIR :
if ( chdir ( de - > d_name ) )
fatal ( " Unable to access slab %s \n " , slab - > name ) ;
2010-10-21 22:01:56 +04:00
slab - > name = strdup ( de - > d_name ) ;
2007-05-07 01:49:48 +04:00
slab - > alias = 0 ;
slab - > refs = 0 ;
slab - > aliases = get_obj ( " aliases " ) ;
slab - > align = get_obj ( " align " ) ;
slab - > cache_dma = get_obj ( " cache_dma " ) ;
slab - > cpu_slabs = get_obj ( " cpu_slabs " ) ;
slab - > destroy_by_rcu = get_obj ( " destroy_by_rcu " ) ;
slab - > hwcache_align = get_obj ( " hwcache_align " ) ;
slab - > object_size = get_obj ( " object_size " ) ;
slab - > objects = get_obj ( " objects " ) ;
2008-04-14 20:11:40 +04:00
slab - > objects_partial = get_obj ( " objects_partial " ) ;
slab - > objects_total = get_obj ( " objects_total " ) ;
2007-05-07 01:49:48 +04:00
slab - > objs_per_slab = get_obj ( " objs_per_slab " ) ;
slab - > order = get_obj ( " order " ) ;
slab - > partial = get_obj ( " partial " ) ;
slab - > partial = get_obj_and_str ( " partial " , & t ) ;
decode_numa_list ( slab - > numa_partial , t ) ;
2007-10-17 10:31:29 +04:00
free ( t ) ;
2007-05-07 01:49:48 +04:00
slab - > poison = get_obj ( " poison " ) ;
slab - > reclaim_account = get_obj ( " reclaim_account " ) ;
slab - > red_zone = get_obj ( " red_zone " ) ;
slab - > sanity_checks = get_obj ( " sanity_checks " ) ;
slab - > slab_size = get_obj ( " slab_size " ) ;
slab - > slabs = get_obj_and_str ( " slabs " , & t ) ;
decode_numa_list ( slab - > numa , t ) ;
2007-10-17 10:31:29 +04:00
free ( t ) ;
2007-05-07 01:49:48 +04:00
slab - > store_user = get_obj ( " store_user " ) ;
slab - > trace = get_obj ( " trace " ) ;
2008-02-08 04:47:41 +03:00
slab - > alloc_fastpath = get_obj ( " alloc_fastpath " ) ;
slab - > alloc_slowpath = get_obj ( " alloc_slowpath " ) ;
slab - > free_fastpath = get_obj ( " free_fastpath " ) ;
slab - > free_slowpath = get_obj ( " free_slowpath " ) ;
slab - > free_frozen = get_obj ( " free_frozen " ) ;
slab - > free_add_partial = get_obj ( " free_add_partial " ) ;
slab - > free_remove_partial = get_obj ( " free_remove_partial " ) ;
slab - > alloc_from_partial = get_obj ( " alloc_from_partial " ) ;
slab - > alloc_slab = get_obj ( " alloc_slab " ) ;
slab - > alloc_refill = get_obj ( " alloc_refill " ) ;
slab - > free_slab = get_obj ( " free_slab " ) ;
slab - > cpuslab_flush = get_obj ( " cpuslab_flush " ) ;
slab - > deactivate_full = get_obj ( " deactivate_full " ) ;
slab - > deactivate_empty = get_obj ( " deactivate_empty " ) ;
slab - > deactivate_to_head = get_obj ( " deactivate_to_head " ) ;
slab - > deactivate_to_tail = get_obj ( " deactivate_to_tail " ) ;
slab - > deactivate_remote_frees = get_obj ( " deactivate_remote_frees " ) ;
2008-04-30 03:14:46 +04:00
slab - > order_fallback = get_obj ( " order_fallback " ) ;
2011-06-01 21:26:00 +04:00
slab - > cmpxchg_double_cpu_fail = get_obj ( " cmpxchg_double_cpu_fail " ) ;
slab - > cmpxchg_double_fail = get_obj ( " cmpxchg_double_fail " ) ;
2011-08-10 01:12:28 +04:00
slab - > cpu_partial_alloc = get_obj ( " cpu_partial_alloc " ) ;
slab - > cpu_partial_free = get_obj ( " cpu_partial_free " ) ;
2011-06-01 21:26:00 +04:00
slab - > alloc_node_mismatch = get_obj ( " alloc_node_mismatch " ) ;
slab - > deactivate_bypass = get_obj ( " deactivate_bypass " ) ;
2007-05-07 01:49:48 +04:00
chdir ( " .. " ) ;
if ( slab - > name [ 0 ] = = ' : ' )
alias_targets + + ;
slab + + ;
break ;
default :
fatal ( " Unknown file type %lx \n " , de - > d_type ) ;
}
}
closedir ( dir ) ;
slabs = slab - slabinfo ;
2007-05-09 13:32:37 +04:00
actual_slabs = slabs ;
2007-05-07 01:49:48 +04:00
aliases = alias - aliasinfo ;
if ( slabs > MAX_SLABS )
fatal ( " Too many slabs \n " ) ;
if ( aliases > MAX_ALIASES )
fatal ( " Too many aliases \n " ) ;
}
2009-09-23 03:43:42 +04:00
static void output_slabs ( void )
2007-05-07 01:49:48 +04:00
{
struct slabinfo * slab ;
2015-11-06 05:45:28 +03:00
int lines = output_lines ;
2007-05-07 01:49:48 +04:00
2015-11-06 05:45:20 +03:00
for ( slab = slabinfo ; ( slab < slabinfo + slabs ) & &
2015-11-06 05:45:28 +03:00
lines ! = 0 ; slab + + ) {
2007-05-07 01:49:48 +04:00
if ( slab - > alias )
continue ;
2015-11-06 05:45:28 +03:00
if ( lines ! = - 1 )
lines - - ;
2007-05-07 01:49:48 +04:00
if ( show_numa )
2007-05-09 13:32:37 +04:00
slab_numa ( slab , 0 ) ;
else if ( show_track )
2007-05-07 01:49:48 +04:00
show_tracking ( slab ) ;
2007-05-09 13:32:37 +04:00
else if ( validate )
2007-05-07 01:49:48 +04:00
slab_validate ( slab ) ;
2007-05-09 13:32:37 +04:00
else if ( shrink )
2007-05-07 01:49:48 +04:00
slab_shrink ( slab ) ;
2007-05-09 13:32:37 +04:00
else if ( set_debug )
slab_debug ( slab ) ;
else if ( show_ops )
ops ( slab ) ;
else if ( show_slab )
slabcache ( slab ) ;
2007-05-17 09:10:55 +04:00
else if ( show_report )
report ( slab ) ;
2007-05-07 01:49:48 +04:00
}
}
2015-11-06 05:45:28 +03:00
static void xtotals ( void )
{
totals ( ) ;
link_slabs ( ) ;
rename_slabs ( ) ;
printf ( " \n Slabs sorted by size \n " ) ;
2015-11-06 05:45:31 +03:00
printf ( " -------------------- \n " ) ;
2015-11-06 05:45:28 +03:00
sort_loss = 0 ;
sort_size = 1 ;
sort_slabs ( ) ;
output_slabs ( ) ;
printf ( " \n Slabs sorted by loss \n " ) ;
2015-11-06 05:45:31 +03:00
printf ( " -------------------- \n " ) ;
2015-11-06 05:45:28 +03:00
line = 0 ;
sort_loss = 1 ;
sort_size = 0 ;
sort_slabs ( ) ;
output_slabs ( ) ;
printf ( " \n " ) ;
}
2007-05-07 01:49:48 +04:00
struct option opts [ ] = {
tools/vm/slabinfo: use getopt no_argument/optional_argument
This patchset adds 'extended' slabinfo mode that provides additional
information:
-- totals summary
-- slabs sorted by size
-- slabs sorted by loss (waste)
The patches also introduces several new slabinfo options to limit the
number of slabs reported, sort slabs by loss (waste); and some fixes.
Extended output example (slabinfo -X -N 2):
Slabcache Totals
----------------
Slabcaches : 91 Aliases : 119->69 Active: 63
Memory used: 199798784 # Loss : 10689376 MRatio: 5%
# Objects : 324301 # PartObj: 18151 ORatio: 5%
Per Cache Average Min Max Total
----------------------------------------------------------------------------
#Objects 5147 1 89068 324301
#Slabs 199 1 3886 12537
#PartSlab 12 0 240 778
%PartSlab 32% 0% 100% 6%
PartObjs 5 0 4569 18151
% PartObj 26% 0% 100% 5%
Memory 3171409 8192 127336448 199798784
Used 3001736 160 121429728 189109408
Loss 169672 0 5906720 10689376
Per Object Average Min Max
-----------------------------------------------------------
Memory 585 8 8192
User 583 8 8192
Loss 2 0 64
Slabs sorted by size
--------------------
Name Objects Objsize Space Slabs/Part/Cpu O/S O %Fr %Ef Flg
ext4_inode_cache 69948 1736 127336448 3871/0/15 18 3 0 95 a
dentry 89068 288 26058752 3164/0/17 28 1 0 98 a
Slabs sorted by loss
--------------------
Name Objects Objsize Loss Slabs/Part/Cpu O/S O %Fr %Ef Flg
ext4_inode_cache 69948 1736 5906720 3871/0/15 18 3 0 95 a
inode_cache 11628 864 537472 642/0/4 18 2 0 94 a
The last patch in the series addresses Linus' comment from
http://marc.info/?l=linux-mm&m=144148518703321&w=2
(well, it's been some time. sorry.)
gnuplot script takes the slabinfo records file, where every record is a `slabinfo -X'
output. So the basic workflow is, for example, as follows:
while [ 1 ]; do slabinfo -X -N 2 >> stats; sleep 1; done
^C
slabinfo-gnuplot.sh stats
The last command will produce 3 png files (and 3 stats files)
-- graph of slabinfo totals
-- graph of slabs by size
-- graph of slabs by loss
It's also possible to select a range of records for plotting (a range of collected
slabinfo outputs) via `-r 10,100` (for example); and compare totals from several
measurements (to visially compare slabs behaviour (10,50 range)) using
pre-parsed totals files:
slabinfo-gnuplot.sh -r 10,50 -t stats-totals1 .. stats-totals2
This also, technically, supports ktest. Upload new slabinfo to target,
collect the stats and give the resulting stats file to slabinfo-gnuplot
This patch (of 8):
Use getopt constants in `struct option' ->has_arg instead of numerical
representations.
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-11-06 05:45:17 +03:00
{ " aliases " , no_argument , NULL , ' a ' } ,
{ " activity " , no_argument , NULL , ' A ' } ,
{ " debug " , optional_argument , NULL , ' d ' } ,
{ " display-activity " , no_argument , NULL , ' D ' } ,
{ " empty " , no_argument , NULL , ' e ' } ,
{ " first-alias " , no_argument , NULL , ' f ' } ,
{ " help " , no_argument , NULL , ' h ' } ,
{ " inverted " , no_argument , NULL , ' i ' } ,
2015-11-06 05:45:25 +03:00
{ " slabs " , no_argument , NULL , ' l ' } ,
tools/vm/slabinfo: use getopt no_argument/optional_argument
This patchset adds 'extended' slabinfo mode that provides additional
information:
-- totals summary
-- slabs sorted by size
-- slabs sorted by loss (waste)
The patches also introduces several new slabinfo options to limit the
number of slabs reported, sort slabs by loss (waste); and some fixes.
Extended output example (slabinfo -X -N 2):
Slabcache Totals
----------------
Slabcaches : 91 Aliases : 119->69 Active: 63
Memory used: 199798784 # Loss : 10689376 MRatio: 5%
# Objects : 324301 # PartObj: 18151 ORatio: 5%
Per Cache Average Min Max Total
----------------------------------------------------------------------------
#Objects 5147 1 89068 324301
#Slabs 199 1 3886 12537
#PartSlab 12 0 240 778
%PartSlab 32% 0% 100% 6%
PartObjs 5 0 4569 18151
% PartObj 26% 0% 100% 5%
Memory 3171409 8192 127336448 199798784
Used 3001736 160 121429728 189109408
Loss 169672 0 5906720 10689376
Per Object Average Min Max
-----------------------------------------------------------
Memory 585 8 8192
User 583 8 8192
Loss 2 0 64
Slabs sorted by size
--------------------
Name Objects Objsize Space Slabs/Part/Cpu O/S O %Fr %Ef Flg
ext4_inode_cache 69948 1736 127336448 3871/0/15 18 3 0 95 a
dentry 89068 288 26058752 3164/0/17 28 1 0 98 a
Slabs sorted by loss
--------------------
Name Objects Objsize Loss Slabs/Part/Cpu O/S O %Fr %Ef Flg
ext4_inode_cache 69948 1736 5906720 3871/0/15 18 3 0 95 a
inode_cache 11628 864 537472 642/0/4 18 2 0 94 a
The last patch in the series addresses Linus' comment from
http://marc.info/?l=linux-mm&m=144148518703321&w=2
(well, it's been some time. sorry.)
gnuplot script takes the slabinfo records file, where every record is a `slabinfo -X'
output. So the basic workflow is, for example, as follows:
while [ 1 ]; do slabinfo -X -N 2 >> stats; sleep 1; done
^C
slabinfo-gnuplot.sh stats
The last command will produce 3 png files (and 3 stats files)
-- graph of slabinfo totals
-- graph of slabs by size
-- graph of slabs by loss
It's also possible to select a range of records for plotting (a range of collected
slabinfo outputs) via `-r 10,100` (for example); and compare totals from several
measurements (to visially compare slabs behaviour (10,50 range)) using
pre-parsed totals files:
slabinfo-gnuplot.sh -r 10,50 -t stats-totals1 .. stats-totals2
This also, technically, supports ktest. Upload new slabinfo to target,
collect the stats and give the resulting stats file to slabinfo-gnuplot
This patch (of 8):
Use getopt constants in `struct option' ->has_arg instead of numerical
representations.
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-11-06 05:45:17 +03:00
{ " numa " , no_argument , NULL , ' n ' } ,
{ " ops " , no_argument , NULL , ' o ' } ,
{ " shrink " , no_argument , NULL , ' s ' } ,
2015-11-06 05:45:25 +03:00
{ " report " , no_argument , NULL , ' r ' } ,
{ " Size " , no_argument , NULL , ' S ' } ,
{ " tracking " , no_argument , NULL , ' t ' } ,
{ " Totals " , no_argument , NULL , ' T ' } ,
tools/vm/slabinfo: use getopt no_argument/optional_argument
This patchset adds 'extended' slabinfo mode that provides additional
information:
-- totals summary
-- slabs sorted by size
-- slabs sorted by loss (waste)
The patches also introduces several new slabinfo options to limit the
number of slabs reported, sort slabs by loss (waste); and some fixes.
Extended output example (slabinfo -X -N 2):
Slabcache Totals
----------------
Slabcaches : 91 Aliases : 119->69 Active: 63
Memory used: 199798784 # Loss : 10689376 MRatio: 5%
# Objects : 324301 # PartObj: 18151 ORatio: 5%
Per Cache Average Min Max Total
----------------------------------------------------------------------------
#Objects 5147 1 89068 324301
#Slabs 199 1 3886 12537
#PartSlab 12 0 240 778
%PartSlab 32% 0% 100% 6%
PartObjs 5 0 4569 18151
% PartObj 26% 0% 100% 5%
Memory 3171409 8192 127336448 199798784
Used 3001736 160 121429728 189109408
Loss 169672 0 5906720 10689376
Per Object Average Min Max
-----------------------------------------------------------
Memory 585 8 8192
User 583 8 8192
Loss 2 0 64
Slabs sorted by size
--------------------
Name Objects Objsize Space Slabs/Part/Cpu O/S O %Fr %Ef Flg
ext4_inode_cache 69948 1736 127336448 3871/0/15 18 3 0 95 a
dentry 89068 288 26058752 3164/0/17 28 1 0 98 a
Slabs sorted by loss
--------------------
Name Objects Objsize Loss Slabs/Part/Cpu O/S O %Fr %Ef Flg
ext4_inode_cache 69948 1736 5906720 3871/0/15 18 3 0 95 a
inode_cache 11628 864 537472 642/0/4 18 2 0 94 a
The last patch in the series addresses Linus' comment from
http://marc.info/?l=linux-mm&m=144148518703321&w=2
(well, it's been some time. sorry.)
gnuplot script takes the slabinfo records file, where every record is a `slabinfo -X'
output. So the basic workflow is, for example, as follows:
while [ 1 ]; do slabinfo -X -N 2 >> stats; sleep 1; done
^C
slabinfo-gnuplot.sh stats
The last command will produce 3 png files (and 3 stats files)
-- graph of slabinfo totals
-- graph of slabs by size
-- graph of slabs by loss
It's also possible to select a range of records for plotting (a range of collected
slabinfo outputs) via `-r 10,100` (for example); and compare totals from several
measurements (to visially compare slabs behaviour (10,50 range)) using
pre-parsed totals files:
slabinfo-gnuplot.sh -r 10,50 -t stats-totals1 .. stats-totals2
This also, technically, supports ktest. Upload new slabinfo to target,
collect the stats and give the resulting stats file to slabinfo-gnuplot
This patch (of 8):
Use getopt constants in `struct option' ->has_arg instead of numerical
representations.
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-11-06 05:45:17 +03:00
{ " validate " , no_argument , NULL , ' v ' } ,
{ " zero " , no_argument , NULL , ' z ' } ,
{ " 1ref " , no_argument , NULL , ' 1 ' } ,
2015-11-06 05:45:20 +03:00
{ " lines " , required_argument , NULL , ' N ' } ,
2015-11-06 05:45:22 +03:00
{ " Loss " , no_argument , NULL , ' L ' } ,
2015-11-06 05:45:28 +03:00
{ " Xtotals " , no_argument , NULL , ' X ' } ,
2015-11-06 05:45:31 +03:00
{ " Bytes " , no_argument , NULL , ' B ' } ,
2007-05-07 01:49:48 +04:00
{ NULL , 0 , NULL , 0 }
} ;
int main ( int argc , char * argv [ ] )
{
int c ;
int err ;
char * pattern_source ;
page_size = getpagesize ( ) ;
2015-11-06 05:45:31 +03:00
while ( ( c = getopt_long ( argc , argv , " aAd::Defhil1noprstvzTSN:LXB " ,
2007-05-09 13:32:37 +04:00
opts , NULL ) ) ! = - 1 )
2007-10-17 10:31:29 +04:00
switch ( c ) {
2007-05-07 01:49:48 +04:00
case ' 1 ' :
show_single_ref = 1 ;
break ;
case ' a ' :
show_alias = 1 ;
break ;
2008-02-08 04:47:41 +03:00
case ' A ' :
sort_active = 1 ;
break ;
2007-05-09 13:32:37 +04:00
case ' d ' :
set_debug = 1 ;
if ( ! debug_opt_scan ( optarg ) )
fatal ( " Invalid debug option '%s' \n " , optarg ) ;
break ;
2008-02-08 04:47:41 +03:00
case ' D ' :
show_activity = 1 ;
break ;
2007-05-09 13:32:37 +04:00
case ' e ' :
show_empty = 1 ;
break ;
2007-05-07 01:49:48 +04:00
case ' f ' :
show_first_alias = 1 ;
break ;
case ' h ' :
usage ( ) ;
return 0 ;
case ' i ' :
show_inverted = 1 ;
break ;
case ' n ' :
show_numa = 1 ;
break ;
2007-05-09 13:32:37 +04:00
case ' o ' :
show_ops = 1 ;
break ;
case ' r ' :
show_report = 1 ;
break ;
2007-05-07 01:49:48 +04:00
case ' s ' :
shrink = 1 ;
break ;
case ' l ' :
show_slab = 1 ;
break ;
case ' t ' :
show_track = 1 ;
break ;
case ' v ' :
validate = 1 ;
break ;
case ' z ' :
skip_zero = 0 ;
break ;
case ' T ' :
show_totals = 1 ;
break ;
case ' S ' :
sort_size = 1 ;
break ;
2015-11-06 05:45:20 +03:00
case ' N ' :
if ( optarg ) {
output_lines = atoi ( optarg ) ;
if ( output_lines < 1 )
output_lines = 1 ;
}
break ;
2015-11-06 05:45:22 +03:00
case ' L ' :
sort_loss = 1 ;
break ;
2015-11-06 05:45:28 +03:00
case ' X ' :
if ( output_lines = = - 1 )
output_lines = 1 ;
extended_totals = 1 ;
2015-11-06 05:45:31 +03:00
show_bytes = 1 ;
break ;
case ' B ' :
show_bytes = 1 ;
2015-11-06 05:45:28 +03:00
break ;
2007-05-07 01:49:48 +04:00
default :
fatal ( " %s: Invalid option '%c' \n " , argv [ 0 ] , optopt ) ;
}
2007-05-09 13:32:37 +04:00
if ( ! show_slab & & ! show_alias & & ! show_track & & ! show_report
& & ! validate & & ! shrink & & ! set_debug & & ! show_ops )
2007-05-07 01:49:48 +04:00
show_slab = 1 ;
if ( argc > optind )
pattern_source = argv [ optind ] ;
else
pattern_source = " .* " ;
err = regcomp ( & pattern , pattern_source , REG_ICASE | REG_NOSUB ) ;
if ( err )
fatal ( " %s: Invalid pattern '%s' code %d \n " ,
argv [ 0 ] , pattern_source , err ) ;
read_slab_dir ( ) ;
2015-11-06 05:45:28 +03:00
if ( show_alias ) {
2007-05-07 01:49:48 +04:00
alias ( ) ;
2015-11-06 05:45:28 +03:00
} else if ( extended_totals ) {
xtotals ( ) ;
} else if ( show_totals ) {
2007-05-07 01:49:48 +04:00
totals ( ) ;
2015-11-06 05:45:28 +03:00
} else {
2007-05-07 01:49:48 +04:00
link_slabs ( ) ;
rename_slabs ( ) ;
sort_slabs ( ) ;
output_slabs ( ) ;
}
return 0 ;
}