1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2ba77c9e1SLi Zefan #include "builtin.h" 3ba77c9e1SLi Zefan #include "perf.h" 4ba77c9e1SLi Zefan 54a3cec84SArnaldo Carvalho de Melo #include "util/dso.h" 60f7d2f1bSArnaldo Carvalho de Melo #include "util/evlist.h" 7fcf65bf1SArnaldo Carvalho de Melo #include "util/evsel.h" 841840d21STaeung Song #include "util/config.h" 91101f69aSArnaldo Carvalho de Melo #include "util/map.h" 10ba77c9e1SLi Zefan #include "util/symbol.h" 11ba77c9e1SLi Zefan #include "util/thread.h" 12ba77c9e1SLi Zefan #include "util/header.h" 1394c744b6SArnaldo Carvalho de Melo #include "util/session.h" 1445694aa7SArnaldo Carvalho de Melo #include "util/tool.h" 15c9758cc4SNamhyung Kim #include "util/callchain.h" 162a865bd8SDavid Ahern #include "util/time-utils.h" 176ef81c55SMamatha Inamdar #include <linux/err.h> 18ba77c9e1SLi Zefan 198520a98dSArnaldo Carvalho de Melo #include <subcmd/pager.h> 204b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 21ba77c9e1SLi Zefan #include "util/trace-event.h" 22f5fc1412SJiri Olsa #include "util/data.h" 234b627957SDon Zickus #include "util/cpumap.h" 24ba77c9e1SLi Zefan 25ba77c9e1SLi Zefan #include "util/debug.h" 266a9fa4e3SArnaldo Carvalho de Melo #include "util/string2.h" 27ba77c9e1SLi Zefan 28877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 29ba77c9e1SLi Zefan #include <linux/rbtree.h> 308d9233f2SArnaldo Carvalho de Melo #include <linux/string.h> 317f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 32a43783aeSArnaldo Carvalho de Melo #include <errno.h> 33fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 3477cfe388SNamhyung Kim #include <locale.h> 35c9758cc4SNamhyung Kim #include <regex.h> 36ba77c9e1SLi Zefan 373052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 383d689ed6SArnaldo Carvalho de Melo 390d68bc92SNamhyung Kim static int kmem_slab; 400d68bc92SNamhyung Kim static int kmem_page; 410d68bc92SNamhyung Kim 420d68bc92SNamhyung Kim static long kmem_page_size; 430c160d49SNamhyung Kim static enum { 440c160d49SNamhyung Kim KMEM_SLAB, 450c160d49SNamhyung Kim KMEM_PAGE, 460c160d49SNamhyung Kim } kmem_default = KMEM_SLAB; /* for backward compatibility */ 470d68bc92SNamhyung Kim 48ba77c9e1SLi Zefan struct alloc_stat; 49fb4f313dSNamhyung Kim typedef int (*sort_fn_t)(void *, void *); 50ba77c9e1SLi Zefan 51ba77c9e1SLi Zefan static int alloc_flag; 52ba77c9e1SLi Zefan static int caller_flag; 53ba77c9e1SLi Zefan 54ba77c9e1SLi Zefan static int alloc_lines = -1; 55ba77c9e1SLi Zefan static int caller_lines = -1; 56ba77c9e1SLi Zefan 577707b6b6SLi Zefan static bool raw_ip; 587707b6b6SLi Zefan 59ba77c9e1SLi Zefan struct alloc_stat { 60ba77c9e1SLi Zefan u64 call_site; 61ba77c9e1SLi Zefan u64 ptr; 62ba77c9e1SLi Zefan u64 bytes_req; 63ba77c9e1SLi Zefan u64 bytes_alloc; 64aa58e9afSDavid Ahern u64 last_alloc; 65ba77c9e1SLi Zefan u32 hit; 66079d3f65SLi Zefan u32 pingpong; 67079d3f65SLi Zefan 68079d3f65SLi Zefan short alloc_cpu; 69ba77c9e1SLi Zefan 70ba77c9e1SLi Zefan struct rb_node node; 71ba77c9e1SLi Zefan }; 72ba77c9e1SLi Zefan 73ba77c9e1SLi Zefan static struct rb_root root_alloc_stat; 74ba77c9e1SLi Zefan static struct rb_root root_alloc_sorted; 75ba77c9e1SLi Zefan static struct rb_root root_caller_stat; 76ba77c9e1SLi Zefan static struct rb_root root_caller_sorted; 77ba77c9e1SLi Zefan 78aa58e9afSDavid Ahern static unsigned long total_requested, total_allocated, total_freed; 797d0d3945SLi Zefan static unsigned long nr_allocs, nr_cross_allocs; 80ba77c9e1SLi Zefan 812a865bd8SDavid Ahern /* filters for controlling start and stop of time of analysis */ 822a865bd8SDavid Ahern static struct perf_time_interval ptime; 832a865bd8SDavid Ahern const char *time_str; 842a865bd8SDavid Ahern 852814eb05SArnaldo Carvalho de Melo static int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 86079d3f65SLi Zefan int bytes_req, int bytes_alloc, int cpu) 87ba77c9e1SLi Zefan { 88ba77c9e1SLi Zefan struct rb_node **node = &root_alloc_stat.rb_node; 89ba77c9e1SLi Zefan struct rb_node *parent = NULL; 90ba77c9e1SLi Zefan struct alloc_stat *data = NULL; 91ba77c9e1SLi Zefan 92ba77c9e1SLi Zefan while (*node) { 93ba77c9e1SLi Zefan parent = *node; 94ba77c9e1SLi Zefan data = rb_entry(*node, struct alloc_stat, node); 95ba77c9e1SLi Zefan 96ba77c9e1SLi Zefan if (ptr > data->ptr) 97ba77c9e1SLi Zefan node = &(*node)->rb_right; 98ba77c9e1SLi Zefan else if (ptr < data->ptr) 99ba77c9e1SLi Zefan node = &(*node)->rb_left; 100ba77c9e1SLi Zefan else 101ba77c9e1SLi Zefan break; 102ba77c9e1SLi Zefan } 103ba77c9e1SLi Zefan 104ba77c9e1SLi Zefan if (data && data->ptr == ptr) { 105ba77c9e1SLi Zefan data->hit++; 106ba77c9e1SLi Zefan data->bytes_req += bytes_req; 1074efb5290SWenji Huang data->bytes_alloc += bytes_alloc; 108ba77c9e1SLi Zefan } else { 109ba77c9e1SLi Zefan data = malloc(sizeof(*data)); 1102814eb05SArnaldo Carvalho de Melo if (!data) { 1112814eb05SArnaldo Carvalho de Melo pr_err("%s: malloc failed\n", __func__); 1122814eb05SArnaldo Carvalho de Melo return -1; 1132814eb05SArnaldo Carvalho de Melo } 114ba77c9e1SLi Zefan data->ptr = ptr; 115079d3f65SLi Zefan data->pingpong = 0; 116ba77c9e1SLi Zefan data->hit = 1; 117ba77c9e1SLi Zefan data->bytes_req = bytes_req; 118ba77c9e1SLi Zefan data->bytes_alloc = bytes_alloc; 119ba77c9e1SLi Zefan 120ba77c9e1SLi Zefan rb_link_node(&data->node, parent, node); 121ba77c9e1SLi Zefan rb_insert_color(&data->node, &root_alloc_stat); 122ba77c9e1SLi Zefan } 123079d3f65SLi Zefan data->call_site = call_site; 124079d3f65SLi Zefan data->alloc_cpu = cpu; 125aa58e9afSDavid Ahern data->last_alloc = bytes_alloc; 126aa58e9afSDavid Ahern 1272814eb05SArnaldo Carvalho de Melo return 0; 128ba77c9e1SLi Zefan } 129ba77c9e1SLi Zefan 1302814eb05SArnaldo Carvalho de Melo static int insert_caller_stat(unsigned long call_site, 131ba77c9e1SLi Zefan int bytes_req, int bytes_alloc) 132ba77c9e1SLi Zefan { 133ba77c9e1SLi Zefan struct rb_node **node = &root_caller_stat.rb_node; 134ba77c9e1SLi Zefan struct rb_node *parent = NULL; 135ba77c9e1SLi Zefan struct alloc_stat *data = NULL; 136ba77c9e1SLi Zefan 137ba77c9e1SLi Zefan while (*node) { 138ba77c9e1SLi Zefan parent = *node; 139ba77c9e1SLi Zefan data = rb_entry(*node, struct alloc_stat, node); 140ba77c9e1SLi Zefan 141ba77c9e1SLi Zefan if (call_site > data->call_site) 142ba77c9e1SLi Zefan node = &(*node)->rb_right; 143ba77c9e1SLi Zefan else if (call_site < data->call_site) 144ba77c9e1SLi Zefan node = &(*node)->rb_left; 145ba77c9e1SLi Zefan else 146ba77c9e1SLi Zefan break; 147ba77c9e1SLi Zefan } 148ba77c9e1SLi Zefan 149ba77c9e1SLi Zefan if (data && data->call_site == call_site) { 150ba77c9e1SLi Zefan data->hit++; 151ba77c9e1SLi Zefan data->bytes_req += bytes_req; 1524efb5290SWenji Huang data->bytes_alloc += bytes_alloc; 153ba77c9e1SLi Zefan } else { 154ba77c9e1SLi Zefan data = malloc(sizeof(*data)); 1552814eb05SArnaldo Carvalho de Melo if (!data) { 1562814eb05SArnaldo Carvalho de Melo pr_err("%s: malloc failed\n", __func__); 1572814eb05SArnaldo Carvalho de Melo return -1; 1582814eb05SArnaldo Carvalho de Melo } 159ba77c9e1SLi Zefan data->call_site = call_site; 160079d3f65SLi Zefan data->pingpong = 0; 161ba77c9e1SLi Zefan data->hit = 1; 162ba77c9e1SLi Zefan data->bytes_req = bytes_req; 163ba77c9e1SLi Zefan data->bytes_alloc = bytes_alloc; 164ba77c9e1SLi Zefan 165ba77c9e1SLi Zefan rb_link_node(&data->node, parent, node); 166ba77c9e1SLi Zefan rb_insert_color(&data->node, &root_caller_stat); 167ba77c9e1SLi Zefan } 1682814eb05SArnaldo Carvalho de Melo 1692814eb05SArnaldo Carvalho de Melo return 0; 170ba77c9e1SLi Zefan } 171ba77c9e1SLi Zefan 1728cf5d0e0SArnaldo Carvalho de Melo static int evsel__process_alloc_event(struct evsel *evsel, struct perf_sample *sample) 173ba77c9e1SLi Zefan { 174efc0cdc9SArnaldo Carvalho de Melo unsigned long ptr = evsel__intval(evsel, sample, "ptr"), 175efc0cdc9SArnaldo Carvalho de Melo call_site = evsel__intval(evsel, sample, "call_site"); 176efc0cdc9SArnaldo Carvalho de Melo int bytes_req = evsel__intval(evsel, sample, "bytes_req"), 177efc0cdc9SArnaldo Carvalho de Melo bytes_alloc = evsel__intval(evsel, sample, "bytes_alloc"); 178ba77c9e1SLi Zefan 1790f7d2f1bSArnaldo Carvalho de Melo if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) || 1802814eb05SArnaldo Carvalho de Melo insert_caller_stat(call_site, bytes_req, bytes_alloc)) 1812814eb05SArnaldo Carvalho de Melo return -1; 182ba77c9e1SLi Zefan 183ba77c9e1SLi Zefan total_requested += bytes_req; 184ba77c9e1SLi Zefan total_allocated += bytes_alloc; 1857d0d3945SLi Zefan 1860f7d2f1bSArnaldo Carvalho de Melo nr_allocs++; 1870f7d2f1bSArnaldo Carvalho de Melo return 0; 1880f7d2f1bSArnaldo Carvalho de Melo } 1890f7d2f1bSArnaldo Carvalho de Melo 1908cf5d0e0SArnaldo Carvalho de Melo static int evsel__process_alloc_node_event(struct evsel *evsel, struct perf_sample *sample) 1910f7d2f1bSArnaldo Carvalho de Melo { 1928cf5d0e0SArnaldo Carvalho de Melo int ret = evsel__process_alloc_event(evsel, sample); 1930f7d2f1bSArnaldo Carvalho de Melo 1940f7d2f1bSArnaldo Carvalho de Melo if (!ret) { 1954b627957SDon Zickus int node1 = cpu__get_node(sample->cpu), 196efc0cdc9SArnaldo Carvalho de Melo node2 = evsel__intval(evsel, sample, "node"); 1970f7d2f1bSArnaldo Carvalho de Melo 1987d0d3945SLi Zefan if (node1 != node2) 1997d0d3945SLi Zefan nr_cross_allocs++; 2007d0d3945SLi Zefan } 2010f7d2f1bSArnaldo Carvalho de Melo 2020f7d2f1bSArnaldo Carvalho de Melo return ret; 203ba77c9e1SLi Zefan } 204ba77c9e1SLi Zefan 205fb4f313dSNamhyung Kim static int ptr_cmp(void *, void *); 206fb4f313dSNamhyung Kim static int slab_callsite_cmp(void *, void *); 207079d3f65SLi Zefan 208079d3f65SLi Zefan static struct alloc_stat *search_alloc_stat(unsigned long ptr, 209079d3f65SLi Zefan unsigned long call_site, 210079d3f65SLi Zefan struct rb_root *root, 211079d3f65SLi Zefan sort_fn_t sort_fn) 212079d3f65SLi Zefan { 213079d3f65SLi Zefan struct rb_node *node = root->rb_node; 214079d3f65SLi Zefan struct alloc_stat key = { .ptr = ptr, .call_site = call_site }; 215079d3f65SLi Zefan 216079d3f65SLi Zefan while (node) { 217079d3f65SLi Zefan struct alloc_stat *data; 218079d3f65SLi Zefan int cmp; 219079d3f65SLi Zefan 220079d3f65SLi Zefan data = rb_entry(node, struct alloc_stat, node); 221079d3f65SLi Zefan 222079d3f65SLi Zefan cmp = sort_fn(&key, data); 223079d3f65SLi Zefan if (cmp < 0) 224079d3f65SLi Zefan node = node->rb_left; 225079d3f65SLi Zefan else if (cmp > 0) 226079d3f65SLi Zefan node = node->rb_right; 227079d3f65SLi Zefan else 228079d3f65SLi Zefan return data; 229079d3f65SLi Zefan } 230079d3f65SLi Zefan return NULL; 231079d3f65SLi Zefan } 232079d3f65SLi Zefan 2338cf5d0e0SArnaldo Carvalho de Melo static int evsel__process_free_event(struct evsel *evsel, struct perf_sample *sample) 234ba77c9e1SLi Zefan { 235efc0cdc9SArnaldo Carvalho de Melo unsigned long ptr = evsel__intval(evsel, sample, "ptr"); 236079d3f65SLi Zefan struct alloc_stat *s_alloc, *s_caller; 237079d3f65SLi Zefan 238079d3f65SLi Zefan s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); 239079d3f65SLi Zefan if (!s_alloc) 2402814eb05SArnaldo Carvalho de Melo return 0; 241079d3f65SLi Zefan 242aa58e9afSDavid Ahern total_freed += s_alloc->last_alloc; 243aa58e9afSDavid Ahern 24422ad798cSArnaldo Carvalho de Melo if ((short)sample->cpu != s_alloc->alloc_cpu) { 245079d3f65SLi Zefan s_alloc->pingpong++; 246079d3f65SLi Zefan 247079d3f65SLi Zefan s_caller = search_alloc_stat(0, s_alloc->call_site, 248fb4f313dSNamhyung Kim &root_caller_stat, 249fb4f313dSNamhyung Kim slab_callsite_cmp); 2502814eb05SArnaldo Carvalho de Melo if (!s_caller) 2512814eb05SArnaldo Carvalho de Melo return -1; 252079d3f65SLi Zefan s_caller->pingpong++; 253079d3f65SLi Zefan } 254079d3f65SLi Zefan s_alloc->alloc_cpu = -1; 2552814eb05SArnaldo Carvalho de Melo 2562814eb05SArnaldo Carvalho de Melo return 0; 257ba77c9e1SLi Zefan } 258ba77c9e1SLi Zefan 2590d68bc92SNamhyung Kim static u64 total_page_alloc_bytes; 2600d68bc92SNamhyung Kim static u64 total_page_free_bytes; 2610d68bc92SNamhyung Kim static u64 total_page_nomatch_bytes; 2620d68bc92SNamhyung Kim static u64 total_page_fail_bytes; 2630d68bc92SNamhyung Kim static unsigned long nr_page_allocs; 2640d68bc92SNamhyung Kim static unsigned long nr_page_frees; 2650d68bc92SNamhyung Kim static unsigned long nr_page_fails; 2660d68bc92SNamhyung Kim static unsigned long nr_page_nomatch; 2670d68bc92SNamhyung Kim 2680d68bc92SNamhyung Kim static bool use_pfn; 2692a7ef02cSNamhyung Kim static bool live_page; 270c9758cc4SNamhyung Kim static struct perf_session *kmem_session; 2710d68bc92SNamhyung Kim 2720d68bc92SNamhyung Kim #define MAX_MIGRATE_TYPES 6 2730d68bc92SNamhyung Kim #define MAX_PAGE_ORDER 11 2740d68bc92SNamhyung Kim 2750d68bc92SNamhyung Kim static int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES]; 2760d68bc92SNamhyung Kim 2770d68bc92SNamhyung Kim struct page_stat { 2780d68bc92SNamhyung Kim struct rb_node node; 2790d68bc92SNamhyung Kim u64 page; 280c9758cc4SNamhyung Kim u64 callsite; 2810d68bc92SNamhyung Kim int order; 2820d68bc92SNamhyung Kim unsigned gfp_flags; 2830d68bc92SNamhyung Kim unsigned migrate_type; 2840d68bc92SNamhyung Kim u64 alloc_bytes; 2850d68bc92SNamhyung Kim u64 free_bytes; 2860d68bc92SNamhyung Kim int nr_alloc; 2870d68bc92SNamhyung Kim int nr_free; 2880d68bc92SNamhyung Kim }; 2890d68bc92SNamhyung Kim 2902a7ef02cSNamhyung Kim static struct rb_root page_live_tree; 2910d68bc92SNamhyung Kim static struct rb_root page_alloc_tree; 2920d68bc92SNamhyung Kim static struct rb_root page_alloc_sorted; 293c9758cc4SNamhyung Kim static struct rb_root page_caller_tree; 294c9758cc4SNamhyung Kim static struct rb_root page_caller_sorted; 2950d68bc92SNamhyung Kim 296c9758cc4SNamhyung Kim struct alloc_func { 297c9758cc4SNamhyung Kim u64 start; 298c9758cc4SNamhyung Kim u64 end; 299c9758cc4SNamhyung Kim char *name; 300c9758cc4SNamhyung Kim }; 301c9758cc4SNamhyung Kim 302c9758cc4SNamhyung Kim static int nr_alloc_funcs; 303c9758cc4SNamhyung Kim static struct alloc_func *alloc_func_list; 304c9758cc4SNamhyung Kim 305c9758cc4SNamhyung Kim static int funcmp(const void *a, const void *b) 306c9758cc4SNamhyung Kim { 307c9758cc4SNamhyung Kim const struct alloc_func *fa = a; 308c9758cc4SNamhyung Kim const struct alloc_func *fb = b; 309c9758cc4SNamhyung Kim 310c9758cc4SNamhyung Kim if (fa->start > fb->start) 311c9758cc4SNamhyung Kim return 1; 312c9758cc4SNamhyung Kim else 313c9758cc4SNamhyung Kim return -1; 314c9758cc4SNamhyung Kim } 315c9758cc4SNamhyung Kim 316c9758cc4SNamhyung Kim static int callcmp(const void *a, const void *b) 317c9758cc4SNamhyung Kim { 318c9758cc4SNamhyung Kim const struct alloc_func *fa = a; 319c9758cc4SNamhyung Kim const struct alloc_func *fb = b; 320c9758cc4SNamhyung Kim 321c9758cc4SNamhyung Kim if (fb->start <= fa->start && fa->end < fb->end) 322c9758cc4SNamhyung Kim return 0; 323c9758cc4SNamhyung Kim 324c9758cc4SNamhyung Kim if (fa->start > fb->start) 325c9758cc4SNamhyung Kim return 1; 326c9758cc4SNamhyung Kim else 327c9758cc4SNamhyung Kim return -1; 328c9758cc4SNamhyung Kim } 329c9758cc4SNamhyung Kim 330c9758cc4SNamhyung Kim static int build_alloc_func_list(void) 331c9758cc4SNamhyung Kim { 332c9758cc4SNamhyung Kim int ret; 333c9758cc4SNamhyung Kim struct map *kernel_map; 334c9758cc4SNamhyung Kim struct symbol *sym; 335c9758cc4SNamhyung Kim struct rb_node *node; 336c9758cc4SNamhyung Kim struct alloc_func *func; 337c9758cc4SNamhyung Kim struct machine *machine = &kmem_session->machines.host; 338c9758cc4SNamhyung Kim regex_t alloc_func_regex; 33949b8e2beSRasmus Villemoes static const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?"; 340c9758cc4SNamhyung Kim 341c9758cc4SNamhyung Kim ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED); 342c9758cc4SNamhyung Kim if (ret) { 343c9758cc4SNamhyung Kim char err[BUFSIZ]; 344c9758cc4SNamhyung Kim 345c9758cc4SNamhyung Kim regerror(ret, &alloc_func_regex, err, sizeof(err)); 346c9758cc4SNamhyung Kim pr_err("Invalid regex: %s\n%s", pattern, err); 347c9758cc4SNamhyung Kim return -EINVAL; 348c9758cc4SNamhyung Kim } 349c9758cc4SNamhyung Kim 350a5e813c6SArnaldo Carvalho de Melo kernel_map = machine__kernel_map(machine); 351be39db9fSArnaldo Carvalho de Melo if (map__load(kernel_map) < 0) { 352c9758cc4SNamhyung Kim pr_err("cannot load kernel map\n"); 353c9758cc4SNamhyung Kim return -ENOENT; 354c9758cc4SNamhyung Kim } 355c9758cc4SNamhyung Kim 356c9758cc4SNamhyung Kim map__for_each_symbol(kernel_map, sym, node) { 357c9758cc4SNamhyung Kim if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0)) 358c9758cc4SNamhyung Kim continue; 359c9758cc4SNamhyung Kim 360c9758cc4SNamhyung Kim func = realloc(alloc_func_list, 361c9758cc4SNamhyung Kim (nr_alloc_funcs + 1) * sizeof(*func)); 362c9758cc4SNamhyung Kim if (func == NULL) 363c9758cc4SNamhyung Kim return -ENOMEM; 364c9758cc4SNamhyung Kim 365c9758cc4SNamhyung Kim pr_debug("alloc func: %s\n", sym->name); 366c9758cc4SNamhyung Kim func[nr_alloc_funcs].start = sym->start; 367c9758cc4SNamhyung Kim func[nr_alloc_funcs].end = sym->end; 368c9758cc4SNamhyung Kim func[nr_alloc_funcs].name = sym->name; 369c9758cc4SNamhyung Kim 370c9758cc4SNamhyung Kim alloc_func_list = func; 371c9758cc4SNamhyung Kim nr_alloc_funcs++; 372c9758cc4SNamhyung Kim } 373c9758cc4SNamhyung Kim 374c9758cc4SNamhyung Kim qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp); 375c9758cc4SNamhyung Kim 376c9758cc4SNamhyung Kim regfree(&alloc_func_regex); 377c9758cc4SNamhyung Kim return 0; 378c9758cc4SNamhyung Kim } 379c9758cc4SNamhyung Kim 380c9758cc4SNamhyung Kim /* 381c9758cc4SNamhyung Kim * Find first non-memory allocation function from callchain. 382c9758cc4SNamhyung Kim * The allocation functions are in the 'alloc_func_list'. 383c9758cc4SNamhyung Kim */ 38432dcd021SJiri Olsa static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample) 385c9758cc4SNamhyung Kim { 386c9758cc4SNamhyung Kim struct addr_location al; 387c9758cc4SNamhyung Kim struct machine *machine = &kmem_session->machines.host; 388c9758cc4SNamhyung Kim struct callchain_cursor_node *node; 389c9758cc4SNamhyung Kim 390c9758cc4SNamhyung Kim if (alloc_func_list == NULL) { 391c9758cc4SNamhyung Kim if (build_alloc_func_list() < 0) 392c9758cc4SNamhyung Kim goto out; 393c9758cc4SNamhyung Kim } 394c9758cc4SNamhyung Kim 395c9758cc4SNamhyung Kim al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); 39691d7b2deSArnaldo Carvalho de Melo sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16); 397c9758cc4SNamhyung Kim 398c9758cc4SNamhyung Kim callchain_cursor_commit(&callchain_cursor); 399c9758cc4SNamhyung Kim while (true) { 400c9758cc4SNamhyung Kim struct alloc_func key, *caller; 401c9758cc4SNamhyung Kim u64 addr; 402c9758cc4SNamhyung Kim 403c9758cc4SNamhyung Kim node = callchain_cursor_current(&callchain_cursor); 404c9758cc4SNamhyung Kim if (node == NULL) 405c9758cc4SNamhyung Kim break; 406c9758cc4SNamhyung Kim 407c9758cc4SNamhyung Kim key.start = key.end = node->ip; 408c9758cc4SNamhyung Kim caller = bsearch(&key, alloc_func_list, nr_alloc_funcs, 409c9758cc4SNamhyung Kim sizeof(key), callcmp); 410c9758cc4SNamhyung Kim if (!caller) { 411c9758cc4SNamhyung Kim /* found */ 4125f0fef8aSArnaldo Carvalho de Melo if (node->ms.map) 4135f0fef8aSArnaldo Carvalho de Melo addr = map__unmap_ip(node->ms.map, node->ip); 414c9758cc4SNamhyung Kim else 415c9758cc4SNamhyung Kim addr = node->ip; 416c9758cc4SNamhyung Kim 417c9758cc4SNamhyung Kim return addr; 418c9758cc4SNamhyung Kim } else 419c9758cc4SNamhyung Kim pr_debug3("skipping alloc function: %s\n", caller->name); 420c9758cc4SNamhyung Kim 421c9758cc4SNamhyung Kim callchain_cursor_advance(&callchain_cursor); 422c9758cc4SNamhyung Kim } 423c9758cc4SNamhyung Kim 424c9758cc4SNamhyung Kim out: 425c9758cc4SNamhyung Kim pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip); 426c9758cc4SNamhyung Kim return sample->ip; 427c9758cc4SNamhyung Kim } 428c9758cc4SNamhyung Kim 4292a7ef02cSNamhyung Kim struct sort_dimension { 4302a7ef02cSNamhyung Kim const char name[20]; 4312a7ef02cSNamhyung Kim sort_fn_t cmp; 4322a7ef02cSNamhyung Kim struct list_head list; 4332a7ef02cSNamhyung Kim }; 4342a7ef02cSNamhyung Kim 4352a7ef02cSNamhyung Kim static LIST_HEAD(page_alloc_sort_input); 4362a7ef02cSNamhyung Kim static LIST_HEAD(page_caller_sort_input); 4372a7ef02cSNamhyung Kim 438c9758cc4SNamhyung Kim static struct page_stat * 4392a7ef02cSNamhyung Kim __page_stat__findnew_page(struct page_stat *pstat, bool create) 4400d68bc92SNamhyung Kim { 4412a7ef02cSNamhyung Kim struct rb_node **node = &page_live_tree.rb_node; 4420d68bc92SNamhyung Kim struct rb_node *parent = NULL; 4430d68bc92SNamhyung Kim struct page_stat *data; 4440d68bc92SNamhyung Kim 4450d68bc92SNamhyung Kim while (*node) { 4460d68bc92SNamhyung Kim s64 cmp; 4470d68bc92SNamhyung Kim 4480d68bc92SNamhyung Kim parent = *node; 4490d68bc92SNamhyung Kim data = rb_entry(*node, struct page_stat, node); 4500d68bc92SNamhyung Kim 4512a7ef02cSNamhyung Kim cmp = data->page - pstat->page; 4520d68bc92SNamhyung Kim if (cmp < 0) 4530d68bc92SNamhyung Kim node = &parent->rb_left; 4540d68bc92SNamhyung Kim else if (cmp > 0) 4550d68bc92SNamhyung Kim node = &parent->rb_right; 4560d68bc92SNamhyung Kim else 4570d68bc92SNamhyung Kim return data; 4580d68bc92SNamhyung Kim } 4590d68bc92SNamhyung Kim 4600d68bc92SNamhyung Kim if (!create) 4610d68bc92SNamhyung Kim return NULL; 4620d68bc92SNamhyung Kim 4630d68bc92SNamhyung Kim data = zalloc(sizeof(*data)); 4640d68bc92SNamhyung Kim if (data != NULL) { 4652a7ef02cSNamhyung Kim data->page = pstat->page; 4662a7ef02cSNamhyung Kim data->order = pstat->order; 4672a7ef02cSNamhyung Kim data->gfp_flags = pstat->gfp_flags; 4682a7ef02cSNamhyung Kim data->migrate_type = pstat->migrate_type; 4690d68bc92SNamhyung Kim 4700d68bc92SNamhyung Kim rb_link_node(&data->node, parent, node); 4712a7ef02cSNamhyung Kim rb_insert_color(&data->node, &page_live_tree); 4720d68bc92SNamhyung Kim } 4730d68bc92SNamhyung Kim 4740d68bc92SNamhyung Kim return data; 4750d68bc92SNamhyung Kim } 4760d68bc92SNamhyung Kim 4772a7ef02cSNamhyung Kim static struct page_stat *page_stat__find_page(struct page_stat *pstat) 478c9758cc4SNamhyung Kim { 4792a7ef02cSNamhyung Kim return __page_stat__findnew_page(pstat, false); 480c9758cc4SNamhyung Kim } 481c9758cc4SNamhyung Kim 4822a7ef02cSNamhyung Kim static struct page_stat *page_stat__findnew_page(struct page_stat *pstat) 483c9758cc4SNamhyung Kim { 4842a7ef02cSNamhyung Kim return __page_stat__findnew_page(pstat, true); 485c9758cc4SNamhyung Kim } 486c9758cc4SNamhyung Kim 487c9758cc4SNamhyung Kim static struct page_stat * 488c9758cc4SNamhyung Kim __page_stat__findnew_alloc(struct page_stat *pstat, bool create) 4890d68bc92SNamhyung Kim { 4900d68bc92SNamhyung Kim struct rb_node **node = &page_alloc_tree.rb_node; 4910d68bc92SNamhyung Kim struct rb_node *parent = NULL; 4920d68bc92SNamhyung Kim struct page_stat *data; 493fb4f313dSNamhyung Kim struct sort_dimension *sort; 4940d68bc92SNamhyung Kim 4950d68bc92SNamhyung Kim while (*node) { 496fb4f313dSNamhyung Kim int cmp = 0; 4970d68bc92SNamhyung Kim 4980d68bc92SNamhyung Kim parent = *node; 4990d68bc92SNamhyung Kim data = rb_entry(*node, struct page_stat, node); 5000d68bc92SNamhyung Kim 501fb4f313dSNamhyung Kim list_for_each_entry(sort, &page_alloc_sort_input, list) { 502fb4f313dSNamhyung Kim cmp = sort->cmp(pstat, data); 503fb4f313dSNamhyung Kim if (cmp) 504fb4f313dSNamhyung Kim break; 505fb4f313dSNamhyung Kim } 506fb4f313dSNamhyung Kim 5070d68bc92SNamhyung Kim if (cmp < 0) 5080d68bc92SNamhyung Kim node = &parent->rb_left; 5090d68bc92SNamhyung Kim else if (cmp > 0) 5100d68bc92SNamhyung Kim node = &parent->rb_right; 5110d68bc92SNamhyung Kim else 5120d68bc92SNamhyung Kim return data; 5130d68bc92SNamhyung Kim } 5140d68bc92SNamhyung Kim 5150d68bc92SNamhyung Kim if (!create) 5160d68bc92SNamhyung Kim return NULL; 5170d68bc92SNamhyung Kim 5180d68bc92SNamhyung Kim data = zalloc(sizeof(*data)); 5190d68bc92SNamhyung Kim if (data != NULL) { 5206b1a2752SDavid Ahern data->page = pstat->page; 5216b1a2752SDavid Ahern data->order = pstat->order; 5226b1a2752SDavid Ahern data->gfp_flags = pstat->gfp_flags; 5236b1a2752SDavid Ahern data->migrate_type = pstat->migrate_type; 5240d68bc92SNamhyung Kim 5250d68bc92SNamhyung Kim rb_link_node(&data->node, parent, node); 5260d68bc92SNamhyung Kim rb_insert_color(&data->node, &page_alloc_tree); 5270d68bc92SNamhyung Kim } 5280d68bc92SNamhyung Kim 5290d68bc92SNamhyung Kim return data; 5300d68bc92SNamhyung Kim } 5310d68bc92SNamhyung Kim 532c9758cc4SNamhyung Kim static struct page_stat *page_stat__find_alloc(struct page_stat *pstat) 533c9758cc4SNamhyung Kim { 534c9758cc4SNamhyung Kim return __page_stat__findnew_alloc(pstat, false); 535c9758cc4SNamhyung Kim } 536c9758cc4SNamhyung Kim 537c9758cc4SNamhyung Kim static struct page_stat *page_stat__findnew_alloc(struct page_stat *pstat) 538c9758cc4SNamhyung Kim { 539c9758cc4SNamhyung Kim return __page_stat__findnew_alloc(pstat, true); 540c9758cc4SNamhyung Kim } 541c9758cc4SNamhyung Kim 542c9758cc4SNamhyung Kim static struct page_stat * 543fb4f313dSNamhyung Kim __page_stat__findnew_caller(struct page_stat *pstat, bool create) 544c9758cc4SNamhyung Kim { 545c9758cc4SNamhyung Kim struct rb_node **node = &page_caller_tree.rb_node; 546c9758cc4SNamhyung Kim struct rb_node *parent = NULL; 547c9758cc4SNamhyung Kim struct page_stat *data; 548fb4f313dSNamhyung Kim struct sort_dimension *sort; 549c9758cc4SNamhyung Kim 550c9758cc4SNamhyung Kim while (*node) { 551fb4f313dSNamhyung Kim int cmp = 0; 552c9758cc4SNamhyung Kim 553c9758cc4SNamhyung Kim parent = *node; 554c9758cc4SNamhyung Kim data = rb_entry(*node, struct page_stat, node); 555c9758cc4SNamhyung Kim 556fb4f313dSNamhyung Kim list_for_each_entry(sort, &page_caller_sort_input, list) { 557fb4f313dSNamhyung Kim cmp = sort->cmp(pstat, data); 558fb4f313dSNamhyung Kim if (cmp) 559fb4f313dSNamhyung Kim break; 560fb4f313dSNamhyung Kim } 561fb4f313dSNamhyung Kim 562c9758cc4SNamhyung Kim if (cmp < 0) 563c9758cc4SNamhyung Kim node = &parent->rb_left; 564c9758cc4SNamhyung Kim else if (cmp > 0) 565c9758cc4SNamhyung Kim node = &parent->rb_right; 566c9758cc4SNamhyung Kim else 567c9758cc4SNamhyung Kim return data; 568c9758cc4SNamhyung Kim } 569c9758cc4SNamhyung Kim 570c9758cc4SNamhyung Kim if (!create) 571c9758cc4SNamhyung Kim return NULL; 572c9758cc4SNamhyung Kim 573c9758cc4SNamhyung Kim data = zalloc(sizeof(*data)); 574c9758cc4SNamhyung Kim if (data != NULL) { 575fb4f313dSNamhyung Kim data->callsite = pstat->callsite; 576fb4f313dSNamhyung Kim data->order = pstat->order; 577fb4f313dSNamhyung Kim data->gfp_flags = pstat->gfp_flags; 578fb4f313dSNamhyung Kim data->migrate_type = pstat->migrate_type; 579c9758cc4SNamhyung Kim 580c9758cc4SNamhyung Kim rb_link_node(&data->node, parent, node); 581c9758cc4SNamhyung Kim rb_insert_color(&data->node, &page_caller_tree); 582c9758cc4SNamhyung Kim } 583c9758cc4SNamhyung Kim 584c9758cc4SNamhyung Kim return data; 585c9758cc4SNamhyung Kim } 586c9758cc4SNamhyung Kim 587fb4f313dSNamhyung Kim static struct page_stat *page_stat__find_caller(struct page_stat *pstat) 588c9758cc4SNamhyung Kim { 589fb4f313dSNamhyung Kim return __page_stat__findnew_caller(pstat, false); 590c9758cc4SNamhyung Kim } 591c9758cc4SNamhyung Kim 592fb4f313dSNamhyung Kim static struct page_stat *page_stat__findnew_caller(struct page_stat *pstat) 593c9758cc4SNamhyung Kim { 594fb4f313dSNamhyung Kim return __page_stat__findnew_caller(pstat, true); 595c9758cc4SNamhyung Kim } 596c9758cc4SNamhyung Kim 5970d68bc92SNamhyung Kim static bool valid_page(u64 pfn_or_page) 5980d68bc92SNamhyung Kim { 5990d68bc92SNamhyung Kim if (use_pfn && pfn_or_page == -1UL) 6000d68bc92SNamhyung Kim return false; 6010d68bc92SNamhyung Kim if (!use_pfn && pfn_or_page == 0) 6020d68bc92SNamhyung Kim return false; 6030d68bc92SNamhyung Kim return true; 6040d68bc92SNamhyung Kim } 6050d68bc92SNamhyung Kim 6060e111156SNamhyung Kim struct gfp_flag { 6070e111156SNamhyung Kim unsigned int flags; 6080e111156SNamhyung Kim char *compact_str; 6090e111156SNamhyung Kim char *human_readable; 6100e111156SNamhyung Kim }; 6110e111156SNamhyung Kim 6120e111156SNamhyung Kim static struct gfp_flag *gfps; 6130e111156SNamhyung Kim static int nr_gfps; 6140e111156SNamhyung Kim 6150e111156SNamhyung Kim static int gfpcmp(const void *a, const void *b) 6160e111156SNamhyung Kim { 6170e111156SNamhyung Kim const struct gfp_flag *fa = a; 6180e111156SNamhyung Kim const struct gfp_flag *fb = b; 6190e111156SNamhyung Kim 6200e111156SNamhyung Kim return fa->flags - fb->flags; 6210e111156SNamhyung Kim } 6220e111156SNamhyung Kim 623420adbe9SVlastimil Babka /* see include/trace/events/mmflags.h */ 6240e111156SNamhyung Kim static const struct { 6250e111156SNamhyung Kim const char *original; 6260e111156SNamhyung Kim const char *compact; 6270e111156SNamhyung Kim } gfp_compact_table[] = { 6280e111156SNamhyung Kim { "GFP_TRANSHUGE", "THP" }, 62925160354SVlastimil Babka { "GFP_TRANSHUGE_LIGHT", "THL" }, 6300e111156SNamhyung Kim { "GFP_HIGHUSER_MOVABLE", "HUM" }, 6310e111156SNamhyung Kim { "GFP_HIGHUSER", "HU" }, 6320e111156SNamhyung Kim { "GFP_USER", "U" }, 63314e0a214SVlastimil Babka { "GFP_KERNEL_ACCOUNT", "KAC" }, 6340e111156SNamhyung Kim { "GFP_KERNEL", "K" }, 6350e111156SNamhyung Kim { "GFP_NOFS", "NF" }, 6360e111156SNamhyung Kim { "GFP_ATOMIC", "A" }, 6370e111156SNamhyung Kim { "GFP_NOIO", "NI" }, 6380e111156SNamhyung Kim { "GFP_NOWAIT", "NW" }, 63914e0a214SVlastimil Babka { "GFP_DMA", "D" }, 64014e0a214SVlastimil Babka { "__GFP_HIGHMEM", "HM" }, 64114e0a214SVlastimil Babka { "GFP_DMA32", "D32" }, 64214e0a214SVlastimil Babka { "__GFP_HIGH", "H" }, 64314e0a214SVlastimil Babka { "__GFP_ATOMIC", "_A" }, 64414e0a214SVlastimil Babka { "__GFP_IO", "I" }, 64514e0a214SVlastimil Babka { "__GFP_FS", "F" }, 64614e0a214SVlastimil Babka { "__GFP_NOWARN", "NWR" }, 647dcda9b04SMichal Hocko { "__GFP_RETRY_MAYFAIL", "R" }, 64814e0a214SVlastimil Babka { "__GFP_NOFAIL", "NF" }, 64914e0a214SVlastimil Babka { "__GFP_NORETRY", "NR" }, 65014e0a214SVlastimil Babka { "__GFP_COMP", "C" }, 65114e0a214SVlastimil Babka { "__GFP_ZERO", "Z" }, 65214e0a214SVlastimil Babka { "__GFP_NOMEMALLOC", "NMA" }, 65314e0a214SVlastimil Babka { "__GFP_MEMALLOC", "MA" }, 65414e0a214SVlastimil Babka { "__GFP_HARDWALL", "HW" }, 65514e0a214SVlastimil Babka { "__GFP_THISNODE", "TN" }, 65614e0a214SVlastimil Babka { "__GFP_RECLAIMABLE", "RC" }, 65714e0a214SVlastimil Babka { "__GFP_MOVABLE", "M" }, 65814e0a214SVlastimil Babka { "__GFP_ACCOUNT", "AC" }, 65914e0a214SVlastimil Babka { "__GFP_WRITE", "WR" }, 66014e0a214SVlastimil Babka { "__GFP_RECLAIM", "R" }, 66114e0a214SVlastimil Babka { "__GFP_DIRECT_RECLAIM", "DR" }, 66214e0a214SVlastimil Babka { "__GFP_KSWAPD_RECLAIM", "KR" }, 6630e111156SNamhyung Kim }; 6640e111156SNamhyung Kim 6650e111156SNamhyung Kim static size_t max_gfp_len; 6660e111156SNamhyung Kim 6670e111156SNamhyung Kim static char *compact_gfp_flags(char *gfp_flags) 6680e111156SNamhyung Kim { 6690e111156SNamhyung Kim char *orig_flags = strdup(gfp_flags); 6700e111156SNamhyung Kim char *new_flags = NULL; 671b2365122SArnaldo Carvalho de Melo char *str, *pos = NULL; 6720e111156SNamhyung Kim size_t len = 0; 6730e111156SNamhyung Kim 6740e111156SNamhyung Kim if (orig_flags == NULL) 6750e111156SNamhyung Kim return NULL; 6760e111156SNamhyung Kim 6770e111156SNamhyung Kim str = strtok_r(orig_flags, "|", &pos); 6780e111156SNamhyung Kim while (str) { 6790e111156SNamhyung Kim size_t i; 6800e111156SNamhyung Kim char *new; 6810e111156SNamhyung Kim const char *cpt; 6820e111156SNamhyung Kim 6830e111156SNamhyung Kim for (i = 0; i < ARRAY_SIZE(gfp_compact_table); i++) { 6840e111156SNamhyung Kim if (strcmp(gfp_compact_table[i].original, str)) 6850e111156SNamhyung Kim continue; 6860e111156SNamhyung Kim 6870e111156SNamhyung Kim cpt = gfp_compact_table[i].compact; 6880e111156SNamhyung Kim new = realloc(new_flags, len + strlen(cpt) + 2); 6890e111156SNamhyung Kim if (new == NULL) { 6900e111156SNamhyung Kim free(new_flags); 6911abecfcaSYunfeng Ye free(orig_flags); 6920e111156SNamhyung Kim return NULL; 6930e111156SNamhyung Kim } 6940e111156SNamhyung Kim 6950e111156SNamhyung Kim new_flags = new; 6960e111156SNamhyung Kim 6970e111156SNamhyung Kim if (!len) { 6980e111156SNamhyung Kim strcpy(new_flags, cpt); 6990e111156SNamhyung Kim } else { 7000e111156SNamhyung Kim strcat(new_flags, "|"); 7010e111156SNamhyung Kim strcat(new_flags, cpt); 7020e111156SNamhyung Kim len++; 7030e111156SNamhyung Kim } 7040e111156SNamhyung Kim 7050e111156SNamhyung Kim len += strlen(cpt); 7060e111156SNamhyung Kim } 7070e111156SNamhyung Kim 7080e111156SNamhyung Kim str = strtok_r(NULL, "|", &pos); 7090e111156SNamhyung Kim } 7100e111156SNamhyung Kim 7110e111156SNamhyung Kim if (max_gfp_len < len) 7120e111156SNamhyung Kim max_gfp_len = len; 7130e111156SNamhyung Kim 7140e111156SNamhyung Kim free(orig_flags); 7150e111156SNamhyung Kim return new_flags; 7160e111156SNamhyung Kim } 7170e111156SNamhyung Kim 7180e111156SNamhyung Kim static char *compact_gfp_string(unsigned long gfp_flags) 7190e111156SNamhyung Kim { 7200e111156SNamhyung Kim struct gfp_flag key = { 7210e111156SNamhyung Kim .flags = gfp_flags, 7220e111156SNamhyung Kim }; 7230e111156SNamhyung Kim struct gfp_flag *gfp; 7240e111156SNamhyung Kim 7250e111156SNamhyung Kim gfp = bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp); 7260e111156SNamhyung Kim if (gfp) 7270e111156SNamhyung Kim return gfp->compact_str; 7280e111156SNamhyung Kim 7290e111156SNamhyung Kim return NULL; 7300e111156SNamhyung Kim } 7310e111156SNamhyung Kim 73232dcd021SJiri Olsa static int parse_gfp_flags(struct evsel *evsel, struct perf_sample *sample, 7330e111156SNamhyung Kim unsigned int gfp_flags) 7340e111156SNamhyung Kim { 735cbc49b25STzvetomir Stoyanov (VMware) struct tep_record record = { 7360e111156SNamhyung Kim .cpu = sample->cpu, 7370e111156SNamhyung Kim .data = sample->raw_data, 7380e111156SNamhyung Kim .size = sample->raw_size, 7390e111156SNamhyung Kim }; 7400e111156SNamhyung Kim struct trace_seq seq; 74108a9b985SArnaldo Carvalho de Melo char *str, *pos = NULL; 7420e111156SNamhyung Kim 7430e111156SNamhyung Kim if (nr_gfps) { 7440e111156SNamhyung Kim struct gfp_flag key = { 7450e111156SNamhyung Kim .flags = gfp_flags, 7460e111156SNamhyung Kim }; 7470e111156SNamhyung Kim 7480e111156SNamhyung Kim if (bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp)) 7490e111156SNamhyung Kim return 0; 7500e111156SNamhyung Kim } 7510e111156SNamhyung Kim 7520e111156SNamhyung Kim trace_seq_init(&seq); 75338847db9STzvetomir Stoyanov tep_print_event(evsel->tp_format->tep, 75438847db9STzvetomir Stoyanov &seq, &record, "%s", TEP_PRINT_INFO); 7550e111156SNamhyung Kim 7560e111156SNamhyung Kim str = strtok_r(seq.buffer, " ", &pos); 7570e111156SNamhyung Kim while (str) { 7580e111156SNamhyung Kim if (!strncmp(str, "gfp_flags=", 10)) { 7590e111156SNamhyung Kim struct gfp_flag *new; 7600e111156SNamhyung Kim 7610e111156SNamhyung Kim new = realloc(gfps, (nr_gfps + 1) * sizeof(*gfps)); 7620e111156SNamhyung Kim if (new == NULL) 7630e111156SNamhyung Kim return -ENOMEM; 7640e111156SNamhyung Kim 7650e111156SNamhyung Kim gfps = new; 7660e111156SNamhyung Kim new += nr_gfps++; 7670e111156SNamhyung Kim 7680e111156SNamhyung Kim new->flags = gfp_flags; 7690e111156SNamhyung Kim new->human_readable = strdup(str + 10); 7700e111156SNamhyung Kim new->compact_str = compact_gfp_flags(str + 10); 7710e111156SNamhyung Kim if (!new->human_readable || !new->compact_str) 7720e111156SNamhyung Kim return -ENOMEM; 7730e111156SNamhyung Kim 7740e111156SNamhyung Kim qsort(gfps, nr_gfps, sizeof(*gfps), gfpcmp); 7750e111156SNamhyung Kim } 7760e111156SNamhyung Kim 7770e111156SNamhyung Kim str = strtok_r(NULL, " ", &pos); 7780e111156SNamhyung Kim } 7790e111156SNamhyung Kim 7800e111156SNamhyung Kim trace_seq_destroy(&seq); 7810e111156SNamhyung Kim return 0; 7820e111156SNamhyung Kim } 7830e111156SNamhyung Kim 7848cf5d0e0SArnaldo Carvalho de Melo static int evsel__process_page_alloc_event(struct evsel *evsel, struct perf_sample *sample) 7850d68bc92SNamhyung Kim { 7860d68bc92SNamhyung Kim u64 page; 787efc0cdc9SArnaldo Carvalho de Melo unsigned int order = evsel__intval(evsel, sample, "order"); 788efc0cdc9SArnaldo Carvalho de Melo unsigned int gfp_flags = evsel__intval(evsel, sample, "gfp_flags"); 789efc0cdc9SArnaldo Carvalho de Melo unsigned int migrate_type = evsel__intval(evsel, sample, 7900d68bc92SNamhyung Kim "migratetype"); 7910d68bc92SNamhyung Kim u64 bytes = kmem_page_size << order; 792c9758cc4SNamhyung Kim u64 callsite; 7936b1a2752SDavid Ahern struct page_stat *pstat; 7940d68bc92SNamhyung Kim struct page_stat this = { 7950d68bc92SNamhyung Kim .order = order, 7960d68bc92SNamhyung Kim .gfp_flags = gfp_flags, 7970d68bc92SNamhyung Kim .migrate_type = migrate_type, 7980d68bc92SNamhyung Kim }; 7990d68bc92SNamhyung Kim 8000d68bc92SNamhyung Kim if (use_pfn) 801efc0cdc9SArnaldo Carvalho de Melo page = evsel__intval(evsel, sample, "pfn"); 8020d68bc92SNamhyung Kim else 803efc0cdc9SArnaldo Carvalho de Melo page = evsel__intval(evsel, sample, "page"); 8040d68bc92SNamhyung Kim 8050d68bc92SNamhyung Kim nr_page_allocs++; 8060d68bc92SNamhyung Kim total_page_alloc_bytes += bytes; 8070d68bc92SNamhyung Kim 8080d68bc92SNamhyung Kim if (!valid_page(page)) { 8090d68bc92SNamhyung Kim nr_page_fails++; 8100d68bc92SNamhyung Kim total_page_fail_bytes += bytes; 8110d68bc92SNamhyung Kim 8120d68bc92SNamhyung Kim return 0; 8130d68bc92SNamhyung Kim } 8140d68bc92SNamhyung Kim 8150e111156SNamhyung Kim if (parse_gfp_flags(evsel, sample, gfp_flags) < 0) 8160e111156SNamhyung Kim return -1; 8170e111156SNamhyung Kim 818c9758cc4SNamhyung Kim callsite = find_callsite(evsel, sample); 819c9758cc4SNamhyung Kim 8200d68bc92SNamhyung Kim /* 8210d68bc92SNamhyung Kim * This is to find the current page (with correct gfp flags and 8220d68bc92SNamhyung Kim * migrate type) at free event. 8230d68bc92SNamhyung Kim */ 8242a7ef02cSNamhyung Kim this.page = page; 8252a7ef02cSNamhyung Kim pstat = page_stat__findnew_page(&this); 8266b1a2752SDavid Ahern if (pstat == NULL) 8270d68bc92SNamhyung Kim return -ENOMEM; 8280d68bc92SNamhyung Kim 8292a7ef02cSNamhyung Kim pstat->nr_alloc++; 8302a7ef02cSNamhyung Kim pstat->alloc_bytes += bytes; 831c9758cc4SNamhyung Kim pstat->callsite = callsite; 8320d68bc92SNamhyung Kim 8332a7ef02cSNamhyung Kim if (!live_page) { 834c9758cc4SNamhyung Kim pstat = page_stat__findnew_alloc(&this); 8356b1a2752SDavid Ahern if (pstat == NULL) 8360d68bc92SNamhyung Kim return -ENOMEM; 8370d68bc92SNamhyung Kim 8386b1a2752SDavid Ahern pstat->nr_alloc++; 8396b1a2752SDavid Ahern pstat->alloc_bytes += bytes; 840c9758cc4SNamhyung Kim pstat->callsite = callsite; 8412a7ef02cSNamhyung Kim } 842c9758cc4SNamhyung Kim 843fb4f313dSNamhyung Kim this.callsite = callsite; 844fb4f313dSNamhyung Kim pstat = page_stat__findnew_caller(&this); 845c9758cc4SNamhyung Kim if (pstat == NULL) 846c9758cc4SNamhyung Kim return -ENOMEM; 847c9758cc4SNamhyung Kim 848c9758cc4SNamhyung Kim pstat->nr_alloc++; 849c9758cc4SNamhyung Kim pstat->alloc_bytes += bytes; 8500d68bc92SNamhyung Kim 8510d68bc92SNamhyung Kim order_stats[order][migrate_type]++; 8520d68bc92SNamhyung Kim 8530d68bc92SNamhyung Kim return 0; 8540d68bc92SNamhyung Kim } 8550d68bc92SNamhyung Kim 8568cf5d0e0SArnaldo Carvalho de Melo static int evsel__process_page_free_event(struct evsel *evsel, struct perf_sample *sample) 8570d68bc92SNamhyung Kim { 8580d68bc92SNamhyung Kim u64 page; 859efc0cdc9SArnaldo Carvalho de Melo unsigned int order = evsel__intval(evsel, sample, "order"); 8600d68bc92SNamhyung Kim u64 bytes = kmem_page_size << order; 8616b1a2752SDavid Ahern struct page_stat *pstat; 8620d68bc92SNamhyung Kim struct page_stat this = { 8630d68bc92SNamhyung Kim .order = order, 8640d68bc92SNamhyung Kim }; 8650d68bc92SNamhyung Kim 8660d68bc92SNamhyung Kim if (use_pfn) 867efc0cdc9SArnaldo Carvalho de Melo page = evsel__intval(evsel, sample, "pfn"); 8680d68bc92SNamhyung Kim else 869efc0cdc9SArnaldo Carvalho de Melo page = evsel__intval(evsel, sample, "page"); 8700d68bc92SNamhyung Kim 8710d68bc92SNamhyung Kim nr_page_frees++; 8720d68bc92SNamhyung Kim total_page_free_bytes += bytes; 8730d68bc92SNamhyung Kim 8742a7ef02cSNamhyung Kim this.page = page; 8752a7ef02cSNamhyung Kim pstat = page_stat__find_page(&this); 8766b1a2752SDavid Ahern if (pstat == NULL) { 8770d68bc92SNamhyung Kim pr_debug2("missing free at page %"PRIx64" (order: %d)\n", 8780d68bc92SNamhyung Kim page, order); 8790d68bc92SNamhyung Kim 8800d68bc92SNamhyung Kim nr_page_nomatch++; 8810d68bc92SNamhyung Kim total_page_nomatch_bytes += bytes; 8820d68bc92SNamhyung Kim 8830d68bc92SNamhyung Kim return 0; 8840d68bc92SNamhyung Kim } 8850d68bc92SNamhyung Kim 8866b1a2752SDavid Ahern this.gfp_flags = pstat->gfp_flags; 8876b1a2752SDavid Ahern this.migrate_type = pstat->migrate_type; 888c9758cc4SNamhyung Kim this.callsite = pstat->callsite; 8890d68bc92SNamhyung Kim 8902a7ef02cSNamhyung Kim rb_erase(&pstat->node, &page_live_tree); 8916b1a2752SDavid Ahern free(pstat); 8920d68bc92SNamhyung Kim 8932a7ef02cSNamhyung Kim if (live_page) { 8942a7ef02cSNamhyung Kim order_stats[this.order][this.migrate_type]--; 8952a7ef02cSNamhyung Kim } else { 896c9758cc4SNamhyung Kim pstat = page_stat__find_alloc(&this); 897c9758cc4SNamhyung Kim if (pstat == NULL) 8982a7ef02cSNamhyung Kim return -ENOMEM; 899c9758cc4SNamhyung Kim 900c9758cc4SNamhyung Kim pstat->nr_free++; 901c9758cc4SNamhyung Kim pstat->free_bytes += bytes; 9022a7ef02cSNamhyung Kim } 903c9758cc4SNamhyung Kim 904fb4f313dSNamhyung Kim pstat = page_stat__find_caller(&this); 9056b1a2752SDavid Ahern if (pstat == NULL) 9060d68bc92SNamhyung Kim return -ENOENT; 9070d68bc92SNamhyung Kim 9086b1a2752SDavid Ahern pstat->nr_free++; 9096b1a2752SDavid Ahern pstat->free_bytes += bytes; 9100d68bc92SNamhyung Kim 9112a7ef02cSNamhyung Kim if (live_page) { 9122a7ef02cSNamhyung Kim pstat->nr_alloc--; 9132a7ef02cSNamhyung Kim pstat->alloc_bytes -= bytes; 9142a7ef02cSNamhyung Kim 9152a7ef02cSNamhyung Kim if (pstat->nr_alloc == 0) { 9162a7ef02cSNamhyung Kim rb_erase(&pstat->node, &page_caller_tree); 9172a7ef02cSNamhyung Kim free(pstat); 9182a7ef02cSNamhyung Kim } 9192a7ef02cSNamhyung Kim } 9202a7ef02cSNamhyung Kim 9210d68bc92SNamhyung Kim return 0; 9220d68bc92SNamhyung Kim } 9230d68bc92SNamhyung Kim 9242a865bd8SDavid Ahern static bool perf_kmem__skip_sample(struct perf_sample *sample) 9252a865bd8SDavid Ahern { 9262a865bd8SDavid Ahern /* skip sample based on time? */ 9272a865bd8SDavid Ahern if (perf_time__skip_sample(&ptime, sample->time)) 9282a865bd8SDavid Ahern return true; 9292a865bd8SDavid Ahern 9302a865bd8SDavid Ahern return false; 9312a865bd8SDavid Ahern } 9322a865bd8SDavid Ahern 93332dcd021SJiri Olsa typedef int (*tracepoint_handler)(struct evsel *evsel, 9340f7d2f1bSArnaldo Carvalho de Melo struct perf_sample *sample); 935ba77c9e1SLi Zefan 9361d037ca1SIrina Tirdea static int process_sample_event(struct perf_tool *tool __maybe_unused, 937d20deb64SArnaldo Carvalho de Melo union perf_event *event, 9388115d60cSArnaldo Carvalho de Melo struct perf_sample *sample, 93932dcd021SJiri Olsa struct evsel *evsel, 940743eb868SArnaldo Carvalho de Melo struct machine *machine) 941ba77c9e1SLi Zefan { 942b91fc39fSArnaldo Carvalho de Melo int err = 0; 943ef89325fSAdrian Hunter struct thread *thread = machine__findnew_thread(machine, sample->pid, 94413ce34dfSNamhyung Kim sample->tid); 945ba77c9e1SLi Zefan 946ba77c9e1SLi Zefan if (thread == NULL) { 947ba77c9e1SLi Zefan pr_debug("problem processing %d event, skipping it.\n", 948ba77c9e1SLi Zefan event->header.type); 949ba77c9e1SLi Zefan return -1; 950ba77c9e1SLi Zefan } 951ba77c9e1SLi Zefan 9522a865bd8SDavid Ahern if (perf_kmem__skip_sample(sample)) 9532a865bd8SDavid Ahern return 0; 9542a865bd8SDavid Ahern 955b9c5143aSFrederic Weisbecker dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); 956ba77c9e1SLi Zefan 957744a9719SArnaldo Carvalho de Melo if (evsel->handler != NULL) { 958744a9719SArnaldo Carvalho de Melo tracepoint_handler f = evsel->handler; 959b91fc39fSArnaldo Carvalho de Melo err = f(evsel, sample); 9600f7d2f1bSArnaldo Carvalho de Melo } 9610f7d2f1bSArnaldo Carvalho de Melo 962b91fc39fSArnaldo Carvalho de Melo thread__put(thread); 963b91fc39fSArnaldo Carvalho de Melo 964b91fc39fSArnaldo Carvalho de Melo return err; 965ba77c9e1SLi Zefan } 966ba77c9e1SLi Zefan 967fcf65bf1SArnaldo Carvalho de Melo static struct perf_tool perf_kmem = { 96855aa640fSArnaldo Carvalho de Melo .sample = process_sample_event, 9698115d60cSArnaldo Carvalho de Melo .comm = perf_event__process_comm, 97064c40908SNamhyung Kim .mmap = perf_event__process_mmap, 97164c40908SNamhyung Kim .mmap2 = perf_event__process_mmap2, 972f3b3614aSHari Bathini .namespaces = perf_event__process_namespaces, 9730a8cb85cSJiri Olsa .ordered_events = true, 974ba77c9e1SLi Zefan }; 975ba77c9e1SLi Zefan 976ba77c9e1SLi Zefan static double fragmentation(unsigned long n_req, unsigned long n_alloc) 977ba77c9e1SLi Zefan { 978ba77c9e1SLi Zefan if (n_alloc == 0) 979ba77c9e1SLi Zefan return 0.0; 980ba77c9e1SLi Zefan else 981ba77c9e1SLi Zefan return 100.0 - (100.0 * n_req / n_alloc); 982ba77c9e1SLi Zefan } 983ba77c9e1SLi Zefan 9840d68bc92SNamhyung Kim static void __print_slab_result(struct rb_root *root, 9850d68bc92SNamhyung Kim struct perf_session *session, 9864aa65636SArnaldo Carvalho de Melo int n_lines, int is_caller) 987ba77c9e1SLi Zefan { 988ba77c9e1SLi Zefan struct rb_node *next; 98934ba5122SArnaldo Carvalho de Melo struct machine *machine = &session->machines.host; 990ba77c9e1SLi Zefan 99165f46e02SNamhyung Kim printf("%.105s\n", graph_dotted_line); 992079d3f65SLi Zefan printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 993079d3f65SLi Zefan printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); 99465f46e02SNamhyung Kim printf("%.105s\n", graph_dotted_line); 995ba77c9e1SLi Zefan 996ba77c9e1SLi Zefan next = rb_first(root); 997ba77c9e1SLi Zefan 998ba77c9e1SLi Zefan while (next && n_lines--) { 9991b145ae5SArnaldo Carvalho de Melo struct alloc_stat *data = rb_entry(next, struct alloc_stat, 10001b145ae5SArnaldo Carvalho de Melo node); 10011b145ae5SArnaldo Carvalho de Melo struct symbol *sym = NULL; 100271cf8b8fSArnaldo Carvalho de Melo struct map *map; 1003079d3f65SLi Zefan char buf[BUFSIZ]; 10041b145ae5SArnaldo Carvalho de Melo u64 addr; 1005ba77c9e1SLi Zefan 10061b145ae5SArnaldo Carvalho de Melo if (is_caller) { 10071b145ae5SArnaldo Carvalho de Melo addr = data->call_site; 10087707b6b6SLi Zefan if (!raw_ip) 1009107cad95SArnaldo Carvalho de Melo sym = machine__find_kernel_symbol(machine, addr, &map); 10101b145ae5SArnaldo Carvalho de Melo } else 10111b145ae5SArnaldo Carvalho de Melo addr = data->ptr; 1012ba77c9e1SLi Zefan 10131b145ae5SArnaldo Carvalho de Melo if (sym != NULL) 10149486aa38SArnaldo Carvalho de Melo snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name, 101571cf8b8fSArnaldo Carvalho de Melo addr - map->unmap_ip(map, sym->start)); 10161b145ae5SArnaldo Carvalho de Melo else 10179486aa38SArnaldo Carvalho de Melo snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr); 1018079d3f65SLi Zefan printf(" %-34s |", buf); 10191b145ae5SArnaldo Carvalho de Melo 102065f46e02SNamhyung Kim printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %9lu | %6.3f%%\n", 1021079d3f65SLi Zefan (unsigned long long)data->bytes_alloc, 1022ba77c9e1SLi Zefan (unsigned long)data->bytes_alloc / data->hit, 1023ba77c9e1SLi Zefan (unsigned long long)data->bytes_req, 1024ba77c9e1SLi Zefan (unsigned long)data->bytes_req / data->hit, 1025ba77c9e1SLi Zefan (unsigned long)data->hit, 1026079d3f65SLi Zefan (unsigned long)data->pingpong, 1027ba77c9e1SLi Zefan fragmentation(data->bytes_req, data->bytes_alloc)); 1028ba77c9e1SLi Zefan 1029ba77c9e1SLi Zefan next = rb_next(next); 1030ba77c9e1SLi Zefan } 1031ba77c9e1SLi Zefan 1032ba77c9e1SLi Zefan if (n_lines == -1) 1033079d3f65SLi Zefan printf(" ... | ... | ... | ... | ... | ... \n"); 1034ba77c9e1SLi Zefan 103565f46e02SNamhyung Kim printf("%.105s\n", graph_dotted_line); 1036ba77c9e1SLi Zefan } 1037ba77c9e1SLi Zefan 10380d68bc92SNamhyung Kim static const char * const migrate_type_str[] = { 10390d68bc92SNamhyung Kim "UNMOVABL", 10400d68bc92SNamhyung Kim "RECLAIM", 10410d68bc92SNamhyung Kim "MOVABLE", 10420d68bc92SNamhyung Kim "RESERVED", 10430d68bc92SNamhyung Kim "CMA/ISLT", 10440d68bc92SNamhyung Kim "UNKNOWN", 10450d68bc92SNamhyung Kim }; 10460d68bc92SNamhyung Kim 1047c9758cc4SNamhyung Kim static void __print_page_alloc_result(struct perf_session *session, int n_lines) 1048ba77c9e1SLi Zefan { 1049c9758cc4SNamhyung Kim struct rb_node *next = rb_first(&page_alloc_sorted); 1050c9758cc4SNamhyung Kim struct machine *machine = &session->machines.host; 10510d68bc92SNamhyung Kim const char *format; 10520e111156SNamhyung Kim int gfp_len = max(strlen("GFP flags"), max_gfp_len); 10530d68bc92SNamhyung Kim 1054c9758cc4SNamhyung Kim printf("\n%.105s\n", graph_dotted_line); 10550e111156SNamhyung Kim printf(" %-16s | %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n", 10560e111156SNamhyung Kim use_pfn ? "PFN" : "Page", live_page ? "Live" : "Total", 10570e111156SNamhyung Kim gfp_len, "GFP flags"); 1058c9758cc4SNamhyung Kim printf("%.105s\n", graph_dotted_line); 10590d68bc92SNamhyung Kim 10600d68bc92SNamhyung Kim if (use_pfn) 10610e111156SNamhyung Kim format = " %16llu | %'16llu | %'9d | %5d | %8s | %-*s | %s\n"; 10620d68bc92SNamhyung Kim else 10630e111156SNamhyung Kim format = " %016llx | %'16llu | %'9d | %5d | %8s | %-*s | %s\n"; 10640d68bc92SNamhyung Kim 10650d68bc92SNamhyung Kim while (next && n_lines--) { 10660d68bc92SNamhyung Kim struct page_stat *data; 1067c9758cc4SNamhyung Kim struct symbol *sym; 1068c9758cc4SNamhyung Kim struct map *map; 1069c9758cc4SNamhyung Kim char buf[32]; 1070c9758cc4SNamhyung Kim char *caller = buf; 10710d68bc92SNamhyung Kim 10720d68bc92SNamhyung Kim data = rb_entry(next, struct page_stat, node); 1073107cad95SArnaldo Carvalho de Melo sym = machine__find_kernel_symbol(machine, data->callsite, &map); 1074a7c3899cSArnaldo Carvalho de Melo if (sym) 1075c9758cc4SNamhyung Kim caller = sym->name; 1076c9758cc4SNamhyung Kim else 1077c9758cc4SNamhyung Kim scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite); 10780d68bc92SNamhyung Kim 10790d68bc92SNamhyung Kim printf(format, (unsigned long long)data->page, 10800d68bc92SNamhyung Kim (unsigned long long)data->alloc_bytes / 1024, 10810d68bc92SNamhyung Kim data->nr_alloc, data->order, 10820d68bc92SNamhyung Kim migrate_type_str[data->migrate_type], 10830e111156SNamhyung Kim gfp_len, compact_gfp_string(data->gfp_flags), caller); 1084c9758cc4SNamhyung Kim 1085c9758cc4SNamhyung Kim next = rb_next(next); 1086c9758cc4SNamhyung Kim } 1087c9758cc4SNamhyung Kim 10880e111156SNamhyung Kim if (n_lines == -1) { 10890e111156SNamhyung Kim printf(" ... | ... | ... | ... | ... | %-*s | ...\n", 10900e111156SNamhyung Kim gfp_len, "..."); 10910e111156SNamhyung Kim } 1092c9758cc4SNamhyung Kim 1093c9758cc4SNamhyung Kim printf("%.105s\n", graph_dotted_line); 1094c9758cc4SNamhyung Kim } 1095c9758cc4SNamhyung Kim 1096c9758cc4SNamhyung Kim static void __print_page_caller_result(struct perf_session *session, int n_lines) 1097c9758cc4SNamhyung Kim { 1098c9758cc4SNamhyung Kim struct rb_node *next = rb_first(&page_caller_sorted); 1099c9758cc4SNamhyung Kim struct machine *machine = &session->machines.host; 11000e111156SNamhyung Kim int gfp_len = max(strlen("GFP flags"), max_gfp_len); 1101c9758cc4SNamhyung Kim 1102c9758cc4SNamhyung Kim printf("\n%.105s\n", graph_dotted_line); 11030e111156SNamhyung Kim printf(" %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n", 11040e111156SNamhyung Kim live_page ? "Live" : "Total", gfp_len, "GFP flags"); 1105c9758cc4SNamhyung Kim printf("%.105s\n", graph_dotted_line); 1106c9758cc4SNamhyung Kim 1107c9758cc4SNamhyung Kim while (next && n_lines--) { 1108c9758cc4SNamhyung Kim struct page_stat *data; 1109c9758cc4SNamhyung Kim struct symbol *sym; 1110c9758cc4SNamhyung Kim struct map *map; 1111c9758cc4SNamhyung Kim char buf[32]; 1112c9758cc4SNamhyung Kim char *caller = buf; 1113c9758cc4SNamhyung Kim 1114c9758cc4SNamhyung Kim data = rb_entry(next, struct page_stat, node); 1115107cad95SArnaldo Carvalho de Melo sym = machine__find_kernel_symbol(machine, data->callsite, &map); 1116a7c3899cSArnaldo Carvalho de Melo if (sym) 1117c9758cc4SNamhyung Kim caller = sym->name; 1118c9758cc4SNamhyung Kim else 1119c9758cc4SNamhyung Kim scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite); 1120c9758cc4SNamhyung Kim 11210e111156SNamhyung Kim printf(" %'16llu | %'9d | %5d | %8s | %-*s | %s\n", 1122c9758cc4SNamhyung Kim (unsigned long long)data->alloc_bytes / 1024, 1123c9758cc4SNamhyung Kim data->nr_alloc, data->order, 1124c9758cc4SNamhyung Kim migrate_type_str[data->migrate_type], 11250e111156SNamhyung Kim gfp_len, compact_gfp_string(data->gfp_flags), caller); 11260d68bc92SNamhyung Kim 11270d68bc92SNamhyung Kim next = rb_next(next); 11280d68bc92SNamhyung Kim } 11290d68bc92SNamhyung Kim 11300e111156SNamhyung Kim if (n_lines == -1) { 11310e111156SNamhyung Kim printf(" ... | ... | ... | ... | %-*s | ...\n", 11320e111156SNamhyung Kim gfp_len, "..."); 11330e111156SNamhyung Kim } 11340d68bc92SNamhyung Kim 1135c9758cc4SNamhyung Kim printf("%.105s\n", graph_dotted_line); 11360d68bc92SNamhyung Kim } 11370d68bc92SNamhyung Kim 11380e111156SNamhyung Kim static void print_gfp_flags(void) 11390e111156SNamhyung Kim { 11400e111156SNamhyung Kim int i; 11410e111156SNamhyung Kim 11420e111156SNamhyung Kim printf("#\n"); 11430e111156SNamhyung Kim printf("# GFP flags\n"); 11440e111156SNamhyung Kim printf("# ---------\n"); 11450e111156SNamhyung Kim for (i = 0; i < nr_gfps; i++) { 11460e111156SNamhyung Kim printf("# %08x: %*s: %s\n", gfps[i].flags, 11470e111156SNamhyung Kim (int) max_gfp_len, gfps[i].compact_str, 11480e111156SNamhyung Kim gfps[i].human_readable); 11490e111156SNamhyung Kim } 11500e111156SNamhyung Kim } 11510e111156SNamhyung Kim 11520d68bc92SNamhyung Kim static void print_slab_summary(void) 11530d68bc92SNamhyung Kim { 11540d68bc92SNamhyung Kim printf("\nSUMMARY (SLAB allocator)"); 11550d68bc92SNamhyung Kim printf("\n========================\n"); 115677cfe388SNamhyung Kim printf("Total bytes requested: %'lu\n", total_requested); 115777cfe388SNamhyung Kim printf("Total bytes allocated: %'lu\n", total_allocated); 1158aa58e9afSDavid Ahern printf("Total bytes freed: %'lu\n", total_freed); 1159aa58e9afSDavid Ahern if (total_allocated > total_freed) { 1160aa58e9afSDavid Ahern printf("Net total bytes allocated: %'lu\n", 1161aa58e9afSDavid Ahern total_allocated - total_freed); 1162aa58e9afSDavid Ahern } 116377cfe388SNamhyung Kim printf("Total bytes wasted on internal fragmentation: %'lu\n", 1164ba77c9e1SLi Zefan total_allocated - total_requested); 1165ba77c9e1SLi Zefan printf("Internal fragmentation: %f%%\n", 1166ba77c9e1SLi Zefan fragmentation(total_requested, total_allocated)); 116777cfe388SNamhyung Kim printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs); 1168ba77c9e1SLi Zefan } 1169ba77c9e1SLi Zefan 11700d68bc92SNamhyung Kim static void print_page_summary(void) 11710d68bc92SNamhyung Kim { 11720d68bc92SNamhyung Kim int o, m; 11730d68bc92SNamhyung Kim u64 nr_alloc_freed = nr_page_frees - nr_page_nomatch; 11740d68bc92SNamhyung Kim u64 total_alloc_freed_bytes = total_page_free_bytes - total_page_nomatch_bytes; 11750d68bc92SNamhyung Kim 11760d68bc92SNamhyung Kim printf("\nSUMMARY (page allocator)"); 11770d68bc92SNamhyung Kim printf("\n========================\n"); 11780d68bc92SNamhyung Kim printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation requests", 11790d68bc92SNamhyung Kim nr_page_allocs, total_page_alloc_bytes / 1024); 11800d68bc92SNamhyung Kim printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free requests", 11810d68bc92SNamhyung Kim nr_page_frees, total_page_free_bytes / 1024); 11820d68bc92SNamhyung Kim printf("\n"); 11830d68bc92SNamhyung Kim 11846145c259SWill Deacon printf("%-30s: %'16"PRIu64" [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests", 11850d68bc92SNamhyung Kim nr_alloc_freed, (total_alloc_freed_bytes) / 1024); 11866145c259SWill Deacon printf("%-30s: %'16"PRIu64" [ %'16"PRIu64" KB ]\n", "Total alloc-only requests", 11870d68bc92SNamhyung Kim nr_page_allocs - nr_alloc_freed, 11880d68bc92SNamhyung Kim (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024); 11890d68bc92SNamhyung Kim printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free-only requests", 11900d68bc92SNamhyung Kim nr_page_nomatch, total_page_nomatch_bytes / 1024); 11910d68bc92SNamhyung Kim printf("\n"); 11920d68bc92SNamhyung Kim 11930d68bc92SNamhyung Kim printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation failures", 11940d68bc92SNamhyung Kim nr_page_fails, total_page_fail_bytes / 1024); 11950d68bc92SNamhyung Kim printf("\n"); 11960d68bc92SNamhyung Kim 11970d68bc92SNamhyung Kim printf("%5s %12s %12s %12s %12s %12s\n", "Order", "Unmovable", 11980d68bc92SNamhyung Kim "Reclaimable", "Movable", "Reserved", "CMA/Isolated"); 11990d68bc92SNamhyung Kim printf("%.5s %.12s %.12s %.12s %.12s %.12s\n", graph_dotted_line, 12000d68bc92SNamhyung Kim graph_dotted_line, graph_dotted_line, graph_dotted_line, 12010d68bc92SNamhyung Kim graph_dotted_line, graph_dotted_line); 12020d68bc92SNamhyung Kim 12030d68bc92SNamhyung Kim for (o = 0; o < MAX_PAGE_ORDER; o++) { 12040d68bc92SNamhyung Kim printf("%5d", o); 12050d68bc92SNamhyung Kim for (m = 0; m < MAX_MIGRATE_TYPES - 1; m++) { 12060d68bc92SNamhyung Kim if (order_stats[o][m]) 12070d68bc92SNamhyung Kim printf(" %'12d", order_stats[o][m]); 12080d68bc92SNamhyung Kim else 12090d68bc92SNamhyung Kim printf(" %12c", '.'); 12100d68bc92SNamhyung Kim } 12110d68bc92SNamhyung Kim printf("\n"); 12120d68bc92SNamhyung Kim } 12130d68bc92SNamhyung Kim } 12140d68bc92SNamhyung Kim 12150d68bc92SNamhyung Kim static void print_slab_result(struct perf_session *session) 1216ba77c9e1SLi Zefan { 1217ba77c9e1SLi Zefan if (caller_flag) 12180d68bc92SNamhyung Kim __print_slab_result(&root_caller_sorted, session, caller_lines, 1); 1219ba77c9e1SLi Zefan if (alloc_flag) 12200d68bc92SNamhyung Kim __print_slab_result(&root_alloc_sorted, session, alloc_lines, 0); 12210d68bc92SNamhyung Kim print_slab_summary(); 12220d68bc92SNamhyung Kim } 12230d68bc92SNamhyung Kim 12240d68bc92SNamhyung Kim static void print_page_result(struct perf_session *session) 12250d68bc92SNamhyung Kim { 12260e111156SNamhyung Kim if (caller_flag || alloc_flag) 12270e111156SNamhyung Kim print_gfp_flags(); 1228c9758cc4SNamhyung Kim if (caller_flag) 1229c9758cc4SNamhyung Kim __print_page_caller_result(session, caller_lines); 12300d68bc92SNamhyung Kim if (alloc_flag) 1231c9758cc4SNamhyung Kim __print_page_alloc_result(session, alloc_lines); 12320d68bc92SNamhyung Kim print_page_summary(); 12330d68bc92SNamhyung Kim } 12340d68bc92SNamhyung Kim 12350d68bc92SNamhyung Kim static void print_result(struct perf_session *session) 12360d68bc92SNamhyung Kim { 12370d68bc92SNamhyung Kim if (kmem_slab) 12380d68bc92SNamhyung Kim print_slab_result(session); 12390d68bc92SNamhyung Kim if (kmem_page) 12400d68bc92SNamhyung Kim print_page_result(session); 1241ba77c9e1SLi Zefan } 1242ba77c9e1SLi Zefan 1243fb4f313dSNamhyung Kim static LIST_HEAD(slab_caller_sort); 1244fb4f313dSNamhyung Kim static LIST_HEAD(slab_alloc_sort); 1245fb4f313dSNamhyung Kim static LIST_HEAD(page_caller_sort); 1246fb4f313dSNamhyung Kim static LIST_HEAD(page_alloc_sort); 124729b3e152SLi Zefan 12480d68bc92SNamhyung Kim static void sort_slab_insert(struct rb_root *root, struct alloc_stat *data, 124929b3e152SLi Zefan struct list_head *sort_list) 1250ba77c9e1SLi Zefan { 1251ba77c9e1SLi Zefan struct rb_node **new = &(root->rb_node); 1252ba77c9e1SLi Zefan struct rb_node *parent = NULL; 125329b3e152SLi Zefan struct sort_dimension *sort; 1254ba77c9e1SLi Zefan 1255ba77c9e1SLi Zefan while (*new) { 1256ba77c9e1SLi Zefan struct alloc_stat *this; 125729b3e152SLi Zefan int cmp = 0; 1258ba77c9e1SLi Zefan 1259ba77c9e1SLi Zefan this = rb_entry(*new, struct alloc_stat, node); 1260ba77c9e1SLi Zefan parent = *new; 1261ba77c9e1SLi Zefan 126229b3e152SLi Zefan list_for_each_entry(sort, sort_list, list) { 126329b3e152SLi Zefan cmp = sort->cmp(data, this); 126429b3e152SLi Zefan if (cmp) 126529b3e152SLi Zefan break; 126629b3e152SLi Zefan } 1267ba77c9e1SLi Zefan 1268ba77c9e1SLi Zefan if (cmp > 0) 1269ba77c9e1SLi Zefan new = &((*new)->rb_left); 1270ba77c9e1SLi Zefan else 1271ba77c9e1SLi Zefan new = &((*new)->rb_right); 1272ba77c9e1SLi Zefan } 1273ba77c9e1SLi Zefan 1274ba77c9e1SLi Zefan rb_link_node(&data->node, parent, new); 1275ba77c9e1SLi Zefan rb_insert_color(&data->node, root); 1276ba77c9e1SLi Zefan } 1277ba77c9e1SLi Zefan 12780d68bc92SNamhyung Kim static void __sort_slab_result(struct rb_root *root, struct rb_root *root_sorted, 127929b3e152SLi Zefan struct list_head *sort_list) 1280ba77c9e1SLi Zefan { 1281ba77c9e1SLi Zefan struct rb_node *node; 1282ba77c9e1SLi Zefan struct alloc_stat *data; 1283ba77c9e1SLi Zefan 1284ba77c9e1SLi Zefan for (;;) { 1285ba77c9e1SLi Zefan node = rb_first(root); 1286ba77c9e1SLi Zefan if (!node) 1287ba77c9e1SLi Zefan break; 1288ba77c9e1SLi Zefan 1289ba77c9e1SLi Zefan rb_erase(node, root); 1290ba77c9e1SLi Zefan data = rb_entry(node, struct alloc_stat, node); 12910d68bc92SNamhyung Kim sort_slab_insert(root_sorted, data, sort_list); 12920d68bc92SNamhyung Kim } 12930d68bc92SNamhyung Kim } 12940d68bc92SNamhyung Kim 1295fb4f313dSNamhyung Kim static void sort_page_insert(struct rb_root *root, struct page_stat *data, 1296fb4f313dSNamhyung Kim struct list_head *sort_list) 12970d68bc92SNamhyung Kim { 12980d68bc92SNamhyung Kim struct rb_node **new = &root->rb_node; 12990d68bc92SNamhyung Kim struct rb_node *parent = NULL; 1300fb4f313dSNamhyung Kim struct sort_dimension *sort; 13010d68bc92SNamhyung Kim 13020d68bc92SNamhyung Kim while (*new) { 13030d68bc92SNamhyung Kim struct page_stat *this; 13040d68bc92SNamhyung Kim int cmp = 0; 13050d68bc92SNamhyung Kim 13060d68bc92SNamhyung Kim this = rb_entry(*new, struct page_stat, node); 13070d68bc92SNamhyung Kim parent = *new; 13080d68bc92SNamhyung Kim 1309fb4f313dSNamhyung Kim list_for_each_entry(sort, sort_list, list) { 1310fb4f313dSNamhyung Kim cmp = sort->cmp(data, this); 1311fb4f313dSNamhyung Kim if (cmp) 1312fb4f313dSNamhyung Kim break; 1313fb4f313dSNamhyung Kim } 13140d68bc92SNamhyung Kim 13150d68bc92SNamhyung Kim if (cmp > 0) 13160d68bc92SNamhyung Kim new = &parent->rb_left; 13170d68bc92SNamhyung Kim else 13180d68bc92SNamhyung Kim new = &parent->rb_right; 13190d68bc92SNamhyung Kim } 13200d68bc92SNamhyung Kim 13210d68bc92SNamhyung Kim rb_link_node(&data->node, parent, new); 13220d68bc92SNamhyung Kim rb_insert_color(&data->node, root); 13230d68bc92SNamhyung Kim } 13240d68bc92SNamhyung Kim 1325fb4f313dSNamhyung Kim static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted, 1326fb4f313dSNamhyung Kim struct list_head *sort_list) 13270d68bc92SNamhyung Kim { 13280d68bc92SNamhyung Kim struct rb_node *node; 13290d68bc92SNamhyung Kim struct page_stat *data; 13300d68bc92SNamhyung Kim 13310d68bc92SNamhyung Kim for (;;) { 13320d68bc92SNamhyung Kim node = rb_first(root); 13330d68bc92SNamhyung Kim if (!node) 13340d68bc92SNamhyung Kim break; 13350d68bc92SNamhyung Kim 13360d68bc92SNamhyung Kim rb_erase(node, root); 13370d68bc92SNamhyung Kim data = rb_entry(node, struct page_stat, node); 1338fb4f313dSNamhyung Kim sort_page_insert(root_sorted, data, sort_list); 1339ba77c9e1SLi Zefan } 1340ba77c9e1SLi Zefan } 1341ba77c9e1SLi Zefan 1342ba77c9e1SLi Zefan static void sort_result(void) 1343ba77c9e1SLi Zefan { 13440d68bc92SNamhyung Kim if (kmem_slab) { 13450d68bc92SNamhyung Kim __sort_slab_result(&root_alloc_stat, &root_alloc_sorted, 1346fb4f313dSNamhyung Kim &slab_alloc_sort); 13470d68bc92SNamhyung Kim __sort_slab_result(&root_caller_stat, &root_caller_sorted, 1348fb4f313dSNamhyung Kim &slab_caller_sort); 13490d68bc92SNamhyung Kim } 13500d68bc92SNamhyung Kim if (kmem_page) { 13512a7ef02cSNamhyung Kim if (live_page) 13522a7ef02cSNamhyung Kim __sort_page_result(&page_live_tree, &page_alloc_sorted, 13532a7ef02cSNamhyung Kim &page_alloc_sort); 13542a7ef02cSNamhyung Kim else 1355fb4f313dSNamhyung Kim __sort_page_result(&page_alloc_tree, &page_alloc_sorted, 1356fb4f313dSNamhyung Kim &page_alloc_sort); 13572a7ef02cSNamhyung Kim 1358fb4f313dSNamhyung Kim __sort_page_result(&page_caller_tree, &page_caller_sorted, 1359fb4f313dSNamhyung Kim &page_caller_sort); 13600d68bc92SNamhyung Kim } 1361ba77c9e1SLi Zefan } 1362ba77c9e1SLi Zefan 13632b2b2c68SNamhyung Kim static int __cmd_kmem(struct perf_session *session) 1364ba77c9e1SLi Zefan { 1365d549c769SArnaldo Carvalho de Melo int err = -EINVAL; 136632dcd021SJiri Olsa struct evsel *evsel; 136732dcd021SJiri Olsa const struct evsel_str_handler kmem_tracepoints[] = { 13680d68bc92SNamhyung Kim /* slab allocator */ 13698cf5d0e0SArnaldo Carvalho de Melo { "kmem:kmalloc", evsel__process_alloc_event, }, 13708cf5d0e0SArnaldo Carvalho de Melo { "kmem:kmem_cache_alloc", evsel__process_alloc_event, }, 13718cf5d0e0SArnaldo Carvalho de Melo { "kmem:kmalloc_node", evsel__process_alloc_node_event, }, 13728cf5d0e0SArnaldo Carvalho de Melo { "kmem:kmem_cache_alloc_node", evsel__process_alloc_node_event, }, 13738cf5d0e0SArnaldo Carvalho de Melo { "kmem:kfree", evsel__process_free_event, }, 13748cf5d0e0SArnaldo Carvalho de Melo { "kmem:kmem_cache_free", evsel__process_free_event, }, 13750d68bc92SNamhyung Kim /* page allocator */ 13768cf5d0e0SArnaldo Carvalho de Melo { "kmem:mm_page_alloc", evsel__process_page_alloc_event, }, 13778cf5d0e0SArnaldo Carvalho de Melo { "kmem:mm_page_free", evsel__process_page_free_event, }, 13780f7d2f1bSArnaldo Carvalho de Melo }; 1379ba77c9e1SLi Zefan 1380d549c769SArnaldo Carvalho de Melo if (!perf_session__has_traces(session, "kmem record")) 13812b2b2c68SNamhyung Kim goto out; 1382d549c769SArnaldo Carvalho de Melo 13830f7d2f1bSArnaldo Carvalho de Melo if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) { 13840f7d2f1bSArnaldo Carvalho de Melo pr_err("Initializing perf session tracepoint handlers failed\n"); 13852b2b2c68SNamhyung Kim goto out; 13860f7d2f1bSArnaldo Carvalho de Melo } 13870f7d2f1bSArnaldo Carvalho de Melo 1388e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(session->evlist, evsel) { 13898ab2e96dSArnaldo Carvalho de Melo if (!strcmp(evsel__name(evsel), "kmem:mm_page_alloc") && 1390efc0cdc9SArnaldo Carvalho de Melo evsel__field(evsel, "pfn")) { 13910d68bc92SNamhyung Kim use_pfn = true; 13920d68bc92SNamhyung Kim break; 13930d68bc92SNamhyung Kim } 13940d68bc92SNamhyung Kim } 13950d68bc92SNamhyung Kim 13964aa65636SArnaldo Carvalho de Melo setup_pager(); 1397b7b61cbeSArnaldo Carvalho de Melo err = perf_session__process_events(session); 13980d68bc92SNamhyung Kim if (err != 0) { 13990d68bc92SNamhyung Kim pr_err("error during process events: %d\n", err); 14002b2b2c68SNamhyung Kim goto out; 14010d68bc92SNamhyung Kim } 14024aa65636SArnaldo Carvalho de Melo sort_result(); 14034aa65636SArnaldo Carvalho de Melo print_result(session); 14042b2b2c68SNamhyung Kim out: 14054aa65636SArnaldo Carvalho de Melo return err; 1406ba77c9e1SLi Zefan } 1407ba77c9e1SLi Zefan 1408fb4f313dSNamhyung Kim /* slab sort keys */ 1409fb4f313dSNamhyung Kim static int ptr_cmp(void *a, void *b) 1410ba77c9e1SLi Zefan { 1411fb4f313dSNamhyung Kim struct alloc_stat *l = a; 1412fb4f313dSNamhyung Kim struct alloc_stat *r = b; 1413fb4f313dSNamhyung Kim 1414ba77c9e1SLi Zefan if (l->ptr < r->ptr) 1415ba77c9e1SLi Zefan return -1; 1416ba77c9e1SLi Zefan else if (l->ptr > r->ptr) 1417ba77c9e1SLi Zefan return 1; 1418ba77c9e1SLi Zefan return 0; 1419ba77c9e1SLi Zefan } 1420ba77c9e1SLi Zefan 142129b3e152SLi Zefan static struct sort_dimension ptr_sort_dimension = { 142229b3e152SLi Zefan .name = "ptr", 142329b3e152SLi Zefan .cmp = ptr_cmp, 142429b3e152SLi Zefan }; 142529b3e152SLi Zefan 1426fb4f313dSNamhyung Kim static int slab_callsite_cmp(void *a, void *b) 1427ba77c9e1SLi Zefan { 1428fb4f313dSNamhyung Kim struct alloc_stat *l = a; 1429fb4f313dSNamhyung Kim struct alloc_stat *r = b; 1430fb4f313dSNamhyung Kim 1431ba77c9e1SLi Zefan if (l->call_site < r->call_site) 1432ba77c9e1SLi Zefan return -1; 1433ba77c9e1SLi Zefan else if (l->call_site > r->call_site) 1434ba77c9e1SLi Zefan return 1; 1435ba77c9e1SLi Zefan return 0; 1436ba77c9e1SLi Zefan } 1437ba77c9e1SLi Zefan 143829b3e152SLi Zefan static struct sort_dimension callsite_sort_dimension = { 143929b3e152SLi Zefan .name = "callsite", 1440fb4f313dSNamhyung Kim .cmp = slab_callsite_cmp, 144129b3e152SLi Zefan }; 144229b3e152SLi Zefan 1443fb4f313dSNamhyung Kim static int hit_cmp(void *a, void *b) 1444f3ced7cdSPekka Enberg { 1445fb4f313dSNamhyung Kim struct alloc_stat *l = a; 1446fb4f313dSNamhyung Kim struct alloc_stat *r = b; 1447fb4f313dSNamhyung Kim 1448f3ced7cdSPekka Enberg if (l->hit < r->hit) 1449f3ced7cdSPekka Enberg return -1; 1450f3ced7cdSPekka Enberg else if (l->hit > r->hit) 1451f3ced7cdSPekka Enberg return 1; 1452f3ced7cdSPekka Enberg return 0; 1453f3ced7cdSPekka Enberg } 1454f3ced7cdSPekka Enberg 145529b3e152SLi Zefan static struct sort_dimension hit_sort_dimension = { 145629b3e152SLi Zefan .name = "hit", 145729b3e152SLi Zefan .cmp = hit_cmp, 145829b3e152SLi Zefan }; 145929b3e152SLi Zefan 1460fb4f313dSNamhyung Kim static int bytes_cmp(void *a, void *b) 1461ba77c9e1SLi Zefan { 1462fb4f313dSNamhyung Kim struct alloc_stat *l = a; 1463fb4f313dSNamhyung Kim struct alloc_stat *r = b; 1464fb4f313dSNamhyung Kim 1465ba77c9e1SLi Zefan if (l->bytes_alloc < r->bytes_alloc) 1466ba77c9e1SLi Zefan return -1; 1467ba77c9e1SLi Zefan else if (l->bytes_alloc > r->bytes_alloc) 1468ba77c9e1SLi Zefan return 1; 1469ba77c9e1SLi Zefan return 0; 1470ba77c9e1SLi Zefan } 1471ba77c9e1SLi Zefan 147229b3e152SLi Zefan static struct sort_dimension bytes_sort_dimension = { 147329b3e152SLi Zefan .name = "bytes", 147429b3e152SLi Zefan .cmp = bytes_cmp, 147529b3e152SLi Zefan }; 147629b3e152SLi Zefan 1477fb4f313dSNamhyung Kim static int frag_cmp(void *a, void *b) 1478f3ced7cdSPekka Enberg { 1479f3ced7cdSPekka Enberg double x, y; 1480fb4f313dSNamhyung Kim struct alloc_stat *l = a; 1481fb4f313dSNamhyung Kim struct alloc_stat *r = b; 1482f3ced7cdSPekka Enberg 1483f3ced7cdSPekka Enberg x = fragmentation(l->bytes_req, l->bytes_alloc); 1484f3ced7cdSPekka Enberg y = fragmentation(r->bytes_req, r->bytes_alloc); 1485f3ced7cdSPekka Enberg 1486f3ced7cdSPekka Enberg if (x < y) 1487f3ced7cdSPekka Enberg return -1; 1488f3ced7cdSPekka Enberg else if (x > y) 1489f3ced7cdSPekka Enberg return 1; 1490f3ced7cdSPekka Enberg return 0; 1491f3ced7cdSPekka Enberg } 1492f3ced7cdSPekka Enberg 149329b3e152SLi Zefan static struct sort_dimension frag_sort_dimension = { 149429b3e152SLi Zefan .name = "frag", 149529b3e152SLi Zefan .cmp = frag_cmp, 149629b3e152SLi Zefan }; 149729b3e152SLi Zefan 1498fb4f313dSNamhyung Kim static int pingpong_cmp(void *a, void *b) 1499079d3f65SLi Zefan { 1500fb4f313dSNamhyung Kim struct alloc_stat *l = a; 1501fb4f313dSNamhyung Kim struct alloc_stat *r = b; 1502fb4f313dSNamhyung Kim 1503079d3f65SLi Zefan if (l->pingpong < r->pingpong) 1504079d3f65SLi Zefan return -1; 1505079d3f65SLi Zefan else if (l->pingpong > r->pingpong) 1506079d3f65SLi Zefan return 1; 1507079d3f65SLi Zefan return 0; 1508079d3f65SLi Zefan } 1509079d3f65SLi Zefan 1510079d3f65SLi Zefan static struct sort_dimension pingpong_sort_dimension = { 1511079d3f65SLi Zefan .name = "pingpong", 1512079d3f65SLi Zefan .cmp = pingpong_cmp, 1513079d3f65SLi Zefan }; 1514079d3f65SLi Zefan 1515fb4f313dSNamhyung Kim /* page sort keys */ 1516fb4f313dSNamhyung Kim static int page_cmp(void *a, void *b) 1517fb4f313dSNamhyung Kim { 1518fb4f313dSNamhyung Kim struct page_stat *l = a; 1519fb4f313dSNamhyung Kim struct page_stat *r = b; 1520fb4f313dSNamhyung Kim 1521fb4f313dSNamhyung Kim if (l->page < r->page) 1522fb4f313dSNamhyung Kim return -1; 1523fb4f313dSNamhyung Kim else if (l->page > r->page) 1524fb4f313dSNamhyung Kim return 1; 1525fb4f313dSNamhyung Kim return 0; 1526fb4f313dSNamhyung Kim } 1527fb4f313dSNamhyung Kim 1528fb4f313dSNamhyung Kim static struct sort_dimension page_sort_dimension = { 1529fb4f313dSNamhyung Kim .name = "page", 1530fb4f313dSNamhyung Kim .cmp = page_cmp, 1531fb4f313dSNamhyung Kim }; 1532fb4f313dSNamhyung Kim 1533fb4f313dSNamhyung Kim static int page_callsite_cmp(void *a, void *b) 1534fb4f313dSNamhyung Kim { 1535fb4f313dSNamhyung Kim struct page_stat *l = a; 1536fb4f313dSNamhyung Kim struct page_stat *r = b; 1537fb4f313dSNamhyung Kim 1538fb4f313dSNamhyung Kim if (l->callsite < r->callsite) 1539fb4f313dSNamhyung Kim return -1; 1540fb4f313dSNamhyung Kim else if (l->callsite > r->callsite) 1541fb4f313dSNamhyung Kim return 1; 1542fb4f313dSNamhyung Kim return 0; 1543fb4f313dSNamhyung Kim } 1544fb4f313dSNamhyung Kim 1545fb4f313dSNamhyung Kim static struct sort_dimension page_callsite_sort_dimension = { 1546fb4f313dSNamhyung Kim .name = "callsite", 1547fb4f313dSNamhyung Kim .cmp = page_callsite_cmp, 1548fb4f313dSNamhyung Kim }; 1549fb4f313dSNamhyung Kim 1550fb4f313dSNamhyung Kim static int page_hit_cmp(void *a, void *b) 1551fb4f313dSNamhyung Kim { 1552fb4f313dSNamhyung Kim struct page_stat *l = a; 1553fb4f313dSNamhyung Kim struct page_stat *r = b; 1554fb4f313dSNamhyung Kim 1555fb4f313dSNamhyung Kim if (l->nr_alloc < r->nr_alloc) 1556fb4f313dSNamhyung Kim return -1; 1557fb4f313dSNamhyung Kim else if (l->nr_alloc > r->nr_alloc) 1558fb4f313dSNamhyung Kim return 1; 1559fb4f313dSNamhyung Kim return 0; 1560fb4f313dSNamhyung Kim } 1561fb4f313dSNamhyung Kim 1562fb4f313dSNamhyung Kim static struct sort_dimension page_hit_sort_dimension = { 1563fb4f313dSNamhyung Kim .name = "hit", 1564fb4f313dSNamhyung Kim .cmp = page_hit_cmp, 1565fb4f313dSNamhyung Kim }; 1566fb4f313dSNamhyung Kim 1567fb4f313dSNamhyung Kim static int page_bytes_cmp(void *a, void *b) 1568fb4f313dSNamhyung Kim { 1569fb4f313dSNamhyung Kim struct page_stat *l = a; 1570fb4f313dSNamhyung Kim struct page_stat *r = b; 1571fb4f313dSNamhyung Kim 1572fb4f313dSNamhyung Kim if (l->alloc_bytes < r->alloc_bytes) 1573fb4f313dSNamhyung Kim return -1; 1574fb4f313dSNamhyung Kim else if (l->alloc_bytes > r->alloc_bytes) 1575fb4f313dSNamhyung Kim return 1; 1576fb4f313dSNamhyung Kim return 0; 1577fb4f313dSNamhyung Kim } 1578fb4f313dSNamhyung Kim 1579fb4f313dSNamhyung Kim static struct sort_dimension page_bytes_sort_dimension = { 1580fb4f313dSNamhyung Kim .name = "bytes", 1581fb4f313dSNamhyung Kim .cmp = page_bytes_cmp, 1582fb4f313dSNamhyung Kim }; 1583fb4f313dSNamhyung Kim 1584fb4f313dSNamhyung Kim static int page_order_cmp(void *a, void *b) 1585fb4f313dSNamhyung Kim { 1586fb4f313dSNamhyung Kim struct page_stat *l = a; 1587fb4f313dSNamhyung Kim struct page_stat *r = b; 1588fb4f313dSNamhyung Kim 1589fb4f313dSNamhyung Kim if (l->order < r->order) 1590fb4f313dSNamhyung Kim return -1; 1591fb4f313dSNamhyung Kim else if (l->order > r->order) 1592fb4f313dSNamhyung Kim return 1; 1593fb4f313dSNamhyung Kim return 0; 1594fb4f313dSNamhyung Kim } 1595fb4f313dSNamhyung Kim 1596fb4f313dSNamhyung Kim static struct sort_dimension page_order_sort_dimension = { 1597fb4f313dSNamhyung Kim .name = "order", 1598fb4f313dSNamhyung Kim .cmp = page_order_cmp, 1599fb4f313dSNamhyung Kim }; 1600fb4f313dSNamhyung Kim 1601fb4f313dSNamhyung Kim static int migrate_type_cmp(void *a, void *b) 1602fb4f313dSNamhyung Kim { 1603fb4f313dSNamhyung Kim struct page_stat *l = a; 1604fb4f313dSNamhyung Kim struct page_stat *r = b; 1605fb4f313dSNamhyung Kim 1606fb4f313dSNamhyung Kim /* for internal use to find free'd page */ 1607fb4f313dSNamhyung Kim if (l->migrate_type == -1U) 1608fb4f313dSNamhyung Kim return 0; 1609fb4f313dSNamhyung Kim 1610fb4f313dSNamhyung Kim if (l->migrate_type < r->migrate_type) 1611fb4f313dSNamhyung Kim return -1; 1612fb4f313dSNamhyung Kim else if (l->migrate_type > r->migrate_type) 1613fb4f313dSNamhyung Kim return 1; 1614fb4f313dSNamhyung Kim return 0; 1615fb4f313dSNamhyung Kim } 1616fb4f313dSNamhyung Kim 1617fb4f313dSNamhyung Kim static struct sort_dimension migrate_type_sort_dimension = { 1618fb4f313dSNamhyung Kim .name = "migtype", 1619fb4f313dSNamhyung Kim .cmp = migrate_type_cmp, 1620fb4f313dSNamhyung Kim }; 1621fb4f313dSNamhyung Kim 1622fb4f313dSNamhyung Kim static int gfp_flags_cmp(void *a, void *b) 1623fb4f313dSNamhyung Kim { 1624fb4f313dSNamhyung Kim struct page_stat *l = a; 1625fb4f313dSNamhyung Kim struct page_stat *r = b; 1626fb4f313dSNamhyung Kim 1627fb4f313dSNamhyung Kim /* for internal use to find free'd page */ 1628fb4f313dSNamhyung Kim if (l->gfp_flags == -1U) 1629fb4f313dSNamhyung Kim return 0; 1630fb4f313dSNamhyung Kim 1631fb4f313dSNamhyung Kim if (l->gfp_flags < r->gfp_flags) 1632fb4f313dSNamhyung Kim return -1; 1633fb4f313dSNamhyung Kim else if (l->gfp_flags > r->gfp_flags) 1634fb4f313dSNamhyung Kim return 1; 1635fb4f313dSNamhyung Kim return 0; 1636fb4f313dSNamhyung Kim } 1637fb4f313dSNamhyung Kim 1638fb4f313dSNamhyung Kim static struct sort_dimension gfp_flags_sort_dimension = { 1639fb4f313dSNamhyung Kim .name = "gfp", 1640fb4f313dSNamhyung Kim .cmp = gfp_flags_cmp, 1641fb4f313dSNamhyung Kim }; 1642fb4f313dSNamhyung Kim 1643fb4f313dSNamhyung Kim static struct sort_dimension *slab_sorts[] = { 164429b3e152SLi Zefan &ptr_sort_dimension, 164529b3e152SLi Zefan &callsite_sort_dimension, 164629b3e152SLi Zefan &hit_sort_dimension, 164729b3e152SLi Zefan &bytes_sort_dimension, 164829b3e152SLi Zefan &frag_sort_dimension, 1649079d3f65SLi Zefan &pingpong_sort_dimension, 165029b3e152SLi Zefan }; 165129b3e152SLi Zefan 1652fb4f313dSNamhyung Kim static struct sort_dimension *page_sorts[] = { 1653fb4f313dSNamhyung Kim &page_sort_dimension, 1654fb4f313dSNamhyung Kim &page_callsite_sort_dimension, 1655fb4f313dSNamhyung Kim &page_hit_sort_dimension, 1656fb4f313dSNamhyung Kim &page_bytes_sort_dimension, 1657fb4f313dSNamhyung Kim &page_order_sort_dimension, 1658fb4f313dSNamhyung Kim &migrate_type_sort_dimension, 1659fb4f313dSNamhyung Kim &gfp_flags_sort_dimension, 1660fb4f313dSNamhyung Kim }; 166129b3e152SLi Zefan 1662fb4f313dSNamhyung Kim static int slab_sort_dimension__add(const char *tok, struct list_head *list) 166329b3e152SLi Zefan { 166429b3e152SLi Zefan struct sort_dimension *sort; 166529b3e152SLi Zefan int i; 166629b3e152SLi Zefan 1667fb4f313dSNamhyung Kim for (i = 0; i < (int)ARRAY_SIZE(slab_sorts); i++) { 1668fb4f313dSNamhyung Kim if (!strcmp(slab_sorts[i]->name, tok)) { 1669fb4f313dSNamhyung Kim sort = memdup(slab_sorts[i], sizeof(*slab_sorts[i])); 16702814eb05SArnaldo Carvalho de Melo if (!sort) { 16718d9233f2SArnaldo Carvalho de Melo pr_err("%s: memdup failed\n", __func__); 16722814eb05SArnaldo Carvalho de Melo return -1; 16732814eb05SArnaldo Carvalho de Melo } 167429b3e152SLi Zefan list_add_tail(&sort->list, list); 167529b3e152SLi Zefan return 0; 167629b3e152SLi Zefan } 167729b3e152SLi Zefan } 167829b3e152SLi Zefan 167929b3e152SLi Zefan return -1; 168029b3e152SLi Zefan } 168129b3e152SLi Zefan 1682fb4f313dSNamhyung Kim static int page_sort_dimension__add(const char *tok, struct list_head *list) 1683fb4f313dSNamhyung Kim { 1684fb4f313dSNamhyung Kim struct sort_dimension *sort; 1685fb4f313dSNamhyung Kim int i; 1686fb4f313dSNamhyung Kim 1687fb4f313dSNamhyung Kim for (i = 0; i < (int)ARRAY_SIZE(page_sorts); i++) { 1688fb4f313dSNamhyung Kim if (!strcmp(page_sorts[i]->name, tok)) { 1689fb4f313dSNamhyung Kim sort = memdup(page_sorts[i], sizeof(*page_sorts[i])); 1690fb4f313dSNamhyung Kim if (!sort) { 1691fb4f313dSNamhyung Kim pr_err("%s: memdup failed\n", __func__); 1692fb4f313dSNamhyung Kim return -1; 1693fb4f313dSNamhyung Kim } 1694fb4f313dSNamhyung Kim list_add_tail(&sort->list, list); 1695fb4f313dSNamhyung Kim return 0; 1696fb4f313dSNamhyung Kim } 1697fb4f313dSNamhyung Kim } 1698fb4f313dSNamhyung Kim 1699fb4f313dSNamhyung Kim return -1; 1700fb4f313dSNamhyung Kim } 1701fb4f313dSNamhyung Kim 1702fb4f313dSNamhyung Kim static int setup_slab_sorting(struct list_head *sort_list, const char *arg) 170329b3e152SLi Zefan { 170429b3e152SLi Zefan char *tok; 170529b3e152SLi Zefan char *str = strdup(arg); 1706405f8755SNamhyung Kim char *pos = str; 170729b3e152SLi Zefan 17082814eb05SArnaldo Carvalho de Melo if (!str) { 17092814eb05SArnaldo Carvalho de Melo pr_err("%s: strdup failed\n", __func__); 17102814eb05SArnaldo Carvalho de Melo return -1; 17112814eb05SArnaldo Carvalho de Melo } 171229b3e152SLi Zefan 171329b3e152SLi Zefan while (true) { 1714405f8755SNamhyung Kim tok = strsep(&pos, ","); 171529b3e152SLi Zefan if (!tok) 171629b3e152SLi Zefan break; 1717fb4f313dSNamhyung Kim if (slab_sort_dimension__add(tok, sort_list) < 0) { 171862d94b00SArnaldo Carvalho de Melo pr_err("Unknown slab --sort key: '%s'", tok); 1719fb4f313dSNamhyung Kim free(str); 1720fb4f313dSNamhyung Kim return -1; 1721fb4f313dSNamhyung Kim } 1722fb4f313dSNamhyung Kim } 1723fb4f313dSNamhyung Kim 1724fb4f313dSNamhyung Kim free(str); 1725fb4f313dSNamhyung Kim return 0; 1726fb4f313dSNamhyung Kim } 1727fb4f313dSNamhyung Kim 1728fb4f313dSNamhyung Kim static int setup_page_sorting(struct list_head *sort_list, const char *arg) 1729fb4f313dSNamhyung Kim { 1730fb4f313dSNamhyung Kim char *tok; 1731fb4f313dSNamhyung Kim char *str = strdup(arg); 1732fb4f313dSNamhyung Kim char *pos = str; 1733fb4f313dSNamhyung Kim 1734fb4f313dSNamhyung Kim if (!str) { 1735fb4f313dSNamhyung Kim pr_err("%s: strdup failed\n", __func__); 1736fb4f313dSNamhyung Kim return -1; 1737fb4f313dSNamhyung Kim } 1738fb4f313dSNamhyung Kim 1739fb4f313dSNamhyung Kim while (true) { 1740fb4f313dSNamhyung Kim tok = strsep(&pos, ","); 1741fb4f313dSNamhyung Kim if (!tok) 1742fb4f313dSNamhyung Kim break; 1743fb4f313dSNamhyung Kim if (page_sort_dimension__add(tok, sort_list) < 0) { 174462d94b00SArnaldo Carvalho de Melo pr_err("Unknown page --sort key: '%s'", tok); 17451b22859dSNamhyung Kim free(str); 174629b3e152SLi Zefan return -1; 174729b3e152SLi Zefan } 174829b3e152SLi Zefan } 174929b3e152SLi Zefan 175029b3e152SLi Zefan free(str); 175129b3e152SLi Zefan return 0; 175229b3e152SLi Zefan } 175329b3e152SLi Zefan 17541d037ca1SIrina Tirdea static int parse_sort_opt(const struct option *opt __maybe_unused, 17551d037ca1SIrina Tirdea const char *arg, int unset __maybe_unused) 1756ba77c9e1SLi Zefan { 1757ba77c9e1SLi Zefan if (!arg) 1758ba77c9e1SLi Zefan return -1; 1759ba77c9e1SLi Zefan 17600c160d49SNamhyung Kim if (kmem_page > kmem_slab || 17610c160d49SNamhyung Kim (kmem_page == 0 && kmem_slab == 0 && kmem_default == KMEM_PAGE)) { 1762ba77c9e1SLi Zefan if (caller_flag > alloc_flag) 1763fb4f313dSNamhyung Kim return setup_page_sorting(&page_caller_sort, arg); 1764ba77c9e1SLi Zefan else 1765fb4f313dSNamhyung Kim return setup_page_sorting(&page_alloc_sort, arg); 1766fb4f313dSNamhyung Kim } else { 1767fb4f313dSNamhyung Kim if (caller_flag > alloc_flag) 1768fb4f313dSNamhyung Kim return setup_slab_sorting(&slab_caller_sort, arg); 1769fb4f313dSNamhyung Kim else 1770fb4f313dSNamhyung Kim return setup_slab_sorting(&slab_alloc_sort, arg); 1771fb4f313dSNamhyung Kim } 1772ba77c9e1SLi Zefan 1773ba77c9e1SLi Zefan return 0; 1774ba77c9e1SLi Zefan } 1775ba77c9e1SLi Zefan 17761d037ca1SIrina Tirdea static int parse_caller_opt(const struct option *opt __maybe_unused, 17771d037ca1SIrina Tirdea const char *arg __maybe_unused, 17781d037ca1SIrina Tirdea int unset __maybe_unused) 1779ba77c9e1SLi Zefan { 1780ba77c9e1SLi Zefan caller_flag = (alloc_flag + 1); 178190b86a9fSLi Zefan return 0; 178290b86a9fSLi Zefan } 178390b86a9fSLi Zefan 17841d037ca1SIrina Tirdea static int parse_alloc_opt(const struct option *opt __maybe_unused, 17851d037ca1SIrina Tirdea const char *arg __maybe_unused, 17861d037ca1SIrina Tirdea int unset __maybe_unused) 178790b86a9fSLi Zefan { 178890b86a9fSLi Zefan alloc_flag = (caller_flag + 1); 1789ba77c9e1SLi Zefan return 0; 1790ba77c9e1SLi Zefan } 1791ba77c9e1SLi Zefan 17920d68bc92SNamhyung Kim static int parse_slab_opt(const struct option *opt __maybe_unused, 17930d68bc92SNamhyung Kim const char *arg __maybe_unused, 17940d68bc92SNamhyung Kim int unset __maybe_unused) 17950d68bc92SNamhyung Kim { 17960d68bc92SNamhyung Kim kmem_slab = (kmem_page + 1); 17970d68bc92SNamhyung Kim return 0; 17980d68bc92SNamhyung Kim } 17990d68bc92SNamhyung Kim 18000d68bc92SNamhyung Kim static int parse_page_opt(const struct option *opt __maybe_unused, 18010d68bc92SNamhyung Kim const char *arg __maybe_unused, 18020d68bc92SNamhyung Kim int unset __maybe_unused) 18030d68bc92SNamhyung Kim { 18040d68bc92SNamhyung Kim kmem_page = (kmem_slab + 1); 18050d68bc92SNamhyung Kim return 0; 18060d68bc92SNamhyung Kim } 18070d68bc92SNamhyung Kim 18081d037ca1SIrina Tirdea static int parse_line_opt(const struct option *opt __maybe_unused, 18091d037ca1SIrina Tirdea const char *arg, int unset __maybe_unused) 1810ba77c9e1SLi Zefan { 1811ba77c9e1SLi Zefan int lines; 1812ba77c9e1SLi Zefan 1813ba77c9e1SLi Zefan if (!arg) 1814ba77c9e1SLi Zefan return -1; 1815ba77c9e1SLi Zefan 1816ba77c9e1SLi Zefan lines = strtoul(arg, NULL, 10); 1817ba77c9e1SLi Zefan 1818ba77c9e1SLi Zefan if (caller_flag > alloc_flag) 1819ba77c9e1SLi Zefan caller_lines = lines; 1820ba77c9e1SLi Zefan else 1821ba77c9e1SLi Zefan alloc_lines = lines; 1822ba77c9e1SLi Zefan 1823ba77c9e1SLi Zefan return 0; 1824ba77c9e1SLi Zefan } 1825ba77c9e1SLi Zefan 18260433ffbeSArnaldo Carvalho de Melo static int __cmd_record(int argc, const char **argv) 18270433ffbeSArnaldo Carvalho de Melo { 18280433ffbeSArnaldo Carvalho de Melo const char * const record_args[] = { 18294a4d371aSJiri Olsa "record", "-a", "-R", "-c", "1", 18300d68bc92SNamhyung Kim }; 18310d68bc92SNamhyung Kim const char * const slab_events[] = { 1832ba77c9e1SLi Zefan "-e", "kmem:kmalloc", 1833ba77c9e1SLi Zefan "-e", "kmem:kmalloc_node", 1834ba77c9e1SLi Zefan "-e", "kmem:kfree", 1835ba77c9e1SLi Zefan "-e", "kmem:kmem_cache_alloc", 1836ba77c9e1SLi Zefan "-e", "kmem:kmem_cache_alloc_node", 1837ba77c9e1SLi Zefan "-e", "kmem:kmem_cache_free", 1838ba77c9e1SLi Zefan }; 18390d68bc92SNamhyung Kim const char * const page_events[] = { 18400d68bc92SNamhyung Kim "-e", "kmem:mm_page_alloc", 18410d68bc92SNamhyung Kim "-e", "kmem:mm_page_free", 18420d68bc92SNamhyung Kim }; 1843ba77c9e1SLi Zefan unsigned int rec_argc, i, j; 1844ba77c9e1SLi Zefan const char **rec_argv; 1845ba77c9e1SLi Zefan 1846ba77c9e1SLi Zefan rec_argc = ARRAY_SIZE(record_args) + argc - 1; 18470d68bc92SNamhyung Kim if (kmem_slab) 18480d68bc92SNamhyung Kim rec_argc += ARRAY_SIZE(slab_events); 18490d68bc92SNamhyung Kim if (kmem_page) 1850c9758cc4SNamhyung Kim rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */ 18510d68bc92SNamhyung Kim 1852ba77c9e1SLi Zefan rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1853ba77c9e1SLi Zefan 1854ce47dc56SChris Samuel if (rec_argv == NULL) 1855ce47dc56SChris Samuel return -ENOMEM; 1856ce47dc56SChris Samuel 1857ba77c9e1SLi Zefan for (i = 0; i < ARRAY_SIZE(record_args); i++) 1858ba77c9e1SLi Zefan rec_argv[i] = strdup(record_args[i]); 1859ba77c9e1SLi Zefan 18600d68bc92SNamhyung Kim if (kmem_slab) { 18610d68bc92SNamhyung Kim for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++) 18620d68bc92SNamhyung Kim rec_argv[i] = strdup(slab_events[j]); 18630d68bc92SNamhyung Kim } 18640d68bc92SNamhyung Kim if (kmem_page) { 1865c9758cc4SNamhyung Kim rec_argv[i++] = strdup("-g"); 1866c9758cc4SNamhyung Kim 18670d68bc92SNamhyung Kim for (j = 0; j < ARRAY_SIZE(page_events); j++, i++) 18680d68bc92SNamhyung Kim rec_argv[i] = strdup(page_events[j]); 18690d68bc92SNamhyung Kim } 18700d68bc92SNamhyung Kim 1871ba77c9e1SLi Zefan for (j = 1; j < (unsigned int)argc; j++, i++) 1872ba77c9e1SLi Zefan rec_argv[i] = argv[j]; 1873ba77c9e1SLi Zefan 1874b0ad8ea6SArnaldo Carvalho de Melo return cmd_record(i, rec_argv); 1875ba77c9e1SLi Zefan } 1876ba77c9e1SLi Zefan 1877b8cbb349SWang Nan static int kmem_config(const char *var, const char *value, void *cb __maybe_unused) 18780c160d49SNamhyung Kim { 18790c160d49SNamhyung Kim if (!strcmp(var, "kmem.default")) { 18800c160d49SNamhyung Kim if (!strcmp(value, "slab")) 18810c160d49SNamhyung Kim kmem_default = KMEM_SLAB; 18820c160d49SNamhyung Kim else if (!strcmp(value, "page")) 18830c160d49SNamhyung Kim kmem_default = KMEM_PAGE; 18840c160d49SNamhyung Kim else 18850c160d49SNamhyung Kim pr_err("invalid default value ('slab' or 'page' required): %s\n", 18860c160d49SNamhyung Kim value); 18870c160d49SNamhyung Kim return 0; 18880c160d49SNamhyung Kim } 18890c160d49SNamhyung Kim 1890b8cbb349SWang Nan return 0; 18910c160d49SNamhyung Kim } 18920c160d49SNamhyung Kim 1893b0ad8ea6SArnaldo Carvalho de Melo int cmd_kmem(int argc, const char **argv) 1894ba77c9e1SLi Zefan { 1895fb4f313dSNamhyung Kim const char * const default_slab_sort = "frag,hit,bytes"; 1896fb4f313dSNamhyung Kim const char * const default_page_sort = "bytes,hit"; 18978ceb41d7SJiri Olsa struct perf_data data = { 1898d1eeb77cSYunlong Song .mode = PERF_DATA_MODE_READ, 1899d1eeb77cSYunlong Song }; 19000433ffbeSArnaldo Carvalho de Melo const struct option kmem_options[] = { 19010433ffbeSArnaldo Carvalho de Melo OPT_STRING('i', "input", &input_name, "file", "input file name"), 1902bd72a33eSNamhyung Kim OPT_INCR('v', "verbose", &verbose, 1903bd72a33eSNamhyung Kim "be more verbose (show symbol address, etc)"), 19040433ffbeSArnaldo Carvalho de Melo OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, 19050433ffbeSArnaldo Carvalho de Melo "show per-callsite statistics", parse_caller_opt), 19060433ffbeSArnaldo Carvalho de Melo OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, 19070433ffbeSArnaldo Carvalho de Melo "show per-allocation statistics", parse_alloc_opt), 19080433ffbeSArnaldo Carvalho de Melo OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", 1909fb4f313dSNamhyung Kim "sort by keys: ptr, callsite, bytes, hit, pingpong, frag, " 1910fb4f313dSNamhyung Kim "page, order, migtype, gfp", parse_sort_opt), 19110433ffbeSArnaldo Carvalho de Melo OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt), 19120433ffbeSArnaldo Carvalho de Melo OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 19138ceb41d7SJiri Olsa OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), 19140d68bc92SNamhyung Kim OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator", 19150d68bc92SNamhyung Kim parse_slab_opt), 19160d68bc92SNamhyung Kim OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator", 19170d68bc92SNamhyung Kim parse_page_opt), 19182a7ef02cSNamhyung Kim OPT_BOOLEAN(0, "live", &live_page, "Show live page stat"), 19192a865bd8SDavid Ahern OPT_STRING(0, "time", &time_str, "str", 19202a865bd8SDavid Ahern "Time span of interest (start,stop)"), 19210433ffbeSArnaldo Carvalho de Melo OPT_END() 19220433ffbeSArnaldo Carvalho de Melo }; 19233bca2354SRamkumar Ramachandra const char *const kmem_subcommands[] = { "record", "stat", NULL }; 19243bca2354SRamkumar Ramachandra const char *kmem_usage[] = { 19253bca2354SRamkumar Ramachandra NULL, 19260433ffbeSArnaldo Carvalho de Melo NULL 19270433ffbeSArnaldo Carvalho de Melo }; 19282b2b2c68SNamhyung Kim struct perf_session *session; 192949b8e2beSRasmus Villemoes static const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n"; 1930ecc4c561SArnaldo Carvalho de Melo int ret = perf_config(kmem_config, NULL); 19312b2b2c68SNamhyung Kim 1932ecc4c561SArnaldo Carvalho de Melo if (ret) 1933ecc4c561SArnaldo Carvalho de Melo return ret; 1934ecc4c561SArnaldo Carvalho de Melo 19353bca2354SRamkumar Ramachandra argc = parse_options_subcommand(argc, argv, kmem_options, 1936be8299e4SIan Rogers kmem_subcommands, kmem_usage, 1937be8299e4SIan Rogers PARSE_OPT_STOP_AT_NON_OPTION); 1938ba77c9e1SLi Zefan 193990b86a9fSLi Zefan if (!argc) 1940ba77c9e1SLi Zefan usage_with_options(kmem_usage, kmem_options); 1941ba77c9e1SLi Zefan 19420c160d49SNamhyung Kim if (kmem_slab == 0 && kmem_page == 0) { 19430c160d49SNamhyung Kim if (kmem_default == KMEM_SLAB) 19440c160d49SNamhyung Kim kmem_slab = 1; 19450c160d49SNamhyung Kim else 19460c160d49SNamhyung Kim kmem_page = 1; 19470c160d49SNamhyung Kim } 19480d68bc92SNamhyung Kim 19492b2b2c68SNamhyung Kim if (!strncmp(argv[0], "rec", 3)) { 19500a7e6d1bSNamhyung Kim symbol__init(NULL); 19512b2b2c68SNamhyung Kim return __cmd_record(argc, argv); 19522b2b2c68SNamhyung Kim } 19532b2b2c68SNamhyung Kim 19542d4f2799SJiri Olsa data.path = input_name; 195528939e1aSJiri Olsa 1956*2681bd85SNamhyung Kim kmem_session = session = perf_session__new(&data, &perf_kmem); 19576ef81c55SMamatha Inamdar if (IS_ERR(session)) 19586ef81c55SMamatha Inamdar return PTR_ERR(session); 19592b2b2c68SNamhyung Kim 1960ecc4c561SArnaldo Carvalho de Melo ret = -1; 1961ecc4c561SArnaldo Carvalho de Melo 1962a923e2c4SNamhyung Kim if (kmem_slab) { 1963b02736f7SArnaldo Carvalho de Melo if (!evlist__find_tracepoint_by_name(session->evlist, "kmem:kmalloc")) { 1964a923e2c4SNamhyung Kim pr_err(errmsg, "slab", "slab"); 1965249ca1a8STaeung Song goto out_delete; 1966a923e2c4SNamhyung Kim } 1967a923e2c4SNamhyung Kim } 19680d68bc92SNamhyung Kim 1969a923e2c4SNamhyung Kim if (kmem_page) { 1970b02736f7SArnaldo Carvalho de Melo struct evsel *evsel = evlist__find_tracepoint_by_name(session->evlist, "kmem:mm_page_alloc"); 1971a923e2c4SNamhyung Kim 1972a923e2c4SNamhyung Kim if (evsel == NULL) { 1973a923e2c4SNamhyung Kim pr_err(errmsg, "page", "page"); 1974249ca1a8STaeung Song goto out_delete; 19750d68bc92SNamhyung Kim } 19760d68bc92SNamhyung Kim 197769769ce1STzvetomir Stoyanov kmem_page_size = tep_get_page_size(evsel->tp_format->tep); 1978c9758cc4SNamhyung Kim symbol_conf.use_callchain = true; 19790d68bc92SNamhyung Kim } 19800d68bc92SNamhyung Kim 19810a7e6d1bSNamhyung Kim symbol__init(&session->header.env); 1982655000e7SArnaldo Carvalho de Melo 19832a865bd8SDavid Ahern if (perf_time__parse_str(&ptime, time_str) != 0) { 19842a865bd8SDavid Ahern pr_err("Invalid time string\n"); 198579f56ebeSChristophe JAILLET ret = -EINVAL; 198679f56ebeSChristophe JAILLET goto out_delete; 19872a865bd8SDavid Ahern } 19882a865bd8SDavid Ahern 19892b2b2c68SNamhyung Kim if (!strcmp(argv[0], "stat")) { 199077cfe388SNamhyung Kim setlocale(LC_ALL, ""); 199177cfe388SNamhyung Kim 19924b627957SDon Zickus if (cpu__setup_cpunode_map()) 19932b2b2c68SNamhyung Kim goto out_delete; 199490b86a9fSLi Zefan 1995fb4f313dSNamhyung Kim if (list_empty(&slab_caller_sort)) 1996fb4f313dSNamhyung Kim setup_slab_sorting(&slab_caller_sort, default_slab_sort); 1997fb4f313dSNamhyung Kim if (list_empty(&slab_alloc_sort)) 1998fb4f313dSNamhyung Kim setup_slab_sorting(&slab_alloc_sort, default_slab_sort); 1999fb4f313dSNamhyung Kim if (list_empty(&page_caller_sort)) 2000fb4f313dSNamhyung Kim setup_page_sorting(&page_caller_sort, default_page_sort); 2001fb4f313dSNamhyung Kim if (list_empty(&page_alloc_sort)) 2002fb4f313dSNamhyung Kim setup_page_sorting(&page_alloc_sort, default_page_sort); 2003ba77c9e1SLi Zefan 2004fb4f313dSNamhyung Kim if (kmem_page) { 2005fb4f313dSNamhyung Kim setup_page_sorting(&page_alloc_sort_input, 2006fb4f313dSNamhyung Kim "page,order,migtype,gfp"); 2007fb4f313dSNamhyung Kim setup_page_sorting(&page_caller_sort_input, 2008fb4f313dSNamhyung Kim "callsite,order,migtype,gfp"); 2009fb4f313dSNamhyung Kim } 20102b2b2c68SNamhyung Kim ret = __cmd_kmem(session); 2011b00eca8cSPekka Enberg } else 2012b00eca8cSPekka Enberg usage_with_options(kmem_usage, kmem_options); 2013ba77c9e1SLi Zefan 20142b2b2c68SNamhyung Kim out_delete: 20152b2b2c68SNamhyung Kim perf_session__delete(session); 20162b2b2c68SNamhyung Kim 20172b2b2c68SNamhyung Kim return ret; 201890b86a9fSLi Zefan } 201990b86a9fSLi Zefan 2020