2 * Slabinfo: Tool to get reports about slabs
4 * (C) 2007 sgi, Christoph Lameter
6 * Reworked by Lin Ming <ming.m.lin@intel.com> for SLQB
10 * gcc -o slabinfo slabinfo.c
14 #include <sys/types.h>
25 #define MAX_ALIASES 500
26 #define MAX_NODES 1024
30 int align
, cache_dma
, destroy_by_rcu
;
31 int hwcache_align
, object_size
, objs_per_slab
;
32 int slab_size
, store_user
;
33 int order
, poison
, reclaim_account
, red_zone
;
35 unsigned long objects
, slabs
, total_objects
;
36 unsigned long alloc
, alloc_slab_fill
, alloc_slab_new
;
37 unsigned long free
, free_remote
;
38 unsigned long claim_remote_list
, claim_remote_list_objects
;
39 unsigned long flush_free_list
, flush_free_list_objects
, flush_free_list_remote
;
40 unsigned long flush_rfree_list
, flush_rfree_list_objects
;
41 unsigned long flush_slab_free
, flush_slab_partial
;
43 int numa_partial
[MAX_NODES
];
44 } slabinfo
[MAX_SLABS
];
60 int show_inverted
= 0;
66 int show_activity
= 0;
79 void fatal(const char *x
, ...)
84 vfprintf(stderr
, x
, ap
);
91 printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
92 "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
93 "-A|--activity Most active slabs first\n"
94 "-d<options>|--debug=<options> Set/Clear Debug options\n"
95 "-D|--display-active Switch line format to activity\n"
96 "-e|--empty Show empty slabs\n"
97 "-h|--help Show usage information\n"
98 "-i|--inverted Inverted list\n"
99 "-l|--slabs Show slabs\n"
100 "-n|--numa Show NUMA information\n"
101 "-o|--ops Show kmem_cache_ops\n"
102 "-s|--shrink Shrink slabs\n"
103 "-r|--report Detailed report on single slabs\n"
104 "-S|--Size Sort by size\n"
105 "-t|--tracking Show alloc/free information\n"
106 "-T|--Totals Show summary information\n"
107 "-v|--validate Validate slabs\n"
108 "-z|--zero Include empty slabs\n"
109 "\nValid debug options (FZPUT may be combined)\n"
110 "a / A Switch on all debug options (=FZUP)\n"
111 "- Switch off all debug options\n"
112 "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
120 unsigned long read_obj(const char *name
)
122 FILE *f
= fopen(name
, "r");
127 if (!fgets(buffer
, sizeof(buffer
), f
))
130 if (buffer
[strlen(buffer
)] == '\n')
131 buffer
[strlen(buffer
)] = 0;
133 return strlen(buffer
);
138 * Get the contents of an attribute
140 unsigned long get_obj(const char *name
)
148 unsigned long get_obj_and_str(const char *name
, char **x
)
150 unsigned long result
= 0;
155 if (!read_obj(name
)) {
159 result
= strtoul(buffer
, &p
, 10);
167 void set_obj(struct slabinfo
*s
, const char *name
, int n
)
172 snprintf(x
, 100, "%s/%s", s
->name
, name
);
175 fatal("Cannot write to %s\n", x
);
177 fprintf(f
, "%d\n", n
);
181 unsigned long read_slab_obj(struct slabinfo
*s
, const char *name
)
187 snprintf(x
, 100, "%s/%s", s
->name
, name
);
193 l
= fread(buffer
, 1, sizeof(buffer
), f
);
202 * Put a size string together
204 int store_size(char *buffer
, unsigned long value
)
206 unsigned long divisor
= 1;
210 if (value
> 1000000000UL) {
211 divisor
= 100000000UL;
213 } else if (value
> 1000000UL) {
216 } else if (value
> 1000UL) {
222 n
= sprintf(buffer
, "%ld",value
);
229 memmove(buffer
+ n
- 2, buffer
+ n
- 3, 4);
236 void decode_numa_list(int *numa
, char *t
)
241 memset(numa
, 0, MAX_NODES
* sizeof(int));
248 node
= strtoul(t
, &t
, 10);
251 nr
= strtoul(t
, &t
, 10);
253 if (node
> highest_node
)
261 void slab_validate(struct slabinfo
*s
)
263 if (strcmp(s
->name
, "*") == 0)
266 set_obj(s
, "validate", 1);
269 void slab_shrink(struct slabinfo
*s
)
271 if (strcmp(s
->name
, "*") == 0)
274 set_obj(s
, "shrink", 1);
279 void first_line(void)
282 printf("Name Objects Alloc Free %%Fill %%New "
283 "FlushR %%FlushR FlushR_Objs O\n");
285 printf("Name Objects Objsize Space "
286 " O/S O %%Ef Batch Flg\n");
289 unsigned long slab_size(struct slabinfo
*s
)
291 return s
->slabs
* (page_size
<< s
->order
);
294 unsigned long slab_activity(struct slabinfo
*s
)
296 return s
->alloc
+ s
->free
;
299 void slab_numa(struct slabinfo
*s
, int mode
)
303 if (strcmp(s
->name
, "*") == 0)
307 printf("\n%s: No NUMA information available.\n", s
->name
);
311 if (skip_zero
&& !s
->slabs
)
315 printf("\n%-21s:", mode
? "NUMA nodes" : "Slab");
316 for(node
= 0; node
<= highest_node
; node
++)
317 printf(" %4d", node
);
318 printf("\n----------------------");
319 for(node
= 0; node
<= highest_node
; node
++)
323 printf("%-21s ", mode
? "All slabs" : s
->name
);
324 for(node
= 0; node
<= highest_node
; node
++) {
327 store_size(b
, s
->numa
[node
]);
332 printf("%-21s ", "Partial slabs");
333 for(node
= 0; node
<= highest_node
; node
++) {
336 store_size(b
, s
->numa_partial
[node
]);
344 void show_tracking(struct slabinfo
*s
)
346 printf("\n%s: Kernel object allocation\n", s
->name
);
347 printf("-----------------------------------------------------------------------\n");
348 if (read_slab_obj(s
, "alloc_calls"))
353 printf("\n%s: Kernel object freeing\n", s
->name
);
354 printf("------------------------------------------------------------------------\n");
355 if (read_slab_obj(s
, "free_calls"))
362 void ops(struct slabinfo
*s
)
364 if (strcmp(s
->name
, "*") == 0)
367 if (read_slab_obj(s
, "ops")) {
368 printf("\n%s: kmem_cache operations\n", s
->name
);
369 printf("--------------------------------------------\n");
372 printf("\n%s has no kmem_cache operations\n", s
->name
);
375 const char *onoff(int x
)
382 void slab_stats(struct slabinfo
*s
)
384 unsigned long total_alloc
;
385 unsigned long total_free
;
387 total_alloc
= s
->alloc
;
388 total_free
= s
->free
;
394 printf("Slab Perf Counter\n");
395 printf("------------------------------------------------------------------------\n");
396 printf("Alloc: %8lu, partial %8lu, page allocator %8lu\n",
398 s
->alloc_slab_fill
, s
->alloc_slab_new
);
399 printf("Free: %8lu, partial %8lu, page allocator %8lu, remote %5lu\n",
401 s
->flush_slab_partial
,
404 printf("Claim: %8lu, objects %8lu\n",
405 s
->claim_remote_list
,
406 s
->claim_remote_list_objects
);
407 printf("Flush: %8lu, objects %8lu, remote: %8lu\n",
409 s
->flush_free_list_objects
,
410 s
->flush_free_list_remote
);
411 printf("FlushR:%8lu, objects %8lu\n",
413 s
->flush_rfree_list_objects
);
416 void report(struct slabinfo
*s
)
418 if (strcmp(s
->name
, "*") == 0)
421 printf("\nSlabcache: %-20s Order : %2d Objects: %lu\n",
422 s
->name
, s
->order
, s
->objects
);
423 if (s
->hwcache_align
)
424 printf("** Hardware cacheline aligned\n");
426 printf("** Memory is allocated in a special DMA zone\n");
427 if (s
->destroy_by_rcu
)
428 printf("** Slabs are destroyed via RCU\n");
429 if (s
->reclaim_account
)
430 printf("** Reclaim accounting active\n");
432 printf("\nSizes (bytes) Slabs Debug Memory\n");
433 printf("------------------------------------------------------------------------\n");
434 printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
435 s
->object_size
, s
->slabs
, "N/A",
436 s
->slabs
* (page_size
<< s
->order
));
437 printf("SlabObj: %7d Full : %7s Redzoning : %s Used : %7ld\n",
439 onoff(s
->red_zone
), s
->objects
* s
->object_size
);
440 printf("SlabSiz: %7d Partial: %7s Poisoning : %s Loss : %7ld\n",
441 page_size
<< s
->order
, "N/A", onoff(s
->poison
),
442 s
->slabs
* (page_size
<< s
->order
) - s
->objects
* s
->object_size
);
443 printf("Loss : %7d CpuSlab: %7s Tracking : %s Lalig: %7ld\n",
444 s
->slab_size
- s
->object_size
, "N/A", onoff(s
->store_user
),
445 (s
->slab_size
- s
->object_size
) * s
->objects
);
446 printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
447 s
->align
, s
->objs_per_slab
, "N/A",
448 ((page_size
<< s
->order
) - s
->objs_per_slab
* s
->slab_size
) *
457 void slabcache(struct slabinfo
*s
)
463 if (strcmp(s
->name
, "*") == 0)
466 if (actual_slabs
== 1) {
471 if (skip_zero
&& !show_empty
&& !s
->slabs
)
474 if (show_empty
&& s
->slabs
)
477 store_size(size_str
, slab_size(s
));
484 if (s
->hwcache_align
)
488 if (s
->reclaim_account
)
497 unsigned long total_alloc
;
498 unsigned long total_free
;
500 total_alloc
= s
->alloc
;
501 total_free
= s
->free
;
503 printf("%-21s %8ld %10ld %10ld %5ld %5ld %7ld %5ld %7ld %8d\n",
505 total_alloc
, total_free
,
506 total_alloc
? (s
->alloc_slab_fill
* 100 / total_alloc
) : 0,
507 total_alloc
? (s
->alloc_slab_new
* 100 / total_alloc
) : 0,
509 s
->flush_rfree_list
* 100 / (total_alloc
+ total_free
),
510 s
->flush_rfree_list_objects
,
514 printf("%-21s %8ld %7d %8s %4d %1d %3ld %4d %s\n",
515 s
->name
, s
->objects
, s
->object_size
, size_str
,
516 s
->objs_per_slab
, s
->order
,
517 s
->slabs
? (s
->objects
* s
->object_size
* 100) /
518 (s
->slabs
* (page_size
<< s
->order
)) : 100,
523 * Analyze debug options. Return false if something is amiss.
525 int debug_opt_scan(char *opt
)
527 if (!opt
|| !opt
[0] || strcmp(opt
, "-") == 0)
530 if (strcasecmp(opt
, "a") == 0) {
574 int slab_empty(struct slabinfo
*s
)
580 * We may still have slabs even if there are no objects. Shrinking will
584 set_obj(s
, "shrink", 1);
589 void slab_debug(struct slabinfo
*s
)
591 if (strcmp(s
->name
, "*") == 0)
594 if (redzone
&& !s
->red_zone
) {
596 set_obj(s
, "red_zone", 1);
598 fprintf(stderr
, "%s not empty cannot enable redzoning\n", s
->name
);
600 if (!redzone
&& s
->red_zone
) {
602 set_obj(s
, "red_zone", 0);
604 fprintf(stderr
, "%s not empty cannot disable redzoning\n", s
->name
);
606 if (poison
&& !s
->poison
) {
608 set_obj(s
, "poison", 1);
610 fprintf(stderr
, "%s not empty cannot enable poisoning\n", s
->name
);
612 if (!poison
&& s
->poison
) {
614 set_obj(s
, "poison", 0);
616 fprintf(stderr
, "%s not empty cannot disable poisoning\n", s
->name
);
618 if (tracking
&& !s
->store_user
) {
620 set_obj(s
, "store_user", 1);
622 fprintf(stderr
, "%s not empty cannot enable tracking\n", s
->name
);
624 if (!tracking
&& s
->store_user
) {
626 set_obj(s
, "store_user", 0);
628 fprintf(stderr
, "%s not empty cannot disable tracking\n", s
->name
);
637 char b1
[20], b2
[20], b3
[20], b4
[20];
638 unsigned long long max
= 1ULL << 63;
641 unsigned long long min_objsize
= max
, max_objsize
= 0, avg_objsize
;
643 /* Number of slabs in a slab cache */
644 unsigned long long min_slabs
= max
, max_slabs
= 0,
645 avg_slabs
, total_slabs
= 0;
647 /* Size of the whole slab */
648 unsigned long long min_size
= max
, max_size
= 0,
649 avg_size
, total_size
= 0;
651 /* Bytes used for object storage in a slab */
652 unsigned long long min_used
= max
, max_used
= 0,
653 avg_used
, total_used
= 0;
655 /* Waste: Bytes used for alignment and padding */
656 unsigned long long min_waste
= max
, max_waste
= 0,
657 avg_waste
, total_waste
= 0;
658 /* Number of objects in a slab */
659 unsigned long long min_objects
= max
, max_objects
= 0,
660 avg_objects
, total_objects
= 0;
661 /* Waste per object */
662 unsigned long long min_objwaste
= max
,
663 max_objwaste
= 0, avg_objwaste
,
666 /* Memory per object */
667 unsigned long long min_memobj
= max
,
668 max_memobj
= 0, avg_memobj
,
671 for (s
= slabinfo
; s
< slabinfo
+ slabs
; s
++) {
672 unsigned long long size
;
674 unsigned long long wasted
;
675 unsigned long long objwaste
;
677 if (!s
->slabs
|| !s
->objects
)
683 used
= s
->objects
* s
->object_size
;
684 wasted
= size
- used
;
685 objwaste
= s
->slab_size
- s
->object_size
;
687 if (s
->object_size
< min_objsize
)
688 min_objsize
= s
->object_size
;
689 if (s
->slabs
< min_slabs
)
690 min_slabs
= s
->slabs
;
693 if (wasted
< min_waste
)
695 if (objwaste
< min_objwaste
)
696 min_objwaste
= objwaste
;
697 if (s
->objects
< min_objects
)
698 min_objects
= s
->objects
;
701 if (s
->slab_size
< min_memobj
)
702 min_memobj
= s
->slab_size
;
704 if (s
->object_size
> max_objsize
)
705 max_objsize
= s
->object_size
;
706 if (s
->slabs
> max_slabs
)
707 max_slabs
= s
->slabs
;
710 if (wasted
> max_waste
)
712 if (objwaste
> max_objwaste
)
713 max_objwaste
= objwaste
;
714 if (s
->objects
> max_objects
)
715 max_objects
= s
->objects
;
718 if (s
->slab_size
> max_memobj
)
719 max_memobj
= s
->slab_size
;
721 total_slabs
+= s
->slabs
;
723 total_waste
+= wasted
;
725 total_objects
+= s
->objects
;
728 total_objwaste
+= s
->objects
* objwaste
;
729 total_objsize
+= s
->objects
* s
->slab_size
;
732 if (!total_objects
) {
733 printf("No objects\n");
737 printf("No slabs\n");
741 /* Per slab averages */
742 avg_slabs
= total_slabs
/ used_slabs
;
743 avg_size
= total_size
/ used_slabs
;
744 avg_waste
= total_waste
/ used_slabs
;
746 avg_objects
= total_objects
/ used_slabs
;
747 avg_used
= total_used
/ used_slabs
;
749 /* Per object object sizes */
750 avg_objsize
= total_used
/ total_objects
;
751 avg_objwaste
= total_objwaste
/ total_objects
;
752 avg_memobj
= total_objsize
/ total_objects
;
754 printf("Slabcache Totals\n");
755 printf("----------------\n");
756 printf("Slabcaches : %3d Active: %3d\n",
759 store_size(b1
, total_size
);store_size(b2
, total_waste
);
760 store_size(b3
, total_waste
* 100 / total_used
);
761 printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1
, b2
, b3
);
763 store_size(b1
, total_objects
);
764 printf("# Objects : %6s\n", b1
);
767 printf("Per Cache Average Min Max Total\n");
768 printf("---------------------------------------------------------\n");
770 store_size(b1
, avg_objects
);store_size(b2
, min_objects
);
771 store_size(b3
, max_objects
);store_size(b4
, total_objects
);
772 printf("#Objects %10s %10s %10s %10s\n",
775 store_size(b1
, avg_slabs
);store_size(b2
, min_slabs
);
776 store_size(b3
, max_slabs
);store_size(b4
, total_slabs
);
777 printf("#Slabs %10s %10s %10s %10s\n",
780 store_size(b1
, avg_size
);store_size(b2
, min_size
);
781 store_size(b3
, max_size
);store_size(b4
, total_size
);
782 printf("Memory %10s %10s %10s %10s\n",
785 store_size(b1
, avg_used
);store_size(b2
, min_used
);
786 store_size(b3
, max_used
);store_size(b4
, total_used
);
787 printf("Used %10s %10s %10s %10s\n",
790 store_size(b1
, avg_waste
);store_size(b2
, min_waste
);
791 store_size(b3
, max_waste
);store_size(b4
, total_waste
);
792 printf("Loss %10s %10s %10s %10s\n",
796 printf("Per Object Average Min Max\n");
797 printf("---------------------------------------------\n");
799 store_size(b1
, avg_memobj
);store_size(b2
, min_memobj
);
800 store_size(b3
, max_memobj
);
801 printf("Memory %10s %10s %10s\n",
803 store_size(b1
, avg_objsize
);store_size(b2
, min_objsize
);
804 store_size(b3
, max_objsize
);
805 printf("User %10s %10s %10s\n",
808 store_size(b1
, avg_objwaste
);store_size(b2
, min_objwaste
);
809 store_size(b3
, max_objwaste
);
810 printf("Loss %10s %10s %10s\n",
814 void sort_slabs(void)
816 struct slabinfo
*s1
,*s2
;
818 for (s1
= slabinfo
; s1
< slabinfo
+ slabs
; s1
++) {
819 for (s2
= s1
+ 1; s2
< slabinfo
+ slabs
; s2
++) {
823 result
= slab_size(s1
) < slab_size(s2
);
824 else if (sort_active
)
825 result
= slab_activity(s1
) < slab_activity(s2
);
827 result
= strcasecmp(s1
->name
, s2
->name
);
835 memcpy(&t
, s1
, sizeof(struct slabinfo
));
836 memcpy(s1
, s2
, sizeof(struct slabinfo
));
837 memcpy(s2
, &t
, sizeof(struct slabinfo
));
843 int slab_mismatch(char *slab
)
845 return regexec(&pattern
, slab
, 0, NULL
, 0);
848 void read_slab_dir(void)
852 struct slabinfo
*slab
= slabinfo
;
855 if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
856 fatal("SYSFS support for SLUB not active\n");
859 while ((de
= readdir(dir
))) {
860 if (de
->d_name
[0] == '.' ||
861 (de
->d_name
[0] != ':' && slab_mismatch(de
->d_name
)))
863 switch (de
->d_type
) {
865 if (chdir(de
->d_name
))
866 fatal("Unable to access slab %s\n", slab
->name
);
867 slab
->name
= strdup(de
->d_name
);
868 slab
->align
= get_obj("align");
869 slab
->cache_dma
= get_obj("cache_dma");
870 slab
->destroy_by_rcu
= get_obj("destroy_by_rcu");
871 slab
->hwcache_align
= get_obj("hwcache_align");
872 slab
->object_size
= get_obj("object_size");
873 slab
->objects
= get_obj("objects");
874 slab
->total_objects
= get_obj("total_objects");
875 slab
->objs_per_slab
= get_obj("objs_per_slab");
876 slab
->order
= get_obj("order");
877 slab
->poison
= get_obj("poison");
878 slab
->reclaim_account
= get_obj("reclaim_account");
879 slab
->red_zone
= get_obj("red_zone");
880 slab
->slab_size
= get_obj("slab_size");
881 slab
->slabs
= get_obj_and_str("slabs", &t
);
882 decode_numa_list(slab
->numa
, t
);
884 slab
->store_user
= get_obj("store_user");
885 slab
->batch
= get_obj("batch");
886 slab
->alloc
= get_obj("alloc");
887 slab
->alloc_slab_fill
= get_obj("alloc_slab_fill");
888 slab
->alloc_slab_new
= get_obj("alloc_slab_new");
889 slab
->free
= get_obj("free");
890 slab
->free_remote
= get_obj("free_remote");
891 slab
->claim_remote_list
= get_obj("claim_remote_list");
892 slab
->claim_remote_list_objects
= get_obj("claim_remote_list_objects");
893 slab
->flush_free_list
= get_obj("flush_free_list");
894 slab
->flush_free_list_objects
= get_obj("flush_free_list_objects");
895 slab
->flush_free_list_remote
= get_obj("flush_free_list_remote");
896 slab
->flush_rfree_list
= get_obj("flush_rfree_list");
897 slab
->flush_rfree_list_objects
= get_obj("flush_rfree_list_objects");
898 slab
->flush_slab_free
= get_obj("flush_slab_free");
899 slab
->flush_slab_partial
= get_obj("flush_slab_partial");
905 fatal("Unknown file type %lx\n", de
->d_type
);
909 slabs
= slab
- slabinfo
;
910 actual_slabs
= slabs
;
911 if (slabs
> MAX_SLABS
)
912 fatal("Too many slabs\n");
915 void output_slabs(void)
917 struct slabinfo
*slab
;
919 for (slab
= slabinfo
; slab
< slabinfo
+ slabs
; slab
++) {
935 else if (show_report
)
940 struct option opts
[] = {
941 { "activity", 0, NULL
, 'A' },
942 { "debug", 2, NULL
, 'd' },
943 { "display-activity", 0, NULL
, 'D' },
944 { "empty", 0, NULL
, 'e' },
945 { "help", 0, NULL
, 'h' },
946 { "inverted", 0, NULL
, 'i'},
947 { "numa", 0, NULL
, 'n' },
948 { "ops", 0, NULL
, 'o' },
949 { "report", 0, NULL
, 'r' },
950 { "shrink", 0, NULL
, 's' },
951 { "slabs", 0, NULL
, 'l' },
952 { "track", 0, NULL
, 't'},
953 { "validate", 0, NULL
, 'v' },
954 { "zero", 0, NULL
, 'z' },
955 { "1ref", 0, NULL
, '1'},
959 int main(int argc
, char *argv
[])
963 char *pattern_source
;
965 page_size
= getpagesize();
967 while ((c
= getopt_long(argc
, argv
, "Ad::Dehil1noprstvzTS",
975 if (!debug_opt_scan(optarg
))
976 fatal("Invalid debug option '%s'\n", optarg
);
1022 fatal("%s: Invalid option '%c'\n", argv
[0], optopt
);
1026 if (!show_slab
&& !show_track
&& !show_report
1027 && !validate
&& !shrink
&& !set_debug
&& !show_ops
)
1031 pattern_source
= argv
[optind
];
1033 pattern_source
= ".*";
1035 err
= regcomp(&pattern
, pattern_source
, REG_ICASE
|REG_NOSUB
);
1037 fatal("%s: Invalid pattern '%s' code %d\n",
1038 argv
[0], pattern_source
, err
);