aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-kmem.c
diff options
context:
space:
mode:
authorNamhyung Kim <namhyung@kernel.org>2015-04-21 00:55:04 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-05-04 12:34:47 -0400
commit2a7ef02c9ca0172cd48945407893f38c2438e754 (patch)
tree628fd9ac7c2432298f199e3ef65a052812c148a2 /tools/perf/builtin-kmem.c
parentfb4f313d304b0a5120e870a6cd9ecf90c1023037 (diff)
perf kmem: Add --live option for current allocation stat
Currently 'perf kmem stat --page' shows total (page) allocation stat by default, but sometimes one might want to see live (total alloc-only) requests/pages only. The new --live option does this by subtracting freed allocation from the stat. E.g.: # perf kmem stat --page SUMMARY (page allocator) ======================== Total allocation requests : 988,858 [ 4,045,368 KB ] Total free requests : 886,484 [ 3,624,996 KB ] Total alloc+freed requests : 885,969 [ 3,622,628 KB ] Total alloc-only requests : 102,889 [ 422,740 KB ] Total free-only requests : 515 [ 2,368 KB ] Total allocation failures : 0 [ 0 KB ] Order Unmovable Reclaimable Movable Reserved CMA/Isolated ----- ------------ ------------ ------------ ------------ ------------ 0 172,173 3,083 806,686 . . 1 284 . . . . 2 6,124 58 . . . 3 114 335 . . . 4 . . . . . 5 . . . . . 6 . . . . . 7 . . . . . 8 . . . . . 9 . . 1 . . 10 . . . . . # perf kmem stat --page --live SUMMARY (page allocator) ======================== Total allocation requests : 988,858 [ 4,045,368 KB ] Total free requests : 886,484 [ 3,624,996 KB ] Total alloc+freed requests : 885,969 [ 3,622,628 KB ] Total alloc-only requests : 102,889 [ 422,740 KB ] Total free-only requests : 515 [ 2,368 KB ] Total allocation failures : 0 [ 0 KB ] Order Unmovable Reclaimable Movable Reserved CMA/Isolated ----- ------------ ------------ ------------ ------------ ------------ 0 2,214 3,025 97,156 . . 1 59 . . . . 2 19 58 . . . 3 23 335 . . . 4 . . . . . 5 . . . . . 6 . . . . . 7 . . . . . 8 . . . . . 9 . . . . . 10 . . . . . # Signed-off-by: Namhyung Kim <namhyung@kernel.org> Acked-by: Pekka Enberg <penberg@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Joonsoo Kim <js1304@gmail.com> Cc: Minchan Kim <minchan@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/1429592107-1807-4-git-send-email-namhyung@kernel.org [ Added examples to the changeset log ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-kmem.c')
-rw-r--r--tools/perf/builtin-kmem.c110
1 files changed, 68 insertions, 42 deletions
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0393a7f3fa35..7ead9423fd7a 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -244,6 +244,7 @@ static unsigned long nr_page_fails;
244static unsigned long nr_page_nomatch; 244static unsigned long nr_page_nomatch;
245 245
246static bool use_pfn; 246static bool use_pfn;
247static bool live_page;
247static struct perf_session *kmem_session; 248static struct perf_session *kmem_session;
248 249
249#define MAX_MIGRATE_TYPES 6 250#define MAX_MIGRATE_TYPES 6
@@ -264,7 +265,7 @@ struct page_stat {
264 int nr_free; 265 int nr_free;
265}; 266};
266 267
267static struct rb_root page_tree; 268static struct rb_root page_live_tree;
268static struct rb_root page_alloc_tree; 269static struct rb_root page_alloc_tree;
269static struct rb_root page_alloc_sorted; 270static struct rb_root page_alloc_sorted;
270static struct rb_root page_caller_tree; 271static struct rb_root page_caller_tree;
@@ -403,10 +404,19 @@ out:
403 return sample->ip; 404 return sample->ip;
404} 405}
405 406
407struct sort_dimension {
408 const char name[20];
409 sort_fn_t cmp;
410 struct list_head list;
411};
412
413static LIST_HEAD(page_alloc_sort_input);
414static LIST_HEAD(page_caller_sort_input);
415
406static struct page_stat * 416static struct page_stat *
407__page_stat__findnew_page(u64 page, bool create) 417__page_stat__findnew_page(struct page_stat *pstat, bool create)
408{ 418{
409 struct rb_node **node = &page_tree.rb_node; 419 struct rb_node **node = &page_live_tree.rb_node;
410 struct rb_node *parent = NULL; 420 struct rb_node *parent = NULL;
411 struct page_stat *data; 421 struct page_stat *data;
412 422
@@ -416,7 +426,7 @@ __page_stat__findnew_page(u64 page, bool create)
416 parent = *node; 426 parent = *node;
417 data = rb_entry(*node, struct page_stat, node); 427 data = rb_entry(*node, struct page_stat, node);
418 428
419 cmp = data->page - page; 429 cmp = data->page - pstat->page;
420 if (cmp < 0) 430 if (cmp < 0)
421 node = &parent->rb_left; 431 node = &parent->rb_left;
422 else if (cmp > 0) 432 else if (cmp > 0)
@@ -430,34 +440,28 @@ __page_stat__findnew_page(u64 page, bool create)
430 440
431 data = zalloc(sizeof(*data)); 441 data = zalloc(sizeof(*data));
432 if (data != NULL) { 442 if (data != NULL) {
433 data->page = page; 443 data->page = pstat->page;
444 data->order = pstat->order;
445 data->gfp_flags = pstat->gfp_flags;
446 data->migrate_type = pstat->migrate_type;
434 447
435 rb_link_node(&data->node, parent, node); 448 rb_link_node(&data->node, parent, node);
436 rb_insert_color(&data->node, &page_tree); 449 rb_insert_color(&data->node, &page_live_tree);
437 } 450 }
438 451
439 return data; 452 return data;
440} 453}
441 454
442static struct page_stat *page_stat__find_page(u64 page) 455static struct page_stat *page_stat__find_page(struct page_stat *pstat)
443{ 456{
444 return __page_stat__findnew_page(page, false); 457 return __page_stat__findnew_page(pstat, false);
445} 458}
446 459
447static struct page_stat *page_stat__findnew_page(u64 page) 460static struct page_stat *page_stat__findnew_page(struct page_stat *pstat)
448{ 461{
449 return __page_stat__findnew_page(page, true); 462 return __page_stat__findnew_page(pstat, true);
450} 463}
451 464
452struct sort_dimension {
453 const char name[20];
454 sort_fn_t cmp;
455 struct list_head list;
456};
457
458static LIST_HEAD(page_alloc_sort_input);
459static LIST_HEAD(page_caller_sort_input);
460
461static struct page_stat * 465static struct page_stat *
462__page_stat__findnew_alloc(struct page_stat *pstat, bool create) 466__page_stat__findnew_alloc(struct page_stat *pstat, bool create)
463{ 467{
@@ -615,17 +619,8 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
615 * This is to find the current page (with correct gfp flags and 619 * This is to find the current page (with correct gfp flags and
616 * migrate type) at free event. 620 * migrate type) at free event.
617 */ 621 */
618 pstat = page_stat__findnew_page(page);
619 if (pstat == NULL)
620 return -ENOMEM;
621
622 pstat->order = order;
623 pstat->gfp_flags = gfp_flags;
624 pstat->migrate_type = migrate_type;
625 pstat->callsite = callsite;
626
627 this.page = page; 622 this.page = page;
628 pstat = page_stat__findnew_alloc(&this); 623 pstat = page_stat__findnew_page(&this);
629 if (pstat == NULL) 624 if (pstat == NULL)
630 return -ENOMEM; 625 return -ENOMEM;
631 626
@@ -633,6 +628,16 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
633 pstat->alloc_bytes += bytes; 628 pstat->alloc_bytes += bytes;
634 pstat->callsite = callsite; 629 pstat->callsite = callsite;
635 630
631 if (!live_page) {
632 pstat = page_stat__findnew_alloc(&this);
633 if (pstat == NULL)
634 return -ENOMEM;
635
636 pstat->nr_alloc++;
637 pstat->alloc_bytes += bytes;
638 pstat->callsite = callsite;
639 }
640
636 this.callsite = callsite; 641 this.callsite = callsite;
637 pstat = page_stat__findnew_caller(&this); 642 pstat = page_stat__findnew_caller(&this);
638 if (pstat == NULL) 643 if (pstat == NULL)
@@ -665,7 +670,8 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
665 nr_page_frees++; 670 nr_page_frees++;
666 total_page_free_bytes += bytes; 671 total_page_free_bytes += bytes;
667 672
668 pstat = page_stat__find_page(page); 673 this.page = page;
674 pstat = page_stat__find_page(&this);
669 if (pstat == NULL) { 675 if (pstat == NULL) {
670 pr_debug2("missing free at page %"PRIx64" (order: %d)\n", 676 pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
671 page, order); 677 page, order);
@@ -676,20 +682,23 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
676 return 0; 682 return 0;
677 } 683 }
678 684
679 this.page = page;
680 this.gfp_flags = pstat->gfp_flags; 685 this.gfp_flags = pstat->gfp_flags;
681 this.migrate_type = pstat->migrate_type; 686 this.migrate_type = pstat->migrate_type;
682 this.callsite = pstat->callsite; 687 this.callsite = pstat->callsite;
683 688
684 rb_erase(&pstat->node, &page_tree); 689 rb_erase(&pstat->node, &page_live_tree);
685 free(pstat); 690 free(pstat);
686 691
687 pstat = page_stat__find_alloc(&this); 692 if (live_page) {
688 if (pstat == NULL) 693 order_stats[this.order][this.migrate_type]--;
689 return -ENOENT; 694 } else {
695 pstat = page_stat__find_alloc(&this);
696 if (pstat == NULL)
697 return -ENOMEM;
690 698
691 pstat->nr_free++; 699 pstat->nr_free++;
692 pstat->free_bytes += bytes; 700 pstat->free_bytes += bytes;
701 }
693 702
694 pstat = page_stat__find_caller(&this); 703 pstat = page_stat__find_caller(&this);
695 if (pstat == NULL) 704 if (pstat == NULL)
@@ -698,6 +707,16 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
698 pstat->nr_free++; 707 pstat->nr_free++;
699 pstat->free_bytes += bytes; 708 pstat->free_bytes += bytes;
700 709
710 if (live_page) {
711 pstat->nr_alloc--;
712 pstat->alloc_bytes -= bytes;
713
714 if (pstat->nr_alloc == 0) {
715 rb_erase(&pstat->node, &page_caller_tree);
716 free(pstat);
717 }
718 }
719
701 return 0; 720 return 0;
702} 721}
703 722
@@ -815,8 +834,8 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines)
815 const char *format; 834 const char *format;
816 835
817 printf("\n%.105s\n", graph_dotted_line); 836 printf("\n%.105s\n", graph_dotted_line);
818 printf(" %-16s | Total alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n", 837 printf(" %-16s | %5s alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n",
819 use_pfn ? "PFN" : "Page"); 838 use_pfn ? "PFN" : "Page", live_page ? "Live" : "Total");
820 printf("%.105s\n", graph_dotted_line); 839 printf("%.105s\n", graph_dotted_line);
821 840
822 if (use_pfn) 841 if (use_pfn)
@@ -860,7 +879,8 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines
860 struct machine *machine = &session->machines.host; 879 struct machine *machine = &session->machines.host;
861 880
862 printf("\n%.105s\n", graph_dotted_line); 881 printf("\n%.105s\n", graph_dotted_line);
863 printf(" Total alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n"); 882 printf(" %5s alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n",
883 live_page ? "Live" : "Total");
864 printf("%.105s\n", graph_dotted_line); 884 printf("%.105s\n", graph_dotted_line);
865 885
866 while (next && n_lines--) { 886 while (next && n_lines--) {
@@ -1085,8 +1105,13 @@ static void sort_result(void)
1085 &slab_caller_sort); 1105 &slab_caller_sort);
1086 } 1106 }
1087 if (kmem_page) { 1107 if (kmem_page) {
1088 __sort_page_result(&page_alloc_tree, &page_alloc_sorted, 1108 if (live_page)
1089 &page_alloc_sort); 1109 __sort_page_result(&page_live_tree, &page_alloc_sorted,
1110 &page_alloc_sort);
1111 else
1112 __sort_page_result(&page_alloc_tree, &page_alloc_sorted,
1113 &page_alloc_sort);
1114
1090 __sort_page_result(&page_caller_tree, &page_caller_sorted, 1115 __sort_page_result(&page_caller_tree, &page_caller_sorted,
1091 &page_caller_sort); 1116 &page_caller_sort);
1092 } 1117 }
@@ -1630,6 +1655,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1630 parse_slab_opt), 1655 parse_slab_opt),
1631 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator", 1656 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
1632 parse_page_opt), 1657 parse_page_opt),
1658 OPT_BOOLEAN(0, "live", &live_page, "Show live page stat"),
1633 OPT_END() 1659 OPT_END()
1634 }; 1660 };
1635 const char *const kmem_subcommands[] = { "record", "stat", NULL }; 1661 const char *const kmem_subcommands[] = { "record", "stat", NULL };