linux/tools/vm/slabinfo.c
<<
>>
Prefs
   1/*
   2 * Slabinfo: Tool to get reports about slabs
   3 *
   4 * (C) 2007 sgi, Christoph Lameter
   5 * (C) 2011 Linux Foundation, Christoph Lameter
   6 *
   7 * Compile with:
   8 *
   9 * gcc -o slabinfo slabinfo.c
  10 */
  11#include <stdio.h>
  12#include <stdlib.h>
  13#include <sys/types.h>
  14#include <dirent.h>
  15#include <strings.h>
  16#include <string.h>
  17#include <unistd.h>
  18#include <stdarg.h>
  19#include <getopt.h>
  20#include <regex.h>
  21#include <errno.h>
  22
  23#define MAX_SLABS 500
  24#define MAX_ALIASES 500
  25#define MAX_NODES 1024
  26
  27struct slabinfo {
  28        char *name;
  29        int alias;
  30        int refs;
  31        int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
  32        int hwcache_align, object_size, objs_per_slab;
  33        int sanity_checks, slab_size, store_user, trace;
  34        int order, poison, reclaim_account, red_zone;
  35        unsigned long partial, objects, slabs, objects_partial, objects_total;
  36        unsigned long alloc_fastpath, alloc_slowpath;
  37        unsigned long free_fastpath, free_slowpath;
  38        unsigned long free_frozen, free_add_partial, free_remove_partial;
  39        unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
  40        unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
  41        unsigned long deactivate_to_head, deactivate_to_tail;
  42        unsigned long deactivate_remote_frees, order_fallback;
  43        unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
  44        unsigned long alloc_node_mismatch, deactivate_bypass;
  45        unsigned long cpu_partial_alloc, cpu_partial_free;
  46        int numa[MAX_NODES];
  47        int numa_partial[MAX_NODES];
  48} slabinfo[MAX_SLABS];
  49
  50struct aliasinfo {
  51        char *name;
  52        char *ref;
  53        struct slabinfo *slab;
  54} aliasinfo[MAX_ALIASES];
  55
  56int slabs;
  57int actual_slabs;
  58int aliases;
  59int alias_targets;
  60int highest_node;
  61
  62char buffer[4096];
  63
  64int show_empty;
  65int show_report;
  66int show_alias;
  67int show_slab;
  68int skip_zero = 1;
  69int show_numa;
  70int show_track;
  71int show_first_alias;
  72int validate;
  73int shrink;
  74int show_inverted;
  75int show_single_ref;
  76int show_totals;
  77int sort_size;
  78int sort_active;
  79int set_debug;
  80int show_ops;
  81int show_activity;
  82int output_lines = -1;
  83int sort_loss;
  84int extended_totals;
  85int show_bytes;
  86
  87/* Debug options */
  88int sanity;
  89int redzone;
  90int poison;
  91int tracking;
  92int tracing;
  93
  94int page_size;
  95
  96regex_t pattern;
  97
  98static void fatal(const char *x, ...)
  99{
 100        va_list ap;
 101
 102        va_start(ap, x);
 103        vfprintf(stderr, x, ap);
 104        va_end(ap);
 105        exit(EXIT_FAILURE);
 106}
 107
 108static void usage(void)
 109{
 110        printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
 111                "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
 112                "-a|--aliases           Show aliases\n"
 113                "-A|--activity          Most active slabs first\n"
 114                "-d<options>|--debug=<options> Set/Clear Debug options\n"
 115                "-D|--display-active    Switch line format to activity\n"
 116                "-e|--empty             Show empty slabs\n"
 117                "-f|--first-alias       Show first alias\n"
 118                "-h|--help              Show usage information\n"
 119                "-i|--inverted          Inverted list\n"
 120                "-l|--slabs             Show slabs\n"
 121                "-n|--numa              Show NUMA information\n"
 122                "-o|--ops               Show kmem_cache_ops\n"
 123                "-s|--shrink            Shrink slabs\n"
 124                "-r|--report            Detailed report on single slabs\n"
 125                "-S|--Size              Sort by size\n"
 126                "-t|--tracking          Show alloc/free information\n"
 127                "-T|--Totals            Show summary information\n"
 128                "-v|--validate          Validate slabs\n"
 129                "-z|--zero              Include empty slabs\n"
 130                "-1|--1ref              Single reference\n"
 131                "-N|--lines=K           Show the first K slabs\n"
 132                "-L|--Loss              Sort by loss\n"
 133                "-X|--Xtotals           Show extended summary information\n"
 134                "-B|--Bytes             Show size in bytes\n"
 135                "\nValid debug options (FZPUT may be combined)\n"
 136                "a / A          Switch on all debug options (=FZUP)\n"
 137                "-              Switch off all debug options\n"
 138                "f / F          Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n"
 139                "z / Z          Redzoning\n"
 140                "p / P          Poisoning\n"
 141                "u / U          Tracking\n"
 142                "t / T          Tracing\n"
 143        );
 144}
 145
 146static unsigned long read_obj(const char *name)
 147{
 148        FILE *f = fopen(name, "r");
 149
 150        if (!f)
 151                buffer[0] = 0;
 152        else {
 153                if (!fgets(buffer, sizeof(buffer), f))
 154                        buffer[0] = 0;
 155                fclose(f);
 156                if (buffer[strlen(buffer)] == '\n')
 157                        buffer[strlen(buffer)] = 0;
 158        }
 159        return strlen(buffer);
 160}
 161
 162
 163/*
 164 * Get the contents of an attribute
 165 */
 166static unsigned long get_obj(const char *name)
 167{
 168        if (!read_obj(name))
 169                return 0;
 170
 171        return atol(buffer);
 172}
 173
 174static unsigned long get_obj_and_str(const char *name, char **x)
 175{
 176        unsigned long result = 0;
 177        char *p;
 178
 179        *x = NULL;
 180
 181        if (!read_obj(name)) {
 182                x = NULL;
 183                return 0;
 184        }
 185        result = strtoul(buffer, &p, 10);
 186        while (*p == ' ')
 187                p++;
 188        if (*p)
 189                *x = strdup(p);
 190        return result;
 191}
 192
 193static void set_obj(struct slabinfo *s, const char *name, int n)
 194{
 195        char x[100];
 196        FILE *f;
 197
 198        snprintf(x, 100, "%s/%s", s->name, name);
 199        f = fopen(x, "w");
 200        if (!f)
 201                fatal("Cannot write to %s\n", x);
 202
 203        fprintf(f, "%d\n", n);
 204        fclose(f);
 205}
 206
 207static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
 208{
 209        char x[100];
 210        FILE *f;
 211        size_t l;
 212
 213        snprintf(x, 100, "%s/%s", s->name, name);
 214        f = fopen(x, "r");
 215        if (!f) {
 216                buffer[0] = 0;
 217                l = 0;
 218        } else {
 219                l = fread(buffer, 1, sizeof(buffer), f);
 220                buffer[l] = 0;
 221                fclose(f);
 222        }
 223        return l;
 224}
 225
 226
 227/*
 228 * Put a size string together
 229 */
 230static int store_size(char *buffer, unsigned long value)
 231{
 232        unsigned long divisor = 1;
 233        char trailer = 0;
 234        int n;
 235
 236        if (!show_bytes) {
 237                if (value > 1000000000UL) {
 238                        divisor = 100000000UL;
 239                        trailer = 'G';
 240                } else if (value > 1000000UL) {
 241                        divisor = 100000UL;
 242                        trailer = 'M';
 243                } else if (value > 1000UL) {
 244                        divisor = 100;
 245                        trailer = 'K';
 246                }
 247        }
 248
 249        value /= divisor;
 250        n = sprintf(buffer, "%ld",value);
 251        if (trailer) {
 252                buffer[n] = trailer;
 253                n++;
 254                buffer[n] = 0;
 255        }
 256        if (divisor != 1) {
 257                memmove(buffer + n - 2, buffer + n - 3, 4);
 258                buffer[n-2] = '.';
 259                n++;
 260        }
 261        return n;
 262}
 263
 264static void decode_numa_list(int *numa, char *t)
 265{
 266        int node;
 267        int nr;
 268
 269        memset(numa, 0, MAX_NODES * sizeof(int));
 270
 271        if (!t)
 272                return;
 273
 274        while (*t == 'N') {
 275                t++;
 276                node = strtoul(t, &t, 10);
 277                if (*t == '=') {
 278                        t++;
 279                        nr = strtoul(t, &t, 10);
 280                        numa[node] = nr;
 281                        if (node > highest_node)
 282                                highest_node = node;
 283                }
 284                while (*t == ' ')
 285                        t++;
 286        }
 287}
 288
 289static void slab_validate(struct slabinfo *s)
 290{
 291        if (strcmp(s->name, "*") == 0)
 292                return;
 293
 294        set_obj(s, "validate", 1);
 295}
 296
 297static void slab_shrink(struct slabinfo *s)
 298{
 299        if (strcmp(s->name, "*") == 0)
 300                return;
 301
 302        set_obj(s, "shrink", 1);
 303}
 304
 305int line = 0;
 306
 307static void first_line(void)
 308{
 309        if (show_activity)
 310                printf("Name                   Objects      Alloc       Free"
 311                        "   %%Fast Fallb O CmpX   UL\n");
 312        else
 313                printf("Name                   Objects Objsize           %s "
 314                        "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n",
 315                        sort_loss ? " Loss" : "Space");
 316}
 317
 318/*
 319 * Find the shortest alias of a slab
 320 */
 321static struct aliasinfo *find_one_alias(struct slabinfo *find)
 322{
 323        struct aliasinfo *a;
 324        struct aliasinfo *best = NULL;
 325
 326        for(a = aliasinfo;a < aliasinfo + aliases; a++) {
 327                if (a->slab == find &&
 328                        (!best || strlen(best->name) < strlen(a->name))) {
 329                                best = a;
 330                                if (strncmp(a->name,"kmall", 5) == 0)
 331                                        return best;
 332                        }
 333        }
 334        return best;
 335}
 336
 337static unsigned long slab_size(struct slabinfo *s)
 338{
 339        return  s->slabs * (page_size << s->order);
 340}
 341
 342static unsigned long slab_activity(struct slabinfo *s)
 343{
 344        return  s->alloc_fastpath + s->free_fastpath +
 345                s->alloc_slowpath + s->free_slowpath;
 346}
 347
 348static unsigned long slab_waste(struct slabinfo *s)
 349{
 350        return  slab_size(s) - s->objects * s->object_size;
 351}
 352
 353static void slab_numa(struct slabinfo *s, int mode)
 354{
 355        int node;
 356
 357        if (strcmp(s->name, "*") == 0)
 358                return;
 359
 360        if (!highest_node) {
 361                printf("\n%s: No NUMA information available.\n", s->name);
 362                return;
 363        }
 364
 365        if (skip_zero && !s->slabs)
 366                return;
 367
 368        if (!line) {
 369                printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
 370                for(node = 0; node <= highest_node; node++)
 371                        printf(" %4d", node);
 372                printf("\n----------------------");
 373                for(node = 0; node <= highest_node; node++)
 374                        printf("-----");
 375                printf("\n");
 376        }
 377        printf("%-21s ", mode ? "All slabs" : s->name);
 378        for(node = 0; node <= highest_node; node++) {
 379                char b[20];
 380
 381                store_size(b, s->numa[node]);
 382                printf(" %4s", b);
 383        }
 384        printf("\n");
 385        if (mode) {
 386                printf("%-21s ", "Partial slabs");
 387                for(node = 0; node <= highest_node; node++) {
 388                        char b[20];
 389
 390                        store_size(b, s->numa_partial[node]);
 391                        printf(" %4s", b);
 392                }
 393                printf("\n");
 394        }
 395        line++;
 396}
 397
 398static void show_tracking(struct slabinfo *s)
 399{
 400        printf("\n%s: Kernel object allocation\n", s->name);
 401        printf("-----------------------------------------------------------------------\n");
 402        if (read_slab_obj(s, "alloc_calls"))
 403                printf("%s", buffer);
 404        else
 405                printf("No Data\n");
 406
 407        printf("\n%s: Kernel object freeing\n", s->name);
 408        printf("------------------------------------------------------------------------\n");
 409        if (read_slab_obj(s, "free_calls"))
 410                printf("%s", buffer);
 411        else
 412                printf("No Data\n");
 413
 414}
 415
 416static void ops(struct slabinfo *s)
 417{
 418        if (strcmp(s->name, "*") == 0)
 419                return;
 420
 421        if (read_slab_obj(s, "ops")) {
 422                printf("\n%s: kmem_cache operations\n", s->name);
 423                printf("--------------------------------------------\n");
 424                printf("%s", buffer);
 425        } else
 426                printf("\n%s has no kmem_cache operations\n", s->name);
 427}
 428
 429static const char *onoff(int x)
 430{
 431        if (x)
 432                return "On ";
 433        return "Off";
 434}
 435
 436static void slab_stats(struct slabinfo *s)
 437{
 438        unsigned long total_alloc;
 439        unsigned long total_free;
 440        unsigned long total;
 441
 442        if (!s->alloc_slab)
 443                return;
 444
 445        total_alloc = s->alloc_fastpath + s->alloc_slowpath;
 446        total_free = s->free_fastpath + s->free_slowpath;
 447
 448        if (!total_alloc)
 449                return;
 450
 451        printf("\n");
 452        printf("Slab Perf Counter       Alloc     Free %%Al %%Fr\n");
 453        printf("--------------------------------------------------\n");
 454        printf("Fastpath             %8lu %8lu %3lu %3lu\n",
 455                s->alloc_fastpath, s->free_fastpath,
 456                s->alloc_fastpath * 100 / total_alloc,
 457                total_free ? s->free_fastpath * 100 / total_free : 0);
 458        printf("Slowpath             %8lu %8lu %3lu %3lu\n",
 459                total_alloc - s->alloc_fastpath, s->free_slowpath,
 460                (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
 461                total_free ? s->free_slowpath * 100 / total_free : 0);
 462        printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
 463                s->alloc_slab, s->free_slab,
 464                s->alloc_slab * 100 / total_alloc,
 465                total_free ? s->free_slab * 100 / total_free : 0);
 466        printf("Add partial          %8lu %8lu %3lu %3lu\n",
 467                s->deactivate_to_head + s->deactivate_to_tail,
 468                s->free_add_partial,
 469                (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
 470                total_free ? s->free_add_partial * 100 / total_free : 0);
 471        printf("Remove partial       %8lu %8lu %3lu %3lu\n",
 472                s->alloc_from_partial, s->free_remove_partial,
 473                s->alloc_from_partial * 100 / total_alloc,
 474                total_free ? s->free_remove_partial * 100 / total_free : 0);
 475
 476        printf("Cpu partial list     %8lu %8lu %3lu %3lu\n",
 477                s->cpu_partial_alloc, s->cpu_partial_free,
 478                s->cpu_partial_alloc * 100 / total_alloc,
 479                total_free ? s->cpu_partial_free * 100 / total_free : 0);
 480
 481        printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
 482                s->deactivate_remote_frees, s->free_frozen,
 483                s->deactivate_remote_frees * 100 / total_alloc,
 484                total_free ? s->free_frozen * 100 / total_free : 0);
 485
 486        printf("Total                %8lu %8lu\n\n", total_alloc, total_free);
 487
 488        if (s->cpuslab_flush)
 489                printf("Flushes %8lu\n", s->cpuslab_flush);
 490
 491        total = s->deactivate_full + s->deactivate_empty +
 492                        s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass;
 493
 494        if (total) {
 495                printf("\nSlab Deactivation             Ocurrences  %%\n");
 496                printf("-------------------------------------------------\n");
 497                printf("Slab full                     %7lu  %3lu%%\n",
 498                        s->deactivate_full, (s->deactivate_full * 100) / total);
 499                printf("Slab empty                    %7lu  %3lu%%\n",
 500                        s->deactivate_empty, (s->deactivate_empty * 100) / total);
 501                printf("Moved to head of partial list %7lu  %3lu%%\n",
 502                        s->deactivate_to_head, (s->deactivate_to_head * 100) / total);
 503                printf("Moved to tail of partial list %7lu  %3lu%%\n",
 504                        s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
 505                printf("Deactivation bypass           %7lu  %3lu%%\n",
 506                        s->deactivate_bypass, (s->deactivate_bypass * 100) / total);
 507                printf("Refilled from foreign frees   %7lu  %3lu%%\n",
 508                        s->alloc_refill, (s->alloc_refill * 100) / total);
 509                printf("Node mismatch                 %7lu  %3lu%%\n",
 510                        s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
 511        }
 512
 513        if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail)
 514                printf("\nCmpxchg_double Looping\n------------------------\n");
 515                printf("Locked Cmpxchg Double redos   %lu\nUnlocked Cmpxchg Double redos %lu\n",
 516                        s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
 517}
 518
 519static void report(struct slabinfo *s)
 520{
 521        if (strcmp(s->name, "*") == 0)
 522                return;
 523
 524        printf("\nSlabcache: %-15s  Aliases: %2d Order : %2d Objects: %lu\n",
 525                s->name, s->aliases, s->order, s->objects);
 526        if (s->hwcache_align)
 527                printf("** Hardware cacheline aligned\n");
 528        if (s->cache_dma)
 529                printf("** Memory is allocated in a special DMA zone\n");
 530        if (s->destroy_by_rcu)
 531                printf("** Slabs are destroyed via RCU\n");
 532        if (s->reclaim_account)
 533                printf("** Reclaim accounting active\n");
 534
 535        printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
 536        printf("------------------------------------------------------------------------\n");
 537        printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
 538                        s->object_size, s->slabs, onoff(s->sanity_checks),
 539                        s->slabs * (page_size << s->order));
 540        printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
 541                        s->slab_size, s->slabs - s->partial - s->cpu_slabs,
 542                        onoff(s->red_zone), s->objects * s->object_size);
 543        printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
 544                        page_size << s->order, s->partial, onoff(s->poison),
 545                        s->slabs * (page_size << s->order) - s->objects * s->object_size);
 546        printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
 547                        s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
 548                        (s->slab_size - s->object_size) * s->objects);
 549        printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
 550                        s->align, s->objs_per_slab, onoff(s->trace),
 551                        ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
 552                        s->slabs);
 553
 554        ops(s);
 555        show_tracking(s);
 556        slab_numa(s, 1);
 557        slab_stats(s);
 558}
 559
 560static void slabcache(struct slabinfo *s)
 561{
 562        char size_str[20];
 563        char dist_str[40];
 564        char flags[20];
 565        char *p = flags;
 566
 567        if (strcmp(s->name, "*") == 0)
 568                return;
 569
 570        if (actual_slabs == 1) {
 571                report(s);
 572                return;
 573        }
 574
 575        if (skip_zero && !show_empty && !s->slabs)
 576                return;
 577
 578        if (show_empty && s->slabs)
 579                return;
 580
 581        if (sort_loss == 0)
 582                store_size(size_str, slab_size(s));
 583        else
 584                store_size(size_str, slab_waste(s));
 585        snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
 586                                                s->partial, s->cpu_slabs);
 587
 588        if (!line++)
 589                first_line();
 590
 591        if (s->aliases)
 592                *p++ = '*';
 593        if (s->cache_dma)
 594                *p++ = 'd';
 595        if (s->hwcache_align)
 596                *p++ = 'A';
 597        if (s->poison)
 598                *p++ = 'P';
 599        if (s->reclaim_account)
 600                *p++ = 'a';
 601        if (s->red_zone)
 602                *p++ = 'Z';
 603        if (s->sanity_checks)
 604                *p++ = 'F';
 605        if (s->store_user)
 606                *p++ = 'U';
 607        if (s->trace)
 608                *p++ = 'T';
 609
 610        *p = 0;
 611        if (show_activity) {
 612                unsigned long total_alloc;
 613                unsigned long total_free;
 614
 615                total_alloc = s->alloc_fastpath + s->alloc_slowpath;
 616                total_free = s->free_fastpath + s->free_slowpath;
 617
 618                printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n",
 619                        s->name, s->objects,
 620                        total_alloc, total_free,
 621                        total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
 622                        total_free ? (s->free_fastpath * 100 / total_free) : 0,
 623                        s->order_fallback, s->order, s->cmpxchg_double_fail,
 624                        s->cmpxchg_double_cpu_fail);
 625        } else {
 626                printf("%-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s\n",
 627                        s->name, s->objects, s->object_size, size_str, dist_str,
 628                        s->objs_per_slab, s->order,
 629                        s->slabs ? (s->partial * 100) / s->slabs : 100,
 630                        s->slabs ? (s->objects * s->object_size * 100) /
 631                                (s->slabs * (page_size << s->order)) : 100,
 632                        flags);
 633        }
 634}
 635
 636/*
 637 * Analyze debug options. Return false if something is amiss.
 638 */
 639static int debug_opt_scan(char *opt)
 640{
 641        if (!opt || !opt[0] || strcmp(opt, "-") == 0)
 642                return 1;
 643
 644        if (strcasecmp(opt, "a") == 0) {
 645                sanity = 1;
 646                poison = 1;
 647                redzone = 1;
 648                tracking = 1;
 649                return 1;
 650        }
 651
 652        for ( ; *opt; opt++)
 653                switch (*opt) {
 654                case 'F' : case 'f':
 655                        if (sanity)
 656                                return 0;
 657                        sanity = 1;
 658                        break;
 659                case 'P' : case 'p':
 660                        if (poison)
 661                                return 0;
 662                        poison = 1;
 663                        break;
 664
 665                case 'Z' : case 'z':
 666                        if (redzone)
 667                                return 0;
 668                        redzone = 1;
 669                        break;
 670
 671                case 'U' : case 'u':
 672                        if (tracking)
 673                                return 0;
 674                        tracking = 1;
 675                        break;
 676
 677                case 'T' : case 't':
 678                        if (tracing)
 679                                return 0;
 680                        tracing = 1;
 681                        break;
 682                default:
 683                        return 0;
 684                }
 685        return 1;
 686}
 687
 688static int slab_empty(struct slabinfo *s)
 689{
 690        if (s->objects > 0)
 691                return 0;
 692
 693        /*
 694         * We may still have slabs even if there are no objects. Shrinking will
 695         * remove them.
 696         */
 697        if (s->slabs != 0)
 698                set_obj(s, "shrink", 1);
 699
 700        return 1;
 701}
 702
 703static void slab_debug(struct slabinfo *s)
 704{
 705        if (strcmp(s->name, "*") == 0)
 706                return;
 707
 708        if (sanity && !s->sanity_checks) {
 709                set_obj(s, "sanity", 1);
 710        }
 711        if (!sanity && s->sanity_checks) {
 712                if (slab_empty(s))
 713                        set_obj(s, "sanity", 0);
 714                else
 715                        fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
 716        }
 717        if (redzone && !s->red_zone) {
 718                if (slab_empty(s))
 719                        set_obj(s, "red_zone", 1);
 720                else
 721                        fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
 722        }
 723        if (!redzone && s->red_zone) {
 724                if (slab_empty(s))
 725                        set_obj(s, "red_zone", 0);
 726                else
 727                        fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
 728        }
 729        if (poison && !s->poison) {
 730                if (slab_empty(s))
 731                        set_obj(s, "poison", 1);
 732                else
 733                        fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
 734        }
 735        if (!poison && s->poison) {
 736                if (slab_empty(s))
 737                        set_obj(s, "poison", 0);
 738                else
 739                        fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
 740        }
 741        if (tracking && !s->store_user) {
 742                if (slab_empty(s))
 743                        set_obj(s, "store_user", 1);
 744                else
 745                        fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
 746        }
 747        if (!tracking && s->store_user) {
 748                if (slab_empty(s))
 749                        set_obj(s, "store_user", 0);
 750                else
 751                        fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
 752        }
 753        if (tracing && !s->trace) {
 754                if (slabs == 1)
 755                        set_obj(s, "trace", 1);
 756                else
 757                        fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
 758        }
 759        if (!tracing && s->trace)
 760                set_obj(s, "trace", 1);
 761}
 762
 763static void totals(void)
 764{
 765        struct slabinfo *s;
 766
 767        int used_slabs = 0;
 768        char b1[20], b2[20], b3[20], b4[20];
 769        unsigned long long max = 1ULL << 63;
 770
 771        /* Object size */
 772        unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
 773
 774        /* Number of partial slabs in a slabcache */
 775        unsigned long long min_partial = max, max_partial = 0,
 776                                avg_partial, total_partial = 0;
 777
 778        /* Number of slabs in a slab cache */
 779        unsigned long long min_slabs = max, max_slabs = 0,
 780                                avg_slabs, total_slabs = 0;
 781
 782        /* Size of the whole slab */
 783        unsigned long long min_size = max, max_size = 0,
 784                                avg_size, total_size = 0;
 785
 786        /* Bytes used for object storage in a slab */
 787        unsigned long long min_used = max, max_used = 0,
 788                                avg_used, total_used = 0;
 789
 790        /* Waste: Bytes used for alignment and padding */
 791        unsigned long long min_waste = max, max_waste = 0,
 792                                avg_waste, total_waste = 0;
 793        /* Number of objects in a slab */
 794        unsigned long long min_objects = max, max_objects = 0,
 795                                avg_objects, total_objects = 0;
 796        /* Waste per object */
 797        unsigned long long min_objwaste = max,
 798                                max_objwaste = 0, avg_objwaste,
 799                                total_objwaste = 0;
 800
 801        /* Memory per object */
 802        unsigned long long min_memobj = max,
 803                                max_memobj = 0, avg_memobj,
 804                                total_objsize = 0;
 805
 806        /* Percentage of partial slabs per slab */
 807        unsigned long min_ppart = 100, max_ppart = 0,
 808                                avg_ppart, total_ppart = 0;
 809
 810        /* Number of objects in partial slabs */
 811        unsigned long min_partobj = max, max_partobj = 0,
 812                                avg_partobj, total_partobj = 0;
 813
 814        /* Percentage of partial objects of all objects in a slab */
 815        unsigned long min_ppartobj = 100, max_ppartobj = 0,
 816                                avg_ppartobj, total_ppartobj = 0;
 817
 818
 819        for (s = slabinfo; s < slabinfo + slabs; s++) {
 820                unsigned long long size;
 821                unsigned long used;
 822                unsigned long long wasted;
 823                unsigned long long objwaste;
 824                unsigned long percentage_partial_slabs;
 825                unsigned long percentage_partial_objs;
 826
 827                if (!s->slabs || !s->objects)
 828                        continue;
 829
 830                used_slabs++;
 831
 832                size = slab_size(s);
 833                used = s->objects * s->object_size;
 834                wasted = size - used;
 835                objwaste = s->slab_size - s->object_size;
 836
 837                percentage_partial_slabs = s->partial * 100 / s->slabs;
 838                if (percentage_partial_slabs > 100)
 839                        percentage_partial_slabs = 100;
 840
 841                percentage_partial_objs = s->objects_partial * 100
 842                                                        / s->objects;
 843
 844                if (percentage_partial_objs > 100)
 845                        percentage_partial_objs = 100;
 846
 847                if (s->object_size < min_objsize)
 848                        min_objsize = s->object_size;
 849                if (s->partial < min_partial)
 850                        min_partial = s->partial;
 851                if (s->slabs < min_slabs)
 852                        min_slabs = s->slabs;
 853                if (size < min_size)
 854                        min_size = size;
 855                if (wasted < min_waste)
 856                        min_waste = wasted;
 857                if (objwaste < min_objwaste)
 858                        min_objwaste = objwaste;
 859                if (s->objects < min_objects)
 860                        min_objects = s->objects;
 861                if (used < min_used)
 862                        min_used = used;
 863                if (s->objects_partial < min_partobj)
 864                        min_partobj = s->objects_partial;
 865                if (percentage_partial_slabs < min_ppart)
 866                        min_ppart = percentage_partial_slabs;
 867                if (percentage_partial_objs < min_ppartobj)
 868                        min_ppartobj = percentage_partial_objs;
 869                if (s->slab_size < min_memobj)
 870                        min_memobj = s->slab_size;
 871
 872                if (s->object_size > max_objsize)
 873                        max_objsize = s->object_size;
 874                if (s->partial > max_partial)
 875                        max_partial = s->partial;
 876                if (s->slabs > max_slabs)
 877                        max_slabs = s->slabs;
 878                if (size > max_size)
 879                        max_size = size;
 880                if (wasted > max_waste)
 881                        max_waste = wasted;
 882                if (objwaste > max_objwaste)
 883                        max_objwaste = objwaste;
 884                if (s->objects > max_objects)
 885                        max_objects = s->objects;
 886                if (used > max_used)
 887                        max_used = used;
 888                if (s->objects_partial > max_partobj)
 889                        max_partobj = s->objects_partial;
 890                if (percentage_partial_slabs > max_ppart)
 891                        max_ppart = percentage_partial_slabs;
 892                if (percentage_partial_objs > max_ppartobj)
 893                        max_ppartobj = percentage_partial_objs;
 894                if (s->slab_size > max_memobj)
 895                        max_memobj = s->slab_size;
 896
 897                total_partial += s->partial;
 898                total_slabs += s->slabs;
 899                total_size += size;
 900                total_waste += wasted;
 901
 902                total_objects += s->objects;
 903                total_used += used;
 904                total_partobj += s->objects_partial;
 905                total_ppart += percentage_partial_slabs;
 906                total_ppartobj += percentage_partial_objs;
 907
 908                total_objwaste += s->objects * objwaste;
 909                total_objsize += s->objects * s->slab_size;
 910        }
 911
 912        if (!total_objects) {
 913                printf("No objects\n");
 914                return;
 915        }
 916        if (!used_slabs) {
 917                printf("No slabs\n");
 918                return;
 919        }
 920
 921        /* Per slab averages */
 922        avg_partial = total_partial / used_slabs;
 923        avg_slabs = total_slabs / used_slabs;
 924        avg_size = total_size / used_slabs;
 925        avg_waste = total_waste / used_slabs;
 926
 927        avg_objects = total_objects / used_slabs;
 928        avg_used = total_used / used_slabs;
 929        avg_partobj = total_partobj / used_slabs;
 930        avg_ppart = total_ppart / used_slabs;
 931        avg_ppartobj = total_ppartobj / used_slabs;
 932
 933        /* Per object object sizes */
 934        avg_objsize = total_used / total_objects;
 935        avg_objwaste = total_objwaste / total_objects;
 936        avg_partobj = total_partobj * 100 / total_objects;
 937        avg_memobj = total_objsize / total_objects;
 938
 939        printf("Slabcache Totals\n");
 940        printf("----------------\n");
 941        printf("Slabcaches : %15d   Aliases  : %11d->%-3d  Active:    %3d\n",
 942                        slabs, aliases, alias_targets, used_slabs);
 943
 944        store_size(b1, total_size);store_size(b2, total_waste);
 945        store_size(b3, total_waste * 100 / total_used);
 946        printf("Memory used: %15s   # Loss   : %15s   MRatio:%6s%%\n", b1, b2, b3);
 947
 948        store_size(b1, total_objects);store_size(b2, total_partobj);
 949        store_size(b3, total_partobj * 100 / total_objects);
 950        printf("# Objects  : %15s   # PartObj: %15s   ORatio:%6s%%\n", b1, b2, b3);
 951
 952        printf("\n");
 953        printf("Per Cache         Average              "
 954                "Min              Max            Total\n");
 955        printf("---------------------------------------"
 956                "-------------------------------------\n");
 957
 958        store_size(b1, avg_objects);store_size(b2, min_objects);
 959        store_size(b3, max_objects);store_size(b4, total_objects);
 960        printf("#Objects  %15s  %15s  %15s  %15s\n",
 961                        b1,     b2,     b3,     b4);
 962
 963        store_size(b1, avg_slabs);store_size(b2, min_slabs);
 964        store_size(b3, max_slabs);store_size(b4, total_slabs);
 965        printf("#Slabs    %15s  %15s  %15s  %15s\n",
 966                        b1,     b2,     b3,     b4);
 967
 968        store_size(b1, avg_partial);store_size(b2, min_partial);
 969        store_size(b3, max_partial);store_size(b4, total_partial);
 970        printf("#PartSlab %15s  %15s  %15s  %15s\n",
 971                        b1,     b2,     b3,     b4);
 972        store_size(b1, avg_ppart);store_size(b2, min_ppart);
 973        store_size(b3, max_ppart);
 974        store_size(b4, total_partial * 100  / total_slabs);
 975        printf("%%PartSlab%15s%% %15s%% %15s%% %15s%%\n",
 976                        b1,     b2,     b3,     b4);
 977
 978        store_size(b1, avg_partobj);store_size(b2, min_partobj);
 979        store_size(b3, max_partobj);
 980        store_size(b4, total_partobj);
 981        printf("PartObjs  %15s  %15s  %15s  %15s\n",
 982                        b1,     b2,     b3,     b4);
 983
 984        store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
 985        store_size(b3, max_ppartobj);
 986        store_size(b4, total_partobj * 100 / total_objects);
 987        printf("%% PartObj%15s%% %15s%% %15s%% %15s%%\n",
 988                        b1,     b2,     b3,     b4);
 989
 990        store_size(b1, avg_size);store_size(b2, min_size);
 991        store_size(b3, max_size);store_size(b4, total_size);
 992        printf("Memory    %15s  %15s  %15s  %15s\n",
 993                        b1,     b2,     b3,     b4);
 994
 995        store_size(b1, avg_used);store_size(b2, min_used);
 996        store_size(b3, max_used);store_size(b4, total_used);
 997        printf("Used      %15s  %15s  %15s  %15s\n",
 998                        b1,     b2,     b3,     b4);
 999
1000        store_size(b1, avg_waste);store_size(b2, min_waste);
1001        store_size(b3, max_waste);store_size(b4, total_waste);
1002        printf("Loss      %15s  %15s  %15s  %15s\n",
1003                        b1,     b2,     b3,     b4);
1004
1005        printf("\n");
1006        printf("Per Object        Average              "
1007                "Min              Max\n");
1008        printf("---------------------------------------"
1009                "--------------------\n");
1010
1011        store_size(b1, avg_memobj);store_size(b2, min_memobj);
1012        store_size(b3, max_memobj);
1013        printf("Memory    %15s  %15s  %15s\n",
1014                        b1,     b2,     b3);
1015        store_size(b1, avg_objsize);store_size(b2, min_objsize);
1016        store_size(b3, max_objsize);
1017        printf("User      %15s  %15s  %15s\n",
1018                        b1,     b2,     b3);
1019
1020        store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
1021        store_size(b3, max_objwaste);
1022        printf("Loss      %15s  %15s  %15s\n",
1023                        b1,     b2,     b3);
1024}
1025
1026static void sort_slabs(void)
1027{
1028        struct slabinfo *s1,*s2;
1029
1030        for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
1031                for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
1032                        int result;
1033
1034                        if (sort_size)
1035                                result = slab_size(s1) < slab_size(s2);
1036                        else if (sort_active)
1037                                result = slab_activity(s1) < slab_activity(s2);
1038                        else if (sort_loss)
1039                                result = slab_waste(s1) < slab_waste(s2);
1040                        else
1041                                result = strcasecmp(s1->name, s2->name);
1042
1043                        if (show_inverted)
1044                                result = -result;
1045
1046                        if (result > 0) {
1047                                struct slabinfo t;
1048
1049                                memcpy(&t, s1, sizeof(struct slabinfo));
1050                                memcpy(s1, s2, sizeof(struct slabinfo));
1051                                memcpy(s2, &t, sizeof(struct slabinfo));
1052                        }
1053                }
1054        }
1055}
1056
1057static void sort_aliases(void)
1058{
1059        struct aliasinfo *a1,*a2;
1060
1061        for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
1062                for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
1063                        char *n1, *n2;
1064
1065                        n1 = a1->name;
1066                        n2 = a2->name;
1067                        if (show_alias && !show_inverted) {
1068                                n1 = a1->ref;
1069                                n2 = a2->ref;
1070                        }
1071                        if (strcasecmp(n1, n2) > 0) {
1072                                struct aliasinfo t;
1073
1074                                memcpy(&t, a1, sizeof(struct aliasinfo));
1075                                memcpy(a1, a2, sizeof(struct aliasinfo));
1076                                memcpy(a2, &t, sizeof(struct aliasinfo));
1077                        }
1078                }
1079        }
1080}
1081
1082static void link_slabs(void)
1083{
1084        struct aliasinfo *a;
1085        struct slabinfo *s;
1086
1087        for (a = aliasinfo; a < aliasinfo + aliases; a++) {
1088
1089                for (s = slabinfo; s < slabinfo + slabs; s++)
1090                        if (strcmp(a->ref, s->name) == 0) {
1091                                a->slab = s;
1092                                s->refs++;
1093                                break;
1094                        }
1095                if (s == slabinfo + slabs)
1096                        fatal("Unresolved alias %s\n", a->ref);
1097        }
1098}
1099
1100static void alias(void)
1101{
1102        struct aliasinfo *a;
1103        char *active = NULL;
1104
1105        sort_aliases();
1106        link_slabs();
1107
1108        for(a = aliasinfo; a < aliasinfo + aliases; a++) {
1109
1110                if (!show_single_ref && a->slab->refs == 1)
1111                        continue;
1112
1113                if (!show_inverted) {
1114                        if (active) {
1115                                if (strcmp(a->slab->name, active) == 0) {
1116                                        printf(" %s", a->name);
1117                                        continue;
1118                                }
1119                        }
1120                        printf("\n%-12s <- %s", a->slab->name, a->name);
1121                        active = a->slab->name;
1122                }
1123                else
1124                        printf("%-15s -> %s\n", a->name, a->slab->name);
1125        }
1126        if (active)
1127                printf("\n");
1128}
1129
1130
1131static void rename_slabs(void)
1132{
1133        struct slabinfo *s;
1134        struct aliasinfo *a;
1135
1136        for (s = slabinfo; s < slabinfo + slabs; s++) {
1137                if (*s->name != ':')
1138                        continue;
1139
1140                if (s->refs > 1 && !show_first_alias)
1141                        continue;
1142
1143                a = find_one_alias(s);
1144
1145                if (a)
1146                        s->name = a->name;
1147                else {
1148                        s->name = "*";
1149                        actual_slabs--;
1150                }
1151        }
1152}
1153
1154static int slab_mismatch(char *slab)
1155{
1156        return regexec(&pattern, slab, 0, NULL, 0);
1157}
1158
1159static void read_slab_dir(void)
1160{
1161        DIR *dir;
1162        struct dirent *de;
1163        struct slabinfo *slab = slabinfo;
1164        struct aliasinfo *alias = aliasinfo;
1165        char *p;
1166        char *t;
1167        int count;
1168
1169        if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
1170                fatal("SYSFS support for SLUB not active\n");
1171
1172        dir = opendir(".");
1173        while ((de = readdir(dir))) {
1174                if (de->d_name[0] == '.' ||
1175                        (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
1176                                continue;
1177                switch (de->d_type) {
1178                   case DT_LNK:
1179                        alias->name = strdup(de->d_name);
1180                        count = readlink(de->d_name, buffer, sizeof(buffer)-1);
1181
1182                        if (count < 0)
1183                                fatal("Cannot read symlink %s\n", de->d_name);
1184
1185                        buffer[count] = 0;
1186                        p = buffer + count;
1187                        while (p > buffer && p[-1] != '/')
1188                                p--;
1189                        alias->ref = strdup(p);
1190                        alias++;
1191                        break;
1192                   case DT_DIR:
1193                        if (chdir(de->d_name))
1194                                fatal("Unable to access slab %s\n", slab->name);
1195                        slab->name = strdup(de->d_name);
1196                        slab->alias = 0;
1197                        slab->refs = 0;
1198                        slab->aliases = get_obj("aliases");
1199                        slab->align = get_obj("align");
1200                        slab->cache_dma = get_obj("cache_dma");
1201                        slab->cpu_slabs = get_obj("cpu_slabs");
1202                        slab->destroy_by_rcu = get_obj("destroy_by_rcu");
1203                        slab->hwcache_align = get_obj("hwcache_align");
1204                        slab->object_size = get_obj("object_size");
1205                        slab->objects = get_obj("objects");
1206                        slab->objects_partial = get_obj("objects_partial");
1207                        slab->objects_total = get_obj("objects_total");
1208                        slab->objs_per_slab = get_obj("objs_per_slab");
1209                        slab->order = get_obj("order");
1210                        slab->partial = get_obj("partial");
1211                        slab->partial = get_obj_and_str("partial", &t);
1212                        decode_numa_list(slab->numa_partial, t);
1213                        free(t);
1214                        slab->poison = get_obj("poison");
1215                        slab->reclaim_account = get_obj("reclaim_account");
1216                        slab->red_zone = get_obj("red_zone");
1217                        slab->sanity_checks = get_obj("sanity_checks");
1218                        slab->slab_size = get_obj("slab_size");
1219                        slab->slabs = get_obj_and_str("slabs", &t);
1220                        decode_numa_list(slab->numa, t);
1221                        free(t);
1222                        slab->store_user = get_obj("store_user");
1223                        slab->trace = get_obj("trace");
1224                        slab->alloc_fastpath = get_obj("alloc_fastpath");
1225                        slab->alloc_slowpath = get_obj("alloc_slowpath");
1226                        slab->free_fastpath = get_obj("free_fastpath");
1227                        slab->free_slowpath = get_obj("free_slowpath");
1228                        slab->free_frozen= get_obj("free_frozen");
1229                        slab->free_add_partial = get_obj("free_add_partial");
1230                        slab->free_remove_partial = get_obj("free_remove_partial");
1231                        slab->alloc_from_partial = get_obj("alloc_from_partial");
1232                        slab->alloc_slab = get_obj("alloc_slab");
1233                        slab->alloc_refill = get_obj("alloc_refill");
1234                        slab->free_slab = get_obj("free_slab");
1235                        slab->cpuslab_flush = get_obj("cpuslab_flush");
1236                        slab->deactivate_full = get_obj("deactivate_full");
1237                        slab->deactivate_empty = get_obj("deactivate_empty");
1238                        slab->deactivate_to_head = get_obj("deactivate_to_head");
1239                        slab->deactivate_to_tail = get_obj("deactivate_to_tail");
1240                        slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
1241                        slab->order_fallback = get_obj("order_fallback");
1242                        slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
1243                        slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
1244                        slab->cpu_partial_alloc = get_obj("cpu_partial_alloc");
1245                        slab->cpu_partial_free = get_obj("cpu_partial_free");
1246                        slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
1247                        slab->deactivate_bypass = get_obj("deactivate_bypass");
1248                        chdir("..");
1249                        if (slab->name[0] == ':')
1250                                alias_targets++;
1251                        slab++;
1252                        break;
1253                   default :
1254                        fatal("Unknown file type %lx\n", de->d_type);
1255                }
1256        }
1257        closedir(dir);
1258        slabs = slab - slabinfo;
1259        actual_slabs = slabs;
1260        aliases = alias - aliasinfo;
1261        if (slabs > MAX_SLABS)
1262                fatal("Too many slabs\n");
1263        if (aliases > MAX_ALIASES)
1264                fatal("Too many aliases\n");
1265}
1266
1267static void output_slabs(void)
1268{
1269        struct slabinfo *slab;
1270        int lines = output_lines;
1271
1272        for (slab = slabinfo; (slab < slabinfo + slabs) &&
1273                        lines != 0; slab++) {
1274
1275                if (slab->alias)
1276                        continue;
1277
1278                if (lines != -1)
1279                        lines--;
1280
1281                if (show_numa)
1282                        slab_numa(slab, 0);
1283                else if (show_track)
1284                        show_tracking(slab);
1285                else if (validate)
1286                        slab_validate(slab);
1287                else if (shrink)
1288                        slab_shrink(slab);
1289                else if (set_debug)
1290                        slab_debug(slab);
1291                else if (show_ops)
1292                        ops(slab);
1293                else if (show_slab)
1294                        slabcache(slab);
1295                else if (show_report)
1296                        report(slab);
1297        }
1298}
1299
1300static void xtotals(void)
1301{
1302        totals();
1303
1304        link_slabs();
1305        rename_slabs();
1306
1307        printf("\nSlabs sorted by size\n");
1308        printf("--------------------\n");
1309        sort_loss = 0;
1310        sort_size = 1;
1311        sort_slabs();
1312        output_slabs();
1313
1314        printf("\nSlabs sorted by loss\n");
1315        printf("--------------------\n");
1316        line = 0;
1317        sort_loss = 1;
1318        sort_size = 0;
1319        sort_slabs();
1320        output_slabs();
1321        printf("\n");
1322}
1323
1324struct option opts[] = {
1325        { "aliases", no_argument, NULL, 'a' },
1326        { "activity", no_argument, NULL, 'A' },
1327        { "debug", optional_argument, NULL, 'd' },
1328        { "display-activity", no_argument, NULL, 'D' },
1329        { "empty", no_argument, NULL, 'e' },
1330        { "first-alias", no_argument, NULL, 'f' },
1331        { "help", no_argument, NULL, 'h' },
1332        { "inverted", no_argument, NULL, 'i'},
1333        { "slabs", no_argument, NULL, 'l' },
1334        { "numa", no_argument, NULL, 'n' },
1335        { "ops", no_argument, NULL, 'o' },
1336        { "shrink", no_argument, NULL, 's' },
1337        { "report", no_argument, NULL, 'r' },
1338        { "Size", no_argument, NULL, 'S'},
1339        { "tracking", no_argument, NULL, 't'},
1340        { "Totals", no_argument, NULL, 'T'},
1341        { "validate", no_argument, NULL, 'v' },
1342        { "zero", no_argument, NULL, 'z' },
1343        { "1ref", no_argument, NULL, '1'},
1344        { "lines", required_argument, NULL, 'N'},
1345        { "Loss", no_argument, NULL, 'L'},
1346        { "Xtotals", no_argument, NULL, 'X'},
1347        { "Bytes", no_argument, NULL, 'B'},
1348        { NULL, 0, NULL, 0 }
1349};
1350
1351int main(int argc, char *argv[])
1352{
1353        int c;
1354        int err;
1355        char *pattern_source;
1356
1357        page_size = getpagesize();
1358
1359        while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXB",
1360                                                opts, NULL)) != -1)
1361                switch (c) {
1362                case '1':
1363                        show_single_ref = 1;
1364                        break;
1365                case 'a':
1366                        show_alias = 1;
1367                        break;
1368                case 'A':
1369                        sort_active = 1;
1370                        break;
1371                case 'd':
1372                        set_debug = 1;
1373                        if (!debug_opt_scan(optarg))
1374                                fatal("Invalid debug option '%s'\n", optarg);
1375                        break;
1376                case 'D':
1377                        show_activity = 1;
1378                        break;
1379                case 'e':
1380                        show_empty = 1;
1381                        break;
1382                case 'f':
1383                        show_first_alias = 1;
1384                        break;
1385                case 'h':
1386                        usage();
1387                        return 0;
1388                case 'i':
1389                        show_inverted = 1;
1390                        break;
1391                case 'n':
1392                        show_numa = 1;
1393                        break;
1394                case 'o':
1395                        show_ops = 1;
1396                        break;
1397                case 'r':
1398                        show_report = 1;
1399                        break;
1400                case 's':
1401                        shrink = 1;
1402                        break;
1403                case 'l':
1404                        show_slab = 1;
1405                        break;
1406                case 't':
1407                        show_track = 1;
1408                        break;
1409                case 'v':
1410                        validate = 1;
1411                        break;
1412                case 'z':
1413                        skip_zero = 0;
1414                        break;
1415                case 'T':
1416                        show_totals = 1;
1417                        break;
1418                case 'S':
1419                        sort_size = 1;
1420                        break;
1421                case 'N':
1422                        if (optarg) {
1423                                output_lines = atoi(optarg);
1424                                if (output_lines < 1)
1425                                        output_lines = 1;
1426                        }
1427                        break;
1428                case 'L':
1429                        sort_loss = 1;
1430                        break;
1431                case 'X':
1432                        if (output_lines == -1)
1433                                output_lines = 1;
1434                        extended_totals = 1;
1435                        show_bytes = 1;
1436                        break;
1437                case 'B':
1438                        show_bytes = 1;
1439                        break;
1440                default:
1441                        fatal("%s: Invalid option '%c'\n", argv[0], optopt);
1442
1443        }
1444
1445        if (!show_slab && !show_alias && !show_track && !show_report
1446                && !validate && !shrink && !set_debug && !show_ops)
1447                        show_slab = 1;
1448
1449        if (argc > optind)
1450                pattern_source = argv[optind];
1451        else
1452                pattern_source = ".*";
1453
1454        err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
1455        if (err)
1456                fatal("%s: Invalid pattern '%s' code %d\n",
1457                        argv[0], pattern_source, err);
1458        read_slab_dir();
1459        if (show_alias) {
1460                alias();
1461        } else if (extended_totals) {
1462                xtotals();
1463        } else if (show_totals) {
1464                totals();
1465        } else {
1466                link_slabs();
1467                rename_slabs();
1468                sort_slabs();
1469                output_slabs();
1470        }
1471        return 0;
1472}
1473