1ba77c9e1SLi Zefan #include "builtin.h" 2ba77c9e1SLi Zefan #include "perf.h" 3ba77c9e1SLi Zefan 40f7d2f1bSArnaldo Carvalho de Melo #include "util/evlist.h" 5fcf65bf1SArnaldo Carvalho de Melo #include "util/evsel.h" 6ba77c9e1SLi Zefan #include "util/util.h" 741840d21STaeung Song #include "util/config.h" 8ba77c9e1SLi Zefan #include "util/symbol.h" 9ba77c9e1SLi Zefan #include "util/thread.h" 10ba77c9e1SLi Zefan #include "util/header.h" 1194c744b6SArnaldo Carvalho de Melo #include "util/session.h" 1245694aa7SArnaldo Carvalho de Melo #include "util/tool.h" 13c9758cc4SNamhyung Kim #include "util/callchain.h" 142a865bd8SDavid Ahern #include "util/time-utils.h" 15ba77c9e1SLi Zefan 164b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 17ba77c9e1SLi Zefan #include "util/trace-event.h" 18f5fc1412SJiri Olsa #include "util/data.h" 194b627957SDon Zickus #include "util/cpumap.h" 20ba77c9e1SLi Zefan 21ba77c9e1SLi Zefan #include "util/debug.h" 22ba77c9e1SLi Zefan 23877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 24ba77c9e1SLi Zefan #include <linux/rbtree.h> 258d9233f2SArnaldo Carvalho de Melo #include <linux/string.h> 26a43783aeSArnaldo Carvalho de Melo #include <errno.h> 27fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 2877cfe388SNamhyung Kim #include <locale.h> 29c9758cc4SNamhyung Kim #include <regex.h> 30ba77c9e1SLi Zefan 313d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h" 323d689ed6SArnaldo Carvalho de Melo 330d68bc92SNamhyung Kim static int kmem_slab; 340d68bc92SNamhyung Kim static int kmem_page; 350d68bc92SNamhyung Kim 360d68bc92SNamhyung Kim static long kmem_page_size; 370c160d49SNamhyung Kim static enum { 380c160d49SNamhyung Kim KMEM_SLAB, 390c160d49SNamhyung Kim KMEM_PAGE, 400c160d49SNamhyung Kim } kmem_default = KMEM_SLAB; /* for backward compatibility */ 410d68bc92SNamhyung Kim 42ba77c9e1SLi Zefan struct alloc_stat; 43fb4f313dSNamhyung Kim typedef int (*sort_fn_t)(void *, void *); 44ba77c9e1SLi Zefan 45ba77c9e1SLi Zefan static int alloc_flag; 46ba77c9e1SLi Zefan static int caller_flag; 47ba77c9e1SLi Zefan 48ba77c9e1SLi Zefan static int alloc_lines = -1; 49ba77c9e1SLi Zefan static int caller_lines = -1; 50ba77c9e1SLi Zefan 517707b6b6SLi Zefan static bool raw_ip; 527707b6b6SLi Zefan 53ba77c9e1SLi Zefan struct alloc_stat { 54ba77c9e1SLi Zefan u64 call_site; 55ba77c9e1SLi Zefan u64 ptr; 56ba77c9e1SLi Zefan u64 bytes_req; 57ba77c9e1SLi Zefan u64 bytes_alloc; 58aa58e9afSDavid Ahern u64 last_alloc; 59ba77c9e1SLi Zefan u32 hit; 60079d3f65SLi Zefan u32 pingpong; 61079d3f65SLi Zefan 62079d3f65SLi Zefan short alloc_cpu; 63ba77c9e1SLi Zefan 64ba77c9e1SLi Zefan struct rb_node node; 65ba77c9e1SLi Zefan }; 66ba77c9e1SLi Zefan 67ba77c9e1SLi Zefan static struct rb_root root_alloc_stat; 68ba77c9e1SLi Zefan static struct rb_root root_alloc_sorted; 69ba77c9e1SLi Zefan static struct rb_root root_caller_stat; 70ba77c9e1SLi Zefan static struct rb_root root_caller_sorted; 71ba77c9e1SLi Zefan 72aa58e9afSDavid Ahern static unsigned long total_requested, total_allocated, total_freed; 737d0d3945SLi Zefan static unsigned long nr_allocs, nr_cross_allocs; 74ba77c9e1SLi Zefan 752a865bd8SDavid Ahern /* filters for controlling start and stop of time of analysis */ 762a865bd8SDavid Ahern static struct perf_time_interval ptime; 772a865bd8SDavid Ahern const char *time_str; 782a865bd8SDavid Ahern 792814eb05SArnaldo Carvalho de Melo static int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 80079d3f65SLi Zefan int bytes_req, int bytes_alloc, int cpu) 81ba77c9e1SLi Zefan { 82ba77c9e1SLi Zefan struct rb_node **node = &root_alloc_stat.rb_node; 83ba77c9e1SLi Zefan struct rb_node *parent = NULL; 84ba77c9e1SLi Zefan struct alloc_stat *data = NULL; 85ba77c9e1SLi Zefan 86ba77c9e1SLi Zefan while (*node) { 87ba77c9e1SLi Zefan parent = *node; 88ba77c9e1SLi Zefan data = rb_entry(*node, struct alloc_stat, node); 89ba77c9e1SLi Zefan 90ba77c9e1SLi Zefan if (ptr > data->ptr) 91ba77c9e1SLi Zefan node = &(*node)->rb_right; 92ba77c9e1SLi Zefan else if (ptr < data->ptr) 93ba77c9e1SLi Zefan node = &(*node)->rb_left; 94ba77c9e1SLi Zefan else 95ba77c9e1SLi Zefan break; 96ba77c9e1SLi Zefan } 97ba77c9e1SLi Zefan 98ba77c9e1SLi Zefan if (data && data->ptr == ptr) { 99ba77c9e1SLi Zefan data->hit++; 100ba77c9e1SLi Zefan data->bytes_req += bytes_req; 1014efb5290SWenji Huang data->bytes_alloc += bytes_alloc; 102ba77c9e1SLi Zefan } else { 103ba77c9e1SLi Zefan data = malloc(sizeof(*data)); 1042814eb05SArnaldo Carvalho de Melo if (!data) { 1052814eb05SArnaldo Carvalho de Melo pr_err("%s: malloc failed\n", __func__); 1062814eb05SArnaldo Carvalho de Melo return -1; 1072814eb05SArnaldo Carvalho de Melo } 108ba77c9e1SLi Zefan data->ptr = ptr; 109079d3f65SLi Zefan data->pingpong = 0; 110ba77c9e1SLi Zefan data->hit = 1; 111ba77c9e1SLi Zefan data->bytes_req = bytes_req; 112ba77c9e1SLi Zefan data->bytes_alloc = bytes_alloc; 113ba77c9e1SLi Zefan 114ba77c9e1SLi Zefan rb_link_node(&data->node, parent, node); 115ba77c9e1SLi Zefan rb_insert_color(&data->node, &root_alloc_stat); 116ba77c9e1SLi Zefan } 117079d3f65SLi Zefan data->call_site = call_site; 118079d3f65SLi Zefan data->alloc_cpu = cpu; 119aa58e9afSDavid Ahern data->last_alloc = bytes_alloc; 120aa58e9afSDavid Ahern 1212814eb05SArnaldo Carvalho de Melo return 0; 122ba77c9e1SLi Zefan } 123ba77c9e1SLi Zefan 1242814eb05SArnaldo Carvalho de Melo static int insert_caller_stat(unsigned long call_site, 125ba77c9e1SLi Zefan int bytes_req, int bytes_alloc) 126ba77c9e1SLi Zefan { 127ba77c9e1SLi Zefan struct rb_node **node = &root_caller_stat.rb_node; 128ba77c9e1SLi Zefan struct rb_node *parent = NULL; 129ba77c9e1SLi Zefan struct alloc_stat *data = NULL; 130ba77c9e1SLi Zefan 131ba77c9e1SLi Zefan while (*node) { 132ba77c9e1SLi Zefan parent = *node; 133ba77c9e1SLi Zefan data = rb_entry(*node, struct alloc_stat, node); 134ba77c9e1SLi Zefan 135ba77c9e1SLi Zefan if (call_site > data->call_site) 136ba77c9e1SLi Zefan node = &(*node)->rb_right; 137ba77c9e1SLi Zefan else if (call_site < data->call_site) 138ba77c9e1SLi Zefan node = &(*node)->rb_left; 139ba77c9e1SLi Zefan else 140ba77c9e1SLi Zefan break; 141ba77c9e1SLi Zefan } 142ba77c9e1SLi Zefan 143ba77c9e1SLi Zefan if (data && data->call_site == call_site) { 144ba77c9e1SLi Zefan data->hit++; 145ba77c9e1SLi Zefan data->bytes_req += bytes_req; 1464efb5290SWenji Huang data->bytes_alloc += bytes_alloc; 147ba77c9e1SLi Zefan } else { 148ba77c9e1SLi Zefan data = malloc(sizeof(*data)); 1492814eb05SArnaldo Carvalho de Melo if (!data) { 1502814eb05SArnaldo Carvalho de Melo pr_err("%s: malloc failed\n", __func__); 1512814eb05SArnaldo Carvalho de Melo return -1; 1522814eb05SArnaldo Carvalho de Melo } 153ba77c9e1SLi Zefan data->call_site = call_site; 154079d3f65SLi Zefan data->pingpong = 0; 155ba77c9e1SLi Zefan data->hit = 1; 156ba77c9e1SLi Zefan data->bytes_req = bytes_req; 157ba77c9e1SLi Zefan data->bytes_alloc = bytes_alloc; 158ba77c9e1SLi Zefan 159ba77c9e1SLi Zefan rb_link_node(&data->node, parent, node); 160ba77c9e1SLi Zefan rb_insert_color(&data->node, &root_caller_stat); 161ba77c9e1SLi Zefan } 1622814eb05SArnaldo Carvalho de Melo 1632814eb05SArnaldo Carvalho de Melo return 0; 164ba77c9e1SLi Zefan } 165ba77c9e1SLi Zefan 1662814eb05SArnaldo Carvalho de Melo static int perf_evsel__process_alloc_event(struct perf_evsel *evsel, 1670f7d2f1bSArnaldo Carvalho de Melo struct perf_sample *sample) 168ba77c9e1SLi Zefan { 1690f7d2f1bSArnaldo Carvalho de Melo unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"), 1700f7d2f1bSArnaldo Carvalho de Melo call_site = perf_evsel__intval(evsel, sample, "call_site"); 1710f7d2f1bSArnaldo Carvalho de Melo int bytes_req = perf_evsel__intval(evsel, sample, "bytes_req"), 1720f7d2f1bSArnaldo Carvalho de Melo bytes_alloc = perf_evsel__intval(evsel, sample, "bytes_alloc"); 173ba77c9e1SLi Zefan 1740f7d2f1bSArnaldo Carvalho de Melo if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) || 1752814eb05SArnaldo Carvalho de Melo insert_caller_stat(call_site, bytes_req, bytes_alloc)) 1762814eb05SArnaldo Carvalho de Melo return -1; 177ba77c9e1SLi Zefan 178ba77c9e1SLi Zefan total_requested += bytes_req; 179ba77c9e1SLi Zefan total_allocated += bytes_alloc; 1807d0d3945SLi Zefan 1810f7d2f1bSArnaldo Carvalho de Melo nr_allocs++; 1820f7d2f1bSArnaldo Carvalho de Melo return 0; 1830f7d2f1bSArnaldo Carvalho de Melo } 1840f7d2f1bSArnaldo Carvalho de Melo 1850f7d2f1bSArnaldo Carvalho de Melo static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel, 1860f7d2f1bSArnaldo Carvalho de Melo struct perf_sample *sample) 1870f7d2f1bSArnaldo Carvalho de Melo { 1880f7d2f1bSArnaldo Carvalho de Melo int ret = perf_evsel__process_alloc_event(evsel, sample); 1890f7d2f1bSArnaldo Carvalho de Melo 1900f7d2f1bSArnaldo Carvalho de Melo if (!ret) { 1914b627957SDon Zickus int node1 = cpu__get_node(sample->cpu), 1920f7d2f1bSArnaldo Carvalho de Melo node2 = perf_evsel__intval(evsel, sample, "node"); 1930f7d2f1bSArnaldo Carvalho de Melo 1947d0d3945SLi Zefan if (node1 != node2) 1957d0d3945SLi Zefan nr_cross_allocs++; 1967d0d3945SLi Zefan } 1970f7d2f1bSArnaldo Carvalho de Melo 1980f7d2f1bSArnaldo Carvalho de Melo return ret; 199ba77c9e1SLi Zefan } 200ba77c9e1SLi Zefan 201fb4f313dSNamhyung Kim static int ptr_cmp(void *, void *); 202fb4f313dSNamhyung Kim static int slab_callsite_cmp(void *, void *); 203079d3f65SLi Zefan 204079d3f65SLi Zefan static struct alloc_stat *search_alloc_stat(unsigned long ptr, 205079d3f65SLi Zefan unsigned long call_site, 206079d3f65SLi Zefan struct rb_root *root, 207079d3f65SLi Zefan sort_fn_t sort_fn) 208079d3f65SLi Zefan { 209079d3f65SLi Zefan struct rb_node *node = root->rb_node; 210079d3f65SLi Zefan struct alloc_stat key = { .ptr = ptr, .call_site = call_site }; 211079d3f65SLi Zefan 212079d3f65SLi Zefan while (node) { 213079d3f65SLi Zefan struct alloc_stat *data; 214079d3f65SLi Zefan int cmp; 215079d3f65SLi Zefan 216079d3f65SLi Zefan data = rb_entry(node, struct alloc_stat, node); 217079d3f65SLi Zefan 218079d3f65SLi Zefan cmp = sort_fn(&key, data); 219079d3f65SLi Zefan if (cmp < 0) 220079d3f65SLi Zefan node = node->rb_left; 221079d3f65SLi Zefan else if (cmp > 0) 222079d3f65SLi Zefan node = node->rb_right; 223079d3f65SLi Zefan else 224079d3f65SLi Zefan return data; 225079d3f65SLi Zefan } 226079d3f65SLi Zefan return NULL; 227079d3f65SLi Zefan } 228079d3f65SLi Zefan 2292814eb05SArnaldo Carvalho de Melo static int perf_evsel__process_free_event(struct perf_evsel *evsel, 23022ad798cSArnaldo Carvalho de Melo struct perf_sample *sample) 231ba77c9e1SLi Zefan { 2320f7d2f1bSArnaldo Carvalho de Melo unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"); 233079d3f65SLi Zefan struct alloc_stat *s_alloc, *s_caller; 234079d3f65SLi Zefan 235079d3f65SLi Zefan s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); 236079d3f65SLi Zefan if (!s_alloc) 2372814eb05SArnaldo Carvalho de Melo return 0; 238079d3f65SLi Zefan 239aa58e9afSDavid Ahern total_freed += s_alloc->last_alloc; 240aa58e9afSDavid Ahern 24122ad798cSArnaldo Carvalho de Melo if ((short)sample->cpu != s_alloc->alloc_cpu) { 242079d3f65SLi Zefan s_alloc->pingpong++; 243079d3f65SLi Zefan 244079d3f65SLi Zefan s_caller = search_alloc_stat(0, s_alloc->call_site, 245fb4f313dSNamhyung Kim &root_caller_stat, 246fb4f313dSNamhyung Kim slab_callsite_cmp); 2472814eb05SArnaldo Carvalho de Melo if (!s_caller) 2482814eb05SArnaldo Carvalho de Melo return -1; 249079d3f65SLi Zefan s_caller->pingpong++; 250079d3f65SLi Zefan } 251079d3f65SLi Zefan s_alloc->alloc_cpu = -1; 2522814eb05SArnaldo Carvalho de Melo 2532814eb05SArnaldo Carvalho de Melo return 0; 254ba77c9e1SLi Zefan } 255ba77c9e1SLi Zefan 2560d68bc92SNamhyung Kim static u64 total_page_alloc_bytes; 2570d68bc92SNamhyung Kim static u64 total_page_free_bytes; 2580d68bc92SNamhyung Kim static u64 total_page_nomatch_bytes; 2590d68bc92SNamhyung Kim static u64 total_page_fail_bytes; 2600d68bc92SNamhyung Kim static unsigned long nr_page_allocs; 2610d68bc92SNamhyung Kim static unsigned long nr_page_frees; 2620d68bc92SNamhyung Kim static unsigned long nr_page_fails; 2630d68bc92SNamhyung Kim static unsigned long nr_page_nomatch; 2640d68bc92SNamhyung Kim 2650d68bc92SNamhyung Kim static bool use_pfn; 2662a7ef02cSNamhyung Kim static bool live_page; 267c9758cc4SNamhyung Kim static struct perf_session *kmem_session; 2680d68bc92SNamhyung Kim 2690d68bc92SNamhyung Kim #define MAX_MIGRATE_TYPES 6 2700d68bc92SNamhyung Kim #define MAX_PAGE_ORDER 11 2710d68bc92SNamhyung Kim 2720d68bc92SNamhyung Kim static int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES]; 2730d68bc92SNamhyung Kim 2740d68bc92SNamhyung Kim struct page_stat { 2750d68bc92SNamhyung Kim struct rb_node node; 2760d68bc92SNamhyung Kim u64 page; 277c9758cc4SNamhyung Kim u64 callsite; 2780d68bc92SNamhyung Kim int order; 2790d68bc92SNamhyung Kim unsigned gfp_flags; 2800d68bc92SNamhyung Kim unsigned migrate_type; 2810d68bc92SNamhyung Kim u64 alloc_bytes; 2820d68bc92SNamhyung Kim u64 free_bytes; 2830d68bc92SNamhyung Kim int nr_alloc; 2840d68bc92SNamhyung Kim int nr_free; 2850d68bc92SNamhyung Kim }; 2860d68bc92SNamhyung Kim 2872a7ef02cSNamhyung Kim static struct rb_root page_live_tree; 2880d68bc92SNamhyung Kim static struct rb_root page_alloc_tree; 2890d68bc92SNamhyung Kim static struct rb_root page_alloc_sorted; 290c9758cc4SNamhyung Kim static struct rb_root page_caller_tree; 291c9758cc4SNamhyung Kim static struct rb_root page_caller_sorted; 2920d68bc92SNamhyung Kim 293c9758cc4SNamhyung Kim struct alloc_func { 294c9758cc4SNamhyung Kim u64 start; 295c9758cc4SNamhyung Kim u64 end; 296c9758cc4SNamhyung Kim char *name; 297c9758cc4SNamhyung Kim }; 298c9758cc4SNamhyung Kim 299c9758cc4SNamhyung Kim static int nr_alloc_funcs; 300c9758cc4SNamhyung Kim static struct alloc_func *alloc_func_list; 301c9758cc4SNamhyung Kim 302c9758cc4SNamhyung Kim static int funcmp(const void *a, const void *b) 303c9758cc4SNamhyung Kim { 304c9758cc4SNamhyung Kim const struct alloc_func *fa = a; 305c9758cc4SNamhyung Kim const struct alloc_func *fb = b; 306c9758cc4SNamhyung Kim 307c9758cc4SNamhyung Kim if (fa->start > fb->start) 308c9758cc4SNamhyung Kim return 1; 309c9758cc4SNamhyung Kim else 310c9758cc4SNamhyung Kim return -1; 311c9758cc4SNamhyung Kim } 312c9758cc4SNamhyung Kim 313c9758cc4SNamhyung Kim static int callcmp(const void *a, const void *b) 314c9758cc4SNamhyung Kim { 315c9758cc4SNamhyung Kim const struct alloc_func *fa = a; 316c9758cc4SNamhyung Kim const struct alloc_func *fb = b; 317c9758cc4SNamhyung Kim 318c9758cc4SNamhyung Kim if (fb->start <= fa->start && fa->end < fb->end) 319c9758cc4SNamhyung Kim return 0; 320c9758cc4SNamhyung Kim 321c9758cc4SNamhyung Kim if (fa->start > fb->start) 322c9758cc4SNamhyung Kim return 1; 323c9758cc4SNamhyung Kim else 324c9758cc4SNamhyung Kim return -1; 325c9758cc4SNamhyung Kim } 326c9758cc4SNamhyung Kim 327c9758cc4SNamhyung Kim static int build_alloc_func_list(void) 328c9758cc4SNamhyung Kim { 329c9758cc4SNamhyung Kim int ret; 330c9758cc4SNamhyung Kim struct map *kernel_map; 331c9758cc4SNamhyung Kim struct symbol *sym; 332c9758cc4SNamhyung Kim struct rb_node *node; 333c9758cc4SNamhyung Kim struct alloc_func *func; 334c9758cc4SNamhyung Kim struct machine *machine = &kmem_session->machines.host; 335c9758cc4SNamhyung Kim regex_t alloc_func_regex; 336c9758cc4SNamhyung Kim const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?"; 337c9758cc4SNamhyung Kim 338c9758cc4SNamhyung Kim ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED); 339c9758cc4SNamhyung Kim if (ret) { 340c9758cc4SNamhyung Kim char err[BUFSIZ]; 341c9758cc4SNamhyung Kim 342c9758cc4SNamhyung Kim regerror(ret, &alloc_func_regex, err, sizeof(err)); 343c9758cc4SNamhyung Kim pr_err("Invalid regex: %s\n%s", pattern, err); 344c9758cc4SNamhyung Kim return -EINVAL; 345c9758cc4SNamhyung Kim } 346c9758cc4SNamhyung Kim 347a5e813c6SArnaldo Carvalho de Melo kernel_map = machine__kernel_map(machine); 348be39db9fSArnaldo Carvalho de Melo if (map__load(kernel_map) < 0) { 349c9758cc4SNamhyung Kim pr_err("cannot load kernel map\n"); 350c9758cc4SNamhyung Kim return -ENOENT; 351c9758cc4SNamhyung Kim } 352c9758cc4SNamhyung Kim 353c9758cc4SNamhyung Kim map__for_each_symbol(kernel_map, sym, node) { 354c9758cc4SNamhyung Kim if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0)) 355c9758cc4SNamhyung Kim continue; 356c9758cc4SNamhyung Kim 357c9758cc4SNamhyung Kim func = realloc(alloc_func_list, 358c9758cc4SNamhyung Kim (nr_alloc_funcs + 1) * sizeof(*func)); 359c9758cc4SNamhyung Kim if (func == NULL) 360c9758cc4SNamhyung Kim return -ENOMEM; 361c9758cc4SNamhyung Kim 362c9758cc4SNamhyung Kim pr_debug("alloc func: %s\n", sym->name); 363c9758cc4SNamhyung Kim func[nr_alloc_funcs].start = sym->start; 364c9758cc4SNamhyung Kim func[nr_alloc_funcs].end = sym->end; 365c9758cc4SNamhyung Kim func[nr_alloc_funcs].name = sym->name; 366c9758cc4SNamhyung Kim 367c9758cc4SNamhyung Kim alloc_func_list = func; 368c9758cc4SNamhyung Kim nr_alloc_funcs++; 369c9758cc4SNamhyung Kim } 370c9758cc4SNamhyung Kim 371c9758cc4SNamhyung Kim qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp); 372c9758cc4SNamhyung Kim 373c9758cc4SNamhyung Kim regfree(&alloc_func_regex); 374c9758cc4SNamhyung Kim return 0; 375c9758cc4SNamhyung Kim } 376c9758cc4SNamhyung Kim 377c9758cc4SNamhyung Kim /* 378c9758cc4SNamhyung Kim * Find first non-memory allocation function from callchain. 379c9758cc4SNamhyung Kim * The allocation functions are in the 'alloc_func_list'. 380c9758cc4SNamhyung Kim */ 381c9758cc4SNamhyung Kim static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample) 382c9758cc4SNamhyung Kim { 383c9758cc4SNamhyung Kim struct addr_location al; 384c9758cc4SNamhyung Kim struct machine *machine = &kmem_session->machines.host; 385c9758cc4SNamhyung Kim struct callchain_cursor_node *node; 386c9758cc4SNamhyung Kim 387c9758cc4SNamhyung Kim if (alloc_func_list == NULL) { 388c9758cc4SNamhyung Kim if (build_alloc_func_list() < 0) 389c9758cc4SNamhyung Kim goto out; 390c9758cc4SNamhyung Kim } 391c9758cc4SNamhyung Kim 392c9758cc4SNamhyung Kim al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); 39391d7b2deSArnaldo Carvalho de Melo sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16); 394c9758cc4SNamhyung Kim 395c9758cc4SNamhyung Kim callchain_cursor_commit(&callchain_cursor); 396c9758cc4SNamhyung Kim while (true) { 397c9758cc4SNamhyung Kim struct alloc_func key, *caller; 398c9758cc4SNamhyung Kim u64 addr; 399c9758cc4SNamhyung Kim 400c9758cc4SNamhyung Kim node = callchain_cursor_current(&callchain_cursor); 401c9758cc4SNamhyung Kim if (node == NULL) 402c9758cc4SNamhyung Kim break; 403c9758cc4SNamhyung Kim 404c9758cc4SNamhyung Kim key.start = key.end = node->ip; 405c9758cc4SNamhyung Kim caller = bsearch(&key, alloc_func_list, nr_alloc_funcs, 406c9758cc4SNamhyung Kim sizeof(key), callcmp); 407c9758cc4SNamhyung Kim if (!caller) { 408c9758cc4SNamhyung Kim /* found */ 409c9758cc4SNamhyung Kim if (node->map) 410c9758cc4SNamhyung Kim addr = map__unmap_ip(node->map, node->ip); 411c9758cc4SNamhyung Kim else 412c9758cc4SNamhyung Kim addr = node->ip; 413c9758cc4SNamhyung Kim 414c9758cc4SNamhyung Kim return addr; 415c9758cc4SNamhyung Kim } else 416c9758cc4SNamhyung Kim pr_debug3("skipping alloc function: %s\n", caller->name); 417c9758cc4SNamhyung Kim 418c9758cc4SNamhyung Kim callchain_cursor_advance(&callchain_cursor); 419c9758cc4SNamhyung Kim } 420c9758cc4SNamhyung Kim 421c9758cc4SNamhyung Kim out: 422c9758cc4SNamhyung Kim pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip); 423c9758cc4SNamhyung Kim return sample->ip; 424c9758cc4SNamhyung Kim } 425c9758cc4SNamhyung Kim 4262a7ef02cSNamhyung Kim struct sort_dimension { 4272a7ef02cSNamhyung Kim const char name[20]; 4282a7ef02cSNamhyung Kim sort_fn_t cmp; 4292a7ef02cSNamhyung Kim struct list_head list; 4302a7ef02cSNamhyung Kim }; 4312a7ef02cSNamhyung Kim 4322a7ef02cSNamhyung Kim static LIST_HEAD(page_alloc_sort_input); 4332a7ef02cSNamhyung Kim static LIST_HEAD(page_caller_sort_input); 4342a7ef02cSNamhyung Kim 435c9758cc4SNamhyung Kim static struct page_stat * 4362a7ef02cSNamhyung Kim __page_stat__findnew_page(struct page_stat *pstat, bool create) 4370d68bc92SNamhyung Kim { 4382a7ef02cSNamhyung Kim struct rb_node **node = &page_live_tree.rb_node; 4390d68bc92SNamhyung Kim struct rb_node *parent = NULL; 4400d68bc92SNamhyung Kim struct page_stat *data; 4410d68bc92SNamhyung Kim 4420d68bc92SNamhyung Kim while (*node) { 4430d68bc92SNamhyung Kim s64 cmp; 4440d68bc92SNamhyung Kim 4450d68bc92SNamhyung Kim parent = *node; 4460d68bc92SNamhyung Kim data = rb_entry(*node, struct page_stat, node); 4470d68bc92SNamhyung Kim 4482a7ef02cSNamhyung Kim cmp = data->page - pstat->page; 4490d68bc92SNamhyung Kim if (cmp < 0) 4500d68bc92SNamhyung Kim node = &parent->rb_left; 4510d68bc92SNamhyung Kim else if (cmp > 0) 4520d68bc92SNamhyung Kim node = &parent->rb_right; 4530d68bc92SNamhyung Kim else 4540d68bc92SNamhyung Kim return data; 4550d68bc92SNamhyung Kim } 4560d68bc92SNamhyung Kim 4570d68bc92SNamhyung Kim if (!create) 4580d68bc92SNamhyung Kim return NULL; 4590d68bc92SNamhyung Kim 4600d68bc92SNamhyung Kim data = zalloc(sizeof(*data)); 4610d68bc92SNamhyung Kim if (data != NULL) { 4622a7ef02cSNamhyung Kim data->page = pstat->page; 4632a7ef02cSNamhyung Kim data->order = pstat->order; 4642a7ef02cSNamhyung Kim data->gfp_flags = pstat->gfp_flags; 4652a7ef02cSNamhyung Kim data->migrate_type = pstat->migrate_type; 4660d68bc92SNamhyung Kim 4670d68bc92SNamhyung Kim rb_link_node(&data->node, parent, node); 4682a7ef02cSNamhyung Kim rb_insert_color(&data->node, &page_live_tree); 4690d68bc92SNamhyung Kim } 4700d68bc92SNamhyung Kim 4710d68bc92SNamhyung Kim return data; 4720d68bc92SNamhyung Kim } 4730d68bc92SNamhyung Kim 4742a7ef02cSNamhyung Kim static struct page_stat *page_stat__find_page(struct page_stat *pstat) 475c9758cc4SNamhyung Kim { 4762a7ef02cSNamhyung Kim return __page_stat__findnew_page(pstat, false); 477c9758cc4SNamhyung Kim } 478c9758cc4SNamhyung Kim 4792a7ef02cSNamhyung Kim static struct page_stat *page_stat__findnew_page(struct page_stat *pstat) 480c9758cc4SNamhyung Kim { 4812a7ef02cSNamhyung Kim return __page_stat__findnew_page(pstat, true); 482c9758cc4SNamhyung Kim } 483c9758cc4SNamhyung Kim 484c9758cc4SNamhyung Kim static struct page_stat * 485c9758cc4SNamhyung Kim __page_stat__findnew_alloc(struct page_stat *pstat, bool create) 4860d68bc92SNamhyung Kim { 4870d68bc92SNamhyung Kim struct rb_node **node = &page_alloc_tree.rb_node; 4880d68bc92SNamhyung Kim struct rb_node *parent = NULL; 4890d68bc92SNamhyung Kim struct page_stat *data; 490fb4f313dSNamhyung Kim struct sort_dimension *sort; 4910d68bc92SNamhyung Kim 4920d68bc92SNamhyung Kim while (*node) { 493fb4f313dSNamhyung Kim int cmp = 0; 4940d68bc92SNamhyung Kim 4950d68bc92SNamhyung Kim parent = *node; 4960d68bc92SNamhyung Kim data = rb_entry(*node, struct page_stat, node); 4970d68bc92SNamhyung Kim 498fb4f313dSNamhyung Kim list_for_each_entry(sort, &page_alloc_sort_input, list) { 499fb4f313dSNamhyung Kim cmp = sort->cmp(pstat, data); 500fb4f313dSNamhyung Kim if (cmp) 501fb4f313dSNamhyung Kim break; 502fb4f313dSNamhyung Kim } 503fb4f313dSNamhyung Kim 5040d68bc92SNamhyung Kim if (cmp < 0) 5050d68bc92SNamhyung Kim node = &parent->rb_left; 5060d68bc92SNamhyung Kim else if (cmp > 0) 5070d68bc92SNamhyung Kim node = &parent->rb_right; 5080d68bc92SNamhyung Kim else 5090d68bc92SNamhyung Kim return data; 5100d68bc92SNamhyung Kim } 5110d68bc92SNamhyung Kim 5120d68bc92SNamhyung Kim if (!create) 5130d68bc92SNamhyung Kim return NULL; 5140d68bc92SNamhyung Kim 5150d68bc92SNamhyung Kim data = zalloc(sizeof(*data)); 5160d68bc92SNamhyung Kim if (data != NULL) { 5176b1a2752SDavid Ahern data->page = pstat->page; 5186b1a2752SDavid Ahern data->order = pstat->order; 5196b1a2752SDavid Ahern data->gfp_flags = pstat->gfp_flags; 5206b1a2752SDavid Ahern data->migrate_type = pstat->migrate_type; 5210d68bc92SNamhyung Kim 5220d68bc92SNamhyung Kim rb_link_node(&data->node, parent, node); 5230d68bc92SNamhyung Kim rb_insert_color(&data->node, &page_alloc_tree); 5240d68bc92SNamhyung Kim } 5250d68bc92SNamhyung Kim 5260d68bc92SNamhyung Kim return data; 5270d68bc92SNamhyung Kim } 5280d68bc92SNamhyung Kim 529c9758cc4SNamhyung Kim static struct page_stat *page_stat__find_alloc(struct page_stat *pstat) 530c9758cc4SNamhyung Kim { 531c9758cc4SNamhyung Kim return __page_stat__findnew_alloc(pstat, false); 532c9758cc4SNamhyung Kim } 533c9758cc4SNamhyung Kim 534c9758cc4SNamhyung Kim static struct page_stat *page_stat__findnew_alloc(struct page_stat *pstat) 535c9758cc4SNamhyung Kim { 536c9758cc4SNamhyung Kim return __page_stat__findnew_alloc(pstat, true); 537c9758cc4SNamhyung Kim } 538c9758cc4SNamhyung Kim 539c9758cc4SNamhyung Kim static struct page_stat * 540fb4f313dSNamhyung Kim __page_stat__findnew_caller(struct page_stat *pstat, bool create) 541c9758cc4SNamhyung Kim { 542c9758cc4SNamhyung Kim struct rb_node **node = &page_caller_tree.rb_node; 543c9758cc4SNamhyung Kim struct rb_node *parent = NULL; 544c9758cc4SNamhyung Kim struct page_stat *data; 545fb4f313dSNamhyung Kim struct sort_dimension *sort; 546c9758cc4SNamhyung Kim 547c9758cc4SNamhyung Kim while (*node) { 548fb4f313dSNamhyung Kim int cmp = 0; 549c9758cc4SNamhyung Kim 550c9758cc4SNamhyung Kim parent = *node; 551c9758cc4SNamhyung Kim data = rb_entry(*node, struct page_stat, node); 552c9758cc4SNamhyung Kim 553fb4f313dSNamhyung Kim list_for_each_entry(sort, &page_caller_sort_input, list) { 554fb4f313dSNamhyung Kim cmp = sort->cmp(pstat, data); 555fb4f313dSNamhyung Kim if (cmp) 556fb4f313dSNamhyung Kim break; 557fb4f313dSNamhyung Kim } 558fb4f313dSNamhyung Kim 559c9758cc4SNamhyung Kim if (cmp < 0) 560c9758cc4SNamhyung Kim node = &parent->rb_left; 561c9758cc4SNamhyung Kim else if (cmp > 0) 562c9758cc4SNamhyung Kim node = &parent->rb_right; 563c9758cc4SNamhyung Kim else 564c9758cc4SNamhyung Kim return data; 565c9758cc4SNamhyung Kim } 566c9758cc4SNamhyung Kim 567c9758cc4SNamhyung Kim if (!create) 568c9758cc4SNamhyung Kim return NULL; 569c9758cc4SNamhyung Kim 570c9758cc4SNamhyung Kim data = zalloc(sizeof(*data)); 571c9758cc4SNamhyung Kim if (data != NULL) { 572fb4f313dSNamhyung Kim data->callsite = pstat->callsite; 573fb4f313dSNamhyung Kim data->order = pstat->order; 574fb4f313dSNamhyung Kim data->gfp_flags = pstat->gfp_flags; 575fb4f313dSNamhyung Kim data->migrate_type = pstat->migrate_type; 576c9758cc4SNamhyung Kim 577c9758cc4SNamhyung Kim rb_link_node(&data->node, parent, node); 578c9758cc4SNamhyung Kim rb_insert_color(&data->node, &page_caller_tree); 579c9758cc4SNamhyung Kim } 580c9758cc4SNamhyung Kim 581c9758cc4SNamhyung Kim return data; 582c9758cc4SNamhyung Kim } 583c9758cc4SNamhyung Kim 584fb4f313dSNamhyung Kim static struct page_stat *page_stat__find_caller(struct page_stat *pstat) 585c9758cc4SNamhyung Kim { 586fb4f313dSNamhyung Kim return __page_stat__findnew_caller(pstat, false); 587c9758cc4SNamhyung Kim } 588c9758cc4SNamhyung Kim 589fb4f313dSNamhyung Kim static struct page_stat *page_stat__findnew_caller(struct page_stat *pstat) 590c9758cc4SNamhyung Kim { 591fb4f313dSNamhyung Kim return __page_stat__findnew_caller(pstat, true); 592c9758cc4SNamhyung Kim } 593c9758cc4SNamhyung Kim 5940d68bc92SNamhyung Kim static bool valid_page(u64 pfn_or_page) 5950d68bc92SNamhyung Kim { 5960d68bc92SNamhyung Kim if (use_pfn && pfn_or_page == -1UL) 5970d68bc92SNamhyung Kim return false; 5980d68bc92SNamhyung Kim if (!use_pfn && pfn_or_page == 0) 5990d68bc92SNamhyung Kim return false; 6000d68bc92SNamhyung Kim return true; 6010d68bc92SNamhyung Kim } 6020d68bc92SNamhyung Kim 6030e111156SNamhyung Kim struct gfp_flag { 6040e111156SNamhyung Kim unsigned int flags; 6050e111156SNamhyung Kim char *compact_str; 6060e111156SNamhyung Kim char *human_readable; 6070e111156SNamhyung Kim }; 6080e111156SNamhyung Kim 6090e111156SNamhyung Kim static struct gfp_flag *gfps; 6100e111156SNamhyung Kim static int nr_gfps; 6110e111156SNamhyung Kim 6120e111156SNamhyung Kim static int gfpcmp(const void *a, const void *b) 6130e111156SNamhyung Kim { 6140e111156SNamhyung Kim const struct gfp_flag *fa = a; 6150e111156SNamhyung Kim const struct gfp_flag *fb = b; 6160e111156SNamhyung Kim 6170e111156SNamhyung Kim return fa->flags - fb->flags; 6180e111156SNamhyung Kim } 6190e111156SNamhyung Kim 620420adbe9SVlastimil Babka /* see include/trace/events/mmflags.h */ 6210e111156SNamhyung Kim static const struct { 6220e111156SNamhyung Kim const char *original; 6230e111156SNamhyung Kim const char *compact; 6240e111156SNamhyung Kim } gfp_compact_table[] = { 6250e111156SNamhyung Kim { "GFP_TRANSHUGE", "THP" }, 62625160354SVlastimil Babka { "GFP_TRANSHUGE_LIGHT", "THL" }, 6270e111156SNamhyung Kim { "GFP_HIGHUSER_MOVABLE", "HUM" }, 6280e111156SNamhyung Kim { "GFP_HIGHUSER", "HU" }, 6290e111156SNamhyung Kim { "GFP_USER", "U" }, 6300e111156SNamhyung Kim { "GFP_TEMPORARY", "TMP" }, 63114e0a214SVlastimil Babka { "GFP_KERNEL_ACCOUNT", "KAC" }, 6320e111156SNamhyung Kim { "GFP_KERNEL", "K" }, 6330e111156SNamhyung Kim { "GFP_NOFS", "NF" }, 6340e111156SNamhyung Kim { "GFP_ATOMIC", "A" }, 6350e111156SNamhyung Kim { "GFP_NOIO", "NI" }, 6360e111156SNamhyung Kim { "GFP_NOWAIT", "NW" }, 63714e0a214SVlastimil Babka { "GFP_DMA", "D" }, 63814e0a214SVlastimil Babka { "__GFP_HIGHMEM", "HM" }, 63914e0a214SVlastimil Babka { "GFP_DMA32", "D32" }, 64014e0a214SVlastimil Babka { "__GFP_HIGH", "H" }, 64114e0a214SVlastimil Babka { "__GFP_ATOMIC", "_A" }, 64214e0a214SVlastimil Babka { "__GFP_IO", "I" }, 64314e0a214SVlastimil Babka { "__GFP_FS", "F" }, 64414e0a214SVlastimil Babka { "__GFP_COLD", "CO" }, 64514e0a214SVlastimil Babka { "__GFP_NOWARN", "NWR" }, 646*dcda9b04SMichal Hocko { "__GFP_RETRY_MAYFAIL", "R" }, 64714e0a214SVlastimil Babka { "__GFP_NOFAIL", "NF" }, 64814e0a214SVlastimil Babka { "__GFP_NORETRY", "NR" }, 64914e0a214SVlastimil Babka { "__GFP_COMP", "C" }, 65014e0a214SVlastimil Babka { "__GFP_ZERO", "Z" }, 65114e0a214SVlastimil Babka { "__GFP_NOMEMALLOC", "NMA" }, 65214e0a214SVlastimil Babka { "__GFP_MEMALLOC", "MA" }, 65314e0a214SVlastimil Babka { "__GFP_HARDWALL", "HW" }, 65414e0a214SVlastimil Babka { "__GFP_THISNODE", "TN" }, 65514e0a214SVlastimil Babka { "__GFP_RECLAIMABLE", "RC" }, 65614e0a214SVlastimil Babka { "__GFP_MOVABLE", "M" }, 65714e0a214SVlastimil Babka { "__GFP_ACCOUNT", "AC" }, 65814e0a214SVlastimil Babka { "__GFP_NOTRACK", "NT" }, 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); 6910e111156SNamhyung Kim return NULL; 6920e111156SNamhyung Kim } 6930e111156SNamhyung Kim 6940e111156SNamhyung Kim new_flags = new; 6950e111156SNamhyung Kim 6960e111156SNamhyung Kim if (!len) { 6970e111156SNamhyung Kim strcpy(new_flags, cpt); 6980e111156SNamhyung Kim } else { 6990e111156SNamhyung Kim strcat(new_flags, "|"); 7000e111156SNamhyung Kim strcat(new_flags, cpt); 7010e111156SNamhyung Kim len++; 7020e111156SNamhyung Kim } 7030e111156SNamhyung Kim 7040e111156SNamhyung Kim len += strlen(cpt); 7050e111156SNamhyung Kim } 7060e111156SNamhyung Kim 7070e111156SNamhyung Kim str = strtok_r(NULL, "|", &pos); 7080e111156SNamhyung Kim } 7090e111156SNamhyung Kim 7100e111156SNamhyung Kim if (max_gfp_len < len) 7110e111156SNamhyung Kim max_gfp_len = len; 7120e111156SNamhyung Kim 7130e111156SNamhyung Kim free(orig_flags); 7140e111156SNamhyung Kim return new_flags; 7150e111156SNamhyung Kim } 7160e111156SNamhyung Kim 7170e111156SNamhyung Kim static char *compact_gfp_string(unsigned long gfp_flags) 7180e111156SNamhyung Kim { 7190e111156SNamhyung Kim struct gfp_flag key = { 7200e111156SNamhyung Kim .flags = gfp_flags, 7210e111156SNamhyung Kim }; 7220e111156SNamhyung Kim struct gfp_flag *gfp; 7230e111156SNamhyung Kim 7240e111156SNamhyung Kim gfp = bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp); 7250e111156SNamhyung Kim if (gfp) 7260e111156SNamhyung Kim return gfp->compact_str; 7270e111156SNamhyung Kim 7280e111156SNamhyung Kim return NULL; 7290e111156SNamhyung Kim } 7300e111156SNamhyung Kim 7310e111156SNamhyung Kim static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, 7320e111156SNamhyung Kim unsigned int gfp_flags) 7330e111156SNamhyung Kim { 7340e111156SNamhyung Kim struct pevent_record record = { 7350e111156SNamhyung Kim .cpu = sample->cpu, 7360e111156SNamhyung Kim .data = sample->raw_data, 7370e111156SNamhyung Kim .size = sample->raw_size, 7380e111156SNamhyung Kim }; 7390e111156SNamhyung Kim struct trace_seq seq; 74008a9b985SArnaldo Carvalho de Melo char *str, *pos = NULL; 7410e111156SNamhyung Kim 7420e111156SNamhyung Kim if (nr_gfps) { 7430e111156SNamhyung Kim struct gfp_flag key = { 7440e111156SNamhyung Kim .flags = gfp_flags, 7450e111156SNamhyung Kim }; 7460e111156SNamhyung Kim 7470e111156SNamhyung Kim if (bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp)) 7480e111156SNamhyung Kim return 0; 7490e111156SNamhyung Kim } 7500e111156SNamhyung Kim 7510e111156SNamhyung Kim trace_seq_init(&seq); 7520e111156SNamhyung Kim pevent_event_info(&seq, evsel->tp_format, &record); 7530e111156SNamhyung Kim 7540e111156SNamhyung Kim str = strtok_r(seq.buffer, " ", &pos); 7550e111156SNamhyung Kim while (str) { 7560e111156SNamhyung Kim if (!strncmp(str, "gfp_flags=", 10)) { 7570e111156SNamhyung Kim struct gfp_flag *new; 7580e111156SNamhyung Kim 7590e111156SNamhyung Kim new = realloc(gfps, (nr_gfps + 1) * sizeof(*gfps)); 7600e111156SNamhyung Kim if (new == NULL) 7610e111156SNamhyung Kim return -ENOMEM; 7620e111156SNamhyung Kim 7630e111156SNamhyung Kim gfps = new; 7640e111156SNamhyung Kim new += nr_gfps++; 7650e111156SNamhyung Kim 7660e111156SNamhyung Kim new->flags = gfp_flags; 7670e111156SNamhyung Kim new->human_readable = strdup(str + 10); 7680e111156SNamhyung Kim new->compact_str = compact_gfp_flags(str + 10); 7690e111156SNamhyung Kim if (!new->human_readable || !new->compact_str) 7700e111156SNamhyung Kim return -ENOMEM; 7710e111156SNamhyung Kim 7720e111156SNamhyung Kim qsort(gfps, nr_gfps, sizeof(*gfps), gfpcmp); 7730e111156SNamhyung Kim } 7740e111156SNamhyung Kim 7750e111156SNamhyung Kim str = strtok_r(NULL, " ", &pos); 7760e111156SNamhyung Kim } 7770e111156SNamhyung Kim 7780e111156SNamhyung Kim trace_seq_destroy(&seq); 7790e111156SNamhyung Kim return 0; 7800e111156SNamhyung Kim } 7810e111156SNamhyung Kim 7820d68bc92SNamhyung Kim static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel, 7830d68bc92SNamhyung Kim struct perf_sample *sample) 7840d68bc92SNamhyung Kim { 7850d68bc92SNamhyung Kim u64 page; 7860d68bc92SNamhyung Kim unsigned int order = perf_evsel__intval(evsel, sample, "order"); 7870d68bc92SNamhyung Kim unsigned int gfp_flags = perf_evsel__intval(evsel, sample, "gfp_flags"); 7880d68bc92SNamhyung Kim unsigned int migrate_type = perf_evsel__intval(evsel, sample, 7890d68bc92SNamhyung Kim "migratetype"); 7900d68bc92SNamhyung Kim u64 bytes = kmem_page_size << order; 791c9758cc4SNamhyung Kim u64 callsite; 7926b1a2752SDavid Ahern struct page_stat *pstat; 7930d68bc92SNamhyung Kim struct page_stat this = { 7940d68bc92SNamhyung Kim .order = order, 7950d68bc92SNamhyung Kim .gfp_flags = gfp_flags, 7960d68bc92SNamhyung Kim .migrate_type = migrate_type, 7970d68bc92SNamhyung Kim }; 7980d68bc92SNamhyung Kim 7990d68bc92SNamhyung Kim if (use_pfn) 8000d68bc92SNamhyung Kim page = perf_evsel__intval(evsel, sample, "pfn"); 8010d68bc92SNamhyung Kim else 8020d68bc92SNamhyung Kim page = perf_evsel__intval(evsel, sample, "page"); 8030d68bc92SNamhyung Kim 8040d68bc92SNamhyung Kim nr_page_allocs++; 8050d68bc92SNamhyung Kim total_page_alloc_bytes += bytes; 8060d68bc92SNamhyung Kim 8070d68bc92SNamhyung Kim if (!valid_page(page)) { 8080d68bc92SNamhyung Kim nr_page_fails++; 8090d68bc92SNamhyung Kim total_page_fail_bytes += bytes; 8100d68bc92SNamhyung Kim 8110d68bc92SNamhyung Kim return 0; 8120d68bc92SNamhyung Kim } 8130d68bc92SNamhyung Kim 8140e111156SNamhyung Kim if (parse_gfp_flags(evsel, sample, gfp_flags) < 0) 8150e111156SNamhyung Kim return -1; 8160e111156SNamhyung Kim 817c9758cc4SNamhyung Kim callsite = find_callsite(evsel, sample); 818c9758cc4SNamhyung Kim 8190d68bc92SNamhyung Kim /* 8200d68bc92SNamhyung Kim * This is to find the current page (with correct gfp flags and 8210d68bc92SNamhyung Kim * migrate type) at free event. 8220d68bc92SNamhyung Kim */ 8232a7ef02cSNamhyung Kim this.page = page; 8242a7ef02cSNamhyung Kim pstat = page_stat__findnew_page(&this); 8256b1a2752SDavid Ahern if (pstat == NULL) 8260d68bc92SNamhyung Kim return -ENOMEM; 8270d68bc92SNamhyung Kim 8282a7ef02cSNamhyung Kim pstat->nr_alloc++; 8292a7ef02cSNamhyung Kim pstat->alloc_bytes += bytes; 830c9758cc4SNamhyung Kim pstat->callsite = callsite; 8310d68bc92SNamhyung Kim 8322a7ef02cSNamhyung Kim if (!live_page) { 833c9758cc4SNamhyung Kim pstat = page_stat__findnew_alloc(&this); 8346b1a2752SDavid Ahern if (pstat == NULL) 8350d68bc92SNamhyung Kim return -ENOMEM; 8360d68bc92SNamhyung Kim 8376b1a2752SDavid Ahern pstat->nr_alloc++; 8386b1a2752SDavid Ahern pstat->alloc_bytes += bytes; 839c9758cc4SNamhyung Kim pstat->callsite = callsite; 8402a7ef02cSNamhyung Kim } 841c9758cc4SNamhyung Kim 842fb4f313dSNamhyung Kim this.callsite = callsite; 843fb4f313dSNamhyung Kim pstat = page_stat__findnew_caller(&this); 844c9758cc4SNamhyung Kim if (pstat == NULL) 845c9758cc4SNamhyung Kim return -ENOMEM; 846c9758cc4SNamhyung Kim 847c9758cc4SNamhyung Kim pstat->nr_alloc++; 848c9758cc4SNamhyung Kim pstat->alloc_bytes += bytes; 8490d68bc92SNamhyung Kim 8500d68bc92SNamhyung Kim order_stats[order][migrate_type]++; 8510d68bc92SNamhyung Kim 8520d68bc92SNamhyung Kim return 0; 8530d68bc92SNamhyung Kim } 8540d68bc92SNamhyung Kim 8550d68bc92SNamhyung Kim static int perf_evsel__process_page_free_event(struct perf_evsel *evsel, 8560d68bc92SNamhyung Kim struct perf_sample *sample) 8570d68bc92SNamhyung Kim { 8580d68bc92SNamhyung Kim u64 page; 8590d68bc92SNamhyung Kim unsigned int order = perf_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) 8670d68bc92SNamhyung Kim page = perf_evsel__intval(evsel, sample, "pfn"); 8680d68bc92SNamhyung Kim else 8690d68bc92SNamhyung Kim page = perf_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 9330f7d2f1bSArnaldo Carvalho de Melo typedef int (*tracepoint_handler)(struct perf_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, 939fcf65bf1SArnaldo Carvalho de Melo struct perf_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) 1009be39db9fSArnaldo Carvalho de Melo sym = machine__find_kernel_function(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); 1073be39db9fSArnaldo Carvalho de Melo sym = machine__find_kernel_function(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); 1115be39db9fSArnaldo Carvalho de Melo sym = machine__find_kernel_function(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; 13660d68bc92SNamhyung Kim struct perf_evsel *evsel; 13670f7d2f1bSArnaldo Carvalho de Melo const struct perf_evsel_str_handler kmem_tracepoints[] = { 13680d68bc92SNamhyung Kim /* slab allocator */ 13690f7d2f1bSArnaldo Carvalho de Melo { "kmem:kmalloc", perf_evsel__process_alloc_event, }, 13700f7d2f1bSArnaldo Carvalho de Melo { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, }, 13710f7d2f1bSArnaldo Carvalho de Melo { "kmem:kmalloc_node", perf_evsel__process_alloc_node_event, }, 13720f7d2f1bSArnaldo Carvalho de Melo { "kmem:kmem_cache_alloc_node", perf_evsel__process_alloc_node_event, }, 13730f7d2f1bSArnaldo Carvalho de Melo { "kmem:kfree", perf_evsel__process_free_event, }, 13740f7d2f1bSArnaldo Carvalho de Melo { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, 13750d68bc92SNamhyung Kim /* page allocator */ 13760d68bc92SNamhyung Kim { "kmem:mm_page_alloc", perf_evsel__process_page_alloc_event, }, 13770d68bc92SNamhyung Kim { "kmem:mm_page_free", perf_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) { 13890d68bc92SNamhyung Kim if (!strcmp(perf_evsel__name(evsel), "kmem:mm_page_alloc") && 13900d68bc92SNamhyung Kim perf_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"; 1897d1eeb77cSYunlong Song struct perf_data_file file = { 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"), 1913d1eeb77cSYunlong Song OPT_BOOLEAN('f', "force", &file.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; 1929a923e2c4SNamhyung Kim 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, 19363bca2354SRamkumar Ramachandra kmem_subcommands, kmem_usage, 0); 1937ba77c9e1SLi Zefan 193890b86a9fSLi Zefan if (!argc) 1939ba77c9e1SLi Zefan usage_with_options(kmem_usage, kmem_options); 1940ba77c9e1SLi Zefan 19410c160d49SNamhyung Kim if (kmem_slab == 0 && kmem_page == 0) { 19420c160d49SNamhyung Kim if (kmem_default == KMEM_SLAB) 19430c160d49SNamhyung Kim kmem_slab = 1; 19440c160d49SNamhyung Kim else 19450c160d49SNamhyung Kim kmem_page = 1; 19460c160d49SNamhyung Kim } 19470d68bc92SNamhyung Kim 19482b2b2c68SNamhyung Kim if (!strncmp(argv[0], "rec", 3)) { 19490a7e6d1bSNamhyung Kim symbol__init(NULL); 19502b2b2c68SNamhyung Kim return __cmd_record(argc, argv); 19512b2b2c68SNamhyung Kim } 19522b2b2c68SNamhyung Kim 195328939e1aSJiri Olsa file.path = input_name; 195428939e1aSJiri Olsa 1955c9758cc4SNamhyung Kim kmem_session = session = perf_session__new(&file, false, &perf_kmem); 19562b2b2c68SNamhyung Kim if (session == NULL) 195752e02834STaeung Song return -1; 19582b2b2c68SNamhyung Kim 1959ecc4c561SArnaldo Carvalho de Melo ret = -1; 1960ecc4c561SArnaldo Carvalho de Melo 1961a923e2c4SNamhyung Kim if (kmem_slab) { 1962a923e2c4SNamhyung Kim if (!perf_evlist__find_tracepoint_by_name(session->evlist, 1963a923e2c4SNamhyung Kim "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) { 1970a923e2c4SNamhyung Kim struct perf_evsel *evsel; 1971a923e2c4SNamhyung Kim 1972a923e2c4SNamhyung Kim evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 1973a923e2c4SNamhyung Kim "kmem:mm_page_alloc"); 1974a923e2c4SNamhyung Kim if (evsel == NULL) { 1975a923e2c4SNamhyung Kim pr_err(errmsg, "page", "page"); 1976249ca1a8STaeung Song goto out_delete; 19770d68bc92SNamhyung Kim } 19780d68bc92SNamhyung Kim 19790d68bc92SNamhyung Kim kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); 1980c9758cc4SNamhyung Kim symbol_conf.use_callchain = true; 19810d68bc92SNamhyung Kim } 19820d68bc92SNamhyung Kim 19830a7e6d1bSNamhyung Kim symbol__init(&session->header.env); 1984655000e7SArnaldo Carvalho de Melo 19852a865bd8SDavid Ahern if (perf_time__parse_str(&ptime, time_str) != 0) { 19862a865bd8SDavid Ahern pr_err("Invalid time string\n"); 19872a865bd8SDavid Ahern return -EINVAL; 19882a865bd8SDavid Ahern } 19892a865bd8SDavid Ahern 19902b2b2c68SNamhyung Kim if (!strcmp(argv[0], "stat")) { 199177cfe388SNamhyung Kim setlocale(LC_ALL, ""); 199277cfe388SNamhyung Kim 19934b627957SDon Zickus if (cpu__setup_cpunode_map()) 19942b2b2c68SNamhyung Kim goto out_delete; 199590b86a9fSLi Zefan 1996fb4f313dSNamhyung Kim if (list_empty(&slab_caller_sort)) 1997fb4f313dSNamhyung Kim setup_slab_sorting(&slab_caller_sort, default_slab_sort); 1998fb4f313dSNamhyung Kim if (list_empty(&slab_alloc_sort)) 1999fb4f313dSNamhyung Kim setup_slab_sorting(&slab_alloc_sort, default_slab_sort); 2000fb4f313dSNamhyung Kim if (list_empty(&page_caller_sort)) 2001fb4f313dSNamhyung Kim setup_page_sorting(&page_caller_sort, default_page_sort); 2002fb4f313dSNamhyung Kim if (list_empty(&page_alloc_sort)) 2003fb4f313dSNamhyung Kim setup_page_sorting(&page_alloc_sort, default_page_sort); 2004ba77c9e1SLi Zefan 2005fb4f313dSNamhyung Kim if (kmem_page) { 2006fb4f313dSNamhyung Kim setup_page_sorting(&page_alloc_sort_input, 2007fb4f313dSNamhyung Kim "page,order,migtype,gfp"); 2008fb4f313dSNamhyung Kim setup_page_sorting(&page_caller_sort_input, 2009fb4f313dSNamhyung Kim "callsite,order,migtype,gfp"); 2010fb4f313dSNamhyung Kim } 20112b2b2c68SNamhyung Kim ret = __cmd_kmem(session); 2012b00eca8cSPekka Enberg } else 2013b00eca8cSPekka Enberg usage_with_options(kmem_usage, kmem_options); 2014ba77c9e1SLi Zefan 20152b2b2c68SNamhyung Kim out_delete: 20162b2b2c68SNamhyung Kim perf_session__delete(session); 20172b2b2c68SNamhyung Kim 20182b2b2c68SNamhyung Kim return ret; 201990b86a9fSLi Zefan } 202090b86a9fSLi Zefan 2021