📄 slabinfo.c
字号:
/* * Slabinfo: Tool to get reports about slabs * * (C) 2007 sgi, Christoph Lameter <clameter@sgi.com> * * Compile by: * * 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 1024struct 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; 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 = 0;int actual_slabs = 0;int aliases = 0;int alias_targets = 0;int highest_node = 0;char buffer[4096];int show_empty = 0;int show_report = 0;int show_alias = 0;int show_slab = 0;int skip_zero = 1;int show_numa = 0;int show_track = 0;int show_first_alias = 0;int validate = 0;int shrink = 0;int show_inverted = 0;int show_single_ref = 0;int show_totals = 0;int sort_size = 0;int set_debug = 0;int show_ops = 0;/* Debug options */int sanity = 0;int redzone = 0;int poison = 0;int tracking = 0;int tracing = 0;int page_size;regex_t pattern;void fatal(const char *x, ...){ va_list ap; va_start(ap, x); vfprintf(stderr, x, ap); va_end(ap); exit(EXIT_FAILURE);}void usage(void){ printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n" "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" "-a|--aliases Show aliases\n" "-d<options>|--debug=<options> Set/Clear Debug options\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" "\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_DEBUG_FREE)\n" "z / Z Redzoning\n" "p / P Poisoning\n" "u / U Tracking\n" "t / T Tracing\n" );}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);}/* * Get the contents of an attribute */unsigned long get_obj(const char *name){ if (!read_obj(name)) return 0; return atol(buffer);}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;}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);}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;}/* * Put a size string together */int store_size(char *buffer, unsigned long value){ unsigned long divisor = 1; char trailer = 0; int n; 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;}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++; }}void slab_validate(struct slabinfo *s){ if (strcmp(s->name, "*") == 0) return; set_obj(s, "validate", 1);}void slab_shrink(struct slabinfo *s){ if (strcmp(s->name, "*") == 0) return; set_obj(s, "shrink", 1);}int line = 0;void first_line(void){ printf("Name Objects Objsize Space " "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");}/* * Find the shortest alias of a slab */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;}unsigned long slab_size(struct slabinfo *s){ return s->slabs * (page_size << s->order);}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++;}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(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(buffer); else printf("No Data\n");}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(buffer); } else printf("\n%s has no kmem_cache operations\n", s->name);}const char *onoff(int x){ if (x) return "On "; return "Off";}void report(struct slabinfo *s){ if (strcmp(s->name, "*") == 0) return; printf("\nSlabcache: %-20s 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);}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; store_size(size_str, slab_size(s)); snprintf(dist_str, 40, "%lu/%lu/%d", s->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; printf("%-21s %8ld %7d %8s %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)) : 100, flags);}/* * Analyze debug options. Return false if something is amiss. */int debug_opt_scan(char *opt){ if (!opt || !opt[0] || strcmp(opt, "-") == 0) return 1; if (strcasecmp(opt, "a") == 0) { sanity = 1; poison = 1; redzone = 1; tracking = 1; return 1; } for ( ; *opt; opt++) switch (*opt) { case 'F' : case 'f': if (sanity) return 0; sanity = 1; break; case 'P' : case 'p': if (poison) return 0; poison = 1; break; case 'Z' : case 'z': if (redzone) return 0; redzone = 1; break; case 'U' : case 'u': if (tracking) return 0; tracking = 1; break; case 'T' : case 't': if (tracing) return 0; tracing = 1; break; default: return 0; } return 1;}int slab_empty(struct slabinfo *s){ if (s->objects > 0) return 0; /* * We may still have slabs even if there are no objects. Shrinking will * remove them. */ if (s->slabs != 0) set_obj(s, "shrink", 1); return 1;}void slab_debug(struct slabinfo *s){ if (strcmp(s->name, "*") == 0) return; 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);}void totals(void){ struct slabinfo *s;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -