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