]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - tools/perf/builtin-kmem.c
perf kmem: Print gfp flags in human readable string
[mirror_ubuntu-bionic-kernel.git] / tools / perf / builtin-kmem.c
CommitLineData
ba77c9e1
LZ
1#include "builtin.h"
2#include "perf.h"
3
0f7d2f1b 4#include "util/evlist.h"
fcf65bf1 5#include "util/evsel.h"
ba77c9e1
LZ
6#include "util/util.h"
7#include "util/cache.h"
8#include "util/symbol.h"
9#include "util/thread.h"
10#include "util/header.h"
94c744b6 11#include "util/session.h"
45694aa7 12#include "util/tool.h"
c9758cc4 13#include "util/callchain.h"
ba77c9e1
LZ
14
15#include "util/parse-options.h"
16#include "util/trace-event.h"
f5fc1412 17#include "util/data.h"
4b627957 18#include "util/cpumap.h"
ba77c9e1
LZ
19
20#include "util/debug.h"
ba77c9e1
LZ
21
22#include <linux/rbtree.h>
8d9233f2 23#include <linux/string.h>
77cfe388 24#include <locale.h>
c9758cc4 25#include <regex.h>
ba77c9e1 26
0d68bc92
NK
27static int kmem_slab;
28static int kmem_page;
29
30static long kmem_page_size;
31
ba77c9e1 32struct alloc_stat;
fb4f313d 33typedef int (*sort_fn_t)(void *, void *);
ba77c9e1 34
ba77c9e1
LZ
35static int alloc_flag;
36static int caller_flag;
37
ba77c9e1
LZ
38static int alloc_lines = -1;
39static int caller_lines = -1;
40
7707b6b6
LZ
41static bool raw_ip;
42
ba77c9e1 43struct alloc_stat {
079d3f65
LZ
44 u64 call_site;
45 u64 ptr;
ba77c9e1
LZ
46 u64 bytes_req;
47 u64 bytes_alloc;
48 u32 hit;
079d3f65
LZ
49 u32 pingpong;
50
51 short alloc_cpu;
ba77c9e1
LZ
52
53 struct rb_node node;
54};
55
56static struct rb_root root_alloc_stat;
57static struct rb_root root_alloc_sorted;
58static struct rb_root root_caller_stat;
59static struct rb_root root_caller_sorted;
60
61static unsigned long total_requested, total_allocated;
7d0d3945 62static unsigned long nr_allocs, nr_cross_allocs;
ba77c9e1 63
2814eb05
ACM
64static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
65 int bytes_req, int bytes_alloc, int cpu)
ba77c9e1
LZ
66{
67 struct rb_node **node = &root_alloc_stat.rb_node;
68 struct rb_node *parent = NULL;
69 struct alloc_stat *data = NULL;
70
ba77c9e1
LZ
71 while (*node) {
72 parent = *node;
73 data = rb_entry(*node, struct alloc_stat, node);
74
75 if (ptr > data->ptr)
76 node = &(*node)->rb_right;
77 else if (ptr < data->ptr)
78 node = &(*node)->rb_left;
79 else
80 break;
81 }
82
83 if (data && data->ptr == ptr) {
84 data->hit++;
85 data->bytes_req += bytes_req;
4efb5290 86 data->bytes_alloc += bytes_alloc;
ba77c9e1
LZ
87 } else {
88 data = malloc(sizeof(*data));
2814eb05
ACM
89 if (!data) {
90 pr_err("%s: malloc failed\n", __func__);
91 return -1;
92 }
ba77c9e1 93 data->ptr = ptr;
079d3f65 94 data->pingpong = 0;
ba77c9e1
LZ
95 data->hit = 1;
96 data->bytes_req = bytes_req;
97 data->bytes_alloc = bytes_alloc;
98
99 rb_link_node(&data->node, parent, node);
100 rb_insert_color(&data->node, &root_alloc_stat);
101 }
079d3f65
LZ
102 data->call_site = call_site;
103 data->alloc_cpu = cpu;
2814eb05 104 return 0;
ba77c9e1
LZ
105}
106
2814eb05 107static int insert_caller_stat(unsigned long call_site,
ba77c9e1
LZ
108 int bytes_req, int bytes_alloc)
109{
110 struct rb_node **node = &root_caller_stat.rb_node;
111 struct rb_node *parent = NULL;
112 struct alloc_stat *data = NULL;
113
ba77c9e1
LZ
114 while (*node) {
115 parent = *node;
116 data = rb_entry(*node, struct alloc_stat, node);
117
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;
122 else
123 break;
124 }
125
126 if (data && data->call_site == call_site) {
127 data->hit++;
128 data->bytes_req += bytes_req;
4efb5290 129 data->bytes_alloc += bytes_alloc;
ba77c9e1
LZ
130 } else {
131 data = malloc(sizeof(*data));
2814eb05
ACM
132 if (!data) {
133 pr_err("%s: malloc failed\n", __func__);
134 return -1;
135 }
ba77c9e1 136 data->call_site = call_site;
079d3f65 137 data->pingpong = 0;
ba77c9e1
LZ
138 data->hit = 1;
139 data->bytes_req = bytes_req;
140 data->bytes_alloc = bytes_alloc;
141
142 rb_link_node(&data->node, parent, node);
143 rb_insert_color(&data->node, &root_caller_stat);
144 }
2814eb05
ACM
145
146 return 0;
ba77c9e1
LZ
147}
148
2814eb05 149static int perf_evsel__process_alloc_event(struct perf_evsel *evsel,
0f7d2f1b 150 struct perf_sample *sample)
ba77c9e1 151{
0f7d2f1b
ACM
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");
156
157 if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) ||
2814eb05
ACM
158 insert_caller_stat(call_site, bytes_req, bytes_alloc))
159 return -1;
ba77c9e1
LZ
160
161 total_requested += bytes_req;
162 total_allocated += bytes_alloc;
7d0d3945 163
0f7d2f1b
ACM
164 nr_allocs++;
165 return 0;
166}
167
168static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
169 struct perf_sample *sample)
170{
171 int ret = perf_evsel__process_alloc_event(evsel, sample);
172
173 if (!ret) {
4b627957 174 int node1 = cpu__get_node(sample->cpu),
0f7d2f1b
ACM
175 node2 = perf_evsel__intval(evsel, sample, "node");
176
7d0d3945
LZ
177 if (node1 != node2)
178 nr_cross_allocs++;
179 }
0f7d2f1b
ACM
180
181 return ret;
ba77c9e1
LZ
182}
183
fb4f313d
NK
184static int ptr_cmp(void *, void *);
185static int slab_callsite_cmp(void *, void *);
079d3f65
LZ
186
187static struct alloc_stat *search_alloc_stat(unsigned long ptr,
188 unsigned long call_site,
189 struct rb_root *root,
190 sort_fn_t sort_fn)
191{
192 struct rb_node *node = root->rb_node;
193 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
194
195 while (node) {
196 struct alloc_stat *data;
197 int cmp;
198
199 data = rb_entry(node, struct alloc_stat, node);
200
201 cmp = sort_fn(&key, data);
202 if (cmp < 0)
203 node = node->rb_left;
204 else if (cmp > 0)
205 node = node->rb_right;
206 else
207 return data;
208 }
209 return NULL;
210}
211
2814eb05
ACM
212static int perf_evsel__process_free_event(struct perf_evsel *evsel,
213 struct perf_sample *sample)
ba77c9e1 214{
0f7d2f1b 215 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr");
079d3f65
LZ
216 struct alloc_stat *s_alloc, *s_caller;
217
079d3f65
LZ
218 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
219 if (!s_alloc)
2814eb05 220 return 0;
079d3f65 221
22ad798c 222 if ((short)sample->cpu != s_alloc->alloc_cpu) {
079d3f65
LZ
223 s_alloc->pingpong++;
224
225 s_caller = search_alloc_stat(0, s_alloc->call_site,
fb4f313d
NK
226 &root_caller_stat,
227 slab_callsite_cmp);
2814eb05
ACM
228 if (!s_caller)
229 return -1;
079d3f65
LZ
230 s_caller->pingpong++;
231 }
232 s_alloc->alloc_cpu = -1;
2814eb05
ACM
233
234 return 0;
ba77c9e1
LZ
235}
236
0d68bc92
NK
237static u64 total_page_alloc_bytes;
238static u64 total_page_free_bytes;
239static u64 total_page_nomatch_bytes;
240static u64 total_page_fail_bytes;
241static unsigned long nr_page_allocs;
242static unsigned long nr_page_frees;
243static unsigned long nr_page_fails;
244static unsigned long nr_page_nomatch;
245
246static bool use_pfn;
2a7ef02c 247static bool live_page;
c9758cc4 248static struct perf_session *kmem_session;
0d68bc92
NK
249
250#define MAX_MIGRATE_TYPES 6
251#define MAX_PAGE_ORDER 11
252
253static int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES];
254
255struct page_stat {
256 struct rb_node node;
257 u64 page;
c9758cc4 258 u64 callsite;
0d68bc92
NK
259 int order;
260 unsigned gfp_flags;
261 unsigned migrate_type;
262 u64 alloc_bytes;
263 u64 free_bytes;
264 int nr_alloc;
265 int nr_free;
266};
267
2a7ef02c 268static struct rb_root page_live_tree;
0d68bc92
NK
269static struct rb_root page_alloc_tree;
270static struct rb_root page_alloc_sorted;
c9758cc4
NK
271static struct rb_root page_caller_tree;
272static struct rb_root page_caller_sorted;
0d68bc92 273
c9758cc4
NK
274struct alloc_func {
275 u64 start;
276 u64 end;
277 char *name;
278};
279
280static int nr_alloc_funcs;
281static struct alloc_func *alloc_func_list;
282
283static int funcmp(const void *a, const void *b)
284{
285 const struct alloc_func *fa = a;
286 const struct alloc_func *fb = b;
287
288 if (fa->start > fb->start)
289 return 1;
290 else
291 return -1;
292}
293
294static int callcmp(const void *a, const void *b)
295{
296 const struct alloc_func *fa = a;
297 const struct alloc_func *fb = b;
298
299 if (fb->start <= fa->start && fa->end < fb->end)
300 return 0;
301
302 if (fa->start > fb->start)
303 return 1;
304 else
305 return -1;
306}
307
308static int build_alloc_func_list(void)
309{
310 int ret;
311 struct map *kernel_map;
312 struct symbol *sym;
313 struct rb_node *node;
314 struct alloc_func *func;
315 struct machine *machine = &kmem_session->machines.host;
316 regex_t alloc_func_regex;
317 const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?";
318
319 ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED);
320 if (ret) {
321 char err[BUFSIZ];
322
323 regerror(ret, &alloc_func_regex, err, sizeof(err));
324 pr_err("Invalid regex: %s\n%s", pattern, err);
325 return -EINVAL;
326 }
327
328 kernel_map = machine->vmlinux_maps[MAP__FUNCTION];
329 if (map__load(kernel_map, NULL) < 0) {
330 pr_err("cannot load kernel map\n");
331 return -ENOENT;
332 }
333
334 map__for_each_symbol(kernel_map, sym, node) {
335 if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0))
336 continue;
337
338 func = realloc(alloc_func_list,
339 (nr_alloc_funcs + 1) * sizeof(*func));
340 if (func == NULL)
341 return -ENOMEM;
342
343 pr_debug("alloc func: %s\n", sym->name);
344 func[nr_alloc_funcs].start = sym->start;
345 func[nr_alloc_funcs].end = sym->end;
346 func[nr_alloc_funcs].name = sym->name;
347
348 alloc_func_list = func;
349 nr_alloc_funcs++;
350 }
351
352 qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp);
353
354 regfree(&alloc_func_regex);
355 return 0;
356}
357
358/*
359 * Find first non-memory allocation function from callchain.
360 * The allocation functions are in the 'alloc_func_list'.
361 */
362static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample)
363{
364 struct addr_location al;
365 struct machine *machine = &kmem_session->machines.host;
366 struct callchain_cursor_node *node;
367
368 if (alloc_func_list == NULL) {
369 if (build_alloc_func_list() < 0)
370 goto out;
371 }
372
373 al.thread = machine__findnew_thread(machine, sample->pid, sample->tid);
374 sample__resolve_callchain(sample, NULL, evsel, &al, 16);
375
376 callchain_cursor_commit(&callchain_cursor);
377 while (true) {
378 struct alloc_func key, *caller;
379 u64 addr;
380
381 node = callchain_cursor_current(&callchain_cursor);
382 if (node == NULL)
383 break;
384
385 key.start = key.end = node->ip;
386 caller = bsearch(&key, alloc_func_list, nr_alloc_funcs,
387 sizeof(key), callcmp);
388 if (!caller) {
389 /* found */
390 if (node->map)
391 addr = map__unmap_ip(node->map, node->ip);
392 else
393 addr = node->ip;
394
395 return addr;
396 } else
397 pr_debug3("skipping alloc function: %s\n", caller->name);
398
399 callchain_cursor_advance(&callchain_cursor);
400 }
401
402out:
403 pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
404 return sample->ip;
405}
406
2a7ef02c
NK
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
c9758cc4 416static struct page_stat *
2a7ef02c 417__page_stat__findnew_page(struct page_stat *pstat, bool create)
0d68bc92 418{
2a7ef02c 419 struct rb_node **node = &page_live_tree.rb_node;
0d68bc92
NK
420 struct rb_node *parent = NULL;
421 struct page_stat *data;
422
423 while (*node) {
424 s64 cmp;
425
426 parent = *node;
427 data = rb_entry(*node, struct page_stat, node);
428
2a7ef02c 429 cmp = data->page - pstat->page;
0d68bc92
NK
430 if (cmp < 0)
431 node = &parent->rb_left;
432 else if (cmp > 0)
433 node = &parent->rb_right;
434 else
435 return data;
436 }
437
438 if (!create)
439 return NULL;
440
441 data = zalloc(sizeof(*data));
442 if (data != NULL) {
2a7ef02c
NK
443 data->page = pstat->page;
444 data->order = pstat->order;
445 data->gfp_flags = pstat->gfp_flags;
446 data->migrate_type = pstat->migrate_type;
0d68bc92
NK
447
448 rb_link_node(&data->node, parent, node);
2a7ef02c 449 rb_insert_color(&data->node, &page_live_tree);
0d68bc92
NK
450 }
451
452 return data;
453}
454
2a7ef02c 455static struct page_stat *page_stat__find_page(struct page_stat *pstat)
c9758cc4 456{
2a7ef02c 457 return __page_stat__findnew_page(pstat, false);
c9758cc4
NK
458}
459
2a7ef02c 460static struct page_stat *page_stat__findnew_page(struct page_stat *pstat)
c9758cc4 461{
2a7ef02c 462 return __page_stat__findnew_page(pstat, true);
c9758cc4
NK
463}
464
c9758cc4
NK
465static struct page_stat *
466__page_stat__findnew_alloc(struct page_stat *pstat, bool create)
0d68bc92
NK
467{
468 struct rb_node **node = &page_alloc_tree.rb_node;
469 struct rb_node *parent = NULL;
470 struct page_stat *data;
fb4f313d 471 struct sort_dimension *sort;
0d68bc92
NK
472
473 while (*node) {
fb4f313d 474 int cmp = 0;
0d68bc92
NK
475
476 parent = *node;
477 data = rb_entry(*node, struct page_stat, node);
478
fb4f313d
NK
479 list_for_each_entry(sort, &page_alloc_sort_input, list) {
480 cmp = sort->cmp(pstat, data);
481 if (cmp)
482 break;
483 }
484
0d68bc92
NK
485 if (cmp < 0)
486 node = &parent->rb_left;
487 else if (cmp > 0)
488 node = &parent->rb_right;
489 else
490 return data;
491 }
492
493 if (!create)
494 return NULL;
495
496 data = zalloc(sizeof(*data));
497 if (data != NULL) {
6b1a2752
DA
498 data->page = pstat->page;
499 data->order = pstat->order;
500 data->gfp_flags = pstat->gfp_flags;
501 data->migrate_type = pstat->migrate_type;
0d68bc92
NK
502
503 rb_link_node(&data->node, parent, node);
504 rb_insert_color(&data->node, &page_alloc_tree);
505 }
506
507 return data;
508}
509
c9758cc4
NK
510static struct page_stat *page_stat__find_alloc(struct page_stat *pstat)
511{
512 return __page_stat__findnew_alloc(pstat, false);
513}
514
515static struct page_stat *page_stat__findnew_alloc(struct page_stat *pstat)
516{
517 return __page_stat__findnew_alloc(pstat, true);
518}
519
520static struct page_stat *
fb4f313d 521__page_stat__findnew_caller(struct page_stat *pstat, bool create)
c9758cc4
NK
522{
523 struct rb_node **node = &page_caller_tree.rb_node;
524 struct rb_node *parent = NULL;
525 struct page_stat *data;
fb4f313d 526 struct sort_dimension *sort;
c9758cc4
NK
527
528 while (*node) {
fb4f313d 529 int cmp = 0;
c9758cc4
NK
530
531 parent = *node;
532 data = rb_entry(*node, struct page_stat, node);
533
fb4f313d
NK
534 list_for_each_entry(sort, &page_caller_sort_input, list) {
535 cmp = sort->cmp(pstat, data);
536 if (cmp)
537 break;
538 }
539
c9758cc4
NK
540 if (cmp < 0)
541 node = &parent->rb_left;
542 else if (cmp > 0)
543 node = &parent->rb_right;
544 else
545 return data;
546 }
547
548 if (!create)
549 return NULL;
550
551 data = zalloc(sizeof(*data));
552 if (data != NULL) {
fb4f313d
NK
553 data->callsite = pstat->callsite;
554 data->order = pstat->order;
555 data->gfp_flags = pstat->gfp_flags;
556 data->migrate_type = pstat->migrate_type;
c9758cc4
NK
557
558 rb_link_node(&data->node, parent, node);
559 rb_insert_color(&data->node, &page_caller_tree);
560 }
561
562 return data;
563}
564
fb4f313d 565static struct page_stat *page_stat__find_caller(struct page_stat *pstat)
c9758cc4 566{
fb4f313d 567 return __page_stat__findnew_caller(pstat, false);
c9758cc4
NK
568}
569
fb4f313d 570static struct page_stat *page_stat__findnew_caller(struct page_stat *pstat)
c9758cc4 571{
fb4f313d 572 return __page_stat__findnew_caller(pstat, true);
c9758cc4
NK
573}
574
0d68bc92
NK
575static bool valid_page(u64 pfn_or_page)
576{
577 if (use_pfn && pfn_or_page == -1UL)
578 return false;
579 if (!use_pfn && pfn_or_page == 0)
580 return false;
581 return true;
582}
583
0e111156
NK
584struct gfp_flag {
585 unsigned int flags;
586 char *compact_str;
587 char *human_readable;
588};
589
590static struct gfp_flag *gfps;
591static int nr_gfps;
592
593static int gfpcmp(const void *a, const void *b)
594{
595 const struct gfp_flag *fa = a;
596 const struct gfp_flag *fb = b;
597
598 return fa->flags - fb->flags;
599}
600
601/* see include/trace/events/gfpflags.h */
602static const struct {
603 const char *original;
604 const char *compact;
605} gfp_compact_table[] = {
606 { "GFP_TRANSHUGE", "THP" },
607 { "GFP_HIGHUSER_MOVABLE", "HUM" },
608 { "GFP_HIGHUSER", "HU" },
609 { "GFP_USER", "U" },
610 { "GFP_TEMPORARY", "TMP" },
611 { "GFP_KERNEL", "K" },
612 { "GFP_NOFS", "NF" },
613 { "GFP_ATOMIC", "A" },
614 { "GFP_NOIO", "NI" },
615 { "GFP_HIGH", "H" },
616 { "GFP_WAIT", "W" },
617 { "GFP_IO", "I" },
618 { "GFP_COLD", "CO" },
619 { "GFP_NOWARN", "NWR" },
620 { "GFP_REPEAT", "R" },
621 { "GFP_NOFAIL", "NF" },
622 { "GFP_NORETRY", "NR" },
623 { "GFP_COMP", "C" },
624 { "GFP_ZERO", "Z" },
625 { "GFP_NOMEMALLOC", "NMA" },
626 { "GFP_MEMALLOC", "MA" },
627 { "GFP_HARDWALL", "HW" },
628 { "GFP_THISNODE", "TN" },
629 { "GFP_RECLAIMABLE", "RC" },
630 { "GFP_MOVABLE", "M" },
631 { "GFP_NOTRACK", "NT" },
632 { "GFP_NO_KSWAPD", "NK" },
633 { "GFP_OTHER_NODE", "ON" },
634 { "GFP_NOWAIT", "NW" },
635};
636
637static size_t max_gfp_len;
638
639static char *compact_gfp_flags(char *gfp_flags)
640{
641 char *orig_flags = strdup(gfp_flags);
642 char *new_flags = NULL;
643 char *str, *pos;
644 size_t len = 0;
645
646 if (orig_flags == NULL)
647 return NULL;
648
649 str = strtok_r(orig_flags, "|", &pos);
650 while (str) {
651 size_t i;
652 char *new;
653 const char *cpt;
654
655 for (i = 0; i < ARRAY_SIZE(gfp_compact_table); i++) {
656 if (strcmp(gfp_compact_table[i].original, str))
657 continue;
658
659 cpt = gfp_compact_table[i].compact;
660 new = realloc(new_flags, len + strlen(cpt) + 2);
661 if (new == NULL) {
662 free(new_flags);
663 return NULL;
664 }
665
666 new_flags = new;
667
668 if (!len) {
669 strcpy(new_flags, cpt);
670 } else {
671 strcat(new_flags, "|");
672 strcat(new_flags, cpt);
673 len++;
674 }
675
676 len += strlen(cpt);
677 }
678
679 str = strtok_r(NULL, "|", &pos);
680 }
681
682 if (max_gfp_len < len)
683 max_gfp_len = len;
684
685 free(orig_flags);
686 return new_flags;
687}
688
689static char *compact_gfp_string(unsigned long gfp_flags)
690{
691 struct gfp_flag key = {
692 .flags = gfp_flags,
693 };
694 struct gfp_flag *gfp;
695
696 gfp = bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp);
697 if (gfp)
698 return gfp->compact_str;
699
700 return NULL;
701}
702
703static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample,
704 unsigned int gfp_flags)
705{
706 struct pevent_record record = {
707 .cpu = sample->cpu,
708 .data = sample->raw_data,
709 .size = sample->raw_size,
710 };
711 struct trace_seq seq;
712 char *str, *pos;
713
714 if (nr_gfps) {
715 struct gfp_flag key = {
716 .flags = gfp_flags,
717 };
718
719 if (bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp))
720 return 0;
721 }
722
723 trace_seq_init(&seq);
724 pevent_event_info(&seq, evsel->tp_format, &record);
725
726 str = strtok_r(seq.buffer, " ", &pos);
727 while (str) {
728 if (!strncmp(str, "gfp_flags=", 10)) {
729 struct gfp_flag *new;
730
731 new = realloc(gfps, (nr_gfps + 1) * sizeof(*gfps));
732 if (new == NULL)
733 return -ENOMEM;
734
735 gfps = new;
736 new += nr_gfps++;
737
738 new->flags = gfp_flags;
739 new->human_readable = strdup(str + 10);
740 new->compact_str = compact_gfp_flags(str + 10);
741 if (!new->human_readable || !new->compact_str)
742 return -ENOMEM;
743
744 qsort(gfps, nr_gfps, sizeof(*gfps), gfpcmp);
745 }
746
747 str = strtok_r(NULL, " ", &pos);
748 }
749
750 trace_seq_destroy(&seq);
751 return 0;
752}
753
0d68bc92
NK
754static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
755 struct perf_sample *sample)
756{
757 u64 page;
758 unsigned int order = perf_evsel__intval(evsel, sample, "order");
759 unsigned int gfp_flags = perf_evsel__intval(evsel, sample, "gfp_flags");
760 unsigned int migrate_type = perf_evsel__intval(evsel, sample,
761 "migratetype");
762 u64 bytes = kmem_page_size << order;
c9758cc4 763 u64 callsite;
6b1a2752 764 struct page_stat *pstat;
0d68bc92
NK
765 struct page_stat this = {
766 .order = order,
767 .gfp_flags = gfp_flags,
768 .migrate_type = migrate_type,
769 };
770
771 if (use_pfn)
772 page = perf_evsel__intval(evsel, sample, "pfn");
773 else
774 page = perf_evsel__intval(evsel, sample, "page");
775
776 nr_page_allocs++;
777 total_page_alloc_bytes += bytes;
778
779 if (!valid_page(page)) {
780 nr_page_fails++;
781 total_page_fail_bytes += bytes;
782
783 return 0;
784 }
785
0e111156
NK
786 if (parse_gfp_flags(evsel, sample, gfp_flags) < 0)
787 return -1;
788
c9758cc4
NK
789 callsite = find_callsite(evsel, sample);
790
0d68bc92
NK
791 /*
792 * This is to find the current page (with correct gfp flags and
793 * migrate type) at free event.
794 */
0d68bc92 795 this.page = page;
2a7ef02c 796 pstat = page_stat__findnew_page(&this);
6b1a2752 797 if (pstat == NULL)
0d68bc92
NK
798 return -ENOMEM;
799
c9758cc4
NK
800 pstat->nr_alloc++;
801 pstat->alloc_bytes += bytes;
802 pstat->callsite = callsite;
803
2a7ef02c
NK
804 if (!live_page) {
805 pstat = page_stat__findnew_alloc(&this);
806 if (pstat == NULL)
807 return -ENOMEM;
808
809 pstat->nr_alloc++;
810 pstat->alloc_bytes += bytes;
811 pstat->callsite = callsite;
812 }
813
fb4f313d
NK
814 this.callsite = callsite;
815 pstat = page_stat__findnew_caller(&this);
c9758cc4
NK
816 if (pstat == NULL)
817 return -ENOMEM;
818
6b1a2752
DA
819 pstat->nr_alloc++;
820 pstat->alloc_bytes += bytes;
0d68bc92
NK
821
822 order_stats[order][migrate_type]++;
823
824 return 0;
825}
826
827static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
828 struct perf_sample *sample)
829{
830 u64 page;
831 unsigned int order = perf_evsel__intval(evsel, sample, "order");
832 u64 bytes = kmem_page_size << order;
6b1a2752 833 struct page_stat *pstat;
0d68bc92
NK
834 struct page_stat this = {
835 .order = order,
836 };
837
838 if (use_pfn)
839 page = perf_evsel__intval(evsel, sample, "pfn");
840 else
841 page = perf_evsel__intval(evsel, sample, "page");
842
843 nr_page_frees++;
844 total_page_free_bytes += bytes;
845
2a7ef02c
NK
846 this.page = page;
847 pstat = page_stat__find_page(&this);
6b1a2752 848 if (pstat == NULL) {
0d68bc92
NK
849 pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
850 page, order);
851
852 nr_page_nomatch++;
853 total_page_nomatch_bytes += bytes;
854
855 return 0;
856 }
857
6b1a2752
DA
858 this.gfp_flags = pstat->gfp_flags;
859 this.migrate_type = pstat->migrate_type;
c9758cc4 860 this.callsite = pstat->callsite;
0d68bc92 861
2a7ef02c 862 rb_erase(&pstat->node, &page_live_tree);
6b1a2752 863 free(pstat);
0d68bc92 864
2a7ef02c
NK
865 if (live_page) {
866 order_stats[this.order][this.migrate_type]--;
867 } else {
868 pstat = page_stat__find_alloc(&this);
869 if (pstat == NULL)
870 return -ENOMEM;
c9758cc4 871
2a7ef02c
NK
872 pstat->nr_free++;
873 pstat->free_bytes += bytes;
874 }
c9758cc4 875
fb4f313d 876 pstat = page_stat__find_caller(&this);
6b1a2752 877 if (pstat == NULL)
0d68bc92
NK
878 return -ENOENT;
879
6b1a2752
DA
880 pstat->nr_free++;
881 pstat->free_bytes += bytes;
0d68bc92 882
2a7ef02c
NK
883 if (live_page) {
884 pstat->nr_alloc--;
885 pstat->alloc_bytes -= bytes;
886
887 if (pstat->nr_alloc == 0) {
888 rb_erase(&pstat->node, &page_caller_tree);
889 free(pstat);
890 }
891 }
892
0d68bc92
NK
893 return 0;
894}
895
0f7d2f1b
ACM
896typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
897 struct perf_sample *sample);
ba77c9e1 898
1d037ca1 899static int process_sample_event(struct perf_tool *tool __maybe_unused,
d20deb64 900 union perf_event *event,
8115d60c 901 struct perf_sample *sample,
fcf65bf1 902 struct perf_evsel *evsel,
743eb868 903 struct machine *machine)
ba77c9e1 904{
ef89325f 905 struct thread *thread = machine__findnew_thread(machine, sample->pid,
13ce34df 906 sample->tid);
ba77c9e1 907
ba77c9e1
LZ
908 if (thread == NULL) {
909 pr_debug("problem processing %d event, skipping it.\n",
910 event->header.type);
911 return -1;
912 }
913
b9c5143a 914 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
ba77c9e1 915
744a9719
ACM
916 if (evsel->handler != NULL) {
917 tracepoint_handler f = evsel->handler;
0f7d2f1b
ACM
918 return f(evsel, sample);
919 }
920
921 return 0;
ba77c9e1
LZ
922}
923
fcf65bf1
ACM
924static struct perf_tool perf_kmem = {
925 .sample = process_sample_event,
926 .comm = perf_event__process_comm,
64c40908
NK
927 .mmap = perf_event__process_mmap,
928 .mmap2 = perf_event__process_mmap2,
0a8cb85c 929 .ordered_events = true,
ba77c9e1
LZ
930};
931
ba77c9e1
LZ
932static double fragmentation(unsigned long n_req, unsigned long n_alloc)
933{
934 if (n_alloc == 0)
935 return 0.0;
936 else
937 return 100.0 - (100.0 * n_req / n_alloc);
938}
939
0d68bc92
NK
940static void __print_slab_result(struct rb_root *root,
941 struct perf_session *session,
942 int n_lines, int is_caller)
ba77c9e1
LZ
943{
944 struct rb_node *next;
34ba5122 945 struct machine *machine = &session->machines.host;
ba77c9e1 946
65f46e02 947 printf("%.105s\n", graph_dotted_line);
079d3f65 948 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
47103277 949 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
65f46e02 950 printf("%.105s\n", graph_dotted_line);
ba77c9e1
LZ
951
952 next = rb_first(root);
953
954 while (next && n_lines--) {
1b145ae5
ACM
955 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
956 node);
957 struct symbol *sym = NULL;
71cf8b8f 958 struct map *map;
079d3f65 959 char buf[BUFSIZ];
1b145ae5
ACM
960 u64 addr;
961
962 if (is_caller) {
963 addr = data->call_site;
7707b6b6 964 if (!raw_ip)
5c0541d5 965 sym = machine__find_kernel_function(machine, addr, &map, NULL);
1b145ae5
ACM
966 } else
967 addr = data->ptr;
968
969 if (sym != NULL)
9486aa38 970 snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
71cf8b8f 971 addr - map->unmap_ip(map, sym->start));
1b145ae5 972 else
9486aa38 973 snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
079d3f65 974 printf(" %-34s |", buf);
ba77c9e1 975
65f46e02 976 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %9lu | %6.3f%%\n",
079d3f65 977 (unsigned long long)data->bytes_alloc,
ba77c9e1
LZ
978 (unsigned long)data->bytes_alloc / data->hit,
979 (unsigned long long)data->bytes_req,
980 (unsigned long)data->bytes_req / data->hit,
981 (unsigned long)data->hit,
079d3f65 982 (unsigned long)data->pingpong,
ba77c9e1
LZ
983 fragmentation(data->bytes_req, data->bytes_alloc));
984
985 next = rb_next(next);
986 }
987
988 if (n_lines == -1)
65f46e02 989 printf(" ... | ... | ... | ... | ... | ... \n");
ba77c9e1 990
65f46e02 991 printf("%.105s\n", graph_dotted_line);
ba77c9e1
LZ
992}
993
0d68bc92
NK
994static const char * const migrate_type_str[] = {
995 "UNMOVABL",
996 "RECLAIM",
997 "MOVABLE",
998 "RESERVED",
999 "CMA/ISLT",
1000 "UNKNOWN",
1001};
1002
c9758cc4 1003static void __print_page_alloc_result(struct perf_session *session, int n_lines)
0d68bc92 1004{
c9758cc4
NK
1005 struct rb_node *next = rb_first(&page_alloc_sorted);
1006 struct machine *machine = &session->machines.host;
0d68bc92 1007 const char *format;
0e111156 1008 int gfp_len = max(strlen("GFP flags"), max_gfp_len);
0d68bc92 1009
c9758cc4 1010 printf("\n%.105s\n", graph_dotted_line);
0e111156
NK
1011 printf(" %-16s | %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n",
1012 use_pfn ? "PFN" : "Page", live_page ? "Live" : "Total",
1013 gfp_len, "GFP flags");
c9758cc4 1014 printf("%.105s\n", graph_dotted_line);
0d68bc92
NK
1015
1016 if (use_pfn)
0e111156 1017 format = " %16llu | %'16llu | %'9d | %5d | %8s | %-*s | %s\n";
0d68bc92 1018 else
0e111156 1019 format = " %016llx | %'16llu | %'9d | %5d | %8s | %-*s | %s\n";
0d68bc92
NK
1020
1021 while (next && n_lines--) {
1022 struct page_stat *data;
c9758cc4
NK
1023 struct symbol *sym;
1024 struct map *map;
1025 char buf[32];
1026 char *caller = buf;
0d68bc92
NK
1027
1028 data = rb_entry(next, struct page_stat, node);
c9758cc4
NK
1029 sym = machine__find_kernel_function(machine, data->callsite,
1030 &map, NULL);
1031 if (sym && sym->name)
1032 caller = sym->name;
1033 else
1034 scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
0d68bc92
NK
1035
1036 printf(format, (unsigned long long)data->page,
1037 (unsigned long long)data->alloc_bytes / 1024,
1038 data->nr_alloc, data->order,
1039 migrate_type_str[data->migrate_type],
0e111156 1040 gfp_len, compact_gfp_string(data->gfp_flags), caller);
0d68bc92
NK
1041
1042 next = rb_next(next);
1043 }
1044
0e111156
NK
1045 if (n_lines == -1) {
1046 printf(" ... | ... | ... | ... | ... | %-*s | ...\n",
1047 gfp_len, "...");
1048 }
0d68bc92 1049
c9758cc4
NK
1050 printf("%.105s\n", graph_dotted_line);
1051}
1052
1053static void __print_page_caller_result(struct perf_session *session, int n_lines)
1054{
1055 struct rb_node *next = rb_first(&page_caller_sorted);
1056 struct machine *machine = &session->machines.host;
0e111156 1057 int gfp_len = max(strlen("GFP flags"), max_gfp_len);
c9758cc4
NK
1058
1059 printf("\n%.105s\n", graph_dotted_line);
0e111156
NK
1060 printf(" %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n",
1061 live_page ? "Live" : "Total", gfp_len, "GFP flags");
c9758cc4
NK
1062 printf("%.105s\n", graph_dotted_line);
1063
1064 while (next && n_lines--) {
1065 struct page_stat *data;
1066 struct symbol *sym;
1067 struct map *map;
1068 char buf[32];
1069 char *caller = buf;
1070
1071 data = rb_entry(next, struct page_stat, node);
1072 sym = machine__find_kernel_function(machine, data->callsite,
1073 &map, NULL);
1074 if (sym && sym->name)
1075 caller = sym->name;
1076 else
1077 scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
1078
0e111156 1079 printf(" %'16llu | %'9d | %5d | %8s | %-*s | %s\n",
c9758cc4
NK
1080 (unsigned long long)data->alloc_bytes / 1024,
1081 data->nr_alloc, data->order,
1082 migrate_type_str[data->migrate_type],
0e111156 1083 gfp_len, compact_gfp_string(data->gfp_flags), caller);
c9758cc4
NK
1084
1085 next = rb_next(next);
1086 }
1087
0e111156
NK
1088 if (n_lines == -1) {
1089 printf(" ... | ... | ... | ... | %-*s | ...\n",
1090 gfp_len, "...");
1091 }
c9758cc4
NK
1092
1093 printf("%.105s\n", graph_dotted_line);
0d68bc92
NK
1094}
1095
0e111156
NK
1096static void print_gfp_flags(void)
1097{
1098 int i;
1099
1100 printf("#\n");
1101 printf("# GFP flags\n");
1102 printf("# ---------\n");
1103 for (i = 0; i < nr_gfps; i++) {
1104 printf("# %08x: %*s: %s\n", gfps[i].flags,
1105 (int) max_gfp_len, gfps[i].compact_str,
1106 gfps[i].human_readable);
1107 }
1108}
1109
0d68bc92 1110static void print_slab_summary(void)
ba77c9e1 1111{
0d68bc92
NK
1112 printf("\nSUMMARY (SLAB allocator)");
1113 printf("\n========================\n");
77cfe388
NK
1114 printf("Total bytes requested: %'lu\n", total_requested);
1115 printf("Total bytes allocated: %'lu\n", total_allocated);
1116 printf("Total bytes wasted on internal fragmentation: %'lu\n",
ba77c9e1
LZ
1117 total_allocated - total_requested);
1118 printf("Internal fragmentation: %f%%\n",
1119 fragmentation(total_requested, total_allocated));
77cfe388 1120 printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs);
ba77c9e1
LZ
1121}
1122
0d68bc92
NK
1123static void print_page_summary(void)
1124{
1125 int o, m;
1126 u64 nr_alloc_freed = nr_page_frees - nr_page_nomatch;
1127 u64 total_alloc_freed_bytes = total_page_free_bytes - total_page_nomatch_bytes;
1128
1129 printf("\nSUMMARY (page allocator)");
1130 printf("\n========================\n");
1131 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation requests",
1132 nr_page_allocs, total_page_alloc_bytes / 1024);
1133 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free requests",
1134 nr_page_frees, total_page_free_bytes / 1024);
1135 printf("\n");
1136
1137 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests",
1138 nr_alloc_freed, (total_alloc_freed_bytes) / 1024);
1139 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total alloc-only requests",
1140 nr_page_allocs - nr_alloc_freed,
1141 (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024);
1142 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free-only requests",
1143 nr_page_nomatch, total_page_nomatch_bytes / 1024);
1144 printf("\n");
1145
1146 printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation failures",
1147 nr_page_fails, total_page_fail_bytes / 1024);
1148 printf("\n");
1149
1150 printf("%5s %12s %12s %12s %12s %12s\n", "Order", "Unmovable",
1151 "Reclaimable", "Movable", "Reserved", "CMA/Isolated");
1152 printf("%.5s %.12s %.12s %.12s %.12s %.12s\n", graph_dotted_line,
1153 graph_dotted_line, graph_dotted_line, graph_dotted_line,
1154 graph_dotted_line, graph_dotted_line);
1155
1156 for (o = 0; o < MAX_PAGE_ORDER; o++) {
1157 printf("%5d", o);
1158 for (m = 0; m < MAX_MIGRATE_TYPES - 1; m++) {
1159 if (order_stats[o][m])
1160 printf(" %'12d", order_stats[o][m]);
1161 else
1162 printf(" %12c", '.');
1163 }
1164 printf("\n");
1165 }
1166}
1167
1168static void print_slab_result(struct perf_session *session)
ba77c9e1
LZ
1169{
1170 if (caller_flag)
0d68bc92
NK
1171 __print_slab_result(&root_caller_sorted, session, caller_lines, 1);
1172 if (alloc_flag)
1173 __print_slab_result(&root_alloc_sorted, session, alloc_lines, 0);
1174 print_slab_summary();
1175}
1176
1177static void print_page_result(struct perf_session *session)
1178{
0e111156
NK
1179 if (caller_flag || alloc_flag)
1180 print_gfp_flags();
c9758cc4
NK
1181 if (caller_flag)
1182 __print_page_caller_result(session, caller_lines);
ba77c9e1 1183 if (alloc_flag)
c9758cc4 1184 __print_page_alloc_result(session, alloc_lines);
0d68bc92
NK
1185 print_page_summary();
1186}
1187
1188static void print_result(struct perf_session *session)
1189{
1190 if (kmem_slab)
1191 print_slab_result(session);
1192 if (kmem_page)
1193 print_page_result(session);
ba77c9e1
LZ
1194}
1195
fb4f313d
NK
1196static LIST_HEAD(slab_caller_sort);
1197static LIST_HEAD(slab_alloc_sort);
1198static LIST_HEAD(page_caller_sort);
1199static LIST_HEAD(page_alloc_sort);
29b3e152 1200
0d68bc92
NK
1201static void sort_slab_insert(struct rb_root *root, struct alloc_stat *data,
1202 struct list_head *sort_list)
ba77c9e1
LZ
1203{
1204 struct rb_node **new = &(root->rb_node);
1205 struct rb_node *parent = NULL;
29b3e152 1206 struct sort_dimension *sort;
ba77c9e1
LZ
1207
1208 while (*new) {
1209 struct alloc_stat *this;
29b3e152 1210 int cmp = 0;
ba77c9e1
LZ
1211
1212 this = rb_entry(*new, struct alloc_stat, node);
1213 parent = *new;
1214
29b3e152
LZ
1215 list_for_each_entry(sort, sort_list, list) {
1216 cmp = sort->cmp(data, this);
1217 if (cmp)
1218 break;
1219 }
ba77c9e1
LZ
1220
1221 if (cmp > 0)
1222 new = &((*new)->rb_left);
1223 else
1224 new = &((*new)->rb_right);
1225 }
1226
1227 rb_link_node(&data->node, parent, new);
1228 rb_insert_color(&data->node, root);
1229}
1230
0d68bc92
NK
1231static void __sort_slab_result(struct rb_root *root, struct rb_root *root_sorted,
1232 struct list_head *sort_list)
ba77c9e1
LZ
1233{
1234 struct rb_node *node;
1235 struct alloc_stat *data;
1236
1237 for (;;) {
1238 node = rb_first(root);
1239 if (!node)
1240 break;
1241
1242 rb_erase(node, root);
1243 data = rb_entry(node, struct alloc_stat, node);
0d68bc92
NK
1244 sort_slab_insert(root_sorted, data, sort_list);
1245 }
1246}
1247
fb4f313d
NK
1248static void sort_page_insert(struct rb_root *root, struct page_stat *data,
1249 struct list_head *sort_list)
0d68bc92
NK
1250{
1251 struct rb_node **new = &root->rb_node;
1252 struct rb_node *parent = NULL;
fb4f313d 1253 struct sort_dimension *sort;
0d68bc92
NK
1254
1255 while (*new) {
1256 struct page_stat *this;
1257 int cmp = 0;
1258
1259 this = rb_entry(*new, struct page_stat, node);
1260 parent = *new;
1261
fb4f313d
NK
1262 list_for_each_entry(sort, sort_list, list) {
1263 cmp = sort->cmp(data, this);
1264 if (cmp)
1265 break;
1266 }
0d68bc92
NK
1267
1268 if (cmp > 0)
1269 new = &parent->rb_left;
1270 else
1271 new = &parent->rb_right;
1272 }
1273
1274 rb_link_node(&data->node, parent, new);
1275 rb_insert_color(&data->node, root);
1276}
1277
fb4f313d
NK
1278static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted,
1279 struct list_head *sort_list)
0d68bc92
NK
1280{
1281 struct rb_node *node;
1282 struct page_stat *data;
1283
1284 for (;;) {
1285 node = rb_first(root);
1286 if (!node)
1287 break;
1288
1289 rb_erase(node, root);
1290 data = rb_entry(node, struct page_stat, node);
fb4f313d 1291 sort_page_insert(root_sorted, data, sort_list);
ba77c9e1
LZ
1292 }
1293}
1294
1295static void sort_result(void)
1296{
0d68bc92
NK
1297 if (kmem_slab) {
1298 __sort_slab_result(&root_alloc_stat, &root_alloc_sorted,
fb4f313d 1299 &slab_alloc_sort);
0d68bc92 1300 __sort_slab_result(&root_caller_stat, &root_caller_sorted,
fb4f313d 1301 &slab_caller_sort);
0d68bc92
NK
1302 }
1303 if (kmem_page) {
2a7ef02c
NK
1304 if (live_page)
1305 __sort_page_result(&page_live_tree, &page_alloc_sorted,
1306 &page_alloc_sort);
1307 else
1308 __sort_page_result(&page_alloc_tree, &page_alloc_sorted,
1309 &page_alloc_sort);
1310
fb4f313d
NK
1311 __sort_page_result(&page_caller_tree, &page_caller_sorted,
1312 &page_caller_sort);
0d68bc92 1313 }
ba77c9e1
LZ
1314}
1315
2b2b2c68 1316static int __cmd_kmem(struct perf_session *session)
ba77c9e1 1317{
d549c769 1318 int err = -EINVAL;
0d68bc92 1319 struct perf_evsel *evsel;
0f7d2f1b 1320 const struct perf_evsel_str_handler kmem_tracepoints[] = {
0d68bc92 1321 /* slab allocator */
0f7d2f1b
ACM
1322 { "kmem:kmalloc", perf_evsel__process_alloc_event, },
1323 { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, },
1324 { "kmem:kmalloc_node", perf_evsel__process_alloc_node_event, },
1325 { "kmem:kmem_cache_alloc_node", perf_evsel__process_alloc_node_event, },
1326 { "kmem:kfree", perf_evsel__process_free_event, },
1327 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
0d68bc92
NK
1328 /* page allocator */
1329 { "kmem:mm_page_alloc", perf_evsel__process_page_alloc_event, },
1330 { "kmem:mm_page_free", perf_evsel__process_page_free_event, },
0f7d2f1b 1331 };
4aa65636 1332
d549c769 1333 if (!perf_session__has_traces(session, "kmem record"))
2b2b2c68 1334 goto out;
d549c769 1335
0f7d2f1b
ACM
1336 if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
1337 pr_err("Initializing perf session tracepoint handlers failed\n");
2b2b2c68 1338 goto out;
0f7d2f1b
ACM
1339 }
1340
0d68bc92
NK
1341 evlist__for_each(session->evlist, evsel) {
1342 if (!strcmp(perf_evsel__name(evsel), "kmem:mm_page_alloc") &&
1343 perf_evsel__field(evsel, "pfn")) {
1344 use_pfn = true;
1345 break;
1346 }
1347 }
1348
ba77c9e1 1349 setup_pager();
b7b61cbe 1350 err = perf_session__process_events(session);
0d68bc92
NK
1351 if (err != 0) {
1352 pr_err("error during process events: %d\n", err);
2b2b2c68 1353 goto out;
0d68bc92 1354 }
ba77c9e1 1355 sort_result();
4aa65636 1356 print_result(session);
2b2b2c68 1357out:
4aa65636 1358 return err;
ba77c9e1
LZ
1359}
1360
fb4f313d
NK
1361/* slab sort keys */
1362static int ptr_cmp(void *a, void *b)
ba77c9e1 1363{
fb4f313d
NK
1364 struct alloc_stat *l = a;
1365 struct alloc_stat *r = b;
1366
ba77c9e1
LZ
1367 if (l->ptr < r->ptr)
1368 return -1;
1369 else if (l->ptr > r->ptr)
1370 return 1;
1371 return 0;
1372}
1373
29b3e152
LZ
1374static struct sort_dimension ptr_sort_dimension = {
1375 .name = "ptr",
1376 .cmp = ptr_cmp,
1377};
1378
fb4f313d 1379static int slab_callsite_cmp(void *a, void *b)
ba77c9e1 1380{
fb4f313d
NK
1381 struct alloc_stat *l = a;
1382 struct alloc_stat *r = b;
1383
ba77c9e1
LZ
1384 if (l->call_site < r->call_site)
1385 return -1;
1386 else if (l->call_site > r->call_site)
1387 return 1;
1388 return 0;
1389}
1390
29b3e152
LZ
1391static struct sort_dimension callsite_sort_dimension = {
1392 .name = "callsite",
fb4f313d 1393 .cmp = slab_callsite_cmp,
29b3e152
LZ
1394};
1395
fb4f313d 1396static int hit_cmp(void *a, void *b)
f3ced7cd 1397{
fb4f313d
NK
1398 struct alloc_stat *l = a;
1399 struct alloc_stat *r = b;
1400
f3ced7cd
PE
1401 if (l->hit < r->hit)
1402 return -1;
1403 else if (l->hit > r->hit)
1404 return 1;
1405 return 0;
1406}
1407
29b3e152
LZ
1408static struct sort_dimension hit_sort_dimension = {
1409 .name = "hit",
1410 .cmp = hit_cmp,
1411};
1412
fb4f313d 1413static int bytes_cmp(void *a, void *b)
ba77c9e1 1414{
fb4f313d
NK
1415 struct alloc_stat *l = a;
1416 struct alloc_stat *r = b;
1417
ba77c9e1
LZ
1418 if (l->bytes_alloc < r->bytes_alloc)
1419 return -1;
1420 else if (l->bytes_alloc > r->bytes_alloc)
1421 return 1;
1422 return 0;
1423}
1424
29b3e152
LZ
1425static struct sort_dimension bytes_sort_dimension = {
1426 .name = "bytes",
1427 .cmp = bytes_cmp,
1428};
1429
fb4f313d 1430static int frag_cmp(void *a, void *b)
f3ced7cd
PE
1431{
1432 double x, y;
fb4f313d
NK
1433 struct alloc_stat *l = a;
1434 struct alloc_stat *r = b;
f3ced7cd
PE
1435
1436 x = fragmentation(l->bytes_req, l->bytes_alloc);
1437 y = fragmentation(r->bytes_req, r->bytes_alloc);
1438
1439 if (x < y)
1440 return -1;
1441 else if (x > y)
1442 return 1;
1443 return 0;
1444}
1445
29b3e152
LZ
1446static struct sort_dimension frag_sort_dimension = {
1447 .name = "frag",
1448 .cmp = frag_cmp,
1449};
1450
fb4f313d 1451static int pingpong_cmp(void *a, void *b)
079d3f65 1452{
fb4f313d
NK
1453 struct alloc_stat *l = a;
1454 struct alloc_stat *r = b;
1455
079d3f65
LZ
1456 if (l->pingpong < r->pingpong)
1457 return -1;
1458 else if (l->pingpong > r->pingpong)
1459 return 1;
1460 return 0;
1461}
1462
1463static struct sort_dimension pingpong_sort_dimension = {
1464 .name = "pingpong",
1465 .cmp = pingpong_cmp,
1466};
1467
fb4f313d
NK
1468/* page sort keys */
1469static int page_cmp(void *a, void *b)
1470{
1471 struct page_stat *l = a;
1472 struct page_stat *r = b;
1473
1474 if (l->page < r->page)
1475 return -1;
1476 else if (l->page > r->page)
1477 return 1;
1478 return 0;
1479}
1480
1481static struct sort_dimension page_sort_dimension = {
1482 .name = "page",
1483 .cmp = page_cmp,
1484};
1485
1486static int page_callsite_cmp(void *a, void *b)
1487{
1488 struct page_stat *l = a;
1489 struct page_stat *r = b;
1490
1491 if (l->callsite < r->callsite)
1492 return -1;
1493 else if (l->callsite > r->callsite)
1494 return 1;
1495 return 0;
1496}
1497
1498static struct sort_dimension page_callsite_sort_dimension = {
1499 .name = "callsite",
1500 .cmp = page_callsite_cmp,
1501};
1502
1503static int page_hit_cmp(void *a, void *b)
1504{
1505 struct page_stat *l = a;
1506 struct page_stat *r = b;
1507
1508 if (l->nr_alloc < r->nr_alloc)
1509 return -1;
1510 else if (l->nr_alloc > r->nr_alloc)
1511 return 1;
1512 return 0;
1513}
1514
1515static struct sort_dimension page_hit_sort_dimension = {
1516 .name = "hit",
1517 .cmp = page_hit_cmp,
1518};
1519
1520static int page_bytes_cmp(void *a, void *b)
1521{
1522 struct page_stat *l = a;
1523 struct page_stat *r = b;
1524
1525 if (l->alloc_bytes < r->alloc_bytes)
1526 return -1;
1527 else if (l->alloc_bytes > r->alloc_bytes)
1528 return 1;
1529 return 0;
1530}
1531
1532static struct sort_dimension page_bytes_sort_dimension = {
1533 .name = "bytes",
1534 .cmp = page_bytes_cmp,
1535};
1536
1537static int page_order_cmp(void *a, void *b)
1538{
1539 struct page_stat *l = a;
1540 struct page_stat *r = b;
1541
1542 if (l->order < r->order)
1543 return -1;
1544 else if (l->order > r->order)
1545 return 1;
1546 return 0;
1547}
1548
1549static struct sort_dimension page_order_sort_dimension = {
1550 .name = "order",
1551 .cmp = page_order_cmp,
1552};
1553
1554static int migrate_type_cmp(void *a, void *b)
1555{
1556 struct page_stat *l = a;
1557 struct page_stat *r = b;
1558
1559 /* for internal use to find free'd page */
1560 if (l->migrate_type == -1U)
1561 return 0;
1562
1563 if (l->migrate_type < r->migrate_type)
1564 return -1;
1565 else if (l->migrate_type > r->migrate_type)
1566 return 1;
1567 return 0;
1568}
1569
1570static struct sort_dimension migrate_type_sort_dimension = {
1571 .name = "migtype",
1572 .cmp = migrate_type_cmp,
1573};
1574
1575static int gfp_flags_cmp(void *a, void *b)
1576{
1577 struct page_stat *l = a;
1578 struct page_stat *r = b;
1579
1580 /* for internal use to find free'd page */
1581 if (l->gfp_flags == -1U)
1582 return 0;
1583
1584 if (l->gfp_flags < r->gfp_flags)
1585 return -1;
1586 else if (l->gfp_flags > r->gfp_flags)
1587 return 1;
1588 return 0;
1589}
1590
1591static struct sort_dimension gfp_flags_sort_dimension = {
1592 .name = "gfp",
1593 .cmp = gfp_flags_cmp,
1594};
1595
1596static struct sort_dimension *slab_sorts[] = {
29b3e152
LZ
1597 &ptr_sort_dimension,
1598 &callsite_sort_dimension,
1599 &hit_sort_dimension,
1600 &bytes_sort_dimension,
1601 &frag_sort_dimension,
079d3f65 1602 &pingpong_sort_dimension,
29b3e152
LZ
1603};
1604
fb4f313d
NK
1605static struct sort_dimension *page_sorts[] = {
1606 &page_sort_dimension,
1607 &page_callsite_sort_dimension,
1608 &page_hit_sort_dimension,
1609 &page_bytes_sort_dimension,
1610 &page_order_sort_dimension,
1611 &migrate_type_sort_dimension,
1612 &gfp_flags_sort_dimension,
1613};
29b3e152 1614
fb4f313d 1615static int slab_sort_dimension__add(const char *tok, struct list_head *list)
29b3e152
LZ
1616{
1617 struct sort_dimension *sort;
1618 int i;
1619
fb4f313d
NK
1620 for (i = 0; i < (int)ARRAY_SIZE(slab_sorts); i++) {
1621 if (!strcmp(slab_sorts[i]->name, tok)) {
1622 sort = memdup(slab_sorts[i], sizeof(*slab_sorts[i]));
2814eb05 1623 if (!sort) {
8d9233f2 1624 pr_err("%s: memdup failed\n", __func__);
2814eb05
ACM
1625 return -1;
1626 }
29b3e152
LZ
1627 list_add_tail(&sort->list, list);
1628 return 0;
1629 }
1630 }
1631
1632 return -1;
1633}
1634
fb4f313d
NK
1635static int page_sort_dimension__add(const char *tok, struct list_head *list)
1636{
1637 struct sort_dimension *sort;
1638 int i;
1639
1640 for (i = 0; i < (int)ARRAY_SIZE(page_sorts); i++) {
1641 if (!strcmp(page_sorts[i]->name, tok)) {
1642 sort = memdup(page_sorts[i], sizeof(*page_sorts[i]));
1643 if (!sort) {
1644 pr_err("%s: memdup failed\n", __func__);
1645 return -1;
1646 }
1647 list_add_tail(&sort->list, list);
1648 return 0;
1649 }
1650 }
1651
1652 return -1;
1653}
1654
1655static int setup_slab_sorting(struct list_head *sort_list, const char *arg)
29b3e152
LZ
1656{
1657 char *tok;
1658 char *str = strdup(arg);
405f8755 1659 char *pos = str;
29b3e152 1660
2814eb05
ACM
1661 if (!str) {
1662 pr_err("%s: strdup failed\n", __func__);
1663 return -1;
1664 }
29b3e152
LZ
1665
1666 while (true) {
405f8755 1667 tok = strsep(&pos, ",");
29b3e152
LZ
1668 if (!tok)
1669 break;
fb4f313d
NK
1670 if (slab_sort_dimension__add(tok, sort_list) < 0) {
1671 error("Unknown slab --sort key: '%s'", tok);
1672 free(str);
1673 return -1;
1674 }
1675 }
1676
1677 free(str);
1678 return 0;
1679}
1680
1681static int setup_page_sorting(struct list_head *sort_list, const char *arg)
1682{
1683 char *tok;
1684 char *str = strdup(arg);
1685 char *pos = str;
1686
1687 if (!str) {
1688 pr_err("%s: strdup failed\n", __func__);
1689 return -1;
1690 }
1691
1692 while (true) {
1693 tok = strsep(&pos, ",");
1694 if (!tok)
1695 break;
1696 if (page_sort_dimension__add(tok, sort_list) < 0) {
1697 error("Unknown page --sort key: '%s'", tok);
1b22859d 1698 free(str);
29b3e152
LZ
1699 return -1;
1700 }
1701 }
1702
1703 free(str);
1704 return 0;
1705}
1706
1d037ca1
IT
1707static int parse_sort_opt(const struct option *opt __maybe_unused,
1708 const char *arg, int unset __maybe_unused)
ba77c9e1 1709{
ba77c9e1
LZ
1710 if (!arg)
1711 return -1;
1712
fb4f313d
NK
1713 if (kmem_page > kmem_slab) {
1714 if (caller_flag > alloc_flag)
1715 return setup_page_sorting(&page_caller_sort, arg);
1716 else
1717 return setup_page_sorting(&page_alloc_sort, arg);
1718 } else {
1719 if (caller_flag > alloc_flag)
1720 return setup_slab_sorting(&slab_caller_sort, arg);
1721 else
1722 return setup_slab_sorting(&slab_alloc_sort, arg);
1723 }
ba77c9e1
LZ
1724
1725 return 0;
1726}
1727
1d037ca1
IT
1728static int parse_caller_opt(const struct option *opt __maybe_unused,
1729 const char *arg __maybe_unused,
1730 int unset __maybe_unused)
ba77c9e1 1731{
90b86a9f
LZ
1732 caller_flag = (alloc_flag + 1);
1733 return 0;
1734}
ba77c9e1 1735
1d037ca1
IT
1736static int parse_alloc_opt(const struct option *opt __maybe_unused,
1737 const char *arg __maybe_unused,
1738 int unset __maybe_unused)
90b86a9f
LZ
1739{
1740 alloc_flag = (caller_flag + 1);
ba77c9e1
LZ
1741 return 0;
1742}
1743
0d68bc92
NK
1744static int parse_slab_opt(const struct option *opt __maybe_unused,
1745 const char *arg __maybe_unused,
1746 int unset __maybe_unused)
1747{
1748 kmem_slab = (kmem_page + 1);
1749 return 0;
1750}
1751
1752static int parse_page_opt(const struct option *opt __maybe_unused,
1753 const char *arg __maybe_unused,
1754 int unset __maybe_unused)
1755{
1756 kmem_page = (kmem_slab + 1);
1757 return 0;
1758}
1759
1d037ca1
IT
1760static int parse_line_opt(const struct option *opt __maybe_unused,
1761 const char *arg, int unset __maybe_unused)
ba77c9e1
LZ
1762{
1763 int lines;
1764
1765 if (!arg)
1766 return -1;
1767
1768 lines = strtoul(arg, NULL, 10);
1769
1770 if (caller_flag > alloc_flag)
1771 caller_lines = lines;
1772 else
1773 alloc_lines = lines;
1774
1775 return 0;
1776}
1777
0433ffbe
ACM
1778static int __cmd_record(int argc, const char **argv)
1779{
1780 const char * const record_args[] = {
4a4d371a 1781 "record", "-a", "-R", "-c", "1",
0d68bc92
NK
1782 };
1783 const char * const slab_events[] = {
ba77c9e1
LZ
1784 "-e", "kmem:kmalloc",
1785 "-e", "kmem:kmalloc_node",
1786 "-e", "kmem:kfree",
1787 "-e", "kmem:kmem_cache_alloc",
1788 "-e", "kmem:kmem_cache_alloc_node",
1789 "-e", "kmem:kmem_cache_free",
0433ffbe 1790 };
0d68bc92
NK
1791 const char * const page_events[] = {
1792 "-e", "kmem:mm_page_alloc",
1793 "-e", "kmem:mm_page_free",
1794 };
ba77c9e1
LZ
1795 unsigned int rec_argc, i, j;
1796 const char **rec_argv;
1797
1798 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
0d68bc92
NK
1799 if (kmem_slab)
1800 rec_argc += ARRAY_SIZE(slab_events);
1801 if (kmem_page)
c9758cc4 1802 rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */
0d68bc92 1803
ba77c9e1
LZ
1804 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1805
ce47dc56
CS
1806 if (rec_argv == NULL)
1807 return -ENOMEM;
1808
ba77c9e1
LZ
1809 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1810 rec_argv[i] = strdup(record_args[i]);
1811
0d68bc92
NK
1812 if (kmem_slab) {
1813 for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++)
1814 rec_argv[i] = strdup(slab_events[j]);
1815 }
1816 if (kmem_page) {
c9758cc4
NK
1817 rec_argv[i++] = strdup("-g");
1818
0d68bc92
NK
1819 for (j = 0; j < ARRAY_SIZE(page_events); j++, i++)
1820 rec_argv[i] = strdup(page_events[j]);
1821 }
1822
ba77c9e1
LZ
1823 for (j = 1; j < (unsigned int)argc; j++, i++)
1824 rec_argv[i] = argv[j];
1825
1826 return cmd_record(i, rec_argv, NULL);
1827}
1828
1d037ca1 1829int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
ba77c9e1 1830{
fb4f313d
NK
1831 const char * const default_slab_sort = "frag,hit,bytes";
1832 const char * const default_page_sort = "bytes,hit";
d1eeb77c 1833 struct perf_data_file file = {
d1eeb77c
YS
1834 .mode = PERF_DATA_MODE_READ,
1835 };
0433ffbe
ACM
1836 const struct option kmem_options[] = {
1837 OPT_STRING('i', "input", &input_name, "file", "input file name"),
bd72a33e
NK
1838 OPT_INCR('v', "verbose", &verbose,
1839 "be more verbose (show symbol address, etc)"),
0433ffbe
ACM
1840 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
1841 "show per-callsite statistics", parse_caller_opt),
1842 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
1843 "show per-allocation statistics", parse_alloc_opt),
1844 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
fb4f313d
NK
1845 "sort by keys: ptr, callsite, bytes, hit, pingpong, frag, "
1846 "page, order, migtype, gfp", parse_sort_opt),
0433ffbe
ACM
1847 OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
1848 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
d1eeb77c 1849 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
0d68bc92
NK
1850 OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator",
1851 parse_slab_opt),
1852 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
1853 parse_page_opt),
2a7ef02c 1854 OPT_BOOLEAN(0, "live", &live_page, "Show live page stat"),
0433ffbe
ACM
1855 OPT_END()
1856 };
3bca2354
RR
1857 const char *const kmem_subcommands[] = { "record", "stat", NULL };
1858 const char *kmem_usage[] = {
1859 NULL,
0433ffbe
ACM
1860 NULL
1861 };
2b2b2c68 1862 struct perf_session *session;
2b2b2c68
NK
1863 int ret = -1;
1864
3bca2354
RR
1865 argc = parse_options_subcommand(argc, argv, kmem_options,
1866 kmem_subcommands, kmem_usage, 0);
ba77c9e1 1867
90b86a9f 1868 if (!argc)
ba77c9e1
LZ
1869 usage_with_options(kmem_usage, kmem_options);
1870
0d68bc92
NK
1871 if (kmem_slab == 0 && kmem_page == 0)
1872 kmem_slab = 1; /* for backward compatibility */
1873
90b86a9f 1874 if (!strncmp(argv[0], "rec", 3)) {
0a7e6d1b 1875 symbol__init(NULL);
90b86a9f 1876 return __cmd_record(argc, argv);
2b2b2c68
NK
1877 }
1878
28939e1a
JO
1879 file.path = input_name;
1880
c9758cc4 1881 kmem_session = session = perf_session__new(&file, false, &perf_kmem);
2b2b2c68 1882 if (session == NULL)
52e02834 1883 return -1;
2b2b2c68 1884
0d68bc92
NK
1885 if (kmem_page) {
1886 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
1887
1888 if (evsel == NULL || evsel->tp_format == NULL) {
1889 pr_err("invalid event found.. aborting\n");
1890 return -1;
1891 }
1892
1893 kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
c9758cc4 1894 symbol_conf.use_callchain = true;
0d68bc92
NK
1895 }
1896
0a7e6d1b 1897 symbol__init(&session->header.env);
2b2b2c68
NK
1898
1899 if (!strcmp(argv[0], "stat")) {
77cfe388
NK
1900 setlocale(LC_ALL, "");
1901
4b627957 1902 if (cpu__setup_cpunode_map())
2b2b2c68 1903 goto out_delete;
90b86a9f 1904
fb4f313d
NK
1905 if (list_empty(&slab_caller_sort))
1906 setup_slab_sorting(&slab_caller_sort, default_slab_sort);
1907 if (list_empty(&slab_alloc_sort))
1908 setup_slab_sorting(&slab_alloc_sort, default_slab_sort);
1909 if (list_empty(&page_caller_sort))
1910 setup_page_sorting(&page_caller_sort, default_page_sort);
1911 if (list_empty(&page_alloc_sort))
1912 setup_page_sorting(&page_alloc_sort, default_page_sort);
1913
1914 if (kmem_page) {
1915 setup_page_sorting(&page_alloc_sort_input,
1916 "page,order,migtype,gfp");
1917 setup_page_sorting(&page_caller_sort_input,
1918 "callsite,order,migtype,gfp");
1919 }
2b2b2c68 1920 ret = __cmd_kmem(session);
b00eca8c
PE
1921 } else
1922 usage_with_options(kmem_usage, kmem_options);
7d0d3945 1923
2b2b2c68
NK
1924out_delete:
1925 perf_session__delete(session);
1926
1927 return ret;
ba77c9e1
LZ
1928}
1929