4 #include "util/evlist.h"
5 #include "util/evsel.h"
7 #include "util/cache.h"
8 #include "util/symbol.h"
9 #include "util/thread.h"
10 #include "util/header.h"
11 #include "util/session.h"
12 #include "util/tool.h"
13 #include "util/callchain.h"
15 #include "util/parse-options.h"
16 #include "util/trace-event.h"
17 #include "util/data.h"
18 #include "util/cpumap.h"
20 #include "util/debug.h"
22 #include <linux/rbtree.h>
23 #include <linux/string.h>
30 static long kmem_page_size;
33 typedef int (*sort_fn_t)(void *, void *);
35 static int alloc_flag;
36 static int caller_flag;
38 static int alloc_lines = -1;
39 static int caller_lines = -1;
56 static struct rb_root root_alloc_stat;
57 static struct rb_root root_alloc_sorted;
58 static struct rb_root root_caller_stat;
59 static struct rb_root root_caller_sorted;
61 static unsigned long total_requested, total_allocated;
62 static unsigned long nr_allocs, nr_cross_allocs;
64 static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
65 int bytes_req, int bytes_alloc, int cpu)
67 struct rb_node **node = &root_alloc_stat.rb_node;
68 struct rb_node *parent = NULL;
69 struct alloc_stat *data = NULL;
73 data = rb_entry(*node, struct alloc_stat, node);
76 node = &(*node)->rb_right;
77 else if (ptr < data->ptr)
78 node = &(*node)->rb_left;
83 if (data && data->ptr == ptr) {
85 data->bytes_req += bytes_req;
86 data->bytes_alloc += bytes_alloc;
88 data = malloc(sizeof(*data));
90 pr_err("%s: malloc failed\n", __func__);
96 data->bytes_req = bytes_req;
97 data->bytes_alloc = bytes_alloc;
99 rb_link_node(&data->node, parent, node);
100 rb_insert_color(&data->node, &root_alloc_stat);
102 data->call_site = call_site;
103 data->alloc_cpu = cpu;
107 static int insert_caller_stat(unsigned long call_site,
108 int bytes_req, int bytes_alloc)
110 struct rb_node **node = &root_caller_stat.rb_node;
111 struct rb_node *parent = NULL;
112 struct alloc_stat *data = NULL;
116 data = rb_entry(*node, struct alloc_stat, node);
118 if (call_site > data->call_site)
119 node = &(*node)->rb_right;
120 else if (call_site < data->call_site)
121 node = &(*node)->rb_left;
126 if (data && data->call_site == call_site) {
128 data->bytes_req += bytes_req;
129 data->bytes_alloc += bytes_alloc;
131 data = malloc(sizeof(*data));
133 pr_err("%s: malloc failed\n", __func__);
136 data->call_site = call_site;
139 data->bytes_req = bytes_req;
140 data->bytes_alloc = bytes_alloc;
142 rb_link_node(&data->node, parent, node);
143 rb_insert_color(&data->node, &root_caller_stat);
149 static int perf_evsel__process_alloc_event(struct perf_evsel *evsel,
150 struct perf_sample *sample)
152 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"),
153 call_site = perf_evsel__intval(evsel, sample, "call_site");
154 int bytes_req = perf_evsel__intval(evsel, sample, "bytes_req"),
155 bytes_alloc = perf_evsel__intval(evsel, sample, "bytes_alloc");
157 if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) ||
158 insert_caller_stat(call_site, bytes_req, bytes_alloc))
161 total_requested += bytes_req;
162 total_allocated += bytes_alloc;
168 static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
169 struct perf_sample *sample)
171 int ret = perf_evsel__process_alloc_event(evsel, sample);
174 int node1 = cpu__get_node(sample->cpu),
175 node2 = perf_evsel__intval(evsel, sample, "node");
184 static int ptr_cmp(void *, void *);
185 static int slab_callsite_cmp(void *, void *);
187 static struct alloc_stat *search_alloc_stat(unsigned long ptr,
188 unsigned long call_site,
189 struct rb_root *root,
192 struct rb_node *node = root->rb_node;
193 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
196 struct alloc_stat *data;
199 data = rb_entry(node, struct alloc_stat, node);
201 cmp = sort_fn(&key, data);
203 node = node->rb_left;
205 node = node->rb_right;
212 static int perf_evsel__process_free_event(struct perf_evsel *evsel,
213 struct perf_sample *sample)
215 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr");
216 struct alloc_stat *s_alloc, *s_caller;
218 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
222 if ((short)sample->cpu != s_alloc->alloc_cpu) {
225 s_caller = search_alloc_stat(0, s_alloc->call_site,
230 s_caller->pingpong++;
232 s_alloc->alloc_cpu = -1;
237 static u64 total_page_alloc_bytes;
238 static u64 total_page_free_bytes;
239 static u64 total_page_nomatch_bytes;
240 static u64 total_page_fail_bytes;
241 static unsigned long nr_page_allocs;
242 static unsigned long nr_page_frees;
243 static unsigned long nr_page_fails;
244 static unsigned long nr_page_nomatch;
247 static struct perf_session *kmem_session;
249 #define MAX_MIGRATE_TYPES 6
250 #define MAX_PAGE_ORDER 11
252 static int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES];
260 unsigned migrate_type;
267 static struct rb_root page_tree;
268 static struct rb_root page_alloc_tree;
269 static struct rb_root page_alloc_sorted;
270 static struct rb_root page_caller_tree;
271 static struct rb_root page_caller_sorted;
279 static int nr_alloc_funcs;
280 static struct alloc_func *alloc_func_list;
282 static int funcmp(const void *a, const void *b)
284 const struct alloc_func *fa = a;
285 const struct alloc_func *fb = b;
287 if (fa->start > fb->start)
293 static int callcmp(const void *a, const void *b)
295 const struct alloc_func *fa = a;
296 const struct alloc_func *fb = b;
298 if (fb->start <= fa->start && fa->end < fb->end)
301 if (fa->start > fb->start)
307 static int build_alloc_func_list(void)
310 struct map *kernel_map;
312 struct rb_node *node;
313 struct alloc_func *func;
314 struct machine *machine = &kmem_session->machines.host;
315 regex_t alloc_func_regex;
316 const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?";
318 ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED);
322 regerror(ret, &alloc_func_regex, err, sizeof(err));
323 pr_err("Invalid regex: %s\n%s", pattern, err);
327 kernel_map = machine->vmlinux_maps[MAP__FUNCTION];
328 if (map__load(kernel_map, NULL) < 0) {
329 pr_err("cannot load kernel map\n");
333 map__for_each_symbol(kernel_map, sym, node) {
334 if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0))
337 func = realloc(alloc_func_list,
338 (nr_alloc_funcs + 1) * sizeof(*func));
342 pr_debug("alloc func: %s\n", sym->name);
343 func[nr_alloc_funcs].start = sym->start;
344 func[nr_alloc_funcs].end = sym->end;
345 func[nr_alloc_funcs].name = sym->name;
347 alloc_func_list = func;
351 qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp);
353 regfree(&alloc_func_regex);
358 * Find first non-memory allocation function from callchain.
359 * The allocation functions are in the 'alloc_func_list'.
361 static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample)
363 struct addr_location al;
364 struct machine *machine = &kmem_session->machines.host;
365 struct callchain_cursor_node *node;
367 if (alloc_func_list == NULL) {
368 if (build_alloc_func_list() < 0)
372 al.thread = machine__findnew_thread(machine, sample->pid, sample->tid);
373 sample__resolve_callchain(sample, NULL, evsel, &al, 16);
375 callchain_cursor_commit(&callchain_cursor);
377 struct alloc_func key, *caller;
380 node = callchain_cursor_current(&callchain_cursor);
384 key.start = key.end = node->ip;
385 caller = bsearch(&key, alloc_func_list, nr_alloc_funcs,
386 sizeof(key), callcmp);
390 addr = map__unmap_ip(node->map, node->ip);
396 pr_debug3("skipping alloc function: %s\n", caller->name);
398 callchain_cursor_advance(&callchain_cursor);
402 pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
406 static struct page_stat *
407 __page_stat__findnew_page(u64 page, bool create)
409 struct rb_node **node = &page_tree.rb_node;
410 struct rb_node *parent = NULL;
411 struct page_stat *data;
417 data = rb_entry(*node, struct page_stat, node);
419 cmp = data->page - page;
421 node = &parent->rb_left;
423 node = &parent->rb_right;
431 data = zalloc(sizeof(*data));
435 rb_link_node(&data->node, parent, node);
436 rb_insert_color(&data->node, &page_tree);
442 static struct page_stat *page_stat__find_page(u64 page)
444 return __page_stat__findnew_page(page, false);
447 static struct page_stat *page_stat__findnew_page(u64 page)
449 return __page_stat__findnew_page(page, true);
452 struct sort_dimension {
455 struct list_head list;
458 static LIST_HEAD(page_alloc_sort_input);
459 static LIST_HEAD(page_caller_sort_input);
461 static struct page_stat *
462 __page_stat__findnew_alloc(struct page_stat *pstat, bool create)
464 struct rb_node **node = &page_alloc_tree.rb_node;
465 struct rb_node *parent = NULL;
466 struct page_stat *data;
467 struct sort_dimension *sort;
473 data = rb_entry(*node, struct page_stat, node);
475 list_for_each_entry(sort, &page_alloc_sort_input, list) {
476 cmp = sort->cmp(pstat, data);
482 node = &parent->rb_left;
484 node = &parent->rb_right;
492 data = zalloc(sizeof(*data));
494 data->page = pstat->page;
495 data->order = pstat->order;
496 data->gfp_flags = pstat->gfp_flags;
497 data->migrate_type = pstat->migrate_type;
499 rb_link_node(&data->node, parent, node);
500 rb_insert_color(&data->node, &page_alloc_tree);
506 static struct page_stat *page_stat__find_alloc(struct page_stat *pstat)
508 return __page_stat__findnew_alloc(pstat, false);
511 static struct page_stat *page_stat__findnew_alloc(struct page_stat *pstat)
513 return __page_stat__findnew_alloc(pstat, true);
516 static struct page_stat *
517 __page_stat__findnew_caller(struct page_stat *pstat, bool create)
519 struct rb_node **node = &page_caller_tree.rb_node;
520 struct rb_node *parent = NULL;
521 struct page_stat *data;
522 struct sort_dimension *sort;
528 data = rb_entry(*node, struct page_stat, node);
530 list_for_each_entry(sort, &page_caller_sort_input, list) {
531 cmp = sort->cmp(pstat, data);
537 node = &parent->rb_left;
539 node = &parent->rb_right;
547 data = zalloc(sizeof(*data));
549 data->callsite = pstat->callsite;
550 data->order = pstat->order;
551 data->gfp_flags = pstat->gfp_flags;
552 data->migrate_type = pstat->migrate_type;
554 rb_link_node(&data->node, parent, node);
555 rb_insert_color(&data->node, &page_caller_tree);
561 static struct page_stat *page_stat__find_caller(struct page_stat *pstat)
563 return __page_stat__findnew_caller(pstat, false);
566 static struct page_stat *page_stat__findnew_caller(struct page_stat *pstat)
568 return __page_stat__findnew_caller(pstat, true);
571 static bool valid_page(u64 pfn_or_page)
573 if (use_pfn && pfn_or_page == -1UL)
575 if (!use_pfn && pfn_or_page == 0)
580 static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
581 struct perf_sample *sample)
584 unsigned int order = perf_evsel__intval(evsel, sample, "order");
585 unsigned int gfp_flags = perf_evsel__intval(evsel, sample, "gfp_flags");
586 unsigned int migrate_type = perf_evsel__intval(evsel, sample,
588 u64 bytes = kmem_page_size << order;
590 struct page_stat *pstat;
591 struct page_stat this = {
593 .gfp_flags = gfp_flags,
594 .migrate_type = migrate_type,
598 page = perf_evsel__intval(evsel, sample, "pfn");
600 page = perf_evsel__intval(evsel, sample, "page");
603 total_page_alloc_bytes += bytes;
605 if (!valid_page(page)) {
607 total_page_fail_bytes += bytes;
612 callsite = find_callsite(evsel, sample);
615 * This is to find the current page (with correct gfp flags and
616 * migrate type) at free event.
618 pstat = page_stat__findnew_page(page);
622 pstat->order = order;
623 pstat->gfp_flags = gfp_flags;
624 pstat->migrate_type = migrate_type;
625 pstat->callsite = callsite;
628 pstat = page_stat__findnew_alloc(&this);
633 pstat->alloc_bytes += bytes;
634 pstat->callsite = callsite;
636 this.callsite = callsite;
637 pstat = page_stat__findnew_caller(&this);
642 pstat->alloc_bytes += bytes;
644 order_stats[order][migrate_type]++;
649 static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
650 struct perf_sample *sample)
653 unsigned int order = perf_evsel__intval(evsel, sample, "order");
654 u64 bytes = kmem_page_size << order;
655 struct page_stat *pstat;
656 struct page_stat this = {
661 page = perf_evsel__intval(evsel, sample, "pfn");
663 page = perf_evsel__intval(evsel, sample, "page");
666 total_page_free_bytes += bytes;
668 pstat = page_stat__find_page(page);
670 pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
674 total_page_nomatch_bytes += bytes;
680 this.gfp_flags = pstat->gfp_flags;
681 this.migrate_type = pstat->migrate_type;
682 this.callsite = pstat->callsite;
684 rb_erase(&pstat->node, &page_tree);
687 pstat = page_stat__find_alloc(&this);
692 pstat->free_bytes += bytes;
694 pstat = page_stat__find_caller(&this);
699 pstat->free_bytes += bytes;
704 typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
705 struct perf_sample *sample);
707 static int process_sample_event(struct perf_tool *tool __maybe_unused,
708 union perf_event *event,
709 struct perf_sample *sample,
710 struct perf_evsel *evsel,
711 struct machine *machine)
713 struct thread *thread = machine__findnew_thread(machine, sample->pid,
716 if (thread == NULL) {
717 pr_debug("problem processing %d event, skipping it.\n",
722 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
724 if (evsel->handler != NULL) {
725 tracepoint_handler f = evsel->handler;
726 return f(evsel, sample);
732 static struct perf_tool perf_kmem = {
733 .sample = process_sample_event,
734 .comm = perf_event__process_comm,
735 .mmap = perf_event__process_mmap,
736 .mmap2 = perf_event__process_mmap2,
737 .ordered_events = true,
740 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
745 return 100.0 - (100.0 * n_req / n_alloc);
748 static void __print_slab_result(struct rb_root *root,
749 struct perf_session *session,
750 int n_lines, int is_caller)
752 struct rb_node *next;
753 struct machine *machine = &session->machines.host;
755 printf("%.105s\n", graph_dotted_line);
756 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
757 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
758 printf("%.105s\n", graph_dotted_line);
760 next = rb_first(root);
762 while (next && n_lines--) {
763 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
765 struct symbol *sym = NULL;
771 addr = data->call_site;
773 sym = machine__find_kernel_function(machine, addr, &map, NULL);
778 snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
779 addr - map->unmap_ip(map, sym->start));
781 snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
782 printf(" %-34s |", buf);
784 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %9lu | %6.3f%%\n",
785 (unsigned long long)data->bytes_alloc,
786 (unsigned long)data->bytes_alloc / data->hit,
787 (unsigned long long)data->bytes_req,
788 (unsigned long)data->bytes_req / data->hit,
789 (unsigned long)data->hit,
790 (unsigned long)data->pingpong,
791 fragmentation(data->bytes_req, data->bytes_alloc));
793 next = rb_next(next);
797 printf(" ... | ... | ... | ... | ... | ... \n");
799 printf("%.105s\n", graph_dotted_line);
802 static const char * const migrate_type_str[] = {
811 static void __print_page_alloc_result(struct perf_session *session, int n_lines)
813 struct rb_node *next = rb_first(&page_alloc_sorted);
814 struct machine *machine = &session->machines.host;
817 printf("\n%.105s\n", graph_dotted_line);
818 printf(" %-16s | Total alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n",
819 use_pfn ? "PFN" : "Page");
820 printf("%.105s\n", graph_dotted_line);
823 format = " %16llu | %'16llu | %'9d | %5d | %8s | %08lx | %s\n";
825 format = " %016llx | %'16llu | %'9d | %5d | %8s | %08lx | %s\n";
827 while (next && n_lines--) {
828 struct page_stat *data;
834 data = rb_entry(next, struct page_stat, node);
835 sym = machine__find_kernel_function(machine, data->callsite,
837 if (sym && sym->name)
840 scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
842 printf(format, (unsigned long long)data->page,
843 (unsigned long long)data->alloc_bytes / 1024,
844 data->nr_alloc, data->order,
845 migrate_type_str[data->migrate_type],
846 (unsigned long)data->gfp_flags, caller);
848 next = rb_next(next);
852 printf(" ... | ... | ... | ... | ... | ... | ...\n");
854 printf("%.105s\n", graph_dotted_line);
857 static void __print_page_caller_result(struct perf_session *session, int n_lines)
859 struct rb_node *next = rb_first(&page_caller_sorted);
860 struct machine *machine = &session->machines.host;
862 printf("\n%.105s\n", graph_dotted_line);
863 printf(" Total alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n");
864 printf("%.105s\n", graph_dotted_line);
866 while (next && n_lines--) {
867 struct page_stat *data;
873 data = rb_entry(next, struct page_stat, node);
874 sym = machine__find_kernel_function(machine, data->callsite,
876 if (sym && sym->name)
879 scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
881 printf(" %'16llu | %'9d | %5d | %8s | %08lx | %s\n",
882 (unsigned long long)data->alloc_bytes / 1024,
883 data->nr_alloc, data->order,
884 migrate_type_str[data->migrate_type],
885 (unsigned long)data->gfp_flags, caller);
887 next = rb_next(next);
891 printf(" ... | ... | ... | ... | ... | ...\n");
893 printf("%.105s\n", graph_dotted_line);
896 static void print_slab_summary(void)
898 printf("\nSUMMARY (SLAB allocator)");
899 printf("\n========================\n");
900 printf("Total bytes requested: %'lu\n", total_requested);
901 printf("Total bytes allocated: %'lu\n", total_allocated);
902 printf("Total bytes wasted on internal fragmentation: %'lu\n",
903 total_allocated - total_requested);
904 printf("Internal fragmentation: %f%%\n",
905 fragmentation(total_requested, total_allocated));
906 printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs);
909 static void print_page_summary(void)
912 u64 nr_alloc_freed = nr_page_frees - nr_page_nomatch;
913 u64 total_alloc_freed_bytes = total_page_free_bytes - total_page_nomatch_bytes;
915 printf("\nSUMMARY (page allocator)");
916 printf("\n========================\n");
917 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation requests",
918 nr_page_allocs, total_page_alloc_bytes / 1024);
919 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free requests",
920 nr_page_frees, total_page_free_bytes / 1024);
923 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests",
924 nr_alloc_freed, (total_alloc_freed_bytes) / 1024);
925 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc-only requests",
926 nr_page_allocs - nr_alloc_freed,
927 (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024);
928 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free-only requests",
929 nr_page_nomatch, total_page_nomatch_bytes / 1024);
932 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation failures",
933 nr_page_fails, total_page_fail_bytes / 1024);
936 printf("%5s %12s %12s %12s %12s %12s\n", "Order", "Unmovable",
937 "Reclaimable", "Movable", "Reserved", "CMA/Isolated");
938 printf("%.5s %.12s %.12s %.12s %.12s %.12s\n", graph_dotted_line,
939 graph_dotted_line, graph_dotted_line, graph_dotted_line,
940 graph_dotted_line, graph_dotted_line);
942 for (o = 0; o < MAX_PAGE_ORDER; o++) {
944 for (m = 0; m < MAX_MIGRATE_TYPES - 1; m++) {
945 if (order_stats[o][m])
946 printf(" %'12d", order_stats[o][m]);
948 printf(" %12c", '.');
954 static void print_slab_result(struct perf_session *session)
957 __print_slab_result(&root_caller_sorted, session, caller_lines, 1);
959 __print_slab_result(&root_alloc_sorted, session, alloc_lines, 0);
960 print_slab_summary();
963 static void print_page_result(struct perf_session *session)
966 __print_page_caller_result(session, caller_lines);
968 __print_page_alloc_result(session, alloc_lines);
969 print_page_summary();
972 static void print_result(struct perf_session *session)
975 print_slab_result(session);
977 print_page_result(session);
980 static LIST_HEAD(slab_caller_sort);
981 static LIST_HEAD(slab_alloc_sort);
982 static LIST_HEAD(page_caller_sort);
983 static LIST_HEAD(page_alloc_sort);
985 static void sort_slab_insert(struct rb_root *root, struct alloc_stat *data,
986 struct list_head *sort_list)
988 struct rb_node **new = &(root->rb_node);
989 struct rb_node *parent = NULL;
990 struct sort_dimension *sort;
993 struct alloc_stat *this;
996 this = rb_entry(*new, struct alloc_stat, node);
999 list_for_each_entry(sort, sort_list, list) {
1000 cmp = sort->cmp(data, this);
1006 new = &((*new)->rb_left);
1008 new = &((*new)->rb_right);
1011 rb_link_node(&data->node, parent, new);
1012 rb_insert_color(&data->node, root);
1015 static void __sort_slab_result(struct rb_root *root, struct rb_root *root_sorted,
1016 struct list_head *sort_list)
1018 struct rb_node *node;
1019 struct alloc_stat *data;
1022 node = rb_first(root);
1026 rb_erase(node, root);
1027 data = rb_entry(node, struct alloc_stat, node);
1028 sort_slab_insert(root_sorted, data, sort_list);
1032 static void sort_page_insert(struct rb_root *root, struct page_stat *data,
1033 struct list_head *sort_list)
1035 struct rb_node **new = &root->rb_node;
1036 struct rb_node *parent = NULL;
1037 struct sort_dimension *sort;
1040 struct page_stat *this;
1043 this = rb_entry(*new, struct page_stat, node);
1046 list_for_each_entry(sort, sort_list, list) {
1047 cmp = sort->cmp(data, this);
1053 new = &parent->rb_left;
1055 new = &parent->rb_right;
1058 rb_link_node(&data->node, parent, new);
1059 rb_insert_color(&data->node, root);
1062 static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted,
1063 struct list_head *sort_list)
1065 struct rb_node *node;
1066 struct page_stat *data;
1069 node = rb_first(root);
1073 rb_erase(node, root);
1074 data = rb_entry(node, struct page_stat, node);
1075 sort_page_insert(root_sorted, data, sort_list);
1079 static void sort_result(void)
1082 __sort_slab_result(&root_alloc_stat, &root_alloc_sorted,
1084 __sort_slab_result(&root_caller_stat, &root_caller_sorted,
1088 __sort_page_result(&page_alloc_tree, &page_alloc_sorted,
1090 __sort_page_result(&page_caller_tree, &page_caller_sorted,
1095 static int __cmd_kmem(struct perf_session *session)
1098 struct perf_evsel *evsel;
1099 const struct perf_evsel_str_handler kmem_tracepoints[] = {
1100 /* slab allocator */
1101 { "kmem:kmalloc", perf_evsel__process_alloc_event, },
1102 { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, },
1103 { "kmem:kmalloc_node", perf_evsel__process_alloc_node_event, },
1104 { "kmem:kmem_cache_alloc_node", perf_evsel__process_alloc_node_event, },
1105 { "kmem:kfree", perf_evsel__process_free_event, },
1106 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
1107 /* page allocator */
1108 { "kmem:mm_page_alloc", perf_evsel__process_page_alloc_event, },
1109 { "kmem:mm_page_free", perf_evsel__process_page_free_event, },
1112 if (!perf_session__has_traces(session, "kmem record"))
1115 if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
1116 pr_err("Initializing perf session tracepoint handlers failed\n");
1120 evlist__for_each(session->evlist, evsel) {
1121 if (!strcmp(perf_evsel__name(evsel), "kmem:mm_page_alloc") &&
1122 perf_evsel__field(evsel, "pfn")) {
1129 err = perf_session__process_events(session);
1131 pr_err("error during process events: %d\n", err);
1135 print_result(session);
1140 /* slab sort keys */
1141 static int ptr_cmp(void *a, void *b)
1143 struct alloc_stat *l = a;
1144 struct alloc_stat *r = b;
1146 if (l->ptr < r->ptr)
1148 else if (l->ptr > r->ptr)
1153 static struct sort_dimension ptr_sort_dimension = {
1158 static int slab_callsite_cmp(void *a, void *b)
1160 struct alloc_stat *l = a;
1161 struct alloc_stat *r = b;
1163 if (l->call_site < r->call_site)
1165 else if (l->call_site > r->call_site)
1170 static struct sort_dimension callsite_sort_dimension = {
1172 .cmp = slab_callsite_cmp,
1175 static int hit_cmp(void *a, void *b)
1177 struct alloc_stat *l = a;
1178 struct alloc_stat *r = b;
1180 if (l->hit < r->hit)
1182 else if (l->hit > r->hit)
1187 static struct sort_dimension hit_sort_dimension = {
1192 static int bytes_cmp(void *a, void *b)
1194 struct alloc_stat *l = a;
1195 struct alloc_stat *r = b;
1197 if (l->bytes_alloc < r->bytes_alloc)
1199 else if (l->bytes_alloc > r->bytes_alloc)
1204 static struct sort_dimension bytes_sort_dimension = {
1209 static int frag_cmp(void *a, void *b)
1212 struct alloc_stat *l = a;
1213 struct alloc_stat *r = b;
1215 x = fragmentation(l->bytes_req, l->bytes_alloc);
1216 y = fragmentation(r->bytes_req, r->bytes_alloc);
1225 static struct sort_dimension frag_sort_dimension = {
1230 static int pingpong_cmp(void *a, void *b)
1232 struct alloc_stat *l = a;
1233 struct alloc_stat *r = b;
1235 if (l->pingpong < r->pingpong)
1237 else if (l->pingpong > r->pingpong)
1242 static struct sort_dimension pingpong_sort_dimension = {
1244 .cmp = pingpong_cmp,
1247 /* page sort keys */
1248 static int page_cmp(void *a, void *b)
1250 struct page_stat *l = a;
1251 struct page_stat *r = b;
1253 if (l->page < r->page)
1255 else if (l->page > r->page)
1260 static struct sort_dimension page_sort_dimension = {
1265 static int page_callsite_cmp(void *a, void *b)
1267 struct page_stat *l = a;
1268 struct page_stat *r = b;
1270 if (l->callsite < r->callsite)
1272 else if (l->callsite > r->callsite)
1277 static struct sort_dimension page_callsite_sort_dimension = {
1279 .cmp = page_callsite_cmp,
1282 static int page_hit_cmp(void *a, void *b)
1284 struct page_stat *l = a;
1285 struct page_stat *r = b;
1287 if (l->nr_alloc < r->nr_alloc)
1289 else if (l->nr_alloc > r->nr_alloc)
1294 static struct sort_dimension page_hit_sort_dimension = {
1296 .cmp = page_hit_cmp,
1299 static int page_bytes_cmp(void *a, void *b)
1301 struct page_stat *l = a;
1302 struct page_stat *r = b;
1304 if (l->alloc_bytes < r->alloc_bytes)
1306 else if (l->alloc_bytes > r->alloc_bytes)
1311 static struct sort_dimension page_bytes_sort_dimension = {
1313 .cmp = page_bytes_cmp,
1316 static int page_order_cmp(void *a, void *b)
1318 struct page_stat *l = a;
1319 struct page_stat *r = b;
1321 if (l->order < r->order)
1323 else if (l->order > r->order)
1328 static struct sort_dimension page_order_sort_dimension = {
1330 .cmp = page_order_cmp,
1333 static int migrate_type_cmp(void *a, void *b)
1335 struct page_stat *l = a;
1336 struct page_stat *r = b;
1338 /* for internal use to find free'd page */
1339 if (l->migrate_type == -1U)
1342 if (l->migrate_type < r->migrate_type)
1344 else if (l->migrate_type > r->migrate_type)
1349 static struct sort_dimension migrate_type_sort_dimension = {
1351 .cmp = migrate_type_cmp,
1354 static int gfp_flags_cmp(void *a, void *b)
1356 struct page_stat *l = a;
1357 struct page_stat *r = b;
1359 /* for internal use to find free'd page */
1360 if (l->gfp_flags == -1U)
1363 if (l->gfp_flags < r->gfp_flags)
1365 else if (l->gfp_flags > r->gfp_flags)
1370 static struct sort_dimension gfp_flags_sort_dimension = {
1372 .cmp = gfp_flags_cmp,
1375 static struct sort_dimension *slab_sorts[] = {
1376 &ptr_sort_dimension,
1377 &callsite_sort_dimension,
1378 &hit_sort_dimension,
1379 &bytes_sort_dimension,
1380 &frag_sort_dimension,
1381 &pingpong_sort_dimension,
1384 static struct sort_dimension *page_sorts[] = {
1385 &page_sort_dimension,
1386 &page_callsite_sort_dimension,
1387 &page_hit_sort_dimension,
1388 &page_bytes_sort_dimension,
1389 &page_order_sort_dimension,
1390 &migrate_type_sort_dimension,
1391 &gfp_flags_sort_dimension,
1394 static int slab_sort_dimension__add(const char *tok, struct list_head *list)
1396 struct sort_dimension *sort;
1399 for (i = 0; i < (int)ARRAY_SIZE(slab_sorts); i++) {
1400 if (!strcmp(slab_sorts[i]->name, tok)) {
1401 sort = memdup(slab_sorts[i], sizeof(*slab_sorts[i]));
1403 pr_err("%s: memdup failed\n", __func__);
1406 list_add_tail(&sort->list, list);
1414 static int page_sort_dimension__add(const char *tok, struct list_head *list)
1416 struct sort_dimension *sort;
1419 for (i = 0; i < (int)ARRAY_SIZE(page_sorts); i++) {
1420 if (!strcmp(page_sorts[i]->name, tok)) {
1421 sort = memdup(page_sorts[i], sizeof(*page_sorts[i]));
1423 pr_err("%s: memdup failed\n", __func__);
1426 list_add_tail(&sort->list, list);
1434 static int setup_slab_sorting(struct list_head *sort_list, const char *arg)
1437 char *str = strdup(arg);
1441 pr_err("%s: strdup failed\n", __func__);
1446 tok = strsep(&pos, ",");
1449 if (slab_sort_dimension__add(tok, sort_list) < 0) {
1450 error("Unknown slab --sort key: '%s'", tok);
1460 static int setup_page_sorting(struct list_head *sort_list, const char *arg)
1463 char *str = strdup(arg);
1467 pr_err("%s: strdup failed\n", __func__);
1472 tok = strsep(&pos, ",");
1475 if (page_sort_dimension__add(tok, sort_list) < 0) {
1476 error("Unknown page --sort key: '%s'", tok);
1486 static int parse_sort_opt(const struct option *opt __maybe_unused,
1487 const char *arg, int unset __maybe_unused)
1492 if (kmem_page > kmem_slab) {
1493 if (caller_flag > alloc_flag)
1494 return setup_page_sorting(&page_caller_sort, arg);
1496 return setup_page_sorting(&page_alloc_sort, arg);
1498 if (caller_flag > alloc_flag)
1499 return setup_slab_sorting(&slab_caller_sort, arg);
1501 return setup_slab_sorting(&slab_alloc_sort, arg);
1507 static int parse_caller_opt(const struct option *opt __maybe_unused,
1508 const char *arg __maybe_unused,
1509 int unset __maybe_unused)
1511 caller_flag = (alloc_flag + 1);
1515 static int parse_alloc_opt(const struct option *opt __maybe_unused,
1516 const char *arg __maybe_unused,
1517 int unset __maybe_unused)
1519 alloc_flag = (caller_flag + 1);
1523 static int parse_slab_opt(const struct option *opt __maybe_unused,
1524 const char *arg __maybe_unused,
1525 int unset __maybe_unused)
1527 kmem_slab = (kmem_page + 1);
1531 static int parse_page_opt(const struct option *opt __maybe_unused,
1532 const char *arg __maybe_unused,
1533 int unset __maybe_unused)
1535 kmem_page = (kmem_slab + 1);
1539 static int parse_line_opt(const struct option *opt __maybe_unused,
1540 const char *arg, int unset __maybe_unused)
1547 lines = strtoul(arg, NULL, 10);
1549 if (caller_flag > alloc_flag)
1550 caller_lines = lines;
1552 alloc_lines = lines;
1557 static int __cmd_record(int argc, const char **argv)
1559 const char * const record_args[] = {
1560 "record", "-a", "-R", "-c", "1",
1562 const char * const slab_events[] = {
1563 "-e", "kmem:kmalloc",
1564 "-e", "kmem:kmalloc_node",
1566 "-e", "kmem:kmem_cache_alloc",
1567 "-e", "kmem:kmem_cache_alloc_node",
1568 "-e", "kmem:kmem_cache_free",
1570 const char * const page_events[] = {
1571 "-e", "kmem:mm_page_alloc",
1572 "-e", "kmem:mm_page_free",
1574 unsigned int rec_argc, i, j;
1575 const char **rec_argv;
1577 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1579 rec_argc += ARRAY_SIZE(slab_events);
1581 rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */
1583 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1585 if (rec_argv == NULL)
1588 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1589 rec_argv[i] = strdup(record_args[i]);
1592 for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++)
1593 rec_argv[i] = strdup(slab_events[j]);
1596 rec_argv[i++] = strdup("-g");
1598 for (j = 0; j < ARRAY_SIZE(page_events); j++, i++)
1599 rec_argv[i] = strdup(page_events[j]);
1602 for (j = 1; j < (unsigned int)argc; j++, i++)
1603 rec_argv[i] = argv[j];
1605 return cmd_record(i, rec_argv, NULL);
1608 int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1610 const char * const default_slab_sort = "frag,hit,bytes";
1611 const char * const default_page_sort = "bytes,hit";
1612 struct perf_data_file file = {
1613 .mode = PERF_DATA_MODE_READ,
1615 const struct option kmem_options[] = {
1616 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1617 OPT_INCR('v', "verbose", &verbose,
1618 "be more verbose (show symbol address, etc)"),
1619 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
1620 "show per-callsite statistics", parse_caller_opt),
1621 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
1622 "show per-allocation statistics", parse_alloc_opt),
1623 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
1624 "sort by keys: ptr, callsite, bytes, hit, pingpong, frag, "
1625 "page, order, migtype, gfp", parse_sort_opt),
1626 OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
1627 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
1628 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
1629 OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator",
1631 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
1635 const char *const kmem_subcommands[] = { "record", "stat", NULL };
1636 const char *kmem_usage[] = {
1640 struct perf_session *session;
1643 argc = parse_options_subcommand(argc, argv, kmem_options,
1644 kmem_subcommands, kmem_usage, 0);
1647 usage_with_options(kmem_usage, kmem_options);
1649 if (kmem_slab == 0 && kmem_page == 0)
1650 kmem_slab = 1; /* for backward compatibility */
1652 if (!strncmp(argv[0], "rec", 3)) {
1654 return __cmd_record(argc, argv);
1657 file.path = input_name;
1659 kmem_session = session = perf_session__new(&file, false, &perf_kmem);
1660 if (session == NULL)
1664 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
1666 if (evsel == NULL || evsel->tp_format == NULL) {
1667 pr_err("invalid event found.. aborting\n");
1671 kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
1672 symbol_conf.use_callchain = true;
1675 symbol__init(&session->header.env);
1677 if (!strcmp(argv[0], "stat")) {
1678 setlocale(LC_ALL, "");
1680 if (cpu__setup_cpunode_map())
1683 if (list_empty(&slab_caller_sort))
1684 setup_slab_sorting(&slab_caller_sort, default_slab_sort);
1685 if (list_empty(&slab_alloc_sort))
1686 setup_slab_sorting(&slab_alloc_sort, default_slab_sort);
1687 if (list_empty(&page_caller_sort))
1688 setup_page_sorting(&page_caller_sort, default_page_sort);
1689 if (list_empty(&page_alloc_sort))
1690 setup_page_sorting(&page_alloc_sort, default_page_sort);
1693 setup_page_sorting(&page_alloc_sort_input,
1694 "page,order,migtype,gfp");
1695 setup_page_sorting(&page_caller_sort_input,
1696 "callsite,order,migtype,gfp");
1698 ret = __cmd_kmem(session);
1700 usage_with_options(kmem_usage, kmem_options);
1703 perf_session__delete(session);