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