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"
14 #include "util/parse-options.h"
15 #include "util/trace-event.h"
16 #include "util/data.h"
17 #include "util/cpumap.h"
19 #include "util/debug.h"
21 #include <linux/rbtree.h>
22 #include <linux/string.h>
28 static long kmem_page_size;
31 typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
33 static int alloc_flag;
34 static int caller_flag;
36 static int alloc_lines = -1;
37 static int caller_lines = -1;
54 static struct rb_root root_alloc_stat;
55 static struct rb_root root_alloc_sorted;
56 static struct rb_root root_caller_stat;
57 static struct rb_root root_caller_sorted;
59 static unsigned long total_requested, total_allocated;
60 static unsigned long nr_allocs, nr_cross_allocs;
62 static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
63 int bytes_req, int bytes_alloc, int cpu)
65 struct rb_node **node = &root_alloc_stat.rb_node;
66 struct rb_node *parent = NULL;
67 struct alloc_stat *data = NULL;
71 data = rb_entry(*node, struct alloc_stat, node);
74 node = &(*node)->rb_right;
75 else if (ptr < data->ptr)
76 node = &(*node)->rb_left;
81 if (data && data->ptr == ptr) {
83 data->bytes_req += bytes_req;
84 data->bytes_alloc += bytes_alloc;
86 data = malloc(sizeof(*data));
88 pr_err("%s: malloc failed\n", __func__);
94 data->bytes_req = bytes_req;
95 data->bytes_alloc = bytes_alloc;
97 rb_link_node(&data->node, parent, node);
98 rb_insert_color(&data->node, &root_alloc_stat);
100 data->call_site = call_site;
101 data->alloc_cpu = cpu;
105 static int insert_caller_stat(unsigned long call_site,
106 int bytes_req, int bytes_alloc)
108 struct rb_node **node = &root_caller_stat.rb_node;
109 struct rb_node *parent = NULL;
110 struct alloc_stat *data = NULL;
114 data = rb_entry(*node, struct alloc_stat, node);
116 if (call_site > data->call_site)
117 node = &(*node)->rb_right;
118 else if (call_site < data->call_site)
119 node = &(*node)->rb_left;
124 if (data && data->call_site == call_site) {
126 data->bytes_req += bytes_req;
127 data->bytes_alloc += bytes_alloc;
129 data = malloc(sizeof(*data));
131 pr_err("%s: malloc failed\n", __func__);
134 data->call_site = call_site;
137 data->bytes_req = bytes_req;
138 data->bytes_alloc = bytes_alloc;
140 rb_link_node(&data->node, parent, node);
141 rb_insert_color(&data->node, &root_caller_stat);
147 static int perf_evsel__process_alloc_event(struct perf_evsel *evsel,
148 struct perf_sample *sample)
150 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"),
151 call_site = perf_evsel__intval(evsel, sample, "call_site");
152 int bytes_req = perf_evsel__intval(evsel, sample, "bytes_req"),
153 bytes_alloc = perf_evsel__intval(evsel, sample, "bytes_alloc");
155 if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) ||
156 insert_caller_stat(call_site, bytes_req, bytes_alloc))
159 total_requested += bytes_req;
160 total_allocated += bytes_alloc;
166 static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
167 struct perf_sample *sample)
169 int ret = perf_evsel__process_alloc_event(evsel, sample);
172 int node1 = cpu__get_node(sample->cpu),
173 node2 = perf_evsel__intval(evsel, sample, "node");
182 static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
183 static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
185 static struct alloc_stat *search_alloc_stat(unsigned long ptr,
186 unsigned long call_site,
187 struct rb_root *root,
190 struct rb_node *node = root->rb_node;
191 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
194 struct alloc_stat *data;
197 data = rb_entry(node, struct alloc_stat, node);
199 cmp = sort_fn(&key, data);
201 node = node->rb_left;
203 node = node->rb_right;
210 static int perf_evsel__process_free_event(struct perf_evsel *evsel,
211 struct perf_sample *sample)
213 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr");
214 struct alloc_stat *s_alloc, *s_caller;
216 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
220 if ((short)sample->cpu != s_alloc->alloc_cpu) {
223 s_caller = search_alloc_stat(0, s_alloc->call_site,
224 &root_caller_stat, callsite_cmp);
227 s_caller->pingpong++;
229 s_alloc->alloc_cpu = -1;
234 static u64 total_page_alloc_bytes;
235 static u64 total_page_free_bytes;
236 static u64 total_page_nomatch_bytes;
237 static u64 total_page_fail_bytes;
238 static unsigned long nr_page_allocs;
239 static unsigned long nr_page_frees;
240 static unsigned long nr_page_fails;
241 static unsigned long nr_page_nomatch;
245 #define MAX_MIGRATE_TYPES 6
246 #define MAX_PAGE_ORDER 11
248 static int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES];
255 unsigned migrate_type;
262 static struct rb_root page_tree;
263 static struct rb_root page_alloc_tree;
264 static struct rb_root page_alloc_sorted;
266 static struct page_stat *search_page(unsigned long page, bool create)
268 struct rb_node **node = &page_tree.rb_node;
269 struct rb_node *parent = NULL;
270 struct page_stat *data;
276 data = rb_entry(*node, struct page_stat, node);
278 cmp = data->page - page;
280 node = &parent->rb_left;
282 node = &parent->rb_right;
290 data = zalloc(sizeof(*data));
294 rb_link_node(&data->node, parent, node);
295 rb_insert_color(&data->node, &page_tree);
301 static int page_stat_cmp(struct page_stat *a, struct page_stat *b)
303 if (a->page > b->page)
305 if (a->page < b->page)
307 if (a->order > b->order)
309 if (a->order < b->order)
311 if (a->migrate_type > b->migrate_type)
313 if (a->migrate_type < b->migrate_type)
315 if (a->gfp_flags > b->gfp_flags)
317 if (a->gfp_flags < b->gfp_flags)
322 static struct page_stat *search_page_alloc_stat(struct page_stat *pstat, bool create)
324 struct rb_node **node = &page_alloc_tree.rb_node;
325 struct rb_node *parent = NULL;
326 struct page_stat *data;
332 data = rb_entry(*node, struct page_stat, node);
334 cmp = page_stat_cmp(data, pstat);
336 node = &parent->rb_left;
338 node = &parent->rb_right;
346 data = zalloc(sizeof(*data));
348 data->page = pstat->page;
349 data->order = pstat->order;
350 data->gfp_flags = pstat->gfp_flags;
351 data->migrate_type = pstat->migrate_type;
353 rb_link_node(&data->node, parent, node);
354 rb_insert_color(&data->node, &page_alloc_tree);
360 static bool valid_page(u64 pfn_or_page)
362 if (use_pfn && pfn_or_page == -1UL)
364 if (!use_pfn && pfn_or_page == 0)
369 static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
370 struct perf_sample *sample)
373 unsigned int order = perf_evsel__intval(evsel, sample, "order");
374 unsigned int gfp_flags = perf_evsel__intval(evsel, sample, "gfp_flags");
375 unsigned int migrate_type = perf_evsel__intval(evsel, sample,
377 u64 bytes = kmem_page_size << order;
378 struct page_stat *pstat;
379 struct page_stat this = {
381 .gfp_flags = gfp_flags,
382 .migrate_type = migrate_type,
386 page = perf_evsel__intval(evsel, sample, "pfn");
388 page = perf_evsel__intval(evsel, sample, "page");
391 total_page_alloc_bytes += bytes;
393 if (!valid_page(page)) {
395 total_page_fail_bytes += bytes;
401 * This is to find the current page (with correct gfp flags and
402 * migrate type) at free event.
404 pstat = search_page(page, true);
408 pstat->order = order;
409 pstat->gfp_flags = gfp_flags;
410 pstat->migrate_type = migrate_type;
413 pstat = search_page_alloc_stat(&this, true);
418 pstat->alloc_bytes += bytes;
420 order_stats[order][migrate_type]++;
425 static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
426 struct perf_sample *sample)
429 unsigned int order = perf_evsel__intval(evsel, sample, "order");
430 u64 bytes = kmem_page_size << order;
431 struct page_stat *pstat;
432 struct page_stat this = {
437 page = perf_evsel__intval(evsel, sample, "pfn");
439 page = perf_evsel__intval(evsel, sample, "page");
442 total_page_free_bytes += bytes;
444 pstat = search_page(page, false);
446 pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
450 total_page_nomatch_bytes += bytes;
456 this.gfp_flags = pstat->gfp_flags;
457 this.migrate_type = pstat->migrate_type;
459 rb_erase(&pstat->node, &page_tree);
462 pstat = search_page_alloc_stat(&this, false);
467 pstat->free_bytes += bytes;
472 typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
473 struct perf_sample *sample);
475 static int process_sample_event(struct perf_tool *tool __maybe_unused,
476 union perf_event *event,
477 struct perf_sample *sample,
478 struct perf_evsel *evsel,
479 struct machine *machine)
481 struct thread *thread = machine__findnew_thread(machine, sample->pid,
484 if (thread == NULL) {
485 pr_debug("problem processing %d event, skipping it.\n",
490 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
492 if (evsel->handler != NULL) {
493 tracepoint_handler f = evsel->handler;
494 return f(evsel, sample);
500 static struct perf_tool perf_kmem = {
501 .sample = process_sample_event,
502 .comm = perf_event__process_comm,
503 .mmap = perf_event__process_mmap,
504 .mmap2 = perf_event__process_mmap2,
505 .ordered_events = true,
508 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
513 return 100.0 - (100.0 * n_req / n_alloc);
516 static void __print_slab_result(struct rb_root *root,
517 struct perf_session *session,
518 int n_lines, int is_caller)
520 struct rb_node *next;
521 struct machine *machine = &session->machines.host;
523 printf("%.105s\n", graph_dotted_line);
524 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
525 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
526 printf("%.105s\n", graph_dotted_line);
528 next = rb_first(root);
530 while (next && n_lines--) {
531 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
533 struct symbol *sym = NULL;
539 addr = data->call_site;
541 sym = machine__find_kernel_function(machine, addr, &map, NULL);
546 snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
547 addr - map->unmap_ip(map, sym->start));
549 snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
550 printf(" %-34s |", buf);
552 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %9lu | %6.3f%%\n",
553 (unsigned long long)data->bytes_alloc,
554 (unsigned long)data->bytes_alloc / data->hit,
555 (unsigned long long)data->bytes_req,
556 (unsigned long)data->bytes_req / data->hit,
557 (unsigned long)data->hit,
558 (unsigned long)data->pingpong,
559 fragmentation(data->bytes_req, data->bytes_alloc));
561 next = rb_next(next);
565 printf(" ... | ... | ... | ... | ... | ... \n");
567 printf("%.105s\n", graph_dotted_line);
570 static const char * const migrate_type_str[] = {
579 static void __print_page_result(struct rb_root *root,
580 struct perf_session *session __maybe_unused,
583 struct rb_node *next = rb_first(root);
586 printf("\n%.80s\n", graph_dotted_line);
587 printf(" %-16s | Total alloc (KB) | Hits | Order | Mig.type | GFP flags\n",
588 use_pfn ? "PFN" : "Page");
589 printf("%.80s\n", graph_dotted_line);
592 format = " %16llu | %'16llu | %'9d | %5d | %8s | %08lx\n";
594 format = " %016llx | %'16llu | %'9d | %5d | %8s | %08lx\n";
596 while (next && n_lines--) {
597 struct page_stat *data;
599 data = rb_entry(next, struct page_stat, node);
601 printf(format, (unsigned long long)data->page,
602 (unsigned long long)data->alloc_bytes / 1024,
603 data->nr_alloc, data->order,
604 migrate_type_str[data->migrate_type],
605 (unsigned long)data->gfp_flags);
607 next = rb_next(next);
611 printf(" ... | ... | ... | ... | ... | ... \n");
613 printf("%.80s\n", graph_dotted_line);
616 static void print_slab_summary(void)
618 printf("\nSUMMARY (SLAB allocator)");
619 printf("\n========================\n");
620 printf("Total bytes requested: %'lu\n", total_requested);
621 printf("Total bytes allocated: %'lu\n", total_allocated);
622 printf("Total bytes wasted on internal fragmentation: %'lu\n",
623 total_allocated - total_requested);
624 printf("Internal fragmentation: %f%%\n",
625 fragmentation(total_requested, total_allocated));
626 printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs);
629 static void print_page_summary(void)
632 u64 nr_alloc_freed = nr_page_frees - nr_page_nomatch;
633 u64 total_alloc_freed_bytes = total_page_free_bytes - total_page_nomatch_bytes;
635 printf("\nSUMMARY (page allocator)");
636 printf("\n========================\n");
637 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation requests",
638 nr_page_allocs, total_page_alloc_bytes / 1024);
639 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free requests",
640 nr_page_frees, total_page_free_bytes / 1024);
643 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests",
644 nr_alloc_freed, (total_alloc_freed_bytes) / 1024);
645 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc-only requests",
646 nr_page_allocs - nr_alloc_freed,
647 (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024);
648 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free-only requests",
649 nr_page_nomatch, total_page_nomatch_bytes / 1024);
652 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation failures",
653 nr_page_fails, total_page_fail_bytes / 1024);
656 printf("%5s %12s %12s %12s %12s %12s\n", "Order", "Unmovable",
657 "Reclaimable", "Movable", "Reserved", "CMA/Isolated");
658 printf("%.5s %.12s %.12s %.12s %.12s %.12s\n", graph_dotted_line,
659 graph_dotted_line, graph_dotted_line, graph_dotted_line,
660 graph_dotted_line, graph_dotted_line);
662 for (o = 0; o < MAX_PAGE_ORDER; o++) {
664 for (m = 0; m < MAX_MIGRATE_TYPES - 1; m++) {
665 if (order_stats[o][m])
666 printf(" %'12d", order_stats[o][m]);
668 printf(" %12c", '.');
674 static void print_slab_result(struct perf_session *session)
677 __print_slab_result(&root_caller_sorted, session, caller_lines, 1);
679 __print_slab_result(&root_alloc_sorted, session, alloc_lines, 0);
680 print_slab_summary();
683 static void print_page_result(struct perf_session *session)
686 __print_page_result(&page_alloc_sorted, session, alloc_lines);
687 print_page_summary();
690 static void print_result(struct perf_session *session)
693 print_slab_result(session);
695 print_page_result(session);
698 struct sort_dimension {
701 struct list_head list;
704 static LIST_HEAD(caller_sort);
705 static LIST_HEAD(alloc_sort);
707 static void sort_slab_insert(struct rb_root *root, struct alloc_stat *data,
708 struct list_head *sort_list)
710 struct rb_node **new = &(root->rb_node);
711 struct rb_node *parent = NULL;
712 struct sort_dimension *sort;
715 struct alloc_stat *this;
718 this = rb_entry(*new, struct alloc_stat, node);
721 list_for_each_entry(sort, sort_list, list) {
722 cmp = sort->cmp(data, this);
728 new = &((*new)->rb_left);
730 new = &((*new)->rb_right);
733 rb_link_node(&data->node, parent, new);
734 rb_insert_color(&data->node, root);
737 static void __sort_slab_result(struct rb_root *root, struct rb_root *root_sorted,
738 struct list_head *sort_list)
740 struct rb_node *node;
741 struct alloc_stat *data;
744 node = rb_first(root);
748 rb_erase(node, root);
749 data = rb_entry(node, struct alloc_stat, node);
750 sort_slab_insert(root_sorted, data, sort_list);
754 static void sort_page_insert(struct rb_root *root, struct page_stat *data)
756 struct rb_node **new = &root->rb_node;
757 struct rb_node *parent = NULL;
760 struct page_stat *this;
763 this = rb_entry(*new, struct page_stat, node);
766 /* TODO: support more sort key */
767 cmp = data->alloc_bytes - this->alloc_bytes;
770 new = &parent->rb_left;
772 new = &parent->rb_right;
775 rb_link_node(&data->node, parent, new);
776 rb_insert_color(&data->node, root);
779 static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted)
781 struct rb_node *node;
782 struct page_stat *data;
785 node = rb_first(root);
789 rb_erase(node, root);
790 data = rb_entry(node, struct page_stat, node);
791 sort_page_insert(root_sorted, data);
795 static void sort_result(void)
798 __sort_slab_result(&root_alloc_stat, &root_alloc_sorted,
800 __sort_slab_result(&root_caller_stat, &root_caller_sorted,
804 __sort_page_result(&page_alloc_tree, &page_alloc_sorted);
808 static int __cmd_kmem(struct perf_session *session)
811 struct perf_evsel *evsel;
812 const struct perf_evsel_str_handler kmem_tracepoints[] = {
814 { "kmem:kmalloc", perf_evsel__process_alloc_event, },
815 { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, },
816 { "kmem:kmalloc_node", perf_evsel__process_alloc_node_event, },
817 { "kmem:kmem_cache_alloc_node", perf_evsel__process_alloc_node_event, },
818 { "kmem:kfree", perf_evsel__process_free_event, },
819 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
821 { "kmem:mm_page_alloc", perf_evsel__process_page_alloc_event, },
822 { "kmem:mm_page_free", perf_evsel__process_page_free_event, },
825 if (!perf_session__has_traces(session, "kmem record"))
828 if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
829 pr_err("Initializing perf session tracepoint handlers failed\n");
833 evlist__for_each(session->evlist, evsel) {
834 if (!strcmp(perf_evsel__name(evsel), "kmem:mm_page_alloc") &&
835 perf_evsel__field(evsel, "pfn")) {
842 err = perf_session__process_events(session);
844 pr_err("error during process events: %d\n", err);
848 print_result(session);
853 static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
857 else if (l->ptr > r->ptr)
862 static struct sort_dimension ptr_sort_dimension = {
867 static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
869 if (l->call_site < r->call_site)
871 else if (l->call_site > r->call_site)
876 static struct sort_dimension callsite_sort_dimension = {
881 static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
885 else if (l->hit > r->hit)
890 static struct sort_dimension hit_sort_dimension = {
895 static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
897 if (l->bytes_alloc < r->bytes_alloc)
899 else if (l->bytes_alloc > r->bytes_alloc)
904 static struct sort_dimension bytes_sort_dimension = {
909 static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
913 x = fragmentation(l->bytes_req, l->bytes_alloc);
914 y = fragmentation(r->bytes_req, r->bytes_alloc);
923 static struct sort_dimension frag_sort_dimension = {
928 static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
930 if (l->pingpong < r->pingpong)
932 else if (l->pingpong > r->pingpong)
937 static struct sort_dimension pingpong_sort_dimension = {
942 static struct sort_dimension *avail_sorts[] = {
944 &callsite_sort_dimension,
946 &bytes_sort_dimension,
947 &frag_sort_dimension,
948 &pingpong_sort_dimension,
951 #define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts))
953 static int sort_dimension__add(const char *tok, struct list_head *list)
955 struct sort_dimension *sort;
958 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
959 if (!strcmp(avail_sorts[i]->name, tok)) {
960 sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i]));
962 pr_err("%s: memdup failed\n", __func__);
965 list_add_tail(&sort->list, list);
973 static int setup_sorting(struct list_head *sort_list, const char *arg)
976 char *str = strdup(arg);
980 pr_err("%s: strdup failed\n", __func__);
985 tok = strsep(&pos, ",");
988 if (sort_dimension__add(tok, sort_list) < 0) {
989 error("Unknown --sort key: '%s'", tok);
999 static int parse_sort_opt(const struct option *opt __maybe_unused,
1000 const char *arg, int unset __maybe_unused)
1005 if (caller_flag > alloc_flag)
1006 return setup_sorting(&caller_sort, arg);
1008 return setup_sorting(&alloc_sort, arg);
1013 static int parse_caller_opt(const struct option *opt __maybe_unused,
1014 const char *arg __maybe_unused,
1015 int unset __maybe_unused)
1017 caller_flag = (alloc_flag + 1);
1021 static int parse_alloc_opt(const struct option *opt __maybe_unused,
1022 const char *arg __maybe_unused,
1023 int unset __maybe_unused)
1025 alloc_flag = (caller_flag + 1);
1029 static int parse_slab_opt(const struct option *opt __maybe_unused,
1030 const char *arg __maybe_unused,
1031 int unset __maybe_unused)
1033 kmem_slab = (kmem_page + 1);
1037 static int parse_page_opt(const struct option *opt __maybe_unused,
1038 const char *arg __maybe_unused,
1039 int unset __maybe_unused)
1041 kmem_page = (kmem_slab + 1);
1045 static int parse_line_opt(const struct option *opt __maybe_unused,
1046 const char *arg, int unset __maybe_unused)
1053 lines = strtoul(arg, NULL, 10);
1055 if (caller_flag > alloc_flag)
1056 caller_lines = lines;
1058 alloc_lines = lines;
1063 static int __cmd_record(int argc, const char **argv)
1065 const char * const record_args[] = {
1066 "record", "-a", "-R", "-c", "1",
1068 const char * const slab_events[] = {
1069 "-e", "kmem:kmalloc",
1070 "-e", "kmem:kmalloc_node",
1072 "-e", "kmem:kmem_cache_alloc",
1073 "-e", "kmem:kmem_cache_alloc_node",
1074 "-e", "kmem:kmem_cache_free",
1076 const char * const page_events[] = {
1077 "-e", "kmem:mm_page_alloc",
1078 "-e", "kmem:mm_page_free",
1080 unsigned int rec_argc, i, j;
1081 const char **rec_argv;
1083 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1085 rec_argc += ARRAY_SIZE(slab_events);
1087 rec_argc += ARRAY_SIZE(page_events);
1089 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1091 if (rec_argv == NULL)
1094 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1095 rec_argv[i] = strdup(record_args[i]);
1098 for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++)
1099 rec_argv[i] = strdup(slab_events[j]);
1102 for (j = 0; j < ARRAY_SIZE(page_events); j++, i++)
1103 rec_argv[i] = strdup(page_events[j]);
1106 for (j = 1; j < (unsigned int)argc; j++, i++)
1107 rec_argv[i] = argv[j];
1109 return cmd_record(i, rec_argv, NULL);
1112 int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1114 const char * const default_sort_order = "frag,hit,bytes";
1115 struct perf_data_file file = {
1116 .mode = PERF_DATA_MODE_READ,
1118 const struct option kmem_options[] = {
1119 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1120 OPT_INCR('v', "verbose", &verbose,
1121 "be more verbose (show symbol address, etc)"),
1122 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
1123 "show per-callsite statistics", parse_caller_opt),
1124 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
1125 "show per-allocation statistics", parse_alloc_opt),
1126 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
1127 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
1129 OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
1130 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
1131 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
1132 OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator",
1134 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
1138 const char *const kmem_subcommands[] = { "record", "stat", NULL };
1139 const char *kmem_usage[] = {
1143 struct perf_session *session;
1146 argc = parse_options_subcommand(argc, argv, kmem_options,
1147 kmem_subcommands, kmem_usage, 0);
1150 usage_with_options(kmem_usage, kmem_options);
1152 if (kmem_slab == 0 && kmem_page == 0)
1153 kmem_slab = 1; /* for backward compatibility */
1155 if (!strncmp(argv[0], "rec", 3)) {
1157 return __cmd_record(argc, argv);
1160 file.path = input_name;
1162 session = perf_session__new(&file, false, &perf_kmem);
1163 if (session == NULL)
1167 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
1169 if (evsel == NULL || evsel->tp_format == NULL) {
1170 pr_err("invalid event found.. aborting\n");
1174 kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
1177 symbol__init(&session->header.env);
1179 if (!strcmp(argv[0], "stat")) {
1180 setlocale(LC_ALL, "");
1182 if (cpu__setup_cpunode_map())
1185 if (list_empty(&caller_sort))
1186 setup_sorting(&caller_sort, default_sort_order);
1187 if (list_empty(&alloc_sort))
1188 setup_sorting(&alloc_sort, default_sort_order);
1190 ret = __cmd_kmem(session);
1192 usage_with_options(kmem_usage, kmem_options);
1195 perf_session__delete(session);