From 2b10075539d334b4732a07857672972fe971f7df Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:17 -0800 Subject: tools/vm/slabinfo: use getopt no_argument/optional_argument This patchset adds 'extended' slabinfo mode that provides additional information: -- totals summary -- slabs sorted by size -- slabs sorted by loss (waste) The patches also introduces several new slabinfo options to limit the number of slabs reported, sort slabs by loss (waste); and some fixes. Extended output example (slabinfo -X -N 2): Slabcache Totals ---------------- Slabcaches : 91 Aliases : 119->69 Active: 63 Memory used: 199798784 # Loss : 10689376 MRatio: 5% # Objects : 324301 # PartObj: 18151 ORatio: 5% Per Cache Average Min Max Total ---------------------------------------------------------------------------- #Objects 5147 1 89068 324301 #Slabs 199 1 3886 12537 #PartSlab 12 0 240 778 %PartSlab 32% 0% 100% 6% PartObjs 5 0 4569 18151 % PartObj 26% 0% 100% 5% Memory 3171409 8192 127336448 199798784 Used 3001736 160 121429728 189109408 Loss 169672 0 5906720 10689376 Per Object Average Min Max ----------------------------------------------------------- Memory 585 8 8192 User 583 8 8192 Loss 2 0 64 Slabs sorted by size -------------------- Name Objects Objsize Space Slabs/Part/Cpu O/S O %Fr %Ef Flg ext4_inode_cache 69948 1736 127336448 3871/0/15 18 3 0 95 a dentry 89068 288 26058752 3164/0/17 28 1 0 98 a Slabs sorted by loss -------------------- Name Objects Objsize Loss Slabs/Part/Cpu O/S O %Fr %Ef Flg ext4_inode_cache 69948 1736 5906720 3871/0/15 18 3 0 95 a inode_cache 11628 864 537472 642/0/4 18 2 0 94 a The last patch in the series addresses Linus' comment from http://marc.info/?l=linux-mm&m=144148518703321&w=2 (well, it's been some time. sorry.) gnuplot script takes the slabinfo records file, where every record is a `slabinfo -X' output. So the basic workflow is, for example, as follows: while [ 1 ]; do slabinfo -X -N 2 >> stats; sleep 1; done ^C slabinfo-gnuplot.sh stats The last command will produce 3 png files (and 3 stats files) -- graph of slabinfo totals -- graph of slabs by size -- graph of slabs by loss It's also possible to select a range of records for plotting (a range of collected slabinfo outputs) via `-r 10,100` (for example); and compare totals from several measurements (to visially compare slabs behaviour (10,50 range)) using pre-parsed totals files: slabinfo-gnuplot.sh -r 10,50 -t stats-totals1 .. stats-totals2 This also, technically, supports ktest. Upload new slabinfo to target, collect the stats and give the resulting stats file to slabinfo-gnuplot This patch (of 8): Use getopt constants in `struct option' ->has_arg instead of numerical representations. Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 808d5a9d5dcf..258ed014729d 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -1268,23 +1268,23 @@ static void output_slabs(void) } struct option opts[] = { - { "aliases", 0, NULL, 'a' }, - { "activity", 0, NULL, 'A' }, - { "debug", 2, NULL, 'd' }, - { "display-activity", 0, NULL, 'D' }, - { "empty", 0, NULL, 'e' }, - { "first-alias", 0, NULL, 'f' }, - { "help", 0, NULL, 'h' }, - { "inverted", 0, NULL, 'i'}, - { "numa", 0, NULL, 'n' }, - { "ops", 0, NULL, 'o' }, - { "report", 0, NULL, 'r' }, - { "shrink", 0, NULL, 's' }, - { "slabs", 0, NULL, 'l' }, - { "track", 0, NULL, 't'}, - { "validate", 0, NULL, 'v' }, - { "zero", 0, NULL, 'z' }, - { "1ref", 0, NULL, '1'}, + { "aliases", no_argument, NULL, 'a' }, + { "activity", no_argument, NULL, 'A' }, + { "debug", optional_argument, NULL, 'd' }, + { "display-activity", no_argument, NULL, 'D' }, + { "empty", no_argument, NULL, 'e' }, + { "first-alias", no_argument, NULL, 'f' }, + { "help", no_argument, NULL, 'h' }, + { "inverted", no_argument, NULL, 'i'}, + { "numa", no_argument, NULL, 'n' }, + { "ops", no_argument, NULL, 'o' }, + { "report", no_argument, NULL, 'r' }, + { "shrink", no_argument, NULL, 's' }, + { "slabs", no_argument, NULL, 'l' }, + { "track", no_argument, NULL, 't'}, + { "validate", no_argument, NULL, 'v' }, + { "zero", no_argument, NULL, 'z' }, + { "1ref", no_argument, NULL, '1'}, { NULL, 0, NULL, 0 } }; -- cgit v1.2.3-70-g09d2 From 4980a9639b4bf4948f4cba60e3e6c45a635b98ec Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:20 -0800 Subject: tools/vm/slabinfo: limit the number of reported slabs Introduce opt "-N|--lines=K" to limit the number of slabs being reported in output_slabs(). Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 258ed014729d..2ef7f0ca0168 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -79,6 +79,7 @@ int sort_active = 0; int set_debug = 0; int show_ops = 0; int show_activity = 0; +int output_lines = -1; /* Debug options */ int sanity = 0; @@ -124,6 +125,7 @@ static void usage(void) "-v|--validate Validate slabs\n" "-z|--zero Include empty slabs\n" "-1|--1ref Single reference\n" + "-N|--lines=K Show the first K slabs\n" "\nValid debug options (FZPUT may be combined)\n" "a / A Switch on all debug options (=FZUP)\n" "- Switch off all debug options\n" @@ -1242,11 +1244,14 @@ static void output_slabs(void) { struct slabinfo *slab; - for (slab = slabinfo; slab < slabinfo + slabs; slab++) { + for (slab = slabinfo; (slab < slabinfo + slabs) && + output_lines != 0; slab++) { if (slab->alias) continue; + if (output_lines != -1) + output_lines--; if (show_numa) slab_numa(slab, 0); @@ -1285,6 +1290,7 @@ struct option opts[] = { { "validate", no_argument, NULL, 'v' }, { "zero", no_argument, NULL, 'z' }, { "1ref", no_argument, NULL, '1'}, + { "lines", required_argument, NULL, 'N'}, { NULL, 0, NULL, 0 } }; @@ -1296,7 +1302,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS", + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:", opts, NULL)) != -1) switch (c) { case '1': @@ -1358,7 +1364,13 @@ int main(int argc, char *argv[]) case 'S': sort_size = 1; break; - + case 'N': + if (optarg) { + output_lines = atoi(optarg); + if (output_lines < 1) + output_lines = 1; + } + break; default: fatal("%s: Invalid option '%c'\n", argv[0], optopt); -- cgit v1.2.3-70-g09d2 From 2651f6e7fe1c24b0a50691828edd392971d57d4f Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:22 -0800 Subject: tools/vm/slabinfo: sort slabs by loss Introduce opt "-L|--sort-loss" to sort and output slabs by loss (waste) in slabcache(). Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 2ef7f0ca0168..2e154f13c60e 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -80,6 +80,7 @@ int set_debug = 0; int show_ops = 0; int show_activity = 0; int output_lines = -1; +int sort_loss; /* Debug options */ int sanity = 0; @@ -126,6 +127,7 @@ static void usage(void) "-z|--zero Include empty slabs\n" "-1|--1ref Single reference\n" "-N|--lines=K Show the first K slabs\n" + "-L|--Loss Sort by loss\n" "\nValid debug options (FZPUT may be combined)\n" "a / A Switch on all debug options (=FZUP)\n" "- Switch off all debug options\n" @@ -301,8 +303,9 @@ static void first_line(void) if (show_activity) printf("Name Objects Alloc Free %%Fast Fallb O CmpX UL\n"); else - printf("Name Objects Objsize Space " - "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); + printf("Name Objects Objsize %s " + "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n", + sort_loss ? "Loss" : "Space"); } /* @@ -335,6 +338,11 @@ static unsigned long slab_activity(struct slabinfo *s) s->alloc_slowpath + s->free_slowpath; } +static unsigned long slab_waste(struct slabinfo *s) +{ + return slab_size(s) - s->objects * s->object_size; +} + static void slab_numa(struct slabinfo *s, int mode) { int node; @@ -563,7 +571,10 @@ static void slabcache(struct slabinfo *s) if (show_empty && s->slabs) return; - store_size(size_str, slab_size(s)); + if (sort_loss == 0) + store_size(size_str, slab_size(s)); + else + store_size(size_str, slab_waste(s)); snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs, s->partial, s->cpu_slabs); @@ -1013,6 +1024,8 @@ static void sort_slabs(void) result = slab_size(s1) < slab_size(s2); else if (sort_active) result = slab_activity(s1) < slab_activity(s2); + else if (sort_loss) + result = slab_waste(s1) < slab_waste(s2); else result = strcasecmp(s1->name, s2->name); @@ -1291,6 +1304,7 @@ struct option opts[] = { { "zero", no_argument, NULL, 'z' }, { "1ref", no_argument, NULL, '1'}, { "lines", required_argument, NULL, 'N'}, + { "Loss", no_argument, NULL, 'L'}, { NULL, 0, NULL, 0 } }; @@ -1302,7 +1316,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:", + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:L", opts, NULL)) != -1) switch (c) { case '1': @@ -1371,6 +1385,9 @@ int main(int argc, char *argv[]) output_lines = 1; } break; + case 'L': + sort_loss = 1; + break; default: fatal("%s: Invalid option '%c'\n", argv[0], optopt); -- cgit v1.2.3-70-g09d2 From 0d00bf589f0f8976b5bccbb5bd03a497762b5545 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:25 -0800 Subject: tools/vm/slabinfo: fix alternate opts names Fix mismatches between usage() output and real opts[] options. Add missing alternative opt names, e.g., '-S' had no '--Size' opts[] entry, etc. Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 2e154f13c60e..de4974df4255 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -1294,12 +1294,14 @@ struct option opts[] = { { "first-alias", no_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, { "inverted", no_argument, NULL, 'i'}, + { "slabs", no_argument, NULL, 'l' }, { "numa", no_argument, NULL, 'n' }, { "ops", no_argument, NULL, 'o' }, - { "report", no_argument, NULL, 'r' }, { "shrink", no_argument, NULL, 's' }, - { "slabs", no_argument, NULL, 'l' }, - { "track", no_argument, NULL, 't'}, + { "report", no_argument, NULL, 'r' }, + { "Size", no_argument, NULL, 'S'}, + { "tracking", no_argument, NULL, 't'}, + { "Totals", no_argument, NULL, 'T'}, { "validate", no_argument, NULL, 'v' }, { "zero", no_argument, NULL, 'z' }, { "1ref", no_argument, NULL, '1'}, -- cgit v1.2.3-70-g09d2 From 016c6cdf3df8b05a23ff7b0e77aa7f4fe83e700d Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:28 -0800 Subject: tools/vm/slabinfo: introduce extended totals mode Add "-X|--Xtotals" opt to output extended totals summary, which includes: -- totals summary -- slabs sorted by size -- slabs sorted by loss (waste) Example: ======= slabinfo --X -N 1 Slabcache Totals ---------------- Slabcaches : 91 Aliases : 120->69 Active: 65 Memory used: 568.3M # Loss : 30.4M MRatio: 5% # Objects : 920.1K # PartObj: 161.2K ORatio: 17% Per Cache Average Min Max Total --------------------------------------------------------- #Objects 14.1K 1 227.8K 920.1K #Slabs 533 1 11.7K 34.7K #PartSlab 86 0 4.3K 5.6K %PartSlab 24% 0% 100% 16% PartObjs 17 0 129.3K 161.2K % PartObj 17% 0% 100% 17% Memory 8.7M 8.1K 384.7M 568.3M Used 8.2M 160 366.5M 537.9M Loss 468.8K 0 18.2M 30.4M Per Object Average Min Max --------------------------------------------- Memory 587 8 8.1K User 584 8 8.1K Loss 2 0 64 Slabs sorted by size ---------------------- Name Objects Objsize Space Slabs/Part/Cpu O/S O %Fr %Ef Flg ext4_inode_cache 211142 1736 384.7M 11732/40/10 18 3 0 95 a Slabs sorted by loss ---------------------- Name Objects Objsize Loss Slabs/Part/Cpu O/S O %Fr %Ef Flg ext4_inode_cache 211142 1736 18.2M 11732/40/10 18 3 0 95 a Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 54 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index de4974df4255..44b83ce352fd 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -81,6 +81,7 @@ int show_ops = 0; int show_activity = 0; int output_lines = -1; int sort_loss; +int extended_totals; /* Debug options */ int sanity = 0; @@ -128,6 +129,7 @@ static void usage(void) "-1|--1ref Single reference\n" "-N|--lines=K Show the first K slabs\n" "-L|--Loss Sort by loss\n" + "-X|--Xtotals Show extended summary information\n" "\nValid debug options (FZPUT may be combined)\n" "a / A Switch on all debug options (=FZUP)\n" "- Switch off all debug options\n" @@ -615,8 +617,7 @@ static void slabcache(struct slabinfo *s) total_free ? (s->free_fastpath * 100 / total_free) : 0, s->order_fallback, s->order, s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); - } - else + } else { printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", s->name, s->objects, s->object_size, size_str, dist_str, s->objs_per_slab, s->order, @@ -624,6 +625,7 @@ static void slabcache(struct slabinfo *s) s->slabs ? (s->objects * s->object_size * 100) / (s->slabs * (page_size << s->order)) : 100, flags); + } } /* @@ -1256,15 +1258,16 @@ static void read_slab_dir(void) static void output_slabs(void) { struct slabinfo *slab; + int lines = output_lines; for (slab = slabinfo; (slab < slabinfo + slabs) && - output_lines != 0; slab++) { + lines != 0; slab++) { if (slab->alias) continue; - if (output_lines != -1) - output_lines--; + if (lines != -1) + lines--; if (show_numa) slab_numa(slab, 0); @@ -1285,6 +1288,30 @@ static void output_slabs(void) } } +static void xtotals(void) +{ + totals(); + + link_slabs(); + rename_slabs(); + + printf("\nSlabs sorted by size\n"); + printf("----------------------\n"); + sort_loss = 0; + sort_size = 1; + sort_slabs(); + output_slabs(); + + printf("\nSlabs sorted by loss\n"); + printf("----------------------\n"); + line = 0; + sort_loss = 1; + sort_size = 0; + sort_slabs(); + output_slabs(); + printf("\n"); +} + struct option opts[] = { { "aliases", no_argument, NULL, 'a' }, { "activity", no_argument, NULL, 'A' }, @@ -1307,6 +1334,7 @@ struct option opts[] = { { "1ref", no_argument, NULL, '1'}, { "lines", required_argument, NULL, 'N'}, { "Loss", no_argument, NULL, 'L'}, + { "Xtotals", no_argument, NULL, 'X'}, { NULL, 0, NULL, 0 } }; @@ -1318,7 +1346,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:L", + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LX", opts, NULL)) != -1) switch (c) { case '1': @@ -1390,6 +1418,11 @@ int main(int argc, char *argv[]) case 'L': sort_loss = 1; break; + case 'X': + if (output_lines == -1) + output_lines = 1; + extended_totals = 1; + break; default: fatal("%s: Invalid option '%c'\n", argv[0], optopt); @@ -1409,12 +1442,13 @@ int main(int argc, char *argv[]) fatal("%s: Invalid pattern '%s' code %d\n", argv[0], pattern_source, err); read_slab_dir(); - if (show_alias) + if (show_alias) { alias(); - else - if (show_totals) + } else if (extended_totals) { + xtotals(); + } else if (show_totals) { totals(); - else { + } else { link_slabs(); rename_slabs(); sort_slabs(); -- cgit v1.2.3-70-g09d2 From a8ea0bf1286a3a96466139a828f3d161d19ca015 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:31 -0800 Subject: tools/vm/slabinfo: output sizes in bytes Introduce "-B|--Bytes" opt to disable store_size() dynamic size scaling and report size in bytes instead. This `expands' the interface a bit, it's impossible to use printf("%6s") anymore to output sizes. Example: slabinfo -X -N 2 Slabcache Totals ---------------- Slabcaches : 91 Aliases : 119->69 Active: 63 Memory used: 199798784 # Loss : 10689376 MRatio: 5% # Objects : 324301 # PartObj: 18151 ORatio: 5% Per Cache Average Min Max Total ---------------------------------------------------------------------------- #Objects 5147 1 89068 324301 #Slabs 199 1 3886 12537 #PartSlab 12 0 240 778 %PartSlab 32% 0% 100% 6% PartObjs 5 0 4569 18151 % PartObj 26% 0% 100% 5% Memory 3171409 8192 127336448 199798784 Used 3001736 160 121429728 189109408 Loss 169672 0 5906720 10689376 Per Object Average Min Max ----------------------------------------------------------- Memory 585 8 8192 User 583 8 8192 Loss 2 0 64 Slabs sorted by size -------------------- Name Objects Objsize Space Slabs/Part/Cpu O/S O %Fr %Ef Flg ext4_inode_cache 69948 1736 127336448 3871/0/15 18 3 0 95 a dentry 89068 288 26058752 3164/0/17 28 1 0 98 a Slabs sorted by loss -------------------- Name Objects Objsize Loss Slabs/Part/Cpu O/S O %Fr %Ef Flg ext4_inode_cache 69948 1736 5906720 3871/0/15 18 3 0 95 a inode_cache 11628 864 537472 642/0/4 18 2 0 94 a Besides, store_size() does not use powers of two for G/M/K if (value > 1000000000UL) { divisor = 100000000UL; trailer = 'G'; } else if (value > 1000000UL) { divisor = 100000UL; trailer = 'M'; } else if (value > 1000UL) { divisor = 100; trailer = 'K'; } Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 88 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 37 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 44b83ce352fd..60beb91419d4 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -82,6 +82,7 @@ int show_activity = 0; int output_lines = -1; int sort_loss; int extended_totals; +int show_bytes; /* Debug options */ int sanity = 0; @@ -130,6 +131,7 @@ static void usage(void) "-N|--lines=K Show the first K slabs\n" "-L|--Loss Sort by loss\n" "-X|--Xtotals Show extended summary information\n" + "-B|--Bytes Show size in bytes\n" "\nValid debug options (FZPUT may be combined)\n" "a / A Switch on all debug options (=FZUP)\n" "- Switch off all debug options\n" @@ -231,15 +233,17 @@ static int store_size(char *buffer, unsigned long value) char trailer = 0; int n; - if (value > 1000000000UL) { - divisor = 100000000UL; - trailer = 'G'; - } else if (value > 1000000UL) { - divisor = 100000UL; - trailer = 'M'; - } else if (value > 1000UL) { - divisor = 100; - trailer = 'K'; + if (!show_bytes) { + if (value > 1000000000UL) { + divisor = 100000000UL; + trailer = 'G'; + } else if (value > 1000000UL) { + divisor = 100000UL; + trailer = 'M'; + } else if (value > 1000UL) { + divisor = 100; + trailer = 'K'; + } } value /= divisor; @@ -303,11 +307,12 @@ int line = 0; static void first_line(void) { if (show_activity) - printf("Name Objects Alloc Free %%Fast Fallb O CmpX UL\n"); + printf("Name Objects Alloc Free" + " %%Fast Fallb O CmpX UL\n"); else - printf("Name Objects Objsize %s " + printf("Name Objects Objsize %s " "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n", - sort_loss ? "Loss" : "Space"); + sort_loss ? " Loss" : "Space"); } /* @@ -516,7 +521,7 @@ static void report(struct slabinfo *s) if (strcmp(s->name, "*") == 0) return; - printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %lu\n", + printf("\nSlabcache: %-15s Aliases: %2d Order : %2d Objects: %lu\n", s->name, s->aliases, s->order, s->objects); if (s->hwcache_align) printf("** Hardware cacheline aligned\n"); @@ -618,7 +623,7 @@ static void slabcache(struct slabinfo *s) s->order_fallback, s->order, s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); } else { - printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", + printf("%-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s\n", s->name, s->objects, s->object_size, size_str, dist_str, s->objs_per_slab, s->order, s->slabs ? (s->partial * 100) / s->slabs : 100, @@ -933,84 +938,88 @@ static void totals(void) printf("Slabcache Totals\n"); printf("----------------\n"); - printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n", + printf("Slabcaches : %15d Aliases : %11d->%-3d Active: %3d\n", slabs, aliases, alias_targets, used_slabs); store_size(b1, total_size);store_size(b2, total_waste); store_size(b3, total_waste * 100 / total_used); - printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3); + printf("Memory used: %15s # Loss : %15s MRatio:%6s%%\n", b1, b2, b3); store_size(b1, total_objects);store_size(b2, total_partobj); store_size(b3, total_partobj * 100 / total_objects); - printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3); + printf("# Objects : %15s # PartObj: %15s ORatio:%6s%%\n", b1, b2, b3); printf("\n"); - printf("Per Cache Average Min Max Total\n"); - printf("---------------------------------------------------------\n"); + printf("Per Cache Average " + "Min Max Total\n"); + printf("---------------------------------------" + "-------------------------------------\n"); store_size(b1, avg_objects);store_size(b2, min_objects); store_size(b3, max_objects);store_size(b4, total_objects); - printf("#Objects %10s %10s %10s %10s\n", + printf("#Objects %15s %15s %15s %15s\n", b1, b2, b3, b4); store_size(b1, avg_slabs);store_size(b2, min_slabs); store_size(b3, max_slabs);store_size(b4, total_slabs); - printf("#Slabs %10s %10s %10s %10s\n", + printf("#Slabs %15s %15s %15s %15s\n", b1, b2, b3, b4); store_size(b1, avg_partial);store_size(b2, min_partial); store_size(b3, max_partial);store_size(b4, total_partial); - printf("#PartSlab %10s %10s %10s %10s\n", + printf("#PartSlab %15s %15s %15s %15s\n", b1, b2, b3, b4); store_size(b1, avg_ppart);store_size(b2, min_ppart); store_size(b3, max_ppart); store_size(b4, total_partial * 100 / total_slabs); - printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n", + printf("%%PartSlab%15s%% %15s%% %15s%% %15s%%\n", b1, b2, b3, b4); store_size(b1, avg_partobj);store_size(b2, min_partobj); store_size(b3, max_partobj); store_size(b4, total_partobj); - printf("PartObjs %10s %10s %10s %10s\n", + printf("PartObjs %15s %15s %15s %15s\n", b1, b2, b3, b4); store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj); store_size(b3, max_ppartobj); store_size(b4, total_partobj * 100 / total_objects); - printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n", + printf("%% PartObj%15s%% %15s%% %15s%% %15s%%\n", b1, b2, b3, b4); store_size(b1, avg_size);store_size(b2, min_size); store_size(b3, max_size);store_size(b4, total_size); - printf("Memory %10s %10s %10s %10s\n", + printf("Memory %15s %15s %15s %15s\n", b1, b2, b3, b4); store_size(b1, avg_used);store_size(b2, min_used); store_size(b3, max_used);store_size(b4, total_used); - printf("Used %10s %10s %10s %10s\n", + printf("Used %15s %15s %15s %15s\n", b1, b2, b3, b4); store_size(b1, avg_waste);store_size(b2, min_waste); store_size(b3, max_waste);store_size(b4, total_waste); - printf("Loss %10s %10s %10s %10s\n", + printf("Loss %15s %15s %15s %15s\n", b1, b2, b3, b4); printf("\n"); - printf("Per Object Average Min Max\n"); - printf("---------------------------------------------\n"); + printf("Per Object Average " + "Min Max\n"); + printf("---------------------------------------" + "--------------------\n"); store_size(b1, avg_memobj);store_size(b2, min_memobj); store_size(b3, max_memobj); - printf("Memory %10s %10s %10s\n", + printf("Memory %15s %15s %15s\n", b1, b2, b3); store_size(b1, avg_objsize);store_size(b2, min_objsize); store_size(b3, max_objsize); - printf("User %10s %10s %10s\n", + printf("User %15s %15s %15s\n", b1, b2, b3); store_size(b1, avg_objwaste);store_size(b2, min_objwaste); store_size(b3, max_objwaste); - printf("Loss %10s %10s %10s\n", + printf("Loss %15s %15s %15s\n", b1, b2, b3); } @@ -1112,7 +1121,7 @@ static void alias(void) active = a->slab->name; } else - printf("%-20s -> %s\n", a->name, a->slab->name); + printf("%-15s -> %s\n", a->name, a->slab->name); } if (active) printf("\n"); @@ -1296,14 +1305,14 @@ static void xtotals(void) rename_slabs(); printf("\nSlabs sorted by size\n"); - printf("----------------------\n"); + printf("--------------------\n"); sort_loss = 0; sort_size = 1; sort_slabs(); output_slabs(); printf("\nSlabs sorted by loss\n"); - printf("----------------------\n"); + printf("--------------------\n"); line = 0; sort_loss = 1; sort_size = 0; @@ -1335,6 +1344,7 @@ struct option opts[] = { { "lines", required_argument, NULL, 'N'}, { "Loss", no_argument, NULL, 'L'}, { "Xtotals", no_argument, NULL, 'X'}, + { "Bytes", no_argument, NULL, 'B'}, { NULL, 0, NULL, 0 } }; @@ -1346,7 +1356,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LX", + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXB", opts, NULL)) != -1) switch (c) { case '1': @@ -1422,6 +1432,10 @@ int main(int argc, char *argv[]) if (output_lines == -1) output_lines = 1; extended_totals = 1; + show_bytes = 1; + break; + case 'B': + show_bytes = 1; break; default: fatal("%s: Invalid option '%c'\n", argv[0], optopt); -- cgit v1.2.3-70-g09d2 From 2cee611af8638d80d3abb71f878829a7e998bb44 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:34 -0800 Subject: tools/vm/slabinfo: cosmetic globals cleanup checkpatch.pl complains about globals being explicitly zeroed out: "ERROR: do not initialise globals to 0 or NULL". New globals, introduced in this patch set, have no explicit 0 initialization; clean up the old ones to make it less hairy. Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo.c | 54 ++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'tools/vm') diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 60beb91419d4..86e698d07e20 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -53,43 +53,43 @@ struct aliasinfo { struct slabinfo *slab; } aliasinfo[MAX_ALIASES]; -int slabs = 0; -int actual_slabs = 0; -int aliases = 0; -int alias_targets = 0; -int highest_node = 0; +int slabs; +int actual_slabs; +int aliases; +int alias_targets; +int highest_node; char buffer[4096]; -int show_empty = 0; -int show_report = 0; -int show_alias = 0; -int show_slab = 0; +int show_empty; +int show_report; +int show_alias; +int show_slab; int skip_zero = 1; -int show_numa = 0; -int show_track = 0; -int show_first_alias = 0; -int validate = 0; -int shrink = 0; -int show_inverted = 0; -int show_single_ref = 0; -int show_totals = 0; -int sort_size = 0; -int sort_active = 0; -int set_debug = 0; -int show_ops = 0; -int show_activity = 0; +int show_numa; +int show_track; +int show_first_alias; +int validate; +int shrink; +int show_inverted; +int show_single_ref; +int show_totals; +int sort_size; +int sort_active; +int set_debug; +int show_ops; +int show_activity; int output_lines = -1; int sort_loss; int extended_totals; int show_bytes; /* Debug options */ -int sanity = 0; -int redzone = 0; -int poison = 0; -int tracking = 0; -int tracing = 0; +int sanity; +int redzone; +int poison; +int tracking; +int tracing; int page_size; -- cgit v1.2.3-70-g09d2 From 4a981abd115d6ade5fe8a07d5ca1d1f987a0c2f7 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 5 Nov 2015 18:45:37 -0800 Subject: tools/vm/slabinfo: gnuplot slabifo extended stat GNUplot `slabinfo -X' stats, collected, for example, using the following command: while [ 1 ]; do slabinfo -X >> stats; sleep 1; done `slabinfo-gnuplot.sh stats' pre-processes collected records and generate graphs (totals, slabs sorted by size, slabs sorted by size). Graphs can be [individually] regenerate with different samples range and graph width-heigh (-r %d,%d and -s %d,%d options). To visually compare N `totals' graphs: slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals Signed-off-by: Sergey Senozhatsky Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/slabinfo-gnuplot.sh | 275 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 tools/vm/slabinfo-gnuplot.sh (limited to 'tools/vm') diff --git a/tools/vm/slabinfo-gnuplot.sh b/tools/vm/slabinfo-gnuplot.sh new file mode 100644 index 000000000000..35b039864b77 --- /dev/null +++ b/tools/vm/slabinfo-gnuplot.sh @@ -0,0 +1,275 @@ +#!/bin/sh + +# Sergey Senozhatsky, 2015 +# sergey.senozhatsky.work@gmail.com +# +# This software is licensed under the terms of the GNU General Public +# License version 2, as published by the Free Software Foundation, and +# may be copied, distributed, and modified under those terms. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + + +# This program is intended to plot a `slabinfo -X' stats, collected, +# for example, using the following command: +# while [ 1 ]; do slabinfo -X >> stats; sleep 1; done +# +# Use `slabinfo-gnuplot.sh stats' to pre-process collected records +# and generate graphs (totals, slabs sorted by size, slabs sorted +# by size). +# +# Graphs can be [individually] regenerate with different ranges and +# size (-r %d,%d and -s %d,%d options). +# +# To visually compare N `totals' graphs, do +# slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals +# + +min_slab_name_size=11 +xmin=0 +xmax=0 +width=1500 +height=700 +mode=preprocess + +usage() +{ + echo "Usage: [-s W,H] [-r MIN,MAX] [-t|-l] FILE1 [FILE2 ..]" + echo "FILEs must contain 'slabinfo -X' samples" + echo "-t - plot totals for FILE(s)" + echo "-l - plot slabs stats for FILE(s)" + echo "-s %d,%d - set image width and height" + echo "-r %d,%d - use data samples from a given range" +} + +check_file_exist() +{ + if [ ! -f "$1" ]; then + echo "File '$1' does not exist" + exit 1 + fi +} + +do_slabs_plotting() +{ + local file=$1 + local out_file + local range="every ::$xmin" + local xtic="" + local xtic_rotate="norotate" + local lines=2000000 + local wc_lines + + check_file_exist "$file" + + out_file=`basename "$file"` + if [ $xmax -ne 0 ]; then + range="$range::$xmax" + lines=$((xmax-xmin)) + fi + + wc_lines=`cat "$file" | wc -l` + if [ $? -ne 0 ] || [ "$wc_lines" -eq 0 ] ; then + wc_lines=$lines + fi + + if [ "$wc_lines" -lt "$lines" ]; then + lines=$wc_lines + fi + + if [ $((width / lines)) -gt $min_slab_name_size ]; then + xtic=":xtic(1)" + xtic_rotate=90 + fi + +gnuplot -p << EOF +#!/usr/bin/env gnuplot + +set terminal png enhanced size $width,$height large +set output '$out_file.png' +set autoscale xy +set xlabel 'samples' +set ylabel 'bytes' +set style histogram columnstacked title textcolor lt -1 +set style fill solid 0.15 +set xtics rotate $xtic_rotate +set key left above Left title reverse + +plot "$file" $range u 2$xtic title 'SIZE' with boxes,\ + '' $range u 3 title 'LOSS' with boxes +EOF + + if [ $? -eq 0 ]; then + echo "$out_file.png" + fi +} + +do_totals_plotting() +{ + local gnuplot_cmd="" + local range="every ::$xmin" + local file="" + + if [ $xmax -ne 0 ]; then + range="$range::$xmax" + fi + + for i in "${t_files[@]}"; do + check_file_exist "$i" + + file="$file"`basename "$i"` + gnuplot_cmd="$gnuplot_cmd '$i' $range using 1 title\ + '$i Memory usage' with lines," + gnuplot_cmd="$gnuplot_cmd '' $range using 2 title \ + '$i Loss' with lines," + done + +gnuplot -p << EOF +#!/usr/bin/env gnuplot + +set terminal png enhanced size $width,$height large +set autoscale xy +set output '$file.png' +set xlabel 'samples' +set ylabel 'bytes' +set key left above Left title reverse + +plot $gnuplot_cmd +EOF + + if [ $? -eq 0 ]; then + echo "$file.png" + fi +} + +do_preprocess() +{ + local out + local lines + local in=$1 + + check_file_exist "$in" + + # use only 'TOP' slab (biggest memory usage or loss) + let lines=3 + out=`basename "$in"`"-slabs-by-loss" + `cat "$in" | grep -A "$lines" 'Slabs sorted by loss' |\ + egrep -iv '\-\-|Name|Slabs'\ + | awk '{print $1" "$4+$2*$3" "$4}' > "$out"` + if [ $? -eq 0 ]; then + do_slabs_plotting "$out" + fi + + let lines=3 + out=`basename "$in"`"-slabs-by-size" + `cat "$in" | grep -A "$lines" 'Slabs sorted by size' |\ + egrep -iv '\-\-|Name|Slabs'\ + | awk '{print $1" "$4" "$4-$2*$3}' > "$out"` + if [ $? -eq 0 ]; then + do_slabs_plotting "$out" + fi + + out=`basename "$in"`"-totals" + `cat "$in" | grep "Memory used" |\ + awk '{print $3" "$7}' > "$out"` + if [ $? -eq 0 ]; then + t_files[0]=$out + do_totals_plotting + fi +} + +parse_opts() +{ + local opt + + while getopts "tlr::s::h" opt; do + case $opt in + t) + mode=totals + ;; + l) + mode=slabs + ;; + s) + array=(${OPTARG//,/ }) + width=${array[0]} + height=${array[1]} + ;; + r) + array=(${OPTARG//,/ }) + xmin=${array[0]} + xmax=${array[1]} + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + :) + echo "-$OPTARG requires an argument." >&2 + exit 1 + ;; + esac + done + + return $OPTIND +} + +parse_args() +{ + local idx=0 + local p + + for p in "$@"; do + case $mode in + preprocess) + files[$idx]=$p + idx=$idx+1 + ;; + totals) + t_files[$idx]=$p + idx=$idx+1 + ;; + slabs) + files[$idx]=$p + idx=$idx+1 + ;; + esac + done +} + +parse_opts "$@" +argstart=$? +parse_args "${@:$argstart}" + +if [ ${#files[@]} -eq 0 ] && [ ${#t_files[@]} -eq 0 ]; then + usage + exit 1 +fi + +case $mode in + preprocess) + for i in "${files[@]}"; do + do_preprocess "$i" + done + ;; + totals) + do_totals_plotting + ;; + slabs) + for i in "${files[@]}"; do + do_slabs_plotting "$i" + done + ;; + *) + echo "Unknown mode $mode" >&2 + usage + exit 1 + ;; +esac -- cgit v1.2.3-70-g09d2