Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Slabinfo: Tool to get reports about slabs
0004  *
0005  * (C) 2007 sgi, Christoph Lameter
0006  * (C) 2011 Linux Foundation, Christoph Lameter
0007  *
0008  * Compile with:
0009  *
0010  * gcc -o slabinfo slabinfo.c
0011  */
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <sys/types.h>
0015 #include <dirent.h>
0016 #include <strings.h>
0017 #include <string.h>
0018 #include <unistd.h>
0019 #include <stdarg.h>
0020 #include <getopt.h>
0021 #include <regex.h>
0022 #include <errno.h>
0023 
0024 #define MAX_SLABS 500
0025 #define MAX_ALIASES 500
0026 #define MAX_NODES 1024
0027 
0028 struct slabinfo {
0029     char *name;
0030     int alias;
0031     int refs;
0032     int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
0033     unsigned int hwcache_align, object_size, objs_per_slab;
0034     unsigned int sanity_checks, slab_size, store_user, trace;
0035     int order, poison, reclaim_account, red_zone;
0036     unsigned long partial, objects, slabs, objects_partial, objects_total;
0037     unsigned long alloc_fastpath, alloc_slowpath;
0038     unsigned long free_fastpath, free_slowpath;
0039     unsigned long free_frozen, free_add_partial, free_remove_partial;
0040     unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
0041     unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
0042     unsigned long deactivate_to_head, deactivate_to_tail;
0043     unsigned long deactivate_remote_frees, order_fallback;
0044     unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
0045     unsigned long alloc_node_mismatch, deactivate_bypass;
0046     unsigned long cpu_partial_alloc, cpu_partial_free;
0047     int numa[MAX_NODES];
0048     int numa_partial[MAX_NODES];
0049 } slabinfo[MAX_SLABS];
0050 
0051 struct aliasinfo {
0052     char *name;
0053     char *ref;
0054     struct slabinfo *slab;
0055 } aliasinfo[MAX_ALIASES];
0056 
0057 int slabs;
0058 int actual_slabs;
0059 int aliases;
0060 int alias_targets;
0061 int highest_node;
0062 
0063 char buffer[4096];
0064 
0065 int show_empty;
0066 int show_report;
0067 int show_alias;
0068 int show_slab;
0069 int skip_zero = 1;
0070 int show_numa;
0071 int show_track;
0072 int show_first_alias;
0073 int validate;
0074 int shrink;
0075 int show_inverted;
0076 int show_single_ref;
0077 int show_totals;
0078 int sort_size;
0079 int sort_active;
0080 int set_debug;
0081 int show_ops;
0082 int sort_partial;
0083 int show_activity;
0084 int output_lines = -1;
0085 int sort_loss;
0086 int extended_totals;
0087 int show_bytes;
0088 int unreclaim_only;
0089 
0090 /* Debug options */
0091 int sanity;
0092 int redzone;
0093 int poison;
0094 int tracking;
0095 int tracing;
0096 
0097 int page_size;
0098 
0099 regex_t pattern;
0100 
0101 static void fatal(const char *x, ...)
0102 {
0103     va_list ap;
0104 
0105     va_start(ap, x);
0106     vfprintf(stderr, x, ap);
0107     va_end(ap);
0108     exit(EXIT_FAILURE);
0109 }
0110 
0111 static void usage(void)
0112 {
0113     printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
0114         "slabinfo [-aABDefhilLnoPrsStTUvXz1] [N=K] [-dafzput] [slab-regexp]\n"
0115         "-a|--aliases           Show aliases\n"
0116         "-A|--activity          Most active slabs first\n"
0117         "-B|--Bytes             Show size in bytes\n"
0118         "-D|--display-active    Switch line format to activity\n"
0119         "-e|--empty             Show empty slabs\n"
0120         "-f|--first-alias       Show first alias\n"
0121         "-h|--help              Show usage information\n"
0122         "-i|--inverted          Inverted list\n"
0123         "-l|--slabs             Show slabs\n"
0124         "-L|--Loss              Sort by loss\n"
0125         "-n|--numa              Show NUMA information\n"
0126         "-N|--lines=K           Show the first K slabs\n"
0127         "-o|--ops               Show kmem_cache_ops\n"
0128         "-P|--partial           Sort by number of partial slabs\n"
0129         "-r|--report            Detailed report on single slabs\n"
0130         "-s|--shrink            Shrink slabs\n"
0131         "-S|--Size              Sort by size\n"
0132         "-t|--tracking          Show alloc/free information\n"
0133         "-T|--Totals            Show summary information\n"
0134         "-U|--Unreclaim         Show unreclaimable slabs only\n"
0135         "-v|--validate          Validate slabs\n"
0136         "-X|--Xtotals           Show extended summary information\n"
0137         "-z|--zero              Include empty slabs\n"
0138         "-1|--1ref              Single reference\n"
0139 
0140         "\n"
0141         "-d  | --debug          Switch off all debug options\n"
0142         "-da | --debug=a        Switch on all debug options (--debug=FZPU)\n"
0143 
0144         "\n"
0145         "-d[afzput] | --debug=[afzput]\n"
0146         "    f | F              Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n"
0147         "    z | Z              Redzoning\n"
0148         "    p | P              Poisoning\n"
0149         "    u | U              Tracking\n"
0150         "    t | T              Tracing\n"
0151 
0152         "\nSorting options (--Loss, --Size, --Partial) are mutually exclusive\n"
0153     );
0154 }
0155 
0156 static unsigned long read_obj(const char *name)
0157 {
0158     FILE *f = fopen(name, "r");
0159 
0160     if (!f)
0161         buffer[0] = 0;
0162     else {
0163         if (!fgets(buffer, sizeof(buffer), f))
0164             buffer[0] = 0;
0165         fclose(f);
0166         if (buffer[strlen(buffer)] == '\n')
0167             buffer[strlen(buffer)] = 0;
0168     }
0169     return strlen(buffer);
0170 }
0171 
0172 
0173 /*
0174  * Get the contents of an attribute
0175  */
0176 static unsigned long get_obj(const char *name)
0177 {
0178     if (!read_obj(name))
0179         return 0;
0180 
0181     return atol(buffer);
0182 }
0183 
0184 static unsigned long get_obj_and_str(const char *name, char **x)
0185 {
0186     unsigned long result = 0;
0187     char *p;
0188 
0189     *x = NULL;
0190 
0191     if (!read_obj(name)) {
0192         x = NULL;
0193         return 0;
0194     }
0195     result = strtoul(buffer, &p, 10);
0196     while (*p == ' ')
0197         p++;
0198     if (*p)
0199         *x = strdup(p);
0200     return result;
0201 }
0202 
0203 static void set_obj(struct slabinfo *s, const char *name, int n)
0204 {
0205     char x[100];
0206     FILE *f;
0207 
0208     snprintf(x, 100, "%s/%s", s->name, name);
0209     f = fopen(x, "w");
0210     if (!f)
0211         fatal("Cannot write to %s\n", x);
0212 
0213     fprintf(f, "%d\n", n);
0214     fclose(f);
0215 }
0216 
0217 static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
0218 {
0219     char x[100];
0220     FILE *f;
0221     size_t l;
0222 
0223     snprintf(x, 100, "%s/%s", s->name, name);
0224     f = fopen(x, "r");
0225     if (!f) {
0226         buffer[0] = 0;
0227         l = 0;
0228     } else {
0229         l = fread(buffer, 1, sizeof(buffer), f);
0230         buffer[l] = 0;
0231         fclose(f);
0232     }
0233     return l;
0234 }
0235 
0236 static unsigned long read_debug_slab_obj(struct slabinfo *s, const char *name)
0237 {
0238     char x[128];
0239     FILE *f;
0240     size_t l;
0241 
0242     snprintf(x, 128, "/sys/kernel/debug/slab/%s/%s", s->name, name);
0243     f = fopen(x, "r");
0244     if (!f) {
0245         buffer[0] = 0;
0246         l = 0;
0247     } else {
0248         l = fread(buffer, 1, sizeof(buffer), f);
0249         buffer[l] = 0;
0250         fclose(f);
0251     }
0252     return l;
0253 }
0254 
0255 /*
0256  * Put a size string together
0257  */
0258 static int store_size(char *buffer, unsigned long value)
0259 {
0260     unsigned long divisor = 1;
0261     char trailer = 0;
0262     int n;
0263 
0264     if (!show_bytes) {
0265         if (value > 1000000000UL) {
0266             divisor = 100000000UL;
0267             trailer = 'G';
0268         } else if (value > 1000000UL) {
0269             divisor = 100000UL;
0270             trailer = 'M';
0271         } else if (value > 1000UL) {
0272             divisor = 100;
0273             trailer = 'K';
0274         }
0275     }
0276 
0277     value /= divisor;
0278     n = sprintf(buffer, "%ld",value);
0279     if (trailer) {
0280         buffer[n] = trailer;
0281         n++;
0282         buffer[n] = 0;
0283     }
0284     if (divisor != 1) {
0285         memmove(buffer + n - 2, buffer + n - 3, 4);
0286         buffer[n-2] = '.';
0287         n++;
0288     }
0289     return n;
0290 }
0291 
0292 static void decode_numa_list(int *numa, char *t)
0293 {
0294     int node;
0295     int nr;
0296 
0297     memset(numa, 0, MAX_NODES * sizeof(int));
0298 
0299     if (!t)
0300         return;
0301 
0302     while (*t == 'N') {
0303         t++;
0304         node = strtoul(t, &t, 10);
0305         if (*t == '=') {
0306             t++;
0307             nr = strtoul(t, &t, 10);
0308             numa[node] = nr;
0309             if (node > highest_node)
0310                 highest_node = node;
0311         }
0312         while (*t == ' ')
0313             t++;
0314     }
0315 }
0316 
0317 static void slab_validate(struct slabinfo *s)
0318 {
0319     if (strcmp(s->name, "*") == 0)
0320         return;
0321 
0322     set_obj(s, "validate", 1);
0323 }
0324 
0325 static void slab_shrink(struct slabinfo *s)
0326 {
0327     if (strcmp(s->name, "*") == 0)
0328         return;
0329 
0330     set_obj(s, "shrink", 1);
0331 }
0332 
0333 int line = 0;
0334 
0335 static void first_line(void)
0336 {
0337     if (show_activity)
0338         printf("Name                   Objects      Alloc       Free"
0339             "   %%Fast Fallb O CmpX   UL\n");
0340     else
0341         printf("Name                   Objects Objsize           %s "
0342             "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n",
0343             sort_loss ? " Loss" : "Space");
0344 }
0345 
0346 /*
0347  * Find the shortest alias of a slab
0348  */
0349 static struct aliasinfo *find_one_alias(struct slabinfo *find)
0350 {
0351     struct aliasinfo *a;
0352     struct aliasinfo *best = NULL;
0353 
0354     for(a = aliasinfo;a < aliasinfo + aliases; a++) {
0355         if (a->slab == find &&
0356             (!best || strlen(best->name) < strlen(a->name))) {
0357                 best = a;
0358                 if (strncmp(a->name,"kmall", 5) == 0)
0359                     return best;
0360             }
0361     }
0362     return best;
0363 }
0364 
0365 static unsigned long slab_size(struct slabinfo *s)
0366 {
0367     return  s->slabs * (page_size << s->order);
0368 }
0369 
0370 static unsigned long slab_activity(struct slabinfo *s)
0371 {
0372     return  s->alloc_fastpath + s->free_fastpath +
0373         s->alloc_slowpath + s->free_slowpath;
0374 }
0375 
0376 static unsigned long slab_waste(struct slabinfo *s)
0377 {
0378     return  slab_size(s) - s->objects * s->object_size;
0379 }
0380 
0381 static void slab_numa(struct slabinfo *s, int mode)
0382 {
0383     int node;
0384 
0385     if (strcmp(s->name, "*") == 0)
0386         return;
0387 
0388     if (!highest_node) {
0389         printf("\n%s: No NUMA information available.\n", s->name);
0390         return;
0391     }
0392 
0393     if (skip_zero && !s->slabs)
0394         return;
0395 
0396     if (!line) {
0397         printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
0398         for(node = 0; node <= highest_node; node++)
0399             printf(" %4d", node);
0400         printf("\n----------------------");
0401         for(node = 0; node <= highest_node; node++)
0402             printf("-----");
0403         printf("\n");
0404     }
0405     printf("%-21s ", mode ? "All slabs" : s->name);
0406     for(node = 0; node <= highest_node; node++) {
0407         char b[20];
0408 
0409         store_size(b, s->numa[node]);
0410         printf(" %4s", b);
0411     }
0412     printf("\n");
0413     if (mode) {
0414         printf("%-21s ", "Partial slabs");
0415         for(node = 0; node <= highest_node; node++) {
0416             char b[20];
0417 
0418             store_size(b, s->numa_partial[node]);
0419             printf(" %4s", b);
0420         }
0421         printf("\n");
0422     }
0423     line++;
0424 }
0425 
0426 static void show_tracking(struct slabinfo *s)
0427 {
0428     printf("\n%s: Kernel object allocation\n", s->name);
0429     printf("-----------------------------------------------------------------------\n");
0430     if (read_debug_slab_obj(s, "alloc_traces"))
0431         printf("%s", buffer);
0432     else if (read_slab_obj(s, "alloc_calls"))
0433         printf("%s", buffer);
0434     else
0435         printf("No Data\n");
0436 
0437     printf("\n%s: Kernel object freeing\n", s->name);
0438     printf("------------------------------------------------------------------------\n");
0439     if (read_debug_slab_obj(s, "free_traces"))
0440         printf("%s", buffer);
0441     else if (read_slab_obj(s, "free_calls"))
0442         printf("%s", buffer);
0443     else
0444         printf("No Data\n");
0445 
0446 }
0447 
0448 static void ops(struct slabinfo *s)
0449 {
0450     if (strcmp(s->name, "*") == 0)
0451         return;
0452 
0453     if (read_slab_obj(s, "ops")) {
0454         printf("\n%s: kmem_cache operations\n", s->name);
0455         printf("--------------------------------------------\n");
0456         printf("%s", buffer);
0457     } else
0458         printf("\n%s has no kmem_cache operations\n", s->name);
0459 }
0460 
0461 static const char *onoff(int x)
0462 {
0463     if (x)
0464         return "On ";
0465     return "Off";
0466 }
0467 
0468 static void slab_stats(struct slabinfo *s)
0469 {
0470     unsigned long total_alloc;
0471     unsigned long total_free;
0472     unsigned long total;
0473 
0474     if (!s->alloc_slab)
0475         return;
0476 
0477     total_alloc = s->alloc_fastpath + s->alloc_slowpath;
0478     total_free = s->free_fastpath + s->free_slowpath;
0479 
0480     if (!total_alloc)
0481         return;
0482 
0483     printf("\n");
0484     printf("Slab Perf Counter       Alloc     Free %%Al %%Fr\n");
0485     printf("--------------------------------------------------\n");
0486     printf("Fastpath             %8lu %8lu %3lu %3lu\n",
0487         s->alloc_fastpath, s->free_fastpath,
0488         s->alloc_fastpath * 100 / total_alloc,
0489         total_free ? s->free_fastpath * 100 / total_free : 0);
0490     printf("Slowpath             %8lu %8lu %3lu %3lu\n",
0491         total_alloc - s->alloc_fastpath, s->free_slowpath,
0492         (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
0493         total_free ? s->free_slowpath * 100 / total_free : 0);
0494     printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
0495         s->alloc_slab, s->free_slab,
0496         s->alloc_slab * 100 / total_alloc,
0497         total_free ? s->free_slab * 100 / total_free : 0);
0498     printf("Add partial          %8lu %8lu %3lu %3lu\n",
0499         s->deactivate_to_head + s->deactivate_to_tail,
0500         s->free_add_partial,
0501         (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
0502         total_free ? s->free_add_partial * 100 / total_free : 0);
0503     printf("Remove partial       %8lu %8lu %3lu %3lu\n",
0504         s->alloc_from_partial, s->free_remove_partial,
0505         s->alloc_from_partial * 100 / total_alloc,
0506         total_free ? s->free_remove_partial * 100 / total_free : 0);
0507 
0508     printf("Cpu partial list     %8lu %8lu %3lu %3lu\n",
0509         s->cpu_partial_alloc, s->cpu_partial_free,
0510         s->cpu_partial_alloc * 100 / total_alloc,
0511         total_free ? s->cpu_partial_free * 100 / total_free : 0);
0512 
0513     printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
0514         s->deactivate_remote_frees, s->free_frozen,
0515         s->deactivate_remote_frees * 100 / total_alloc,
0516         total_free ? s->free_frozen * 100 / total_free : 0);
0517 
0518     printf("Total                %8lu %8lu\n\n", total_alloc, total_free);
0519 
0520     if (s->cpuslab_flush)
0521         printf("Flushes %8lu\n", s->cpuslab_flush);
0522 
0523     total = s->deactivate_full + s->deactivate_empty +
0524             s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass;
0525 
0526     if (total) {
0527         printf("\nSlab Deactivation             Occurrences %%\n");
0528         printf("-------------------------------------------------\n");
0529         printf("Slab full                     %7lu  %3lu%%\n",
0530             s->deactivate_full, (s->deactivate_full * 100) / total);
0531         printf("Slab empty                    %7lu  %3lu%%\n",
0532             s->deactivate_empty, (s->deactivate_empty * 100) / total);
0533         printf("Moved to head of partial list %7lu  %3lu%%\n",
0534             s->deactivate_to_head, (s->deactivate_to_head * 100) / total);
0535         printf("Moved to tail of partial list %7lu  %3lu%%\n",
0536             s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
0537         printf("Deactivation bypass           %7lu  %3lu%%\n",
0538             s->deactivate_bypass, (s->deactivate_bypass * 100) / total);
0539         printf("Refilled from foreign frees   %7lu  %3lu%%\n",
0540             s->alloc_refill, (s->alloc_refill * 100) / total);
0541         printf("Node mismatch                 %7lu  %3lu%%\n",
0542             s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
0543     }
0544 
0545     if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) {
0546         printf("\nCmpxchg_double Looping\n------------------------\n");
0547         printf("Locked Cmpxchg Double redos   %lu\nUnlocked Cmpxchg Double redos %lu\n",
0548             s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
0549     }
0550 }
0551 
0552 static void report(struct slabinfo *s)
0553 {
0554     if (strcmp(s->name, "*") == 0)
0555         return;
0556 
0557     printf("\nSlabcache: %-15s  Aliases: %2d Order : %2d Objects: %lu\n",
0558         s->name, s->aliases, s->order, s->objects);
0559     if (s->hwcache_align)
0560         printf("** Hardware cacheline aligned\n");
0561     if (s->cache_dma)
0562         printf("** Memory is allocated in a special DMA zone\n");
0563     if (s->destroy_by_rcu)
0564         printf("** Slabs are destroyed via RCU\n");
0565     if (s->reclaim_account)
0566         printf("** Reclaim accounting active\n");
0567 
0568     printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
0569     printf("------------------------------------------------------------------------\n");
0570     printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
0571             s->object_size, s->slabs, onoff(s->sanity_checks),
0572             s->slabs * (page_size << s->order));
0573     printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
0574             s->slab_size, s->slabs - s->partial - s->cpu_slabs,
0575             onoff(s->red_zone), s->objects * s->object_size);
0576     printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
0577             page_size << s->order, s->partial, onoff(s->poison),
0578             s->slabs * (page_size << s->order) - s->objects * s->object_size);
0579     printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
0580             s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
0581             (s->slab_size - s->object_size) * s->objects);
0582     printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
0583             s->align, s->objs_per_slab, onoff(s->trace),
0584             ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
0585             s->slabs);
0586 
0587     ops(s);
0588     show_tracking(s);
0589     slab_numa(s, 1);
0590     slab_stats(s);
0591 }
0592 
0593 static void slabcache(struct slabinfo *s)
0594 {
0595     char size_str[20];
0596     char dist_str[40];
0597     char flags[20];
0598     char *p = flags;
0599 
0600     if (strcmp(s->name, "*") == 0)
0601         return;
0602 
0603     if (unreclaim_only && s->reclaim_account)
0604         return;
0605 
0606     if (actual_slabs == 1) {
0607         report(s);
0608         return;
0609     }
0610 
0611     if (skip_zero && !show_empty && !s->slabs)
0612         return;
0613 
0614     if (show_empty && s->slabs)
0615         return;
0616 
0617     if (sort_loss == 0)
0618         store_size(size_str, slab_size(s));
0619     else
0620         store_size(size_str, slab_waste(s));
0621     snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
0622                         s->partial, s->cpu_slabs);
0623 
0624     if (!line++)
0625         first_line();
0626 
0627     if (s->aliases)
0628         *p++ = '*';
0629     if (s->cache_dma)
0630         *p++ = 'd';
0631     if (s->hwcache_align)
0632         *p++ = 'A';
0633     if (s->poison)
0634         *p++ = 'P';
0635     if (s->reclaim_account)
0636         *p++ = 'a';
0637     if (s->red_zone)
0638         *p++ = 'Z';
0639     if (s->sanity_checks)
0640         *p++ = 'F';
0641     if (s->store_user)
0642         *p++ = 'U';
0643     if (s->trace)
0644         *p++ = 'T';
0645 
0646     *p = 0;
0647     if (show_activity) {
0648         unsigned long total_alloc;
0649         unsigned long total_free;
0650 
0651         total_alloc = s->alloc_fastpath + s->alloc_slowpath;
0652         total_free = s->free_fastpath + s->free_slowpath;
0653 
0654         printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n",
0655             s->name, s->objects,
0656             total_alloc, total_free,
0657             total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
0658             total_free ? (s->free_fastpath * 100 / total_free) : 0,
0659             s->order_fallback, s->order, s->cmpxchg_double_fail,
0660             s->cmpxchg_double_cpu_fail);
0661     } else {
0662         printf("%-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s\n",
0663             s->name, s->objects, s->object_size, size_str, dist_str,
0664             s->objs_per_slab, s->order,
0665             s->slabs ? (s->partial * 100) / s->slabs : 100,
0666             s->slabs ? (s->objects * s->object_size * 100) /
0667                 (s->slabs * (page_size << s->order)) : 100,
0668             flags);
0669     }
0670 }
0671 
0672 /*
0673  * Analyze debug options. Return false if something is amiss.
0674  */
0675 static int debug_opt_scan(char *opt)
0676 {
0677     if (!opt || !opt[0] || strcmp(opt, "-") == 0)
0678         return 1;
0679 
0680     if (strcasecmp(opt, "a") == 0) {
0681         sanity = 1;
0682         poison = 1;
0683         redzone = 1;
0684         tracking = 1;
0685         return 1;
0686     }
0687 
0688     for ( ; *opt; opt++)
0689         switch (*opt) {
0690         case 'F' : case 'f':
0691             if (sanity)
0692                 return 0;
0693             sanity = 1;
0694             break;
0695         case 'P' : case 'p':
0696             if (poison)
0697                 return 0;
0698             poison = 1;
0699             break;
0700 
0701         case 'Z' : case 'z':
0702             if (redzone)
0703                 return 0;
0704             redzone = 1;
0705             break;
0706 
0707         case 'U' : case 'u':
0708             if (tracking)
0709                 return 0;
0710             tracking = 1;
0711             break;
0712 
0713         case 'T' : case 't':
0714             if (tracing)
0715                 return 0;
0716             tracing = 1;
0717             break;
0718         default:
0719             return 0;
0720         }
0721     return 1;
0722 }
0723 
0724 static int slab_empty(struct slabinfo *s)
0725 {
0726     if (s->objects > 0)
0727         return 0;
0728 
0729     /*
0730      * We may still have slabs even if there are no objects. Shrinking will
0731      * remove them.
0732      */
0733     if (s->slabs != 0)
0734         set_obj(s, "shrink", 1);
0735 
0736     return 1;
0737 }
0738 
0739 static void slab_debug(struct slabinfo *s)
0740 {
0741     if (strcmp(s->name, "*") == 0)
0742         return;
0743 
0744     if (sanity && !s->sanity_checks) {
0745         set_obj(s, "sanity_checks", 1);
0746     }
0747     if (!sanity && s->sanity_checks) {
0748         if (slab_empty(s))
0749             set_obj(s, "sanity_checks", 0);
0750         else
0751             fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
0752     }
0753     if (redzone && !s->red_zone) {
0754         if (slab_empty(s))
0755             set_obj(s, "red_zone", 1);
0756         else
0757             fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
0758     }
0759     if (!redzone && s->red_zone) {
0760         if (slab_empty(s))
0761             set_obj(s, "red_zone", 0);
0762         else
0763             fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
0764     }
0765     if (poison && !s->poison) {
0766         if (slab_empty(s))
0767             set_obj(s, "poison", 1);
0768         else
0769             fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
0770     }
0771     if (!poison && s->poison) {
0772         if (slab_empty(s))
0773             set_obj(s, "poison", 0);
0774         else
0775             fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
0776     }
0777     if (tracking && !s->store_user) {
0778         if (slab_empty(s))
0779             set_obj(s, "store_user", 1);
0780         else
0781             fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
0782     }
0783     if (!tracking && s->store_user) {
0784         if (slab_empty(s))
0785             set_obj(s, "store_user", 0);
0786         else
0787             fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
0788     }
0789     if (tracing && !s->trace) {
0790         if (slabs == 1)
0791             set_obj(s, "trace", 1);
0792         else
0793             fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
0794     }
0795     if (!tracing && s->trace)
0796         set_obj(s, "trace", 1);
0797 }
0798 
0799 static void totals(void)
0800 {
0801     struct slabinfo *s;
0802 
0803     int used_slabs = 0;
0804     char b1[20], b2[20], b3[20], b4[20];
0805     unsigned long long max = 1ULL << 63;
0806 
0807     /* Object size */
0808     unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
0809 
0810     /* Number of partial slabs in a slabcache */
0811     unsigned long long min_partial = max, max_partial = 0,
0812                 avg_partial, total_partial = 0;
0813 
0814     /* Number of slabs in a slab cache */
0815     unsigned long long min_slabs = max, max_slabs = 0,
0816                 avg_slabs, total_slabs = 0;
0817 
0818     /* Size of the whole slab */
0819     unsigned long long min_size = max, max_size = 0,
0820                 avg_size, total_size = 0;
0821 
0822     /* Bytes used for object storage in a slab */
0823     unsigned long long min_used = max, max_used = 0,
0824                 avg_used, total_used = 0;
0825 
0826     /* Waste: Bytes used for alignment and padding */
0827     unsigned long long min_waste = max, max_waste = 0,
0828                 avg_waste, total_waste = 0;
0829     /* Number of objects in a slab */
0830     unsigned long long min_objects = max, max_objects = 0,
0831                 avg_objects, total_objects = 0;
0832     /* Waste per object */
0833     unsigned long long min_objwaste = max,
0834                 max_objwaste = 0, avg_objwaste,
0835                 total_objwaste = 0;
0836 
0837     /* Memory per object */
0838     unsigned long long min_memobj = max,
0839                 max_memobj = 0, avg_memobj,
0840                 total_objsize = 0;
0841 
0842     /* Percentage of partial slabs per slab */
0843     unsigned long min_ppart = 100, max_ppart = 0,
0844                 avg_ppart, total_ppart = 0;
0845 
0846     /* Number of objects in partial slabs */
0847     unsigned long min_partobj = max, max_partobj = 0,
0848                 avg_partobj, total_partobj = 0;
0849 
0850     /* Percentage of partial objects of all objects in a slab */
0851     unsigned long min_ppartobj = 100, max_ppartobj = 0,
0852                 avg_ppartobj, total_ppartobj = 0;
0853 
0854 
0855     for (s = slabinfo; s < slabinfo + slabs; s++) {
0856         unsigned long long size;
0857         unsigned long used;
0858         unsigned long long wasted;
0859         unsigned long long objwaste;
0860         unsigned long percentage_partial_slabs;
0861         unsigned long percentage_partial_objs;
0862 
0863         if (!s->slabs || !s->objects)
0864             continue;
0865 
0866         used_slabs++;
0867 
0868         size = slab_size(s);
0869         used = s->objects * s->object_size;
0870         wasted = size - used;
0871         objwaste = s->slab_size - s->object_size;
0872 
0873         percentage_partial_slabs = s->partial * 100 / s->slabs;
0874         if (percentage_partial_slabs > 100)
0875             percentage_partial_slabs = 100;
0876 
0877         percentage_partial_objs = s->objects_partial * 100
0878                             / s->objects;
0879 
0880         if (percentage_partial_objs > 100)
0881             percentage_partial_objs = 100;
0882 
0883         if (s->object_size < min_objsize)
0884             min_objsize = s->object_size;
0885         if (s->partial < min_partial)
0886             min_partial = s->partial;
0887         if (s->slabs < min_slabs)
0888             min_slabs = s->slabs;
0889         if (size < min_size)
0890             min_size = size;
0891         if (wasted < min_waste)
0892             min_waste = wasted;
0893         if (objwaste < min_objwaste)
0894             min_objwaste = objwaste;
0895         if (s->objects < min_objects)
0896             min_objects = s->objects;
0897         if (used < min_used)
0898             min_used = used;
0899         if (s->objects_partial < min_partobj)
0900             min_partobj = s->objects_partial;
0901         if (percentage_partial_slabs < min_ppart)
0902             min_ppart = percentage_partial_slabs;
0903         if (percentage_partial_objs < min_ppartobj)
0904             min_ppartobj = percentage_partial_objs;
0905         if (s->slab_size < min_memobj)
0906             min_memobj = s->slab_size;
0907 
0908         if (s->object_size > max_objsize)
0909             max_objsize = s->object_size;
0910         if (s->partial > max_partial)
0911             max_partial = s->partial;
0912         if (s->slabs > max_slabs)
0913             max_slabs = s->slabs;
0914         if (size > max_size)
0915             max_size = size;
0916         if (wasted > max_waste)
0917             max_waste = wasted;
0918         if (objwaste > max_objwaste)
0919             max_objwaste = objwaste;
0920         if (s->objects > max_objects)
0921             max_objects = s->objects;
0922         if (used > max_used)
0923             max_used = used;
0924         if (s->objects_partial > max_partobj)
0925             max_partobj = s->objects_partial;
0926         if (percentage_partial_slabs > max_ppart)
0927             max_ppart = percentage_partial_slabs;
0928         if (percentage_partial_objs > max_ppartobj)
0929             max_ppartobj = percentage_partial_objs;
0930         if (s->slab_size > max_memobj)
0931             max_memobj = s->slab_size;
0932 
0933         total_partial += s->partial;
0934         total_slabs += s->slabs;
0935         total_size += size;
0936         total_waste += wasted;
0937 
0938         total_objects += s->objects;
0939         total_used += used;
0940         total_partobj += s->objects_partial;
0941         total_ppart += percentage_partial_slabs;
0942         total_ppartobj += percentage_partial_objs;
0943 
0944         total_objwaste += s->objects * objwaste;
0945         total_objsize += s->objects * s->slab_size;
0946     }
0947 
0948     if (!total_objects) {
0949         printf("No objects\n");
0950         return;
0951     }
0952     if (!used_slabs) {
0953         printf("No slabs\n");
0954         return;
0955     }
0956 
0957     /* Per slab averages */
0958     avg_partial = total_partial / used_slabs;
0959     avg_slabs = total_slabs / used_slabs;
0960     avg_size = total_size / used_slabs;
0961     avg_waste = total_waste / used_slabs;
0962 
0963     avg_objects = total_objects / used_slabs;
0964     avg_used = total_used / used_slabs;
0965     avg_partobj = total_partobj / used_slabs;
0966     avg_ppart = total_ppart / used_slabs;
0967     avg_ppartobj = total_ppartobj / used_slabs;
0968 
0969     /* Per object object sizes */
0970     avg_objsize = total_used / total_objects;
0971     avg_objwaste = total_objwaste / total_objects;
0972     avg_partobj = total_partobj * 100 / total_objects;
0973     avg_memobj = total_objsize / total_objects;
0974 
0975     printf("Slabcache Totals\n");
0976     printf("----------------\n");
0977     printf("Slabcaches : %15d   Aliases  : %11d->%-3d  Active:    %3d\n",
0978             slabs, aliases, alias_targets, used_slabs);
0979 
0980     store_size(b1, total_size);store_size(b2, total_waste);
0981     store_size(b3, total_waste * 100 / total_used);
0982     printf("Memory used: %15s   # Loss   : %15s   MRatio:%6s%%\n", b1, b2, b3);
0983 
0984     store_size(b1, total_objects);store_size(b2, total_partobj);
0985     store_size(b3, total_partobj * 100 / total_objects);
0986     printf("# Objects  : %15s   # PartObj: %15s   ORatio:%6s%%\n", b1, b2, b3);
0987 
0988     printf("\n");
0989     printf("Per Cache         Average              "
0990         "Min              Max            Total\n");
0991     printf("---------------------------------------"
0992         "-------------------------------------\n");
0993 
0994     store_size(b1, avg_objects);store_size(b2, min_objects);
0995     store_size(b3, max_objects);store_size(b4, total_objects);
0996     printf("#Objects  %15s  %15s  %15s  %15s\n",
0997             b1, b2, b3, b4);
0998 
0999     store_size(b1, avg_slabs);store_size(b2, min_slabs);
1000     store_size(b3, max_slabs);store_size(b4, total_slabs);
1001     printf("#Slabs    %15s  %15s  %15s  %15s\n",
1002             b1, b2, b3, b4);
1003 
1004     store_size(b1, avg_partial);store_size(b2, min_partial);
1005     store_size(b3, max_partial);store_size(b4, total_partial);
1006     printf("#PartSlab %15s  %15s  %15s  %15s\n",
1007             b1, b2, b3, b4);
1008     store_size(b1, avg_ppart);store_size(b2, min_ppart);
1009     store_size(b3, max_ppart);
1010     store_size(b4, total_partial * 100  / total_slabs);
1011     printf("%%PartSlab%15s%% %15s%% %15s%% %15s%%\n",
1012             b1, b2, b3, b4);
1013 
1014     store_size(b1, avg_partobj);store_size(b2, min_partobj);
1015     store_size(b3, max_partobj);
1016     store_size(b4, total_partobj);
1017     printf("PartObjs  %15s  %15s  %15s  %15s\n",
1018             b1, b2, b3, b4);
1019 
1020     store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
1021     store_size(b3, max_ppartobj);
1022     store_size(b4, total_partobj * 100 / total_objects);
1023     printf("%% PartObj%15s%% %15s%% %15s%% %15s%%\n",
1024             b1, b2, b3, b4);
1025 
1026     store_size(b1, avg_size);store_size(b2, min_size);
1027     store_size(b3, max_size);store_size(b4, total_size);
1028     printf("Memory    %15s  %15s  %15s  %15s\n",
1029             b1, b2, b3, b4);
1030 
1031     store_size(b1, avg_used);store_size(b2, min_used);
1032     store_size(b3, max_used);store_size(b4, total_used);
1033     printf("Used      %15s  %15s  %15s  %15s\n",
1034             b1, b2, b3, b4);
1035 
1036     store_size(b1, avg_waste);store_size(b2, min_waste);
1037     store_size(b3, max_waste);store_size(b4, total_waste);
1038     printf("Loss      %15s  %15s  %15s  %15s\n",
1039             b1, b2, b3, b4);
1040 
1041     printf("\n");
1042     printf("Per Object        Average              "
1043         "Min              Max\n");
1044     printf("---------------------------------------"
1045         "--------------------\n");
1046 
1047     store_size(b1, avg_memobj);store_size(b2, min_memobj);
1048     store_size(b3, max_memobj);
1049     printf("Memory    %15s  %15s  %15s\n",
1050             b1, b2, b3);
1051     store_size(b1, avg_objsize);store_size(b2, min_objsize);
1052     store_size(b3, max_objsize);
1053     printf("User      %15s  %15s  %15s\n",
1054             b1, b2, b3);
1055 
1056     store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
1057     store_size(b3, max_objwaste);
1058     printf("Loss      %15s  %15s  %15s\n",
1059             b1, b2, b3);
1060 }
1061 
1062 static void sort_slabs(void)
1063 {
1064     struct slabinfo *s1,*s2;
1065 
1066     for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
1067         for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
1068             int result;
1069 
1070             if (sort_size) {
1071                 if (slab_size(s1) == slab_size(s2))
1072                     result = strcasecmp(s1->name, s2->name);
1073                 else
1074                     result = slab_size(s1) < slab_size(s2);
1075             } else if (sort_active) {
1076                 if (slab_activity(s1) == slab_activity(s2))
1077                     result = strcasecmp(s1->name, s2->name);
1078                 else
1079                     result = slab_activity(s1) < slab_activity(s2);
1080             } else if (sort_loss) {
1081                 if (slab_waste(s1) == slab_waste(s2))
1082                     result = strcasecmp(s1->name, s2->name);
1083                 else
1084                     result = slab_waste(s1) < slab_waste(s2);
1085             } else if (sort_partial) {
1086                 if (s1->partial == s2->partial)
1087                     result = strcasecmp(s1->name, s2->name);
1088                 else
1089                     result = s1->partial < s2->partial;
1090             } else
1091                 result = strcasecmp(s1->name, s2->name);
1092 
1093             if (show_inverted)
1094                 result = -result;
1095 
1096             if (result > 0) {
1097                 struct slabinfo t;
1098 
1099                 memcpy(&t, s1, sizeof(struct slabinfo));
1100                 memcpy(s1, s2, sizeof(struct slabinfo));
1101                 memcpy(s2, &t, sizeof(struct slabinfo));
1102             }
1103         }
1104     }
1105 }
1106 
1107 static void sort_aliases(void)
1108 {
1109     struct aliasinfo *a1,*a2;
1110 
1111     for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
1112         for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
1113             char *n1, *n2;
1114 
1115             n1 = a1->name;
1116             n2 = a2->name;
1117             if (show_alias && !show_inverted) {
1118                 n1 = a1->ref;
1119                 n2 = a2->ref;
1120             }
1121             if (strcasecmp(n1, n2) > 0) {
1122                 struct aliasinfo t;
1123 
1124                 memcpy(&t, a1, sizeof(struct aliasinfo));
1125                 memcpy(a1, a2, sizeof(struct aliasinfo));
1126                 memcpy(a2, &t, sizeof(struct aliasinfo));
1127             }
1128         }
1129     }
1130 }
1131 
1132 static void link_slabs(void)
1133 {
1134     struct aliasinfo *a;
1135     struct slabinfo *s;
1136 
1137     for (a = aliasinfo; a < aliasinfo + aliases; a++) {
1138 
1139         for (s = slabinfo; s < slabinfo + slabs; s++)
1140             if (strcmp(a->ref, s->name) == 0) {
1141                 a->slab = s;
1142                 s->refs++;
1143                 break;
1144             }
1145         if (s == slabinfo + slabs)
1146             fatal("Unresolved alias %s\n", a->ref);
1147     }
1148 }
1149 
1150 static void alias(void)
1151 {
1152     struct aliasinfo *a;
1153     char *active = NULL;
1154 
1155     sort_aliases();
1156     link_slabs();
1157 
1158     for(a = aliasinfo; a < aliasinfo + aliases; a++) {
1159 
1160         if (!show_single_ref && a->slab->refs == 1)
1161             continue;
1162 
1163         if (!show_inverted) {
1164             if (active) {
1165                 if (strcmp(a->slab->name, active) == 0) {
1166                     printf(" %s", a->name);
1167                     continue;
1168                 }
1169             }
1170             printf("\n%-12s <- %s", a->slab->name, a->name);
1171             active = a->slab->name;
1172         }
1173         else
1174             printf("%-15s -> %s\n", a->name, a->slab->name);
1175     }
1176     if (active)
1177         printf("\n");
1178 }
1179 
1180 
1181 static void rename_slabs(void)
1182 {
1183     struct slabinfo *s;
1184     struct aliasinfo *a;
1185 
1186     for (s = slabinfo; s < slabinfo + slabs; s++) {
1187         if (*s->name != ':')
1188             continue;
1189 
1190         if (s->refs > 1 && !show_first_alias)
1191             continue;
1192 
1193         a = find_one_alias(s);
1194 
1195         if (a)
1196             s->name = a->name;
1197         else {
1198             s->name = "*";
1199             actual_slabs--;
1200         }
1201     }
1202 }
1203 
1204 static int slab_mismatch(char *slab)
1205 {
1206     return regexec(&pattern, slab, 0, NULL, 0);
1207 }
1208 
1209 static void read_slab_dir(void)
1210 {
1211     DIR *dir;
1212     struct dirent *de;
1213     struct slabinfo *slab = slabinfo;
1214     struct aliasinfo *alias = aliasinfo;
1215     char *p;
1216     char *t;
1217     int count;
1218 
1219     if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
1220         fatal("SYSFS support for SLUB not active\n");
1221 
1222     dir = opendir(".");
1223     while ((de = readdir(dir))) {
1224         if (de->d_name[0] == '.' ||
1225             (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
1226                 continue;
1227         switch (de->d_type) {
1228            case DT_LNK:
1229             alias->name = strdup(de->d_name);
1230             count = readlink(de->d_name, buffer, sizeof(buffer)-1);
1231 
1232             if (count < 0)
1233                 fatal("Cannot read symlink %s\n", de->d_name);
1234 
1235             buffer[count] = 0;
1236             p = buffer + count;
1237             while (p > buffer && p[-1] != '/')
1238                 p--;
1239             alias->ref = strdup(p);
1240             alias++;
1241             break;
1242            case DT_DIR:
1243             if (chdir(de->d_name))
1244                 fatal("Unable to access slab %s\n", slab->name);
1245             slab->name = strdup(de->d_name);
1246             slab->alias = 0;
1247             slab->refs = 0;
1248             slab->aliases = get_obj("aliases");
1249             slab->align = get_obj("align");
1250             slab->cache_dma = get_obj("cache_dma");
1251             slab->cpu_slabs = get_obj("cpu_slabs");
1252             slab->destroy_by_rcu = get_obj("destroy_by_rcu");
1253             slab->hwcache_align = get_obj("hwcache_align");
1254             slab->object_size = get_obj("object_size");
1255             slab->objects = get_obj("objects");
1256             slab->objects_partial = get_obj("objects_partial");
1257             slab->objects_total = get_obj("objects_total");
1258             slab->objs_per_slab = get_obj("objs_per_slab");
1259             slab->order = get_obj("order");
1260             slab->partial = get_obj("partial");
1261             slab->partial = get_obj_and_str("partial", &t);
1262             decode_numa_list(slab->numa_partial, t);
1263             free(t);
1264             slab->poison = get_obj("poison");
1265             slab->reclaim_account = get_obj("reclaim_account");
1266             slab->red_zone = get_obj("red_zone");
1267             slab->sanity_checks = get_obj("sanity_checks");
1268             slab->slab_size = get_obj("slab_size");
1269             slab->slabs = get_obj_and_str("slabs", &t);
1270             decode_numa_list(slab->numa, t);
1271             free(t);
1272             slab->store_user = get_obj("store_user");
1273             slab->trace = get_obj("trace");
1274             slab->alloc_fastpath = get_obj("alloc_fastpath");
1275             slab->alloc_slowpath = get_obj("alloc_slowpath");
1276             slab->free_fastpath = get_obj("free_fastpath");
1277             slab->free_slowpath = get_obj("free_slowpath");
1278             slab->free_frozen= get_obj("free_frozen");
1279             slab->free_add_partial = get_obj("free_add_partial");
1280             slab->free_remove_partial = get_obj("free_remove_partial");
1281             slab->alloc_from_partial = get_obj("alloc_from_partial");
1282             slab->alloc_slab = get_obj("alloc_slab");
1283             slab->alloc_refill = get_obj("alloc_refill");
1284             slab->free_slab = get_obj("free_slab");
1285             slab->cpuslab_flush = get_obj("cpuslab_flush");
1286             slab->deactivate_full = get_obj("deactivate_full");
1287             slab->deactivate_empty = get_obj("deactivate_empty");
1288             slab->deactivate_to_head = get_obj("deactivate_to_head");
1289             slab->deactivate_to_tail = get_obj("deactivate_to_tail");
1290             slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
1291             slab->order_fallback = get_obj("order_fallback");
1292             slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
1293             slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
1294             slab->cpu_partial_alloc = get_obj("cpu_partial_alloc");
1295             slab->cpu_partial_free = get_obj("cpu_partial_free");
1296             slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
1297             slab->deactivate_bypass = get_obj("deactivate_bypass");
1298             chdir("..");
1299             if (slab->name[0] == ':')
1300                 alias_targets++;
1301             slab++;
1302             break;
1303            default :
1304             fatal("Unknown file type %lx\n", de->d_type);
1305         }
1306     }
1307     closedir(dir);
1308     slabs = slab - slabinfo;
1309     actual_slabs = slabs;
1310     aliases = alias - aliasinfo;
1311     if (slabs > MAX_SLABS)
1312         fatal("Too many slabs\n");
1313     if (aliases > MAX_ALIASES)
1314         fatal("Too many aliases\n");
1315 }
1316 
1317 static void output_slabs(void)
1318 {
1319     struct slabinfo *slab;
1320     int lines = output_lines;
1321 
1322     for (slab = slabinfo; (slab < slabinfo + slabs) &&
1323             lines != 0; slab++) {
1324 
1325         if (slab->alias)
1326             continue;
1327 
1328         if (lines != -1)
1329             lines--;
1330 
1331         if (show_numa)
1332             slab_numa(slab, 0);
1333         else if (show_track)
1334             show_tracking(slab);
1335         else if (validate)
1336             slab_validate(slab);
1337         else if (shrink)
1338             slab_shrink(slab);
1339         else if (set_debug)
1340             slab_debug(slab);
1341         else if (show_ops)
1342             ops(slab);
1343         else if (show_slab)
1344             slabcache(slab);
1345         else if (show_report)
1346             report(slab);
1347     }
1348 }
1349 
1350 static void _xtotals(char *heading, char *underline,
1351              int loss, int size, int partial)
1352 {
1353     printf("%s%s", heading, underline);
1354     line = 0;
1355     sort_loss = loss;
1356     sort_size = size;
1357     sort_partial = partial;
1358     sort_slabs();
1359     output_slabs();
1360 }
1361 
1362 static void xtotals(void)
1363 {
1364     char *heading, *underline;
1365 
1366     totals();
1367 
1368     link_slabs();
1369     rename_slabs();
1370 
1371     heading = "\nSlabs sorted by size\n";
1372     underline = "--------------------\n";
1373     _xtotals(heading, underline, 0, 1, 0);
1374 
1375     heading = "\nSlabs sorted by loss\n";
1376     underline = "--------------------\n";
1377     _xtotals(heading, underline, 1, 0, 0);
1378 
1379     heading = "\nSlabs sorted by number of partial slabs\n";
1380     underline = "---------------------------------------\n";
1381     _xtotals(heading, underline, 0, 0, 1);
1382 
1383     printf("\n");
1384 }
1385 
1386 struct option opts[] = {
1387     { "aliases", no_argument, NULL, 'a' },
1388     { "activity", no_argument, NULL, 'A' },
1389     { "Bytes", no_argument, NULL, 'B'},
1390     { "debug", optional_argument, NULL, 'd' },
1391     { "display-activity", no_argument, NULL, 'D' },
1392     { "empty", no_argument, NULL, 'e' },
1393     { "first-alias", no_argument, NULL, 'f' },
1394     { "help", no_argument, NULL, 'h' },
1395     { "inverted", no_argument, NULL, 'i'},
1396     { "slabs", no_argument, NULL, 'l' },
1397     { "Loss", no_argument, NULL, 'L'},
1398     { "numa", no_argument, NULL, 'n' },
1399     { "lines", required_argument, NULL, 'N'},
1400     { "ops", no_argument, NULL, 'o' },
1401     { "partial", no_argument, NULL, 'p'},
1402     { "report", no_argument, NULL, 'r' },
1403     { "shrink", no_argument, NULL, 's' },
1404     { "Size", no_argument, NULL, 'S'},
1405     { "tracking", no_argument, NULL, 't'},
1406     { "Totals", no_argument, NULL, 'T'},
1407     { "Unreclaim", no_argument, NULL, 'U'},
1408     { "validate", no_argument, NULL, 'v' },
1409     { "Xtotals", no_argument, NULL, 'X'},
1410     { "zero", no_argument, NULL, 'z' },
1411     { "1ref", no_argument, NULL, '1'},
1412     { NULL, 0, NULL, 0 }
1413 };
1414 
1415 int main(int argc, char *argv[])
1416 {
1417     int c;
1418     int err;
1419     char *pattern_source;
1420 
1421     page_size = getpagesize();
1422 
1423     while ((c = getopt_long(argc, argv, "aABd::DefhilLnN:oPrsStTUvXz1",
1424                         opts, NULL)) != -1)
1425         switch (c) {
1426         case 'a':
1427             show_alias = 1;
1428             break;
1429         case 'A':
1430             sort_active = 1;
1431             break;
1432         case 'B':
1433             show_bytes = 1;
1434             break;
1435         case 'd':
1436             set_debug = 1;
1437             if (!debug_opt_scan(optarg))
1438                 fatal("Invalid debug option '%s'\n", optarg);
1439             break;
1440         case 'D':
1441             show_activity = 1;
1442             break;
1443         case 'e':
1444             show_empty = 1;
1445             break;
1446         case 'f':
1447             show_first_alias = 1;
1448             break;
1449         case 'h':
1450             usage();
1451             return 0;
1452         case 'i':
1453             show_inverted = 1;
1454             break;
1455         case 'l':
1456             show_slab = 1;
1457             break;
1458         case 'L':
1459             sort_loss = 1;
1460             break;
1461         case 'n':
1462             show_numa = 1;
1463             break;
1464         case 'N':
1465             if (optarg) {
1466                 output_lines = atoi(optarg);
1467                 if (output_lines < 1)
1468                     output_lines = 1;
1469             }
1470             break;
1471         case 'o':
1472             show_ops = 1;
1473             break;
1474         case 'r':
1475             show_report = 1;
1476             break;
1477         case 'P':
1478             sort_partial = 1;
1479             break;
1480         case 's':
1481             shrink = 1;
1482             break;
1483         case 'S':
1484             sort_size = 1;
1485             break;
1486         case 't':
1487             show_track = 1;
1488             break;
1489         case 'T':
1490             show_totals = 1;
1491             break;
1492         case 'U':
1493             unreclaim_only = 1;
1494             break;
1495         case 'v':
1496             validate = 1;
1497             break;
1498         case 'X':
1499             if (output_lines == -1)
1500                 output_lines = 1;
1501             extended_totals = 1;
1502             show_bytes = 1;
1503             break;
1504         case 'z':
1505             skip_zero = 0;
1506             break;
1507         case '1':
1508             show_single_ref = 1;
1509             break;
1510         default:
1511             fatal("%s: Invalid option '%c'\n", argv[0], optopt);
1512 
1513     }
1514 
1515     if (!show_slab && !show_alias && !show_track && !show_report
1516         && !validate && !shrink && !set_debug && !show_ops)
1517             show_slab = 1;
1518 
1519     if (argc > optind)
1520         pattern_source = argv[optind];
1521     else
1522         pattern_source = ".*";
1523 
1524     err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
1525     if (err)
1526         fatal("%s: Invalid pattern '%s' code %d\n",
1527             argv[0], pattern_source, err);
1528     read_slab_dir();
1529     if (show_alias) {
1530         alias();
1531     } else if (extended_totals) {
1532         xtotals();
1533     } else if (show_totals) {
1534         totals();
1535     } else {
1536         link_slabs();
1537         rename_slabs();
1538         sort_slabs();
1539         output_slabs();
1540     }
1541     return 0;
1542 }