cregit-Linux how code gets into the kernel

Release 4.14 tools/vm/slabinfo.c

Directory: tools/vm
// SPDX-License-Identifier: GPL-2.0
/*
 * Slabinfo: Tool to get reports about slabs
 *
 * (C) 2007 sgi, Christoph Lameter
 * (C) 2011 Linux Foundation, Christoph Lameter
 *
 * Compile with:
 *
 * gcc -o slabinfo slabinfo.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <getopt.h>
#include <regex.h>
#include <errno.h>


#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;
	




unsigned long partial, objects, slabs, objects_partial, objects_total;
	

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;
	

unsigned long deactivate_remote_frees, order_fallback;
	

unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
	

unsigned long alloc_node_mismatch, deactivate_bypass;
	

unsigned long cpu_partial_alloc, cpu_partial_free;
	
int numa[MAX_NODES];
	
int numa_partial[MAX_NODES];

} slabinfo[MAX_SLABS];


struct aliasinfo {
	
char *name;
	
char *ref;
	
struct slabinfo *slab;

} aliasinfo[MAX_ALIASES];


int slabs;

int actual_slabs;

int aliases;

int alias_targets;

int highest_node;


char buffer[4096];


int show_empty;

int show_report;

int show_alias;

int show_slab;

int skip_zero = 1;

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;

int output_lines = -1;

int sort_loss;

int extended_totals;

int show_bytes;

/* Debug options */

int sanity;

int redzone;

int poison;

int tracking;

int tracing;


int page_size;


regex_t pattern;


static void fatal(const char *x, ...) { va_list ap; va_start(ap, x); vfprintf(stderr, x, ap); va_end(ap); exit(EXIT_FAILURE); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter4095.24%133.33%
Ladinu Chandrasinghe12.38%133.33%
Américo Wang12.38%133.33%
Total42100.00%3100.00%


static void usage(void) { printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n" "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" "-a|--aliases Show aliases\n" "-A|--activity Most active slabs first\n" "-d<options>|--debug=<options> Set/Clear Debug options\n" "-D|--display-active Switch line format to activity\n" "-e|--empty Show empty slabs\n" "-f|--first-alias Show first alias\n" "-h|--help Show usage information\n" "-i|--inverted Inverted list\n" "-l|--slabs Show slabs\n" "-n|--numa Show NUMA information\n" "-o|--ops Show kmem_cache_ops\n" "-s|--shrink Shrink slabs\n" "-r|--report Detailed report on single slabs\n" "-S|--Size Sort by size\n" "-t|--tracking Show alloc/free information\n" "-T|--Totals Show summary information\n" "-v|--validate Validate slabs\n" "-z|--zero Include empty slabs\n" "-1|--1ref Single reference\n" "-N|--lines=K Show the first K slabs\n" "-L|--Loss Sort by loss\n" "-X|--Xtotals Show extended summary information\n" "-B|--Bytes Show size in bytes\n" "\nValid debug options (FZPUT may be combined)\n" "a / A Switch on all debug options (=FZUP)\n" "- Switch off all debug options\n" "f / F Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n" "z / Z Redzoning\n" "p / P Poisoning\n" "u / U Tracking\n" "t / T Tracing\n" ); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter3986.67%440.00%
Sergey Senozhatsky48.89%440.00%
Ladinu Chandrasinghe12.22%110.00%
Laura Abbott12.22%110.00%
Total45100.00%10100.00%


static unsigned long read_obj(const char *name) { FILE *f = fopen(name, "r"); if (!f) buffer[0] = 0; else { if (!fgets(buffer, sizeof(buffer), f)) buffer[0] = 0; fclose(f); if (buffer[strlen(buffer)] == '\n') buffer[strlen(buffer)] = 0; } return strlen(buffer); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter9197.85%133.33%
Américo Wang11.08%133.33%
Ladinu Chandrasinghe11.08%133.33%
Total93100.00%3100.00%

/* * Get the contents of an attribute */
static unsigned long get_obj(const char *name) { if (!read_obj(name)) return 0; return atol(buffer); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter2793.10%133.33%
Américo Wang13.45%133.33%
Ladinu Chandrasinghe13.45%133.33%
Total29100.00%3100.00%


static unsigned long get_obj_and_str(const char *name, char **x) { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter8597.70%133.33%
Ladinu Chandrasinghe11.15%133.33%
Américo Wang11.15%133.33%
Total87100.00%3100.00%


static void set_obj(struct slabinfo *s, const char *name, int n) { char x[100]; FILE *f; snprintf(x, 100, "%s/%s", s->name, name); f = fopen(x, "w"); if (!f) fatal("Cannot write to %s\n", x); fprintf(f, "%d\n", n); fclose(f); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter7493.67%250.00%
Américo Wang45.06%125.00%
Ladinu Chandrasinghe11.27%125.00%
Total79100.00%4100.00%


static unsigned long read_slab_obj(struct slabinfo *s, const char *name) { char x[100]; FILE *f; size_t l; snprintf(x, 100, "%s/%s", s->name, name); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter10094.34%133.33%
Américo Wang54.72%133.33%
Ladinu Chandrasinghe10.94%133.33%
Total106100.00%3100.00%

/* * Put a size string together */
static int store_size(char *buffer, unsigned long value) { unsigned long divisor = 1; char trailer = 0; int n; 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'; } } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter15595.09%133.33%
Sergey Senozhatsky74.29%133.33%
Ladinu Chandrasinghe10.61%133.33%
Total163100.00%3100.00%


static void decode_numa_list(int *numa, char *t) { int node; int nr; memset(numa, 0, MAX_NODES * sizeof(int)); if (!t) return; 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++; } }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter11499.13%266.67%
Ladinu Chandrasinghe10.87%133.33%
Total115100.00%3100.00%


static void slab_validate(struct slabinfo *s) { if (strcmp(s->name, "*") == 0) return; set_obj(s, "validate", 1); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter3397.06%266.67%
Ladinu Chandrasinghe12.94%133.33%
Total34100.00%3100.00%


static void slab_shrink(struct slabinfo *s) { if (strcmp(s->name, "*") == 0) return; set_obj(s, "shrink", 1); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter3397.06%266.67%
Ladinu Chandrasinghe12.94%133.33%
Total34100.00%3100.00%

int line = 0;
static void first_line(void) { if (show_activity) printf("Name Objects Alloc Free" " %%Fast Fallb O CmpX UL\n"); else printf("Name Objects Objsize %s " "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n", sort_loss ? " Loss" : "Space"); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter2167.74%240.00%
Sergey Senozhatsky929.03%240.00%
Ladinu Chandrasinghe13.23%120.00%
Total31100.00%5100.00%

/* * Find the shortest alias of a slab */
static struct aliasinfo *find_one_alias(struct slabinfo *find) { 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; } } return best; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter9598.96%150.00%
Ladinu Chandrasinghe11.04%150.00%
Total96100.00%2100.00%


static unsigned long slab_size(struct slabinfo *s) { return s->slabs * (page_size << s->order); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter2496.00%150.00%
Ladinu Chandrasinghe14.00%150.00%
Total25100.00%2100.00%


static unsigned long slab_activity(struct slabinfo *s) { return s->alloc_fastpath + s->free_fastpath + s->alloc_slowpath + s->free_slowpath; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter2896.55%150.00%
Ladinu Chandrasinghe13.45%150.00%
Total29100.00%2100.00%


static unsigned long slab_waste(struct slabinfo *s) { return slab_size(s) - s->objects * s->object_size; }

Contributors

PersonTokensPropCommitsCommitProp
Sergey Senozhatsky26100.00%1100.00%
Total26100.00%1100.00%


static void slab_numa(struct slabinfo *s, int mode) { 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++; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter24299.59%266.67%
Ladinu Chandrasinghe10.41%133.33%
Total243100.00%3100.00%


static void show_tracking(struct slabinfo *s) { printf("\n%s: Kernel object allocation\n", s->name); printf("-----------------------------------------------------------------------\n"); if (read_slab_obj(s, "alloc_calls")) printf("%s", buffer); else printf("No Data\n"); printf("\n%s: Kernel object freeing\n", s->name); printf("------------------------------------------------------------------------\n"); if (read_slab_obj(s, "free_calls")) printf("%s", buffer); else printf("No Data\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter8298.80%375.00%
Ladinu Chandrasinghe11.20%125.00%
Total83100.00%4100.00%


static void ops(struct slabinfo *s) { if (strcmp(s->name, "*") == 0) return; if (read_slab_obj(s, "ops")) { printf("\n%s: kmem_cache operations\n", s->name); printf("--------------------------------------------\n"); printf("%s", buffer); } else printf("\n%s has no kmem_cache operations\n", s->name); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter6698.51%266.67%
Ladinu Chandrasinghe11.49%133.33%
Total67100.00%3100.00%


static const char *onoff(int x) { if (x) return "On "; return "Off"; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter2095.24%150.00%
Ladinu Chandrasinghe14.76%150.00%
Total21100.00%2100.00%


static void slab_stats(struct slabinfo *s) { 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, total_free ? s->free_fastpath * 100 / total_free : 0); printf("Slowpath %8lu %8lu %3lu %3lu\n", total_alloc - s->alloc_fastpath, s->free_slowpath, (total_alloc - s->alloc_fastpath) * 100 / total_alloc, total_free ? s->free_slowpath * 100 / total_free : 0); printf("Page Alloc %8lu %8lu %3lu %3lu\n", s->alloc_slab, s->free_slab, s->alloc_slab * 100 / total_alloc, total_free ? s->free_slab * 100 / total_free : 0); 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, total_free ? s->free_add_partial * 100 / total_free : 0); printf("Remove partial %8lu %8lu %3lu %3lu\n", s->alloc_from_partial, s->free_remove_partial, s->alloc_from_partial * 100 / total_alloc, total_free ? s->free_remove_partial * 100 / total_free : 0); printf("Cpu partial list %8lu %8lu %3lu %3lu\n", s->cpu_partial_alloc, s->cpu_partial_free, s->cpu_partial_alloc * 100 / total_alloc, total_free ? s->cpu_partial_free * 100 / total_free : 0); printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", s->deactivate_remote_frees, s->free_frozen, s->deactivate_remote_frees * 100 / total_alloc, total_free ? s->free_frozen * 100 / total_free : 0); 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 + s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass; if (total) { printf("\nSlab Deactivation Occurrences %%\n"); 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", s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); 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); } if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) { printf("\nCmpxchg_double Looping\n------------------------\n"); printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n", s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); } }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter51294.12%342.86%
Jianpeng Ma (马建朋)285.15%114.29%
Dan Carpenter20.37%114.29%
Ladinu Chandrasinghe10.18%114.29%
Colin Ian King10.18%114.29%
Total544100.00%7100.00%


static void report(struct slabinfo *s) { if (strcmp(s->name, "*") == 0) return; printf("\nSlabcache: %-15s Aliases: %2d Order : %2d Objects: %lu\n", s->name, s->aliases, s->order, s->objects); 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("\nSizes (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); slab_stats(s); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Lameter31099.36%360.00%
Sergey Senozhatsky10.32%120.00%
Ladinu Chandrasinghe10.32%120.00%
Total312100.00%5100.00%


static void slabcache(struct slabinfo *s) { char size_str[20]; char dist_str[40]; char flags[20]; char *p = flags; 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) return; if (sort_loss == 0) store_size(size_str, slab_size(s)); else store_size(size_str, slab_waste(s)); snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs, s->partial, s->cpu_slabs); 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; 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; printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n", s->name, s->objects, total_alloc, total_free, total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0, total_free ? (s->free_fastpath * 100 / total_free) : 0, s->order_fallback, s->order, s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); } else { printf("%-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s\n", 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))