18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include "builtin.h" 38c2ecf20Sopenharmony_ci#include "perf.h" 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include "util/dso.h" 68c2ecf20Sopenharmony_ci#include "util/evlist.h" 78c2ecf20Sopenharmony_ci#include "util/evsel.h" 88c2ecf20Sopenharmony_ci#include "util/config.h" 98c2ecf20Sopenharmony_ci#include "util/map.h" 108c2ecf20Sopenharmony_ci#include "util/symbol.h" 118c2ecf20Sopenharmony_ci#include "util/thread.h" 128c2ecf20Sopenharmony_ci#include "util/header.h" 138c2ecf20Sopenharmony_ci#include "util/session.h" 148c2ecf20Sopenharmony_ci#include "util/tool.h" 158c2ecf20Sopenharmony_ci#include "util/callchain.h" 168c2ecf20Sopenharmony_ci#include "util/time-utils.h" 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <subcmd/pager.h> 208c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 218c2ecf20Sopenharmony_ci#include "util/trace-event.h" 228c2ecf20Sopenharmony_ci#include "util/data.h" 238c2ecf20Sopenharmony_ci#include "util/cpumap.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "util/debug.h" 268c2ecf20Sopenharmony_ci#include "util/string2.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/kernel.h> 298c2ecf20Sopenharmony_ci#include <linux/rbtree.h> 308c2ecf20Sopenharmony_ci#include <linux/string.h> 318c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 328c2ecf20Sopenharmony_ci#include <errno.h> 338c2ecf20Sopenharmony_ci#include <inttypes.h> 348c2ecf20Sopenharmony_ci#include <locale.h> 358c2ecf20Sopenharmony_ci#include <regex.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/ctype.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int kmem_slab; 408c2ecf20Sopenharmony_cistatic int kmem_page; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic long kmem_page_size; 438c2ecf20Sopenharmony_cistatic enum { 448c2ecf20Sopenharmony_ci KMEM_SLAB, 458c2ecf20Sopenharmony_ci KMEM_PAGE, 468c2ecf20Sopenharmony_ci} kmem_default = KMEM_SLAB; /* for backward compatibility */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct alloc_stat; 498c2ecf20Sopenharmony_citypedef int (*sort_fn_t)(void *, void *); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int alloc_flag; 528c2ecf20Sopenharmony_cistatic int caller_flag; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int alloc_lines = -1; 558c2ecf20Sopenharmony_cistatic int caller_lines = -1; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic bool raw_ip; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct alloc_stat { 608c2ecf20Sopenharmony_ci u64 call_site; 618c2ecf20Sopenharmony_ci u64 ptr; 628c2ecf20Sopenharmony_ci u64 bytes_req; 638c2ecf20Sopenharmony_ci u64 bytes_alloc; 648c2ecf20Sopenharmony_ci u64 last_alloc; 658c2ecf20Sopenharmony_ci u32 hit; 668c2ecf20Sopenharmony_ci u32 pingpong; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci short alloc_cpu; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci struct rb_node node; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic struct rb_root root_alloc_stat; 748c2ecf20Sopenharmony_cistatic struct rb_root root_alloc_sorted; 758c2ecf20Sopenharmony_cistatic struct rb_root root_caller_stat; 768c2ecf20Sopenharmony_cistatic struct rb_root root_caller_sorted; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic unsigned long total_requested, total_allocated, total_freed; 798c2ecf20Sopenharmony_cistatic unsigned long nr_allocs, nr_cross_allocs; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* filters for controlling start and stop of time of analysis */ 828c2ecf20Sopenharmony_cistatic struct perf_time_interval ptime; 838c2ecf20Sopenharmony_ciconst char *time_str; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 868c2ecf20Sopenharmony_ci int bytes_req, int bytes_alloc, int cpu) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct rb_node **node = &root_alloc_stat.rb_node; 898c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 908c2ecf20Sopenharmony_ci struct alloc_stat *data = NULL; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci while (*node) { 938c2ecf20Sopenharmony_ci parent = *node; 948c2ecf20Sopenharmony_ci data = rb_entry(*node, struct alloc_stat, node); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (ptr > data->ptr) 978c2ecf20Sopenharmony_ci node = &(*node)->rb_right; 988c2ecf20Sopenharmony_ci else if (ptr < data->ptr) 998c2ecf20Sopenharmony_ci node = &(*node)->rb_left; 1008c2ecf20Sopenharmony_ci else 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (data && data->ptr == ptr) { 1058c2ecf20Sopenharmony_ci data->hit++; 1068c2ecf20Sopenharmony_ci data->bytes_req += bytes_req; 1078c2ecf20Sopenharmony_ci data->bytes_alloc += bytes_alloc; 1088c2ecf20Sopenharmony_ci } else { 1098c2ecf20Sopenharmony_ci data = malloc(sizeof(*data)); 1108c2ecf20Sopenharmony_ci if (!data) { 1118c2ecf20Sopenharmony_ci pr_err("%s: malloc failed\n", __func__); 1128c2ecf20Sopenharmony_ci return -1; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci data->ptr = ptr; 1158c2ecf20Sopenharmony_ci data->pingpong = 0; 1168c2ecf20Sopenharmony_ci data->hit = 1; 1178c2ecf20Sopenharmony_ci data->bytes_req = bytes_req; 1188c2ecf20Sopenharmony_ci data->bytes_alloc = bytes_alloc; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, node); 1218c2ecf20Sopenharmony_ci rb_insert_color(&data->node, &root_alloc_stat); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci data->call_site = call_site; 1248c2ecf20Sopenharmony_ci data->alloc_cpu = cpu; 1258c2ecf20Sopenharmony_ci data->last_alloc = bytes_alloc; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int insert_caller_stat(unsigned long call_site, 1318c2ecf20Sopenharmony_ci int bytes_req, int bytes_alloc) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct rb_node **node = &root_caller_stat.rb_node; 1348c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 1358c2ecf20Sopenharmony_ci struct alloc_stat *data = NULL; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci while (*node) { 1388c2ecf20Sopenharmony_ci parent = *node; 1398c2ecf20Sopenharmony_ci data = rb_entry(*node, struct alloc_stat, node); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (call_site > data->call_site) 1428c2ecf20Sopenharmony_ci node = &(*node)->rb_right; 1438c2ecf20Sopenharmony_ci else if (call_site < data->call_site) 1448c2ecf20Sopenharmony_ci node = &(*node)->rb_left; 1458c2ecf20Sopenharmony_ci else 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (data && data->call_site == call_site) { 1508c2ecf20Sopenharmony_ci data->hit++; 1518c2ecf20Sopenharmony_ci data->bytes_req += bytes_req; 1528c2ecf20Sopenharmony_ci data->bytes_alloc += bytes_alloc; 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci data = malloc(sizeof(*data)); 1558c2ecf20Sopenharmony_ci if (!data) { 1568c2ecf20Sopenharmony_ci pr_err("%s: malloc failed\n", __func__); 1578c2ecf20Sopenharmony_ci return -1; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci data->call_site = call_site; 1608c2ecf20Sopenharmony_ci data->pingpong = 0; 1618c2ecf20Sopenharmony_ci data->hit = 1; 1628c2ecf20Sopenharmony_ci data->bytes_req = bytes_req; 1638c2ecf20Sopenharmony_ci data->bytes_alloc = bytes_alloc; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, node); 1668c2ecf20Sopenharmony_ci rb_insert_color(&data->node, &root_caller_stat); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int evsel__process_alloc_event(struct evsel *evsel, struct perf_sample *sample) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned long ptr = evsel__intval(evsel, sample, "ptr"), 1758c2ecf20Sopenharmony_ci call_site = evsel__intval(evsel, sample, "call_site"); 1768c2ecf20Sopenharmony_ci int bytes_req = evsel__intval(evsel, sample, "bytes_req"), 1778c2ecf20Sopenharmony_ci bytes_alloc = evsel__intval(evsel, sample, "bytes_alloc"); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) || 1808c2ecf20Sopenharmony_ci insert_caller_stat(call_site, bytes_req, bytes_alloc)) 1818c2ecf20Sopenharmony_ci return -1; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci total_requested += bytes_req; 1848c2ecf20Sopenharmony_ci total_allocated += bytes_alloc; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci nr_allocs++; 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int evsel__process_alloc_node_event(struct evsel *evsel, struct perf_sample *sample) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci int ret = evsel__process_alloc_event(evsel, sample); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!ret) { 1958c2ecf20Sopenharmony_ci int node1 = cpu__get_node(sample->cpu), 1968c2ecf20Sopenharmony_ci node2 = evsel__intval(evsel, sample, "node"); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (node1 != node2) 1998c2ecf20Sopenharmony_ci nr_cross_allocs++; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int ptr_cmp(void *, void *); 2068c2ecf20Sopenharmony_cistatic int slab_callsite_cmp(void *, void *); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic struct alloc_stat *search_alloc_stat(unsigned long ptr, 2098c2ecf20Sopenharmony_ci unsigned long call_site, 2108c2ecf20Sopenharmony_ci struct rb_root *root, 2118c2ecf20Sopenharmony_ci sort_fn_t sort_fn) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct rb_node *node = root->rb_node; 2148c2ecf20Sopenharmony_ci struct alloc_stat key = { .ptr = ptr, .call_site = call_site }; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci while (node) { 2178c2ecf20Sopenharmony_ci struct alloc_stat *data; 2188c2ecf20Sopenharmony_ci int cmp; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci data = rb_entry(node, struct alloc_stat, node); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci cmp = sort_fn(&key, data); 2238c2ecf20Sopenharmony_ci if (cmp < 0) 2248c2ecf20Sopenharmony_ci node = node->rb_left; 2258c2ecf20Sopenharmony_ci else if (cmp > 0) 2268c2ecf20Sopenharmony_ci node = node->rb_right; 2278c2ecf20Sopenharmony_ci else 2288c2ecf20Sopenharmony_ci return data; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci return NULL; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int evsel__process_free_event(struct evsel *evsel, struct perf_sample *sample) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci unsigned long ptr = evsel__intval(evsel, sample, "ptr"); 2368c2ecf20Sopenharmony_ci struct alloc_stat *s_alloc, *s_caller; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); 2398c2ecf20Sopenharmony_ci if (!s_alloc) 2408c2ecf20Sopenharmony_ci return 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci total_freed += s_alloc->last_alloc; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if ((short)sample->cpu != s_alloc->alloc_cpu) { 2458c2ecf20Sopenharmony_ci s_alloc->pingpong++; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci s_caller = search_alloc_stat(0, s_alloc->call_site, 2488c2ecf20Sopenharmony_ci &root_caller_stat, 2498c2ecf20Sopenharmony_ci slab_callsite_cmp); 2508c2ecf20Sopenharmony_ci if (!s_caller) 2518c2ecf20Sopenharmony_ci return -1; 2528c2ecf20Sopenharmony_ci s_caller->pingpong++; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci s_alloc->alloc_cpu = -1; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic u64 total_page_alloc_bytes; 2608c2ecf20Sopenharmony_cistatic u64 total_page_free_bytes; 2618c2ecf20Sopenharmony_cistatic u64 total_page_nomatch_bytes; 2628c2ecf20Sopenharmony_cistatic u64 total_page_fail_bytes; 2638c2ecf20Sopenharmony_cistatic unsigned long nr_page_allocs; 2648c2ecf20Sopenharmony_cistatic unsigned long nr_page_frees; 2658c2ecf20Sopenharmony_cistatic unsigned long nr_page_fails; 2668c2ecf20Sopenharmony_cistatic unsigned long nr_page_nomatch; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic bool use_pfn; 2698c2ecf20Sopenharmony_cistatic bool live_page; 2708c2ecf20Sopenharmony_cistatic struct perf_session *kmem_session; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci#define MAX_MIGRATE_TYPES 6 2738c2ecf20Sopenharmony_ci#define MAX_PAGE_ORDER 11 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES]; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistruct page_stat { 2788c2ecf20Sopenharmony_ci struct rb_node node; 2798c2ecf20Sopenharmony_ci u64 page; 2808c2ecf20Sopenharmony_ci u64 callsite; 2818c2ecf20Sopenharmony_ci int order; 2828c2ecf20Sopenharmony_ci unsigned gfp_flags; 2838c2ecf20Sopenharmony_ci unsigned migrate_type; 2848c2ecf20Sopenharmony_ci u64 alloc_bytes; 2858c2ecf20Sopenharmony_ci u64 free_bytes; 2868c2ecf20Sopenharmony_ci int nr_alloc; 2878c2ecf20Sopenharmony_ci int nr_free; 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct rb_root page_live_tree; 2918c2ecf20Sopenharmony_cistatic struct rb_root page_alloc_tree; 2928c2ecf20Sopenharmony_cistatic struct rb_root page_alloc_sorted; 2938c2ecf20Sopenharmony_cistatic struct rb_root page_caller_tree; 2948c2ecf20Sopenharmony_cistatic struct rb_root page_caller_sorted; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistruct alloc_func { 2978c2ecf20Sopenharmony_ci u64 start; 2988c2ecf20Sopenharmony_ci u64 end; 2998c2ecf20Sopenharmony_ci char *name; 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int nr_alloc_funcs; 3038c2ecf20Sopenharmony_cistatic struct alloc_func *alloc_func_list; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int funcmp(const void *a, const void *b) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci const struct alloc_func *fa = a; 3088c2ecf20Sopenharmony_ci const struct alloc_func *fb = b; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (fa->start > fb->start) 3118c2ecf20Sopenharmony_ci return 1; 3128c2ecf20Sopenharmony_ci else 3138c2ecf20Sopenharmony_ci return -1; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int callcmp(const void *a, const void *b) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci const struct alloc_func *fa = a; 3198c2ecf20Sopenharmony_ci const struct alloc_func *fb = b; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (fb->start <= fa->start && fa->end < fb->end) 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (fa->start > fb->start) 3258c2ecf20Sopenharmony_ci return 1; 3268c2ecf20Sopenharmony_ci else 3278c2ecf20Sopenharmony_ci return -1; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int build_alloc_func_list(void) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci int ret; 3338c2ecf20Sopenharmony_ci struct map *kernel_map; 3348c2ecf20Sopenharmony_ci struct symbol *sym; 3358c2ecf20Sopenharmony_ci struct rb_node *node; 3368c2ecf20Sopenharmony_ci struct alloc_func *func; 3378c2ecf20Sopenharmony_ci struct machine *machine = &kmem_session->machines.host; 3388c2ecf20Sopenharmony_ci regex_t alloc_func_regex; 3398c2ecf20Sopenharmony_ci static const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?"; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED); 3428c2ecf20Sopenharmony_ci if (ret) { 3438c2ecf20Sopenharmony_ci char err[BUFSIZ]; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci regerror(ret, &alloc_func_regex, err, sizeof(err)); 3468c2ecf20Sopenharmony_ci pr_err("Invalid regex: %s\n%s", pattern, err); 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci kernel_map = machine__kernel_map(machine); 3518c2ecf20Sopenharmony_ci if (map__load(kernel_map) < 0) { 3528c2ecf20Sopenharmony_ci pr_err("cannot load kernel map\n"); 3538c2ecf20Sopenharmony_ci return -ENOENT; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci map__for_each_symbol(kernel_map, sym, node) { 3578c2ecf20Sopenharmony_ci if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0)) 3588c2ecf20Sopenharmony_ci continue; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci func = realloc(alloc_func_list, 3618c2ecf20Sopenharmony_ci (nr_alloc_funcs + 1) * sizeof(*func)); 3628c2ecf20Sopenharmony_ci if (func == NULL) 3638c2ecf20Sopenharmony_ci return -ENOMEM; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci pr_debug("alloc func: %s\n", sym->name); 3668c2ecf20Sopenharmony_ci func[nr_alloc_funcs].start = sym->start; 3678c2ecf20Sopenharmony_ci func[nr_alloc_funcs].end = sym->end; 3688c2ecf20Sopenharmony_ci func[nr_alloc_funcs].name = sym->name; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci alloc_func_list = func; 3718c2ecf20Sopenharmony_ci nr_alloc_funcs++; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci regfree(&alloc_func_regex); 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* 3818c2ecf20Sopenharmony_ci * Find first non-memory allocation function from callchain. 3828c2ecf20Sopenharmony_ci * The allocation functions are in the 'alloc_func_list'. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_cistatic u64 find_callsite(struct evsel *evsel, struct perf_sample *sample) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct addr_location al; 3878c2ecf20Sopenharmony_ci struct machine *machine = &kmem_session->machines.host; 3888c2ecf20Sopenharmony_ci struct callchain_cursor_node *node; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (alloc_func_list == NULL) { 3918c2ecf20Sopenharmony_ci if (build_alloc_func_list() < 0) 3928c2ecf20Sopenharmony_ci goto out; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); 3968c2ecf20Sopenharmony_ci sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci callchain_cursor_commit(&callchain_cursor); 3998c2ecf20Sopenharmony_ci while (true) { 4008c2ecf20Sopenharmony_ci struct alloc_func key, *caller; 4018c2ecf20Sopenharmony_ci u64 addr; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci node = callchain_cursor_current(&callchain_cursor); 4048c2ecf20Sopenharmony_ci if (node == NULL) 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci key.start = key.end = node->ip; 4088c2ecf20Sopenharmony_ci caller = bsearch(&key, alloc_func_list, nr_alloc_funcs, 4098c2ecf20Sopenharmony_ci sizeof(key), callcmp); 4108c2ecf20Sopenharmony_ci if (!caller) { 4118c2ecf20Sopenharmony_ci /* found */ 4128c2ecf20Sopenharmony_ci if (node->ms.map) 4138c2ecf20Sopenharmony_ci addr = map__unmap_ip(node->ms.map, node->ip); 4148c2ecf20Sopenharmony_ci else 4158c2ecf20Sopenharmony_ci addr = node->ip; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return addr; 4188c2ecf20Sopenharmony_ci } else 4198c2ecf20Sopenharmony_ci pr_debug3("skipping alloc function: %s\n", caller->name); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci callchain_cursor_advance(&callchain_cursor); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciout: 4258c2ecf20Sopenharmony_ci pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip); 4268c2ecf20Sopenharmony_ci return sample->ip; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistruct sort_dimension { 4308c2ecf20Sopenharmony_ci const char name[20]; 4318c2ecf20Sopenharmony_ci sort_fn_t cmp; 4328c2ecf20Sopenharmony_ci struct list_head list; 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic LIST_HEAD(page_alloc_sort_input); 4368c2ecf20Sopenharmony_cistatic LIST_HEAD(page_caller_sort_input); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct page_stat * 4398c2ecf20Sopenharmony_ci__page_stat__findnew_page(struct page_stat *pstat, bool create) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct rb_node **node = &page_live_tree.rb_node; 4428c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 4438c2ecf20Sopenharmony_ci struct page_stat *data; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci while (*node) { 4468c2ecf20Sopenharmony_ci s64 cmp; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci parent = *node; 4498c2ecf20Sopenharmony_ci data = rb_entry(*node, struct page_stat, node); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci cmp = data->page - pstat->page; 4528c2ecf20Sopenharmony_ci if (cmp < 0) 4538c2ecf20Sopenharmony_ci node = &parent->rb_left; 4548c2ecf20Sopenharmony_ci else if (cmp > 0) 4558c2ecf20Sopenharmony_ci node = &parent->rb_right; 4568c2ecf20Sopenharmony_ci else 4578c2ecf20Sopenharmony_ci return data; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (!create) 4618c2ecf20Sopenharmony_ci return NULL; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci data = zalloc(sizeof(*data)); 4648c2ecf20Sopenharmony_ci if (data != NULL) { 4658c2ecf20Sopenharmony_ci data->page = pstat->page; 4668c2ecf20Sopenharmony_ci data->order = pstat->order; 4678c2ecf20Sopenharmony_ci data->gfp_flags = pstat->gfp_flags; 4688c2ecf20Sopenharmony_ci data->migrate_type = pstat->migrate_type; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, node); 4718c2ecf20Sopenharmony_ci rb_insert_color(&data->node, &page_live_tree); 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return data; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic struct page_stat *page_stat__find_page(struct page_stat *pstat) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci return __page_stat__findnew_page(pstat, false); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic struct page_stat *page_stat__findnew_page(struct page_stat *pstat) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci return __page_stat__findnew_page(pstat, true); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic struct page_stat * 4888c2ecf20Sopenharmony_ci__page_stat__findnew_alloc(struct page_stat *pstat, bool create) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct rb_node **node = &page_alloc_tree.rb_node; 4918c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 4928c2ecf20Sopenharmony_ci struct page_stat *data; 4938c2ecf20Sopenharmony_ci struct sort_dimension *sort; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci while (*node) { 4968c2ecf20Sopenharmony_ci int cmp = 0; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci parent = *node; 4998c2ecf20Sopenharmony_ci data = rb_entry(*node, struct page_stat, node); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci list_for_each_entry(sort, &page_alloc_sort_input, list) { 5028c2ecf20Sopenharmony_ci cmp = sort->cmp(pstat, data); 5038c2ecf20Sopenharmony_ci if (cmp) 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (cmp < 0) 5088c2ecf20Sopenharmony_ci node = &parent->rb_left; 5098c2ecf20Sopenharmony_ci else if (cmp > 0) 5108c2ecf20Sopenharmony_ci node = &parent->rb_right; 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci return data; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (!create) 5168c2ecf20Sopenharmony_ci return NULL; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci data = zalloc(sizeof(*data)); 5198c2ecf20Sopenharmony_ci if (data != NULL) { 5208c2ecf20Sopenharmony_ci data->page = pstat->page; 5218c2ecf20Sopenharmony_ci data->order = pstat->order; 5228c2ecf20Sopenharmony_ci data->gfp_flags = pstat->gfp_flags; 5238c2ecf20Sopenharmony_ci data->migrate_type = pstat->migrate_type; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, node); 5268c2ecf20Sopenharmony_ci rb_insert_color(&data->node, &page_alloc_tree); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return data; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic struct page_stat *page_stat__find_alloc(struct page_stat *pstat) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci return __page_stat__findnew_alloc(pstat, false); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic struct page_stat *page_stat__findnew_alloc(struct page_stat *pstat) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci return __page_stat__findnew_alloc(pstat, true); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic struct page_stat * 5438c2ecf20Sopenharmony_ci__page_stat__findnew_caller(struct page_stat *pstat, bool create) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct rb_node **node = &page_caller_tree.rb_node; 5468c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 5478c2ecf20Sopenharmony_ci struct page_stat *data; 5488c2ecf20Sopenharmony_ci struct sort_dimension *sort; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci while (*node) { 5518c2ecf20Sopenharmony_ci int cmp = 0; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci parent = *node; 5548c2ecf20Sopenharmony_ci data = rb_entry(*node, struct page_stat, node); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci list_for_each_entry(sort, &page_caller_sort_input, list) { 5578c2ecf20Sopenharmony_ci cmp = sort->cmp(pstat, data); 5588c2ecf20Sopenharmony_ci if (cmp) 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (cmp < 0) 5638c2ecf20Sopenharmony_ci node = &parent->rb_left; 5648c2ecf20Sopenharmony_ci else if (cmp > 0) 5658c2ecf20Sopenharmony_ci node = &parent->rb_right; 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci return data; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!create) 5718c2ecf20Sopenharmony_ci return NULL; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci data = zalloc(sizeof(*data)); 5748c2ecf20Sopenharmony_ci if (data != NULL) { 5758c2ecf20Sopenharmony_ci data->callsite = pstat->callsite; 5768c2ecf20Sopenharmony_ci data->order = pstat->order; 5778c2ecf20Sopenharmony_ci data->gfp_flags = pstat->gfp_flags; 5788c2ecf20Sopenharmony_ci data->migrate_type = pstat->migrate_type; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, node); 5818c2ecf20Sopenharmony_ci rb_insert_color(&data->node, &page_caller_tree); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return data; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic struct page_stat *page_stat__find_caller(struct page_stat *pstat) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci return __page_stat__findnew_caller(pstat, false); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic struct page_stat *page_stat__findnew_caller(struct page_stat *pstat) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci return __page_stat__findnew_caller(pstat, true); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic bool valid_page(u64 pfn_or_page) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci if (use_pfn && pfn_or_page == -1UL) 6008c2ecf20Sopenharmony_ci return false; 6018c2ecf20Sopenharmony_ci if (!use_pfn && pfn_or_page == 0) 6028c2ecf20Sopenharmony_ci return false; 6038c2ecf20Sopenharmony_ci return true; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistruct gfp_flag { 6078c2ecf20Sopenharmony_ci unsigned int flags; 6088c2ecf20Sopenharmony_ci char *compact_str; 6098c2ecf20Sopenharmony_ci char *human_readable; 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic struct gfp_flag *gfps; 6138c2ecf20Sopenharmony_cistatic int nr_gfps; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int gfpcmp(const void *a, const void *b) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci const struct gfp_flag *fa = a; 6188c2ecf20Sopenharmony_ci const struct gfp_flag *fb = b; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return fa->flags - fb->flags; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* see include/trace/events/mmflags.h */ 6248c2ecf20Sopenharmony_cistatic const struct { 6258c2ecf20Sopenharmony_ci const char *original; 6268c2ecf20Sopenharmony_ci const char *compact; 6278c2ecf20Sopenharmony_ci} gfp_compact_table[] = { 6288c2ecf20Sopenharmony_ci { "GFP_TRANSHUGE", "THP" }, 6298c2ecf20Sopenharmony_ci { "GFP_TRANSHUGE_LIGHT", "THL" }, 6308c2ecf20Sopenharmony_ci { "GFP_HIGHUSER_MOVABLE", "HUM" }, 6318c2ecf20Sopenharmony_ci { "GFP_HIGHUSER", "HU" }, 6328c2ecf20Sopenharmony_ci { "GFP_USER", "U" }, 6338c2ecf20Sopenharmony_ci { "GFP_KERNEL_ACCOUNT", "KAC" }, 6348c2ecf20Sopenharmony_ci { "GFP_KERNEL", "K" }, 6358c2ecf20Sopenharmony_ci { "GFP_NOFS", "NF" }, 6368c2ecf20Sopenharmony_ci { "GFP_ATOMIC", "A" }, 6378c2ecf20Sopenharmony_ci { "GFP_NOIO", "NI" }, 6388c2ecf20Sopenharmony_ci { "GFP_NOWAIT", "NW" }, 6398c2ecf20Sopenharmony_ci { "GFP_DMA", "D" }, 6408c2ecf20Sopenharmony_ci { "__GFP_HIGHMEM", "HM" }, 6418c2ecf20Sopenharmony_ci { "GFP_DMA32", "D32" }, 6428c2ecf20Sopenharmony_ci { "__GFP_HIGH", "H" }, 6438c2ecf20Sopenharmony_ci { "__GFP_ATOMIC", "_A" }, 6448c2ecf20Sopenharmony_ci { "__GFP_IO", "I" }, 6458c2ecf20Sopenharmony_ci { "__GFP_FS", "F" }, 6468c2ecf20Sopenharmony_ci { "__GFP_NOWARN", "NWR" }, 6478c2ecf20Sopenharmony_ci { "__GFP_RETRY_MAYFAIL", "R" }, 6488c2ecf20Sopenharmony_ci { "__GFP_NOFAIL", "NF" }, 6498c2ecf20Sopenharmony_ci { "__GFP_NORETRY", "NR" }, 6508c2ecf20Sopenharmony_ci { "__GFP_COMP", "C" }, 6518c2ecf20Sopenharmony_ci { "__GFP_ZERO", "Z" }, 6528c2ecf20Sopenharmony_ci { "__GFP_NOMEMALLOC", "NMA" }, 6538c2ecf20Sopenharmony_ci { "__GFP_MEMALLOC", "MA" }, 6548c2ecf20Sopenharmony_ci { "__GFP_HARDWALL", "HW" }, 6558c2ecf20Sopenharmony_ci { "__GFP_THISNODE", "TN" }, 6568c2ecf20Sopenharmony_ci { "__GFP_RECLAIMABLE", "RC" }, 6578c2ecf20Sopenharmony_ci { "__GFP_MOVABLE", "M" }, 6588c2ecf20Sopenharmony_ci { "__GFP_ACCOUNT", "AC" }, 6598c2ecf20Sopenharmony_ci { "__GFP_WRITE", "WR" }, 6608c2ecf20Sopenharmony_ci { "__GFP_RECLAIM", "R" }, 6618c2ecf20Sopenharmony_ci { "__GFP_DIRECT_RECLAIM", "DR" }, 6628c2ecf20Sopenharmony_ci { "__GFP_KSWAPD_RECLAIM", "KR" }, 6638c2ecf20Sopenharmony_ci}; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic size_t max_gfp_len; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic char *compact_gfp_flags(char *gfp_flags) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci char *orig_flags = strdup(gfp_flags); 6708c2ecf20Sopenharmony_ci char *new_flags = NULL; 6718c2ecf20Sopenharmony_ci char *str, *pos = NULL; 6728c2ecf20Sopenharmony_ci size_t len = 0; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (orig_flags == NULL) 6758c2ecf20Sopenharmony_ci return NULL; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci str = strtok_r(orig_flags, "|", &pos); 6788c2ecf20Sopenharmony_ci while (str) { 6798c2ecf20Sopenharmony_ci size_t i; 6808c2ecf20Sopenharmony_ci char *new; 6818c2ecf20Sopenharmony_ci const char *cpt; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gfp_compact_table); i++) { 6848c2ecf20Sopenharmony_ci if (strcmp(gfp_compact_table[i].original, str)) 6858c2ecf20Sopenharmony_ci continue; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci cpt = gfp_compact_table[i].compact; 6888c2ecf20Sopenharmony_ci new = realloc(new_flags, len + strlen(cpt) + 2); 6898c2ecf20Sopenharmony_ci if (new == NULL) { 6908c2ecf20Sopenharmony_ci free(new_flags); 6918c2ecf20Sopenharmony_ci free(orig_flags); 6928c2ecf20Sopenharmony_ci return NULL; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci new_flags = new; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!len) { 6988c2ecf20Sopenharmony_ci strcpy(new_flags, cpt); 6998c2ecf20Sopenharmony_ci } else { 7008c2ecf20Sopenharmony_ci strcat(new_flags, "|"); 7018c2ecf20Sopenharmony_ci strcat(new_flags, cpt); 7028c2ecf20Sopenharmony_ci len++; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci len += strlen(cpt); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci str = strtok_r(NULL, "|", &pos); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (max_gfp_len < len) 7128c2ecf20Sopenharmony_ci max_gfp_len = len; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci free(orig_flags); 7158c2ecf20Sopenharmony_ci return new_flags; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic char *compact_gfp_string(unsigned long gfp_flags) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct gfp_flag key = { 7218c2ecf20Sopenharmony_ci .flags = gfp_flags, 7228c2ecf20Sopenharmony_ci }; 7238c2ecf20Sopenharmony_ci struct gfp_flag *gfp; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci gfp = bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp); 7268c2ecf20Sopenharmony_ci if (gfp) 7278c2ecf20Sopenharmony_ci return gfp->compact_str; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return NULL; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int parse_gfp_flags(struct evsel *evsel, struct perf_sample *sample, 7338c2ecf20Sopenharmony_ci unsigned int gfp_flags) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct tep_record record = { 7368c2ecf20Sopenharmony_ci .cpu = sample->cpu, 7378c2ecf20Sopenharmony_ci .data = sample->raw_data, 7388c2ecf20Sopenharmony_ci .size = sample->raw_size, 7398c2ecf20Sopenharmony_ci }; 7408c2ecf20Sopenharmony_ci struct trace_seq seq; 7418c2ecf20Sopenharmony_ci char *str, *pos = NULL; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (nr_gfps) { 7448c2ecf20Sopenharmony_ci struct gfp_flag key = { 7458c2ecf20Sopenharmony_ci .flags = gfp_flags, 7468c2ecf20Sopenharmony_ci }; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp)) 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci trace_seq_init(&seq); 7538c2ecf20Sopenharmony_ci tep_print_event(evsel->tp_format->tep, 7548c2ecf20Sopenharmony_ci &seq, &record, "%s", TEP_PRINT_INFO); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci str = strtok_r(seq.buffer, " ", &pos); 7578c2ecf20Sopenharmony_ci while (str) { 7588c2ecf20Sopenharmony_ci if (!strncmp(str, "gfp_flags=", 10)) { 7598c2ecf20Sopenharmony_ci struct gfp_flag *new; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci new = realloc(gfps, (nr_gfps + 1) * sizeof(*gfps)); 7628c2ecf20Sopenharmony_ci if (new == NULL) 7638c2ecf20Sopenharmony_ci return -ENOMEM; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci gfps = new; 7668c2ecf20Sopenharmony_ci new += nr_gfps++; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci new->flags = gfp_flags; 7698c2ecf20Sopenharmony_ci new->human_readable = strdup(str + 10); 7708c2ecf20Sopenharmony_ci new->compact_str = compact_gfp_flags(str + 10); 7718c2ecf20Sopenharmony_ci if (!new->human_readable || !new->compact_str) 7728c2ecf20Sopenharmony_ci return -ENOMEM; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci qsort(gfps, nr_gfps, sizeof(*gfps), gfpcmp); 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci str = strtok_r(NULL, " ", &pos); 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci trace_seq_destroy(&seq); 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int evsel__process_page_alloc_event(struct evsel *evsel, struct perf_sample *sample) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci u64 page; 7878c2ecf20Sopenharmony_ci unsigned int order = evsel__intval(evsel, sample, "order"); 7888c2ecf20Sopenharmony_ci unsigned int gfp_flags = evsel__intval(evsel, sample, "gfp_flags"); 7898c2ecf20Sopenharmony_ci unsigned int migrate_type = evsel__intval(evsel, sample, 7908c2ecf20Sopenharmony_ci "migratetype"); 7918c2ecf20Sopenharmony_ci u64 bytes = kmem_page_size << order; 7928c2ecf20Sopenharmony_ci u64 callsite; 7938c2ecf20Sopenharmony_ci struct page_stat *pstat; 7948c2ecf20Sopenharmony_ci struct page_stat this = { 7958c2ecf20Sopenharmony_ci .order = order, 7968c2ecf20Sopenharmony_ci .gfp_flags = gfp_flags, 7978c2ecf20Sopenharmony_ci .migrate_type = migrate_type, 7988c2ecf20Sopenharmony_ci }; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (use_pfn) 8018c2ecf20Sopenharmony_ci page = evsel__intval(evsel, sample, "pfn"); 8028c2ecf20Sopenharmony_ci else 8038c2ecf20Sopenharmony_ci page = evsel__intval(evsel, sample, "page"); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci nr_page_allocs++; 8068c2ecf20Sopenharmony_ci total_page_alloc_bytes += bytes; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (!valid_page(page)) { 8098c2ecf20Sopenharmony_ci nr_page_fails++; 8108c2ecf20Sopenharmony_ci total_page_fail_bytes += bytes; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return 0; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (parse_gfp_flags(evsel, sample, gfp_flags) < 0) 8168c2ecf20Sopenharmony_ci return -1; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci callsite = find_callsite(evsel, sample); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* 8218c2ecf20Sopenharmony_ci * This is to find the current page (with correct gfp flags and 8228c2ecf20Sopenharmony_ci * migrate type) at free event. 8238c2ecf20Sopenharmony_ci */ 8248c2ecf20Sopenharmony_ci this.page = page; 8258c2ecf20Sopenharmony_ci pstat = page_stat__findnew_page(&this); 8268c2ecf20Sopenharmony_ci if (pstat == NULL) 8278c2ecf20Sopenharmony_ci return -ENOMEM; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci pstat->nr_alloc++; 8308c2ecf20Sopenharmony_ci pstat->alloc_bytes += bytes; 8318c2ecf20Sopenharmony_ci pstat->callsite = callsite; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (!live_page) { 8348c2ecf20Sopenharmony_ci pstat = page_stat__findnew_alloc(&this); 8358c2ecf20Sopenharmony_ci if (pstat == NULL) 8368c2ecf20Sopenharmony_ci return -ENOMEM; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci pstat->nr_alloc++; 8398c2ecf20Sopenharmony_ci pstat->alloc_bytes += bytes; 8408c2ecf20Sopenharmony_ci pstat->callsite = callsite; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci this.callsite = callsite; 8448c2ecf20Sopenharmony_ci pstat = page_stat__findnew_caller(&this); 8458c2ecf20Sopenharmony_ci if (pstat == NULL) 8468c2ecf20Sopenharmony_ci return -ENOMEM; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci pstat->nr_alloc++; 8498c2ecf20Sopenharmony_ci pstat->alloc_bytes += bytes; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci order_stats[order][migrate_type]++; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int evsel__process_page_free_event(struct evsel *evsel, struct perf_sample *sample) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci u64 page; 8598c2ecf20Sopenharmony_ci unsigned int order = evsel__intval(evsel, sample, "order"); 8608c2ecf20Sopenharmony_ci u64 bytes = kmem_page_size << order; 8618c2ecf20Sopenharmony_ci struct page_stat *pstat; 8628c2ecf20Sopenharmony_ci struct page_stat this = { 8638c2ecf20Sopenharmony_ci .order = order, 8648c2ecf20Sopenharmony_ci }; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (use_pfn) 8678c2ecf20Sopenharmony_ci page = evsel__intval(evsel, sample, "pfn"); 8688c2ecf20Sopenharmony_ci else 8698c2ecf20Sopenharmony_ci page = evsel__intval(evsel, sample, "page"); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci nr_page_frees++; 8728c2ecf20Sopenharmony_ci total_page_free_bytes += bytes; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci this.page = page; 8758c2ecf20Sopenharmony_ci pstat = page_stat__find_page(&this); 8768c2ecf20Sopenharmony_ci if (pstat == NULL) { 8778c2ecf20Sopenharmony_ci pr_debug2("missing free at page %"PRIx64" (order: %d)\n", 8788c2ecf20Sopenharmony_ci page, order); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci nr_page_nomatch++; 8818c2ecf20Sopenharmony_ci total_page_nomatch_bytes += bytes; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci return 0; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci this.gfp_flags = pstat->gfp_flags; 8878c2ecf20Sopenharmony_ci this.migrate_type = pstat->migrate_type; 8888c2ecf20Sopenharmony_ci this.callsite = pstat->callsite; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci rb_erase(&pstat->node, &page_live_tree); 8918c2ecf20Sopenharmony_ci free(pstat); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (live_page) { 8948c2ecf20Sopenharmony_ci order_stats[this.order][this.migrate_type]--; 8958c2ecf20Sopenharmony_ci } else { 8968c2ecf20Sopenharmony_ci pstat = page_stat__find_alloc(&this); 8978c2ecf20Sopenharmony_ci if (pstat == NULL) 8988c2ecf20Sopenharmony_ci return -ENOMEM; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci pstat->nr_free++; 9018c2ecf20Sopenharmony_ci pstat->free_bytes += bytes; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci pstat = page_stat__find_caller(&this); 9058c2ecf20Sopenharmony_ci if (pstat == NULL) 9068c2ecf20Sopenharmony_ci return -ENOENT; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci pstat->nr_free++; 9098c2ecf20Sopenharmony_ci pstat->free_bytes += bytes; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (live_page) { 9128c2ecf20Sopenharmony_ci pstat->nr_alloc--; 9138c2ecf20Sopenharmony_ci pstat->alloc_bytes -= bytes; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (pstat->nr_alloc == 0) { 9168c2ecf20Sopenharmony_ci rb_erase(&pstat->node, &page_caller_tree); 9178c2ecf20Sopenharmony_ci free(pstat); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci return 0; 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic bool perf_kmem__skip_sample(struct perf_sample *sample) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci /* skip sample based on time? */ 9278c2ecf20Sopenharmony_ci if (perf_time__skip_sample(&ptime, sample->time)) 9288c2ecf20Sopenharmony_ci return true; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return false; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_citypedef int (*tracepoint_handler)(struct evsel *evsel, 9348c2ecf20Sopenharmony_ci struct perf_sample *sample); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic int process_sample_event(struct perf_tool *tool __maybe_unused, 9378c2ecf20Sopenharmony_ci union perf_event *event, 9388c2ecf20Sopenharmony_ci struct perf_sample *sample, 9398c2ecf20Sopenharmony_ci struct evsel *evsel, 9408c2ecf20Sopenharmony_ci struct machine *machine) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci int err = 0; 9438c2ecf20Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, sample->pid, 9448c2ecf20Sopenharmony_ci sample->tid); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (thread == NULL) { 9478c2ecf20Sopenharmony_ci pr_debug("problem processing %d event, skipping it.\n", 9488c2ecf20Sopenharmony_ci event->header.type); 9498c2ecf20Sopenharmony_ci return -1; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (perf_kmem__skip_sample(sample)) 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (evsel->handler != NULL) { 9588c2ecf20Sopenharmony_ci tracepoint_handler f = evsel->handler; 9598c2ecf20Sopenharmony_ci err = f(evsel, sample); 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci thread__put(thread); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return err; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic struct perf_tool perf_kmem = { 9688c2ecf20Sopenharmony_ci .sample = process_sample_event, 9698c2ecf20Sopenharmony_ci .comm = perf_event__process_comm, 9708c2ecf20Sopenharmony_ci .mmap = perf_event__process_mmap, 9718c2ecf20Sopenharmony_ci .mmap2 = perf_event__process_mmap2, 9728c2ecf20Sopenharmony_ci .namespaces = perf_event__process_namespaces, 9738c2ecf20Sopenharmony_ci .ordered_events = true, 9748c2ecf20Sopenharmony_ci}; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic double fragmentation(unsigned long n_req, unsigned long n_alloc) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci if (n_alloc == 0) 9798c2ecf20Sopenharmony_ci return 0.0; 9808c2ecf20Sopenharmony_ci else 9818c2ecf20Sopenharmony_ci return 100.0 - (100.0 * n_req / n_alloc); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic void __print_slab_result(struct rb_root *root, 9858c2ecf20Sopenharmony_ci struct perf_session *session, 9868c2ecf20Sopenharmony_ci int n_lines, int is_caller) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci struct rb_node *next; 9898c2ecf20Sopenharmony_ci struct machine *machine = &session->machines.host; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 9928c2ecf20Sopenharmony_ci printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 9938c2ecf20Sopenharmony_ci printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); 9948c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci next = rb_first(root); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci while (next && n_lines--) { 9998c2ecf20Sopenharmony_ci struct alloc_stat *data = rb_entry(next, struct alloc_stat, 10008c2ecf20Sopenharmony_ci node); 10018c2ecf20Sopenharmony_ci struct symbol *sym = NULL; 10028c2ecf20Sopenharmony_ci struct map *map; 10038c2ecf20Sopenharmony_ci char buf[BUFSIZ]; 10048c2ecf20Sopenharmony_ci u64 addr; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (is_caller) { 10078c2ecf20Sopenharmony_ci addr = data->call_site; 10088c2ecf20Sopenharmony_ci if (!raw_ip) 10098c2ecf20Sopenharmony_ci sym = machine__find_kernel_symbol(machine, addr, &map); 10108c2ecf20Sopenharmony_ci } else 10118c2ecf20Sopenharmony_ci addr = data->ptr; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (sym != NULL) 10148c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name, 10158c2ecf20Sopenharmony_ci addr - map->unmap_ip(map, sym->start)); 10168c2ecf20Sopenharmony_ci else 10178c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr); 10188c2ecf20Sopenharmony_ci printf(" %-34s |", buf); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %9lu | %6.3f%%\n", 10218c2ecf20Sopenharmony_ci (unsigned long long)data->bytes_alloc, 10228c2ecf20Sopenharmony_ci (unsigned long)data->bytes_alloc / data->hit, 10238c2ecf20Sopenharmony_ci (unsigned long long)data->bytes_req, 10248c2ecf20Sopenharmony_ci (unsigned long)data->bytes_req / data->hit, 10258c2ecf20Sopenharmony_ci (unsigned long)data->hit, 10268c2ecf20Sopenharmony_ci (unsigned long)data->pingpong, 10278c2ecf20Sopenharmony_ci fragmentation(data->bytes_req, data->bytes_alloc)); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci next = rb_next(next); 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (n_lines == -1) 10338c2ecf20Sopenharmony_ci printf(" ... | ... | ... | ... | ... | ... \n"); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic const char * const migrate_type_str[] = { 10398c2ecf20Sopenharmony_ci "UNMOVABL", 10408c2ecf20Sopenharmony_ci "RECLAIM", 10418c2ecf20Sopenharmony_ci "MOVABLE", 10428c2ecf20Sopenharmony_ci "RESERVED", 10438c2ecf20Sopenharmony_ci "CMA/ISLT", 10448c2ecf20Sopenharmony_ci "UNKNOWN", 10458c2ecf20Sopenharmony_ci}; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic void __print_page_alloc_result(struct perf_session *session, int n_lines) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct rb_node *next = rb_first(&page_alloc_sorted); 10508c2ecf20Sopenharmony_ci struct machine *machine = &session->machines.host; 10518c2ecf20Sopenharmony_ci const char *format; 10528c2ecf20Sopenharmony_ci int gfp_len = max(strlen("GFP flags"), max_gfp_len); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci printf("\n%.105s\n", graph_dotted_line); 10558c2ecf20Sopenharmony_ci printf(" %-16s | %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n", 10568c2ecf20Sopenharmony_ci use_pfn ? "PFN" : "Page", live_page ? "Live" : "Total", 10578c2ecf20Sopenharmony_ci gfp_len, "GFP flags"); 10588c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (use_pfn) 10618c2ecf20Sopenharmony_ci format = " %16llu | %'16llu | %'9d | %5d | %8s | %-*s | %s\n"; 10628c2ecf20Sopenharmony_ci else 10638c2ecf20Sopenharmony_ci format = " %016llx | %'16llu | %'9d | %5d | %8s | %-*s | %s\n"; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci while (next && n_lines--) { 10668c2ecf20Sopenharmony_ci struct page_stat *data; 10678c2ecf20Sopenharmony_ci struct symbol *sym; 10688c2ecf20Sopenharmony_ci struct map *map; 10698c2ecf20Sopenharmony_ci char buf[32]; 10708c2ecf20Sopenharmony_ci char *caller = buf; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci data = rb_entry(next, struct page_stat, node); 10738c2ecf20Sopenharmony_ci sym = machine__find_kernel_symbol(machine, data->callsite, &map); 10748c2ecf20Sopenharmony_ci if (sym) 10758c2ecf20Sopenharmony_ci caller = sym->name; 10768c2ecf20Sopenharmony_ci else 10778c2ecf20Sopenharmony_ci scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci printf(format, (unsigned long long)data->page, 10808c2ecf20Sopenharmony_ci (unsigned long long)data->alloc_bytes / 1024, 10818c2ecf20Sopenharmony_ci data->nr_alloc, data->order, 10828c2ecf20Sopenharmony_ci migrate_type_str[data->migrate_type], 10838c2ecf20Sopenharmony_ci gfp_len, compact_gfp_string(data->gfp_flags), caller); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci next = rb_next(next); 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (n_lines == -1) { 10898c2ecf20Sopenharmony_ci printf(" ... | ... | ... | ... | ... | %-*s | ...\n", 10908c2ecf20Sopenharmony_ci gfp_len, "..."); 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic void __print_page_caller_result(struct perf_session *session, int n_lines) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct rb_node *next = rb_first(&page_caller_sorted); 10998c2ecf20Sopenharmony_ci struct machine *machine = &session->machines.host; 11008c2ecf20Sopenharmony_ci int gfp_len = max(strlen("GFP flags"), max_gfp_len); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci printf("\n%.105s\n", graph_dotted_line); 11038c2ecf20Sopenharmony_ci printf(" %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n", 11048c2ecf20Sopenharmony_ci live_page ? "Live" : "Total", gfp_len, "GFP flags"); 11058c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci while (next && n_lines--) { 11088c2ecf20Sopenharmony_ci struct page_stat *data; 11098c2ecf20Sopenharmony_ci struct symbol *sym; 11108c2ecf20Sopenharmony_ci struct map *map; 11118c2ecf20Sopenharmony_ci char buf[32]; 11128c2ecf20Sopenharmony_ci char *caller = buf; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci data = rb_entry(next, struct page_stat, node); 11158c2ecf20Sopenharmony_ci sym = machine__find_kernel_symbol(machine, data->callsite, &map); 11168c2ecf20Sopenharmony_ci if (sym) 11178c2ecf20Sopenharmony_ci caller = sym->name; 11188c2ecf20Sopenharmony_ci else 11198c2ecf20Sopenharmony_ci scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci printf(" %'16llu | %'9d | %5d | %8s | %-*s | %s\n", 11228c2ecf20Sopenharmony_ci (unsigned long long)data->alloc_bytes / 1024, 11238c2ecf20Sopenharmony_ci data->nr_alloc, data->order, 11248c2ecf20Sopenharmony_ci migrate_type_str[data->migrate_type], 11258c2ecf20Sopenharmony_ci gfp_len, compact_gfp_string(data->gfp_flags), caller); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci next = rb_next(next); 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (n_lines == -1) { 11318c2ecf20Sopenharmony_ci printf(" ... | ... | ... | ... | %-*s | ...\n", 11328c2ecf20Sopenharmony_ci gfp_len, "..."); 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci printf("%.105s\n", graph_dotted_line); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic void print_gfp_flags(void) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci int i; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci printf("#\n"); 11438c2ecf20Sopenharmony_ci printf("# GFP flags\n"); 11448c2ecf20Sopenharmony_ci printf("# ---------\n"); 11458c2ecf20Sopenharmony_ci for (i = 0; i < nr_gfps; i++) { 11468c2ecf20Sopenharmony_ci printf("# %08x: %*s: %s\n", gfps[i].flags, 11478c2ecf20Sopenharmony_ci (int) max_gfp_len, gfps[i].compact_str, 11488c2ecf20Sopenharmony_ci gfps[i].human_readable); 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic void print_slab_summary(void) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci printf("\nSUMMARY (SLAB allocator)"); 11558c2ecf20Sopenharmony_ci printf("\n========================\n"); 11568c2ecf20Sopenharmony_ci printf("Total bytes requested: %'lu\n", total_requested); 11578c2ecf20Sopenharmony_ci printf("Total bytes allocated: %'lu\n", total_allocated); 11588c2ecf20Sopenharmony_ci printf("Total bytes freed: %'lu\n", total_freed); 11598c2ecf20Sopenharmony_ci if (total_allocated > total_freed) { 11608c2ecf20Sopenharmony_ci printf("Net total bytes allocated: %'lu\n", 11618c2ecf20Sopenharmony_ci total_allocated - total_freed); 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci printf("Total bytes wasted on internal fragmentation: %'lu\n", 11648c2ecf20Sopenharmony_ci total_allocated - total_requested); 11658c2ecf20Sopenharmony_ci printf("Internal fragmentation: %f%%\n", 11668c2ecf20Sopenharmony_ci fragmentation(total_requested, total_allocated)); 11678c2ecf20Sopenharmony_ci printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic void print_page_summary(void) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci int o, m; 11738c2ecf20Sopenharmony_ci u64 nr_alloc_freed = nr_page_frees - nr_page_nomatch; 11748c2ecf20Sopenharmony_ci u64 total_alloc_freed_bytes = total_page_free_bytes - total_page_nomatch_bytes; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci printf("\nSUMMARY (page allocator)"); 11778c2ecf20Sopenharmony_ci printf("\n========================\n"); 11788c2ecf20Sopenharmony_ci printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation requests", 11798c2ecf20Sopenharmony_ci nr_page_allocs, total_page_alloc_bytes / 1024); 11808c2ecf20Sopenharmony_ci printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free requests", 11818c2ecf20Sopenharmony_ci nr_page_frees, total_page_free_bytes / 1024); 11828c2ecf20Sopenharmony_ci printf("\n"); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci printf("%-30s: %'16"PRIu64" [ %'16"PRIu64" KB ]\n", "Total alloc+freed requests", 11858c2ecf20Sopenharmony_ci nr_alloc_freed, (total_alloc_freed_bytes) / 1024); 11868c2ecf20Sopenharmony_ci printf("%-30s: %'16"PRIu64" [ %'16"PRIu64" KB ]\n", "Total alloc-only requests", 11878c2ecf20Sopenharmony_ci nr_page_allocs - nr_alloc_freed, 11888c2ecf20Sopenharmony_ci (total_page_alloc_bytes - total_alloc_freed_bytes) / 1024); 11898c2ecf20Sopenharmony_ci printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total free-only requests", 11908c2ecf20Sopenharmony_ci nr_page_nomatch, total_page_nomatch_bytes / 1024); 11918c2ecf20Sopenharmony_ci printf("\n"); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci printf("%-30s: %'16lu [ %'16"PRIu64" KB ]\n", "Total allocation failures", 11948c2ecf20Sopenharmony_ci nr_page_fails, total_page_fail_bytes / 1024); 11958c2ecf20Sopenharmony_ci printf("\n"); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci printf("%5s %12s %12s %12s %12s %12s\n", "Order", "Unmovable", 11988c2ecf20Sopenharmony_ci "Reclaimable", "Movable", "Reserved", "CMA/Isolated"); 11998c2ecf20Sopenharmony_ci printf("%.5s %.12s %.12s %.12s %.12s %.12s\n", graph_dotted_line, 12008c2ecf20Sopenharmony_ci graph_dotted_line, graph_dotted_line, graph_dotted_line, 12018c2ecf20Sopenharmony_ci graph_dotted_line, graph_dotted_line); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci for (o = 0; o < MAX_PAGE_ORDER; o++) { 12048c2ecf20Sopenharmony_ci printf("%5d", o); 12058c2ecf20Sopenharmony_ci for (m = 0; m < MAX_MIGRATE_TYPES - 1; m++) { 12068c2ecf20Sopenharmony_ci if (order_stats[o][m]) 12078c2ecf20Sopenharmony_ci printf(" %'12d", order_stats[o][m]); 12088c2ecf20Sopenharmony_ci else 12098c2ecf20Sopenharmony_ci printf(" %12c", '.'); 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci printf("\n"); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic void print_slab_result(struct perf_session *session) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci if (caller_flag) 12188c2ecf20Sopenharmony_ci __print_slab_result(&root_caller_sorted, session, caller_lines, 1); 12198c2ecf20Sopenharmony_ci if (alloc_flag) 12208c2ecf20Sopenharmony_ci __print_slab_result(&root_alloc_sorted, session, alloc_lines, 0); 12218c2ecf20Sopenharmony_ci print_slab_summary(); 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic void print_page_result(struct perf_session *session) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci if (caller_flag || alloc_flag) 12278c2ecf20Sopenharmony_ci print_gfp_flags(); 12288c2ecf20Sopenharmony_ci if (caller_flag) 12298c2ecf20Sopenharmony_ci __print_page_caller_result(session, caller_lines); 12308c2ecf20Sopenharmony_ci if (alloc_flag) 12318c2ecf20Sopenharmony_ci __print_page_alloc_result(session, alloc_lines); 12328c2ecf20Sopenharmony_ci print_page_summary(); 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_cistatic void print_result(struct perf_session *session) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci if (kmem_slab) 12388c2ecf20Sopenharmony_ci print_slab_result(session); 12398c2ecf20Sopenharmony_ci if (kmem_page) 12408c2ecf20Sopenharmony_ci print_page_result(session); 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic LIST_HEAD(slab_caller_sort); 12448c2ecf20Sopenharmony_cistatic LIST_HEAD(slab_alloc_sort); 12458c2ecf20Sopenharmony_cistatic LIST_HEAD(page_caller_sort); 12468c2ecf20Sopenharmony_cistatic LIST_HEAD(page_alloc_sort); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic void sort_slab_insert(struct rb_root *root, struct alloc_stat *data, 12498c2ecf20Sopenharmony_ci struct list_head *sort_list) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci struct rb_node **new = &(root->rb_node); 12528c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 12538c2ecf20Sopenharmony_ci struct sort_dimension *sort; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci while (*new) { 12568c2ecf20Sopenharmony_ci struct alloc_stat *this; 12578c2ecf20Sopenharmony_ci int cmp = 0; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci this = rb_entry(*new, struct alloc_stat, node); 12608c2ecf20Sopenharmony_ci parent = *new; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci list_for_each_entry(sort, sort_list, list) { 12638c2ecf20Sopenharmony_ci cmp = sort->cmp(data, this); 12648c2ecf20Sopenharmony_ci if (cmp) 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (cmp > 0) 12698c2ecf20Sopenharmony_ci new = &((*new)->rb_left); 12708c2ecf20Sopenharmony_ci else 12718c2ecf20Sopenharmony_ci new = &((*new)->rb_right); 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, new); 12758c2ecf20Sopenharmony_ci rb_insert_color(&data->node, root); 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic void __sort_slab_result(struct rb_root *root, struct rb_root *root_sorted, 12798c2ecf20Sopenharmony_ci struct list_head *sort_list) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci struct rb_node *node; 12828c2ecf20Sopenharmony_ci struct alloc_stat *data; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci for (;;) { 12858c2ecf20Sopenharmony_ci node = rb_first(root); 12868c2ecf20Sopenharmony_ci if (!node) 12878c2ecf20Sopenharmony_ci break; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci rb_erase(node, root); 12908c2ecf20Sopenharmony_ci data = rb_entry(node, struct alloc_stat, node); 12918c2ecf20Sopenharmony_ci sort_slab_insert(root_sorted, data, sort_list); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic void sort_page_insert(struct rb_root *root, struct page_stat *data, 12968c2ecf20Sopenharmony_ci struct list_head *sort_list) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci struct rb_node **new = &root->rb_node; 12998c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 13008c2ecf20Sopenharmony_ci struct sort_dimension *sort; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci while (*new) { 13038c2ecf20Sopenharmony_ci struct page_stat *this; 13048c2ecf20Sopenharmony_ci int cmp = 0; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci this = rb_entry(*new, struct page_stat, node); 13078c2ecf20Sopenharmony_ci parent = *new; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci list_for_each_entry(sort, sort_list, list) { 13108c2ecf20Sopenharmony_ci cmp = sort->cmp(data, this); 13118c2ecf20Sopenharmony_ci if (cmp) 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (cmp > 0) 13168c2ecf20Sopenharmony_ci new = &parent->rb_left; 13178c2ecf20Sopenharmony_ci else 13188c2ecf20Sopenharmony_ci new = &parent->rb_right; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci rb_link_node(&data->node, parent, new); 13228c2ecf20Sopenharmony_ci rb_insert_color(&data->node, root); 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted, 13268c2ecf20Sopenharmony_ci struct list_head *sort_list) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct rb_node *node; 13298c2ecf20Sopenharmony_ci struct page_stat *data; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci for (;;) { 13328c2ecf20Sopenharmony_ci node = rb_first(root); 13338c2ecf20Sopenharmony_ci if (!node) 13348c2ecf20Sopenharmony_ci break; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci rb_erase(node, root); 13378c2ecf20Sopenharmony_ci data = rb_entry(node, struct page_stat, node); 13388c2ecf20Sopenharmony_ci sort_page_insert(root_sorted, data, sort_list); 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic void sort_result(void) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci if (kmem_slab) { 13458c2ecf20Sopenharmony_ci __sort_slab_result(&root_alloc_stat, &root_alloc_sorted, 13468c2ecf20Sopenharmony_ci &slab_alloc_sort); 13478c2ecf20Sopenharmony_ci __sort_slab_result(&root_caller_stat, &root_caller_sorted, 13488c2ecf20Sopenharmony_ci &slab_caller_sort); 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci if (kmem_page) { 13518c2ecf20Sopenharmony_ci if (live_page) 13528c2ecf20Sopenharmony_ci __sort_page_result(&page_live_tree, &page_alloc_sorted, 13538c2ecf20Sopenharmony_ci &page_alloc_sort); 13548c2ecf20Sopenharmony_ci else 13558c2ecf20Sopenharmony_ci __sort_page_result(&page_alloc_tree, &page_alloc_sorted, 13568c2ecf20Sopenharmony_ci &page_alloc_sort); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci __sort_page_result(&page_caller_tree, &page_caller_sorted, 13598c2ecf20Sopenharmony_ci &page_caller_sort); 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic int __cmd_kmem(struct perf_session *session) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci int err = -EINVAL; 13668c2ecf20Sopenharmony_ci struct evsel *evsel; 13678c2ecf20Sopenharmony_ci const struct evsel_str_handler kmem_tracepoints[] = { 13688c2ecf20Sopenharmony_ci /* slab allocator */ 13698c2ecf20Sopenharmony_ci { "kmem:kmalloc", evsel__process_alloc_event, }, 13708c2ecf20Sopenharmony_ci { "kmem:kmem_cache_alloc", evsel__process_alloc_event, }, 13718c2ecf20Sopenharmony_ci { "kmem:kmalloc_node", evsel__process_alloc_node_event, }, 13728c2ecf20Sopenharmony_ci { "kmem:kmem_cache_alloc_node", evsel__process_alloc_node_event, }, 13738c2ecf20Sopenharmony_ci { "kmem:kfree", evsel__process_free_event, }, 13748c2ecf20Sopenharmony_ci { "kmem:kmem_cache_free", evsel__process_free_event, }, 13758c2ecf20Sopenharmony_ci /* page allocator */ 13768c2ecf20Sopenharmony_ci { "kmem:mm_page_alloc", evsel__process_page_alloc_event, }, 13778c2ecf20Sopenharmony_ci { "kmem:mm_page_free", evsel__process_page_free_event, }, 13788c2ecf20Sopenharmony_ci }; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!perf_session__has_traces(session, "kmem record")) 13818c2ecf20Sopenharmony_ci goto out; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) { 13848c2ecf20Sopenharmony_ci pr_err("Initializing perf session tracepoint handlers failed\n"); 13858c2ecf20Sopenharmony_ci goto out; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 13898c2ecf20Sopenharmony_ci if (!strcmp(evsel__name(evsel), "kmem:mm_page_alloc") && 13908c2ecf20Sopenharmony_ci evsel__field(evsel, "pfn")) { 13918c2ecf20Sopenharmony_ci use_pfn = true; 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci setup_pager(); 13978c2ecf20Sopenharmony_ci err = perf_session__process_events(session); 13988c2ecf20Sopenharmony_ci if (err != 0) { 13998c2ecf20Sopenharmony_ci pr_err("error during process events: %d\n", err); 14008c2ecf20Sopenharmony_ci goto out; 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci sort_result(); 14038c2ecf20Sopenharmony_ci print_result(session); 14048c2ecf20Sopenharmony_ciout: 14058c2ecf20Sopenharmony_ci return err; 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci/* slab sort keys */ 14098c2ecf20Sopenharmony_cistatic int ptr_cmp(void *a, void *b) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci struct alloc_stat *l = a; 14128c2ecf20Sopenharmony_ci struct alloc_stat *r = b; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (l->ptr < r->ptr) 14158c2ecf20Sopenharmony_ci return -1; 14168c2ecf20Sopenharmony_ci else if (l->ptr > r->ptr) 14178c2ecf20Sopenharmony_ci return 1; 14188c2ecf20Sopenharmony_ci return 0; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_cistatic struct sort_dimension ptr_sort_dimension = { 14228c2ecf20Sopenharmony_ci .name = "ptr", 14238c2ecf20Sopenharmony_ci .cmp = ptr_cmp, 14248c2ecf20Sopenharmony_ci}; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_cistatic int slab_callsite_cmp(void *a, void *b) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci struct alloc_stat *l = a; 14298c2ecf20Sopenharmony_ci struct alloc_stat *r = b; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (l->call_site < r->call_site) 14328c2ecf20Sopenharmony_ci return -1; 14338c2ecf20Sopenharmony_ci else if (l->call_site > r->call_site) 14348c2ecf20Sopenharmony_ci return 1; 14358c2ecf20Sopenharmony_ci return 0; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic struct sort_dimension callsite_sort_dimension = { 14398c2ecf20Sopenharmony_ci .name = "callsite", 14408c2ecf20Sopenharmony_ci .cmp = slab_callsite_cmp, 14418c2ecf20Sopenharmony_ci}; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic int hit_cmp(void *a, void *b) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct alloc_stat *l = a; 14468c2ecf20Sopenharmony_ci struct alloc_stat *r = b; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (l->hit < r->hit) 14498c2ecf20Sopenharmony_ci return -1; 14508c2ecf20Sopenharmony_ci else if (l->hit > r->hit) 14518c2ecf20Sopenharmony_ci return 1; 14528c2ecf20Sopenharmony_ci return 0; 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic struct sort_dimension hit_sort_dimension = { 14568c2ecf20Sopenharmony_ci .name = "hit", 14578c2ecf20Sopenharmony_ci .cmp = hit_cmp, 14588c2ecf20Sopenharmony_ci}; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_cistatic int bytes_cmp(void *a, void *b) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci struct alloc_stat *l = a; 14638c2ecf20Sopenharmony_ci struct alloc_stat *r = b; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (l->bytes_alloc < r->bytes_alloc) 14668c2ecf20Sopenharmony_ci return -1; 14678c2ecf20Sopenharmony_ci else if (l->bytes_alloc > r->bytes_alloc) 14688c2ecf20Sopenharmony_ci return 1; 14698c2ecf20Sopenharmony_ci return 0; 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic struct sort_dimension bytes_sort_dimension = { 14738c2ecf20Sopenharmony_ci .name = "bytes", 14748c2ecf20Sopenharmony_ci .cmp = bytes_cmp, 14758c2ecf20Sopenharmony_ci}; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_cistatic int frag_cmp(void *a, void *b) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci double x, y; 14808c2ecf20Sopenharmony_ci struct alloc_stat *l = a; 14818c2ecf20Sopenharmony_ci struct alloc_stat *r = b; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci x = fragmentation(l->bytes_req, l->bytes_alloc); 14848c2ecf20Sopenharmony_ci y = fragmentation(r->bytes_req, r->bytes_alloc); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (x < y) 14878c2ecf20Sopenharmony_ci return -1; 14888c2ecf20Sopenharmony_ci else if (x > y) 14898c2ecf20Sopenharmony_ci return 1; 14908c2ecf20Sopenharmony_ci return 0; 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic struct sort_dimension frag_sort_dimension = { 14948c2ecf20Sopenharmony_ci .name = "frag", 14958c2ecf20Sopenharmony_ci .cmp = frag_cmp, 14968c2ecf20Sopenharmony_ci}; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic int pingpong_cmp(void *a, void *b) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci struct alloc_stat *l = a; 15018c2ecf20Sopenharmony_ci struct alloc_stat *r = b; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if (l->pingpong < r->pingpong) 15048c2ecf20Sopenharmony_ci return -1; 15058c2ecf20Sopenharmony_ci else if (l->pingpong > r->pingpong) 15068c2ecf20Sopenharmony_ci return 1; 15078c2ecf20Sopenharmony_ci return 0; 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cistatic struct sort_dimension pingpong_sort_dimension = { 15118c2ecf20Sopenharmony_ci .name = "pingpong", 15128c2ecf20Sopenharmony_ci .cmp = pingpong_cmp, 15138c2ecf20Sopenharmony_ci}; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci/* page sort keys */ 15168c2ecf20Sopenharmony_cistatic int page_cmp(void *a, void *b) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci struct page_stat *l = a; 15198c2ecf20Sopenharmony_ci struct page_stat *r = b; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (l->page < r->page) 15228c2ecf20Sopenharmony_ci return -1; 15238c2ecf20Sopenharmony_ci else if (l->page > r->page) 15248c2ecf20Sopenharmony_ci return 1; 15258c2ecf20Sopenharmony_ci return 0; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic struct sort_dimension page_sort_dimension = { 15298c2ecf20Sopenharmony_ci .name = "page", 15308c2ecf20Sopenharmony_ci .cmp = page_cmp, 15318c2ecf20Sopenharmony_ci}; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic int page_callsite_cmp(void *a, void *b) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci struct page_stat *l = a; 15368c2ecf20Sopenharmony_ci struct page_stat *r = b; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (l->callsite < r->callsite) 15398c2ecf20Sopenharmony_ci return -1; 15408c2ecf20Sopenharmony_ci else if (l->callsite > r->callsite) 15418c2ecf20Sopenharmony_ci return 1; 15428c2ecf20Sopenharmony_ci return 0; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic struct sort_dimension page_callsite_sort_dimension = { 15468c2ecf20Sopenharmony_ci .name = "callsite", 15478c2ecf20Sopenharmony_ci .cmp = page_callsite_cmp, 15488c2ecf20Sopenharmony_ci}; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_cistatic int page_hit_cmp(void *a, void *b) 15518c2ecf20Sopenharmony_ci{ 15528c2ecf20Sopenharmony_ci struct page_stat *l = a; 15538c2ecf20Sopenharmony_ci struct page_stat *r = b; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (l->nr_alloc < r->nr_alloc) 15568c2ecf20Sopenharmony_ci return -1; 15578c2ecf20Sopenharmony_ci else if (l->nr_alloc > r->nr_alloc) 15588c2ecf20Sopenharmony_ci return 1; 15598c2ecf20Sopenharmony_ci return 0; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic struct sort_dimension page_hit_sort_dimension = { 15638c2ecf20Sopenharmony_ci .name = "hit", 15648c2ecf20Sopenharmony_ci .cmp = page_hit_cmp, 15658c2ecf20Sopenharmony_ci}; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic int page_bytes_cmp(void *a, void *b) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci struct page_stat *l = a; 15708c2ecf20Sopenharmony_ci struct page_stat *r = b; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci if (l->alloc_bytes < r->alloc_bytes) 15738c2ecf20Sopenharmony_ci return -1; 15748c2ecf20Sopenharmony_ci else if (l->alloc_bytes > r->alloc_bytes) 15758c2ecf20Sopenharmony_ci return 1; 15768c2ecf20Sopenharmony_ci return 0; 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_cistatic struct sort_dimension page_bytes_sort_dimension = { 15808c2ecf20Sopenharmony_ci .name = "bytes", 15818c2ecf20Sopenharmony_ci .cmp = page_bytes_cmp, 15828c2ecf20Sopenharmony_ci}; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_cistatic int page_order_cmp(void *a, void *b) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci struct page_stat *l = a; 15878c2ecf20Sopenharmony_ci struct page_stat *r = b; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (l->order < r->order) 15908c2ecf20Sopenharmony_ci return -1; 15918c2ecf20Sopenharmony_ci else if (l->order > r->order) 15928c2ecf20Sopenharmony_ci return 1; 15938c2ecf20Sopenharmony_ci return 0; 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_cistatic struct sort_dimension page_order_sort_dimension = { 15978c2ecf20Sopenharmony_ci .name = "order", 15988c2ecf20Sopenharmony_ci .cmp = page_order_cmp, 15998c2ecf20Sopenharmony_ci}; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_cistatic int migrate_type_cmp(void *a, void *b) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci struct page_stat *l = a; 16048c2ecf20Sopenharmony_ci struct page_stat *r = b; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* for internal use to find free'd page */ 16078c2ecf20Sopenharmony_ci if (l->migrate_type == -1U) 16088c2ecf20Sopenharmony_ci return 0; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (l->migrate_type < r->migrate_type) 16118c2ecf20Sopenharmony_ci return -1; 16128c2ecf20Sopenharmony_ci else if (l->migrate_type > r->migrate_type) 16138c2ecf20Sopenharmony_ci return 1; 16148c2ecf20Sopenharmony_ci return 0; 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic struct sort_dimension migrate_type_sort_dimension = { 16188c2ecf20Sopenharmony_ci .name = "migtype", 16198c2ecf20Sopenharmony_ci .cmp = migrate_type_cmp, 16208c2ecf20Sopenharmony_ci}; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic int gfp_flags_cmp(void *a, void *b) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci struct page_stat *l = a; 16258c2ecf20Sopenharmony_ci struct page_stat *r = b; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* for internal use to find free'd page */ 16288c2ecf20Sopenharmony_ci if (l->gfp_flags == -1U) 16298c2ecf20Sopenharmony_ci return 0; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (l->gfp_flags < r->gfp_flags) 16328c2ecf20Sopenharmony_ci return -1; 16338c2ecf20Sopenharmony_ci else if (l->gfp_flags > r->gfp_flags) 16348c2ecf20Sopenharmony_ci return 1; 16358c2ecf20Sopenharmony_ci return 0; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic struct sort_dimension gfp_flags_sort_dimension = { 16398c2ecf20Sopenharmony_ci .name = "gfp", 16408c2ecf20Sopenharmony_ci .cmp = gfp_flags_cmp, 16418c2ecf20Sopenharmony_ci}; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic struct sort_dimension *slab_sorts[] = { 16448c2ecf20Sopenharmony_ci &ptr_sort_dimension, 16458c2ecf20Sopenharmony_ci &callsite_sort_dimension, 16468c2ecf20Sopenharmony_ci &hit_sort_dimension, 16478c2ecf20Sopenharmony_ci &bytes_sort_dimension, 16488c2ecf20Sopenharmony_ci &frag_sort_dimension, 16498c2ecf20Sopenharmony_ci &pingpong_sort_dimension, 16508c2ecf20Sopenharmony_ci}; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic struct sort_dimension *page_sorts[] = { 16538c2ecf20Sopenharmony_ci &page_sort_dimension, 16548c2ecf20Sopenharmony_ci &page_callsite_sort_dimension, 16558c2ecf20Sopenharmony_ci &page_hit_sort_dimension, 16568c2ecf20Sopenharmony_ci &page_bytes_sort_dimension, 16578c2ecf20Sopenharmony_ci &page_order_sort_dimension, 16588c2ecf20Sopenharmony_ci &migrate_type_sort_dimension, 16598c2ecf20Sopenharmony_ci &gfp_flags_sort_dimension, 16608c2ecf20Sopenharmony_ci}; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_cistatic int slab_sort_dimension__add(const char *tok, struct list_head *list) 16638c2ecf20Sopenharmony_ci{ 16648c2ecf20Sopenharmony_ci struct sort_dimension *sort; 16658c2ecf20Sopenharmony_ci int i; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(slab_sorts); i++) { 16688c2ecf20Sopenharmony_ci if (!strcmp(slab_sorts[i]->name, tok)) { 16698c2ecf20Sopenharmony_ci sort = memdup(slab_sorts[i], sizeof(*slab_sorts[i])); 16708c2ecf20Sopenharmony_ci if (!sort) { 16718c2ecf20Sopenharmony_ci pr_err("%s: memdup failed\n", __func__); 16728c2ecf20Sopenharmony_ci return -1; 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci list_add_tail(&sort->list, list); 16758c2ecf20Sopenharmony_ci return 0; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci return -1; 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic int page_sort_dimension__add(const char *tok, struct list_head *list) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci struct sort_dimension *sort; 16858c2ecf20Sopenharmony_ci int i; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(page_sorts); i++) { 16888c2ecf20Sopenharmony_ci if (!strcmp(page_sorts[i]->name, tok)) { 16898c2ecf20Sopenharmony_ci sort = memdup(page_sorts[i], sizeof(*page_sorts[i])); 16908c2ecf20Sopenharmony_ci if (!sort) { 16918c2ecf20Sopenharmony_ci pr_err("%s: memdup failed\n", __func__); 16928c2ecf20Sopenharmony_ci return -1; 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci list_add_tail(&sort->list, list); 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci return -1; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic int setup_slab_sorting(struct list_head *sort_list, const char *arg) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci char *tok; 17058c2ecf20Sopenharmony_ci char *str = strdup(arg); 17068c2ecf20Sopenharmony_ci char *pos = str; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (!str) { 17098c2ecf20Sopenharmony_ci pr_err("%s: strdup failed\n", __func__); 17108c2ecf20Sopenharmony_ci return -1; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci while (true) { 17148c2ecf20Sopenharmony_ci tok = strsep(&pos, ","); 17158c2ecf20Sopenharmony_ci if (!tok) 17168c2ecf20Sopenharmony_ci break; 17178c2ecf20Sopenharmony_ci if (slab_sort_dimension__add(tok, sort_list) < 0) { 17188c2ecf20Sopenharmony_ci pr_err("Unknown slab --sort key: '%s'", tok); 17198c2ecf20Sopenharmony_ci free(str); 17208c2ecf20Sopenharmony_ci return -1; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci free(str); 17258c2ecf20Sopenharmony_ci return 0; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic int setup_page_sorting(struct list_head *sort_list, const char *arg) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci char *tok; 17318c2ecf20Sopenharmony_ci char *str = strdup(arg); 17328c2ecf20Sopenharmony_ci char *pos = str; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (!str) { 17358c2ecf20Sopenharmony_ci pr_err("%s: strdup failed\n", __func__); 17368c2ecf20Sopenharmony_ci return -1; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci while (true) { 17408c2ecf20Sopenharmony_ci tok = strsep(&pos, ","); 17418c2ecf20Sopenharmony_ci if (!tok) 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci if (page_sort_dimension__add(tok, sort_list) < 0) { 17448c2ecf20Sopenharmony_ci pr_err("Unknown page --sort key: '%s'", tok); 17458c2ecf20Sopenharmony_ci free(str); 17468c2ecf20Sopenharmony_ci return -1; 17478c2ecf20Sopenharmony_ci } 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci free(str); 17518c2ecf20Sopenharmony_ci return 0; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic int parse_sort_opt(const struct option *opt __maybe_unused, 17558c2ecf20Sopenharmony_ci const char *arg, int unset __maybe_unused) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci if (!arg) 17588c2ecf20Sopenharmony_ci return -1; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci if (kmem_page > kmem_slab || 17618c2ecf20Sopenharmony_ci (kmem_page == 0 && kmem_slab == 0 && kmem_default == KMEM_PAGE)) { 17628c2ecf20Sopenharmony_ci if (caller_flag > alloc_flag) 17638c2ecf20Sopenharmony_ci return setup_page_sorting(&page_caller_sort, arg); 17648c2ecf20Sopenharmony_ci else 17658c2ecf20Sopenharmony_ci return setup_page_sorting(&page_alloc_sort, arg); 17668c2ecf20Sopenharmony_ci } else { 17678c2ecf20Sopenharmony_ci if (caller_flag > alloc_flag) 17688c2ecf20Sopenharmony_ci return setup_slab_sorting(&slab_caller_sort, arg); 17698c2ecf20Sopenharmony_ci else 17708c2ecf20Sopenharmony_ci return setup_slab_sorting(&slab_alloc_sort, arg); 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci return 0; 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_cistatic int parse_caller_opt(const struct option *opt __maybe_unused, 17778c2ecf20Sopenharmony_ci const char *arg __maybe_unused, 17788c2ecf20Sopenharmony_ci int unset __maybe_unused) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci caller_flag = (alloc_flag + 1); 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cistatic int parse_alloc_opt(const struct option *opt __maybe_unused, 17858c2ecf20Sopenharmony_ci const char *arg __maybe_unused, 17868c2ecf20Sopenharmony_ci int unset __maybe_unused) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci alloc_flag = (caller_flag + 1); 17898c2ecf20Sopenharmony_ci return 0; 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic int parse_slab_opt(const struct option *opt __maybe_unused, 17938c2ecf20Sopenharmony_ci const char *arg __maybe_unused, 17948c2ecf20Sopenharmony_ci int unset __maybe_unused) 17958c2ecf20Sopenharmony_ci{ 17968c2ecf20Sopenharmony_ci kmem_slab = (kmem_page + 1); 17978c2ecf20Sopenharmony_ci return 0; 17988c2ecf20Sopenharmony_ci} 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_cistatic int parse_page_opt(const struct option *opt __maybe_unused, 18018c2ecf20Sopenharmony_ci const char *arg __maybe_unused, 18028c2ecf20Sopenharmony_ci int unset __maybe_unused) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci kmem_page = (kmem_slab + 1); 18058c2ecf20Sopenharmony_ci return 0; 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cistatic int parse_line_opt(const struct option *opt __maybe_unused, 18098c2ecf20Sopenharmony_ci const char *arg, int unset __maybe_unused) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci int lines; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci if (!arg) 18148c2ecf20Sopenharmony_ci return -1; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci lines = strtoul(arg, NULL, 10); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (caller_flag > alloc_flag) 18198c2ecf20Sopenharmony_ci caller_lines = lines; 18208c2ecf20Sopenharmony_ci else 18218c2ecf20Sopenharmony_ci alloc_lines = lines; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci return 0; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_cistatic int __cmd_record(int argc, const char **argv) 18278c2ecf20Sopenharmony_ci{ 18288c2ecf20Sopenharmony_ci const char * const record_args[] = { 18298c2ecf20Sopenharmony_ci "record", "-a", "-R", "-c", "1", 18308c2ecf20Sopenharmony_ci }; 18318c2ecf20Sopenharmony_ci const char * const slab_events[] = { 18328c2ecf20Sopenharmony_ci "-e", "kmem:kmalloc", 18338c2ecf20Sopenharmony_ci "-e", "kmem:kmalloc_node", 18348c2ecf20Sopenharmony_ci "-e", "kmem:kfree", 18358c2ecf20Sopenharmony_ci "-e", "kmem:kmem_cache_alloc", 18368c2ecf20Sopenharmony_ci "-e", "kmem:kmem_cache_alloc_node", 18378c2ecf20Sopenharmony_ci "-e", "kmem:kmem_cache_free", 18388c2ecf20Sopenharmony_ci }; 18398c2ecf20Sopenharmony_ci const char * const page_events[] = { 18408c2ecf20Sopenharmony_ci "-e", "kmem:mm_page_alloc", 18418c2ecf20Sopenharmony_ci "-e", "kmem:mm_page_free", 18428c2ecf20Sopenharmony_ci }; 18438c2ecf20Sopenharmony_ci unsigned int rec_argc, i, j; 18448c2ecf20Sopenharmony_ci const char **rec_argv; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci rec_argc = ARRAY_SIZE(record_args) + argc - 1; 18478c2ecf20Sopenharmony_ci if (kmem_slab) 18488c2ecf20Sopenharmony_ci rec_argc += ARRAY_SIZE(slab_events); 18498c2ecf20Sopenharmony_ci if (kmem_page) 18508c2ecf20Sopenharmony_ci rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */ 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci rec_argv = calloc(rec_argc + 1, sizeof(char *)); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if (rec_argv == NULL) 18558c2ecf20Sopenharmony_ci return -ENOMEM; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(record_args); i++) 18588c2ecf20Sopenharmony_ci rec_argv[i] = strdup(record_args[i]); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (kmem_slab) { 18618c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++) 18628c2ecf20Sopenharmony_ci rec_argv[i] = strdup(slab_events[j]); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci if (kmem_page) { 18658c2ecf20Sopenharmony_ci rec_argv[i++] = strdup("-g"); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(page_events); j++, i++) 18688c2ecf20Sopenharmony_ci rec_argv[i] = strdup(page_events[j]); 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci for (j = 1; j < (unsigned int)argc; j++, i++) 18728c2ecf20Sopenharmony_ci rec_argv[i] = argv[j]; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci return cmd_record(i, rec_argv); 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cistatic int kmem_config(const char *var, const char *value, void *cb __maybe_unused) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci if (!strcmp(var, "kmem.default")) { 18808c2ecf20Sopenharmony_ci if (!strcmp(value, "slab")) 18818c2ecf20Sopenharmony_ci kmem_default = KMEM_SLAB; 18828c2ecf20Sopenharmony_ci else if (!strcmp(value, "page")) 18838c2ecf20Sopenharmony_ci kmem_default = KMEM_PAGE; 18848c2ecf20Sopenharmony_ci else 18858c2ecf20Sopenharmony_ci pr_err("invalid default value ('slab' or 'page' required): %s\n", 18868c2ecf20Sopenharmony_ci value); 18878c2ecf20Sopenharmony_ci return 0; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ciint cmd_kmem(int argc, const char **argv) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci const char * const default_slab_sort = "frag,hit,bytes"; 18968c2ecf20Sopenharmony_ci const char * const default_page_sort = "bytes,hit"; 18978c2ecf20Sopenharmony_ci struct perf_data data = { 18988c2ecf20Sopenharmony_ci .mode = PERF_DATA_MODE_READ, 18998c2ecf20Sopenharmony_ci }; 19008c2ecf20Sopenharmony_ci const struct option kmem_options[] = { 19018c2ecf20Sopenharmony_ci OPT_STRING('i', "input", &input_name, "file", "input file name"), 19028c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 19038c2ecf20Sopenharmony_ci "be more verbose (show symbol address, etc)"), 19048c2ecf20Sopenharmony_ci OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, 19058c2ecf20Sopenharmony_ci "show per-callsite statistics", parse_caller_opt), 19068c2ecf20Sopenharmony_ci OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, 19078c2ecf20Sopenharmony_ci "show per-allocation statistics", parse_alloc_opt), 19088c2ecf20Sopenharmony_ci OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", 19098c2ecf20Sopenharmony_ci "sort by keys: ptr, callsite, bytes, hit, pingpong, frag, " 19108c2ecf20Sopenharmony_ci "page, order, migtype, gfp", parse_sort_opt), 19118c2ecf20Sopenharmony_ci OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt), 19128c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 19138c2ecf20Sopenharmony_ci OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), 19148c2ecf20Sopenharmony_ci OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator", 19158c2ecf20Sopenharmony_ci parse_slab_opt), 19168c2ecf20Sopenharmony_ci OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator", 19178c2ecf20Sopenharmony_ci parse_page_opt), 19188c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "live", &live_page, "Show live page stat"), 19198c2ecf20Sopenharmony_ci OPT_STRING(0, "time", &time_str, "str", 19208c2ecf20Sopenharmony_ci "Time span of interest (start,stop)"), 19218c2ecf20Sopenharmony_ci OPT_END() 19228c2ecf20Sopenharmony_ci }; 19238c2ecf20Sopenharmony_ci const char *const kmem_subcommands[] = { "record", "stat", NULL }; 19248c2ecf20Sopenharmony_ci const char *kmem_usage[] = { 19258c2ecf20Sopenharmony_ci NULL, 19268c2ecf20Sopenharmony_ci NULL 19278c2ecf20Sopenharmony_ci }; 19288c2ecf20Sopenharmony_ci struct perf_session *session; 19298c2ecf20Sopenharmony_ci static const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n"; 19308c2ecf20Sopenharmony_ci int ret = perf_config(kmem_config, NULL); 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci if (ret) 19338c2ecf20Sopenharmony_ci return ret; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci argc = parse_options_subcommand(argc, argv, kmem_options, 19368c2ecf20Sopenharmony_ci kmem_subcommands, kmem_usage, 19378c2ecf20Sopenharmony_ci PARSE_OPT_STOP_AT_NON_OPTION); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (!argc) 19408c2ecf20Sopenharmony_ci usage_with_options(kmem_usage, kmem_options); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci if (kmem_slab == 0 && kmem_page == 0) { 19438c2ecf20Sopenharmony_ci if (kmem_default == KMEM_SLAB) 19448c2ecf20Sopenharmony_ci kmem_slab = 1; 19458c2ecf20Sopenharmony_ci else 19468c2ecf20Sopenharmony_ci kmem_page = 1; 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (!strncmp(argv[0], "rec", 3)) { 19508c2ecf20Sopenharmony_ci symbol__init(NULL); 19518c2ecf20Sopenharmony_ci return __cmd_record(argc, argv); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci data.path = input_name; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci kmem_session = session = perf_session__new(&data, false, &perf_kmem); 19578c2ecf20Sopenharmony_ci if (IS_ERR(session)) 19588c2ecf20Sopenharmony_ci return PTR_ERR(session); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci ret = -1; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (kmem_slab) { 19638c2ecf20Sopenharmony_ci if (!perf_evlist__find_tracepoint_by_name(session->evlist, 19648c2ecf20Sopenharmony_ci "kmem:kmalloc")) { 19658c2ecf20Sopenharmony_ci pr_err(errmsg, "slab", "slab"); 19668c2ecf20Sopenharmony_ci goto out_delete; 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci if (kmem_page) { 19718c2ecf20Sopenharmony_ci struct evsel *evsel; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 19748c2ecf20Sopenharmony_ci "kmem:mm_page_alloc"); 19758c2ecf20Sopenharmony_ci if (evsel == NULL) { 19768c2ecf20Sopenharmony_ci pr_err(errmsg, "page", "page"); 19778c2ecf20Sopenharmony_ci goto out_delete; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci kmem_page_size = tep_get_page_size(evsel->tp_format->tep); 19818c2ecf20Sopenharmony_ci symbol_conf.use_callchain = true; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci symbol__init(&session->header.env); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (perf_time__parse_str(&ptime, time_str) != 0) { 19878c2ecf20Sopenharmony_ci pr_err("Invalid time string\n"); 19888c2ecf20Sopenharmony_ci ret = -EINVAL; 19898c2ecf20Sopenharmony_ci goto out_delete; 19908c2ecf20Sopenharmony_ci } 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (!strcmp(argv[0], "stat")) { 19938c2ecf20Sopenharmony_ci setlocale(LC_ALL, ""); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (cpu__setup_cpunode_map()) 19968c2ecf20Sopenharmony_ci goto out_delete; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci if (list_empty(&slab_caller_sort)) 19998c2ecf20Sopenharmony_ci setup_slab_sorting(&slab_caller_sort, default_slab_sort); 20008c2ecf20Sopenharmony_ci if (list_empty(&slab_alloc_sort)) 20018c2ecf20Sopenharmony_ci setup_slab_sorting(&slab_alloc_sort, default_slab_sort); 20028c2ecf20Sopenharmony_ci if (list_empty(&page_caller_sort)) 20038c2ecf20Sopenharmony_ci setup_page_sorting(&page_caller_sort, default_page_sort); 20048c2ecf20Sopenharmony_ci if (list_empty(&page_alloc_sort)) 20058c2ecf20Sopenharmony_ci setup_page_sorting(&page_alloc_sort, default_page_sort); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (kmem_page) { 20088c2ecf20Sopenharmony_ci setup_page_sorting(&page_alloc_sort_input, 20098c2ecf20Sopenharmony_ci "page,order,migtype,gfp"); 20108c2ecf20Sopenharmony_ci setup_page_sorting(&page_caller_sort_input, 20118c2ecf20Sopenharmony_ci "callsite,order,migtype,gfp"); 20128c2ecf20Sopenharmony_ci } 20138c2ecf20Sopenharmony_ci ret = __cmd_kmem(session); 20148c2ecf20Sopenharmony_ci } else 20158c2ecf20Sopenharmony_ci usage_with_options(kmem_usage, kmem_options); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ciout_delete: 20188c2ecf20Sopenharmony_ci perf_session__delete(session); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci return ret; 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 2023