Blame view
tools/perf/builtin-kmem.c
17.2 KB
ba77c9e11 perf: Add 'perf k... |
1 2 3 4 5 6 7 8 |
#include "builtin.h" #include "perf.h" #include "util/util.h" #include "util/cache.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" |
94c744b6c perf tools: Intro... |
9 |
#include "util/session.h" |
ba77c9e11 perf: Add 'perf k... |
10 11 12 13 14 |
#include "util/parse-options.h" #include "util/trace-event.h" #include "util/debug.h" |
ba77c9e11 perf: Add 'perf k... |
15 16 17 18 19 20 21 |
#include <linux/rbtree.h> struct alloc_stat; typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); static char const *input_name = "perf.data"; |
ba77c9e11 perf: Add 'perf k... |
22 23 |
static int alloc_flag; static int caller_flag; |
ba77c9e11 perf: Add 'perf k... |
24 25 |
static int alloc_lines = -1; static int caller_lines = -1; |
7707b6b6f perf kmem: Add ne... |
26 |
static bool raw_ip; |
29b3e1528 perf kmem: Defaul... |
27 |
static char default_sort_order[] = "frag,hit,bytes"; |
7d0d39459 perf kmem: Collec... |
28 29 |
static int *cpunode_map; static int max_cpu_num; |
ba77c9e11 perf: Add 'perf k... |
30 |
struct alloc_stat { |
079d3f653 perf kmem: Measur... |
31 32 |
u64 call_site; u64 ptr; |
ba77c9e11 perf: Add 'perf k... |
33 34 35 |
u64 bytes_req; u64 bytes_alloc; u32 hit; |
079d3f653 perf kmem: Measur... |
36 37 38 |
u32 pingpong; short alloc_cpu; |
ba77c9e11 perf: Add 'perf k... |
39 40 41 42 43 44 45 46 47 48 |
struct rb_node node; }; static struct rb_root root_alloc_stat; static struct rb_root root_alloc_sorted; static struct rb_root root_caller_stat; static struct rb_root root_caller_sorted; static unsigned long total_requested, total_allocated; |
7d0d39459 perf kmem: Collec... |
49 |
static unsigned long nr_allocs, nr_cross_allocs; |
ba77c9e11 perf: Add 'perf k... |
50 |
|
7d0d39459 perf kmem: Collec... |
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#define PATH_SYS_NODE "/sys/devices/system/node" static void init_cpunode_map(void) { FILE *fp; int i; fp = fopen("/sys/devices/system/cpu/kernel_max", "r"); if (!fp) { max_cpu_num = 4096; return; } if (fscanf(fp, "%d", &max_cpu_num) < 1) die("Failed to read 'kernel_max' from sysfs"); max_cpu_num++; cpunode_map = calloc(max_cpu_num, sizeof(int)); if (!cpunode_map) die("calloc"); for (i = 0; i < max_cpu_num; i++) cpunode_map[i] = -1; fclose(fp); } static void setup_cpunode_map(void) { struct dirent *dent1, *dent2; DIR *dir1, *dir2; unsigned int cpu, mem; char buf[PATH_MAX]; init_cpunode_map(); dir1 = opendir(PATH_SYS_NODE); if (!dir1) return; |
659d8cfbb perf tools: Do a ... |
88 89 90 |
while ((dent1 = readdir(dir1)) != NULL) { if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1) |
7d0d39459 perf kmem: Collec... |
91 92 93 94 95 96 |
continue; snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); dir2 = opendir(buf); if (!dir2) continue; |
659d8cfbb perf tools: Do a ... |
97 98 99 |
while ((dent2 = readdir(dir2)) != NULL) { if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1) |
7d0d39459 perf kmem: Collec... |
100 101 102 103 104 |
continue; cpunode_map[cpu] = mem; } } } |
079d3f653 perf kmem: Measur... |
105 106 |
static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, int bytes_req, int bytes_alloc, int cpu) |
ba77c9e11 perf: Add 'perf k... |
107 108 109 110 |
{ struct rb_node **node = &root_alloc_stat.rb_node; struct rb_node *parent = NULL; struct alloc_stat *data = NULL; |
ba77c9e11 perf: Add 'perf k... |
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
while (*node) { parent = *node; data = rb_entry(*node, struct alloc_stat, node); if (ptr > data->ptr) node = &(*node)->rb_right; else if (ptr < data->ptr) node = &(*node)->rb_left; else break; } if (data && data->ptr == ptr) { data->hit++; data->bytes_req += bytes_req; |
4efb5290a perf kmem: Fix st... |
126 |
data->bytes_alloc += bytes_alloc; |
ba77c9e11 perf: Add 'perf k... |
127 128 |
} else { data = malloc(sizeof(*data)); |
079d3f653 perf kmem: Measur... |
129 130 |
if (!data) die("malloc"); |
ba77c9e11 perf: Add 'perf k... |
131 |
data->ptr = ptr; |
079d3f653 perf kmem: Measur... |
132 |
data->pingpong = 0; |
ba77c9e11 perf: Add 'perf k... |
133 134 135 136 137 138 139 |
data->hit = 1; data->bytes_req = bytes_req; data->bytes_alloc = bytes_alloc; rb_link_node(&data->node, parent, node); rb_insert_color(&data->node, &root_alloc_stat); } |
079d3f653 perf kmem: Measur... |
140 141 |
data->call_site = call_site; data->alloc_cpu = cpu; |
ba77c9e11 perf: Add 'perf k... |
142 143 144 145 146 147 148 149 |
} static void insert_caller_stat(unsigned long call_site, int bytes_req, int bytes_alloc) { struct rb_node **node = &root_caller_stat.rb_node; struct rb_node *parent = NULL; struct alloc_stat *data = NULL; |
ba77c9e11 perf: Add 'perf k... |
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
while (*node) { parent = *node; data = rb_entry(*node, struct alloc_stat, node); if (call_site > data->call_site) node = &(*node)->rb_right; else if (call_site < data->call_site) node = &(*node)->rb_left; else break; } if (data && data->call_site == call_site) { data->hit++; data->bytes_req += bytes_req; |
4efb5290a perf kmem: Fix st... |
165 |
data->bytes_alloc += bytes_alloc; |
ba77c9e11 perf: Add 'perf k... |
166 167 |
} else { data = malloc(sizeof(*data)); |
079d3f653 perf kmem: Measur... |
168 169 |
if (!data) die("malloc"); |
ba77c9e11 perf: Add 'perf k... |
170 |
data->call_site = call_site; |
079d3f653 perf kmem: Measur... |
171 |
data->pingpong = 0; |
ba77c9e11 perf: Add 'perf k... |
172 173 174 175 176 177 178 179 |
data->hit = 1; data->bytes_req = bytes_req; data->bytes_alloc = bytes_alloc; rb_link_node(&data->node, parent, node); rb_insert_color(&data->node, &root_caller_stat); } } |
f48f669d4 perf_event: Elimi... |
180 |
static void process_alloc_event(void *data, |
ba77c9e11 perf: Add 'perf k... |
181 |
struct event *event, |
7d0d39459 perf kmem: Collec... |
182 |
int cpu, |
ba77c9e11 perf: Add 'perf k... |
183 184 |
u64 timestamp __used, struct thread *thread __used, |
7d0d39459 perf kmem: Collec... |
185 |
int node) |
ba77c9e11 perf: Add 'perf k... |
186 187 188 189 190 |
{ unsigned long call_site; unsigned long ptr; int bytes_req; int bytes_alloc; |
7d0d39459 perf kmem: Collec... |
191 |
int node1, node2; |
ba77c9e11 perf: Add 'perf k... |
192 |
|
f48f669d4 perf_event: Elimi... |
193 194 195 196 |
ptr = raw_field_value(event, "ptr", data); call_site = raw_field_value(event, "call_site", data); bytes_req = raw_field_value(event, "bytes_req", data); bytes_alloc = raw_field_value(event, "bytes_alloc", data); |
ba77c9e11 perf: Add 'perf k... |
197 |
|
079d3f653 perf kmem: Measur... |
198 |
insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); |
ba77c9e11 perf: Add 'perf k... |
199 200 201 202 |
insert_caller_stat(call_site, bytes_req, bytes_alloc); total_requested += bytes_req; total_allocated += bytes_alloc; |
7d0d39459 perf kmem: Collec... |
203 204 205 |
if (node) { node1 = cpunode_map[cpu]; |
f48f669d4 perf_event: Elimi... |
206 |
node2 = raw_field_value(event, "node", data); |
7d0d39459 perf kmem: Collec... |
207 208 209 210 |
if (node1 != node2) nr_cross_allocs++; } nr_allocs++; |
ba77c9e11 perf: Add 'perf k... |
211 |
} |
079d3f653 perf kmem: Measur... |
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
static int ptr_cmp(struct alloc_stat *, struct alloc_stat *); static int callsite_cmp(struct alloc_stat *, struct alloc_stat *); static struct alloc_stat *search_alloc_stat(unsigned long ptr, unsigned long call_site, struct rb_root *root, sort_fn_t sort_fn) { struct rb_node *node = root->rb_node; struct alloc_stat key = { .ptr = ptr, .call_site = call_site }; while (node) { struct alloc_stat *data; int cmp; data = rb_entry(node, struct alloc_stat, node); cmp = sort_fn(&key, data); if (cmp < 0) node = node->rb_left; else if (cmp > 0) node = node->rb_right; else return data; } return NULL; } |
f48f669d4 perf_event: Elimi... |
239 |
static void process_free_event(void *data, |
079d3f653 perf kmem: Measur... |
240 241 |
struct event *event, int cpu, |
ba77c9e11 perf: Add 'perf k... |
242 243 244 |
u64 timestamp __used, struct thread *thread __used) { |
079d3f653 perf kmem: Measur... |
245 246 |
unsigned long ptr; struct alloc_stat *s_alloc, *s_caller; |
f48f669d4 perf_event: Elimi... |
247 |
ptr = raw_field_value(event, "ptr", data); |
079d3f653 perf kmem: Measur... |
248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); if (!s_alloc) return; if (cpu != s_alloc->alloc_cpu) { s_alloc->pingpong++; s_caller = search_alloc_stat(0, s_alloc->call_site, &root_caller_stat, callsite_cmp); assert(s_caller); s_caller->pingpong++; } s_alloc->alloc_cpu = -1; |
ba77c9e11 perf: Add 'perf k... |
262 |
} |
8115d60c3 perf tools: Kill ... |
263 264 |
static void process_raw_event(union perf_event *raw_event __used, void *data, int cpu, u64 timestamp, struct thread *thread) |
ba77c9e11 perf: Add 'perf k... |
265 |
{ |
ba77c9e11 perf: Add 'perf k... |
266 267 |
struct event *event; int type; |
f48f669d4 perf_event: Elimi... |
268 |
type = trace_parse_common_type(data); |
ba77c9e11 perf: Add 'perf k... |
269 270 271 272 |
event = trace_find_event(type); if (!strcmp(event->name, "kmalloc") || !strcmp(event->name, "kmem_cache_alloc")) { |
f48f669d4 perf_event: Elimi... |
273 |
process_alloc_event(data, event, cpu, timestamp, thread, 0); |
ba77c9e11 perf: Add 'perf k... |
274 275 276 277 278 |
return; } if (!strcmp(event->name, "kmalloc_node") || !strcmp(event->name, "kmem_cache_alloc_node")) { |
f48f669d4 perf_event: Elimi... |
279 |
process_alloc_event(data, event, cpu, timestamp, thread, 1); |
ba77c9e11 perf: Add 'perf k... |
280 281 282 283 284 |
return; } if (!strcmp(event->name, "kfree") || !strcmp(event->name, "kmem_cache_free")) { |
f48f669d4 perf_event: Elimi... |
285 |
process_free_event(data, event, cpu, timestamp, thread); |
ba77c9e11 perf: Add 'perf k... |
286 287 288 |
return; } } |
8115d60c3 perf tools: Kill ... |
289 290 |
static int process_sample_event(union perf_event *event, struct perf_sample *sample, |
9e69c2108 perf session: Pas... |
291 |
struct perf_evsel *evsel __used, |
640c03ce8 perf session: Par... |
292 |
struct perf_session *session) |
ba77c9e11 perf: Add 'perf k... |
293 |
{ |
640c03ce8 perf session: Par... |
294 |
struct thread *thread = perf_session__findnew(session, event->ip.pid); |
ba77c9e11 perf: Add 'perf k... |
295 |
|
ba77c9e11 perf: Add 'perf k... |
296 297 298 299 300 301 302 303 304 |
if (thread == NULL) { pr_debug("problem processing %d event, skipping it. ", event->header.type); return -1; } dump_printf(" ... thread: %s:%d ", thread->comm, thread->pid); |
640c03ce8 perf session: Par... |
305 306 |
process_raw_event(event, sample->raw_data, sample->cpu, sample->time, thread); |
ba77c9e11 perf: Add 'perf k... |
307 308 309 |
return 0; } |
301a0b020 perf session: Dit... |
310 |
static struct perf_event_ops event_ops = { |
587570d4c perf: Use generic... |
311 |
.sample = process_sample_event, |
8115d60c3 perf tools: Kill ... |
312 |
.comm = perf_event__process_comm, |
587570d4c perf: Use generic... |
313 |
.ordered_samples = true, |
ba77c9e11 perf: Add 'perf k... |
314 |
}; |
ba77c9e11 perf: Add 'perf k... |
315 316 317 318 319 320 321 |
static double fragmentation(unsigned long n_req, unsigned long n_alloc) { if (n_alloc == 0) return 0.0; else return 100.0 - (100.0 * n_req / n_alloc); } |
4aa656364 perf session: Mov... |
322 323 |
static void __print_result(struct rb_root *root, struct perf_session *session, int n_lines, int is_caller) |
ba77c9e11 perf: Add 'perf k... |
324 325 |
{ struct rb_node *next; |
23346f21b perf tools: Renam... |
326 |
struct machine *machine; |
ba77c9e11 perf: Add 'perf k... |
327 |
|
079d3f653 perf kmem: Measur... |
328 329 330 |
printf("%.102s ", graph_dotted_line); printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); |
47103277f perf kmem: Increa... |
331 332 |
printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag "); |
079d3f653 perf kmem: Measur... |
333 334 |
printf("%.102s ", graph_dotted_line); |
ba77c9e11 perf: Add 'perf k... |
335 336 |
next = rb_first(root); |
23346f21b perf tools: Renam... |
337 338 |
machine = perf_session__find_host_machine(session); if (!machine) { |
a1645ce12 perf: 'perf kvm' ... |
339 340 341 342 |
pr_err("__print_result: couldn't find kernel information "); return; } |
ba77c9e11 perf: Add 'perf k... |
343 |
while (next && n_lines--) { |
1b145ae58 perf kmem: Resolv... |
344 345 346 |
struct alloc_stat *data = rb_entry(next, struct alloc_stat, node); struct symbol *sym = NULL; |
71cf8b8ff perf kmem: Fixup ... |
347 |
struct map *map; |
079d3f653 perf kmem: Measur... |
348 |
char buf[BUFSIZ]; |
1b145ae58 perf kmem: Resolv... |
349 350 351 352 |
u64 addr; if (is_caller) { addr = data->call_site; |
7707b6b6f perf kmem: Add ne... |
353 |
if (!raw_ip) |
5c0541d53 perf symbols: Add... |
354 |
sym = machine__find_kernel_function(machine, addr, &map, NULL); |
1b145ae58 perf kmem: Resolv... |
355 356 357 358 |
} else addr = data->ptr; if (sym != NULL) |
9486aa387 perf tools: Fix 6... |
359 |
snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name, |
71cf8b8ff perf kmem: Fixup ... |
360 |
addr - map->unmap_ip(map, sym->start)); |
1b145ae58 perf kmem: Resolv... |
361 |
else |
9486aa387 perf tools: Fix 6... |
362 |
snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr); |
079d3f653 perf kmem: Measur... |
363 |
printf(" %-34s |", buf); |
ba77c9e11 perf: Add 'perf k... |
364 |
|
47103277f perf kmem: Increa... |
365 366 |
printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%% ", |
079d3f653 perf kmem: Measur... |
367 |
(unsigned long long)data->bytes_alloc, |
ba77c9e11 perf: Add 'perf k... |
368 369 370 371 |
(unsigned long)data->bytes_alloc / data->hit, (unsigned long long)data->bytes_req, (unsigned long)data->bytes_req / data->hit, (unsigned long)data->hit, |
079d3f653 perf kmem: Measur... |
372 |
(unsigned long)data->pingpong, |
ba77c9e11 perf: Add 'perf k... |
373 374 375 376 377 378 |
fragmentation(data->bytes_req, data->bytes_alloc)); next = rb_next(next); } if (n_lines == -1) |
079d3f653 perf kmem: Measur... |
379 380 |
printf(" ... | ... | ... | ... | ... | ... "); |
ba77c9e11 perf: Add 'perf k... |
381 |
|
079d3f653 perf kmem: Measur... |
382 383 |
printf("%.102s ", graph_dotted_line); |
ba77c9e11 perf: Add 'perf k... |
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
} static void print_summary(void) { printf(" SUMMARY ======= "); printf("Total bytes requested: %lu ", total_requested); printf("Total bytes allocated: %lu ", total_allocated); printf("Total bytes wasted on internal fragmentation: %lu ", total_allocated - total_requested); printf("Internal fragmentation: %f%% ", fragmentation(total_requested, total_allocated)); |
7d0d39459 perf kmem: Collec... |
402 403 |
printf("Cross CPU allocations: %lu/%lu ", nr_cross_allocs, nr_allocs); |
ba77c9e11 perf: Add 'perf k... |
404 |
} |
4aa656364 perf session: Mov... |
405 |
static void print_result(struct perf_session *session) |
ba77c9e11 perf: Add 'perf k... |
406 407 |
{ if (caller_flag) |
4aa656364 perf session: Mov... |
408 |
__print_result(&root_caller_sorted, session, caller_lines, 1); |
ba77c9e11 perf: Add 'perf k... |
409 |
if (alloc_flag) |
4aa656364 perf session: Mov... |
410 |
__print_result(&root_alloc_sorted, session, alloc_lines, 0); |
ba77c9e11 perf: Add 'perf k... |
411 412 |
print_summary(); } |
29b3e1528 perf kmem: Defaul... |
413 414 415 416 417 418 419 420 |
struct sort_dimension { const char name[20]; sort_fn_t cmp; struct list_head list; }; static LIST_HEAD(caller_sort); static LIST_HEAD(alloc_sort); |
ba77c9e11 perf: Add 'perf k... |
421 |
static void sort_insert(struct rb_root *root, struct alloc_stat *data, |
29b3e1528 perf kmem: Defaul... |
422 |
struct list_head *sort_list) |
ba77c9e11 perf: Add 'perf k... |
423 424 425 |
{ struct rb_node **new = &(root->rb_node); struct rb_node *parent = NULL; |
29b3e1528 perf kmem: Defaul... |
426 |
struct sort_dimension *sort; |
ba77c9e11 perf: Add 'perf k... |
427 428 429 |
while (*new) { struct alloc_stat *this; |
29b3e1528 perf kmem: Defaul... |
430 |
int cmp = 0; |
ba77c9e11 perf: Add 'perf k... |
431 432 433 |
this = rb_entry(*new, struct alloc_stat, node); parent = *new; |
29b3e1528 perf kmem: Defaul... |
434 435 436 437 438 |
list_for_each_entry(sort, sort_list, list) { cmp = sort->cmp(data, this); if (cmp) break; } |
ba77c9e11 perf: Add 'perf k... |
439 440 441 442 443 444 445 446 447 448 449 450 |
if (cmp > 0) new = &((*new)->rb_left); else new = &((*new)->rb_right); } rb_link_node(&data->node, parent, new); rb_insert_color(&data->node, root); } static void __sort_result(struct rb_root *root, struct rb_root *root_sorted, |
29b3e1528 perf kmem: Defaul... |
451 |
struct list_head *sort_list) |
ba77c9e11 perf: Add 'perf k... |
452 453 454 455 456 457 458 459 460 461 462 |
{ struct rb_node *node; struct alloc_stat *data; for (;;) { node = rb_first(root); if (!node) break; rb_erase(node, root); data = rb_entry(node, struct alloc_stat, node); |
29b3e1528 perf kmem: Defaul... |
463 |
sort_insert(root_sorted, data, sort_list); |
ba77c9e11 perf: Add 'perf k... |
464 465 466 467 468 |
} } static void sort_result(void) { |
29b3e1528 perf kmem: Defaul... |
469 470 |
__sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort); __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); |
ba77c9e11 perf: Add 'perf k... |
471 472 473 474 |
} static int __cmd_kmem(void) { |
d549c7690 perf session: Rem... |
475 |
int err = -EINVAL; |
21ef97f05 perf session: Fal... |
476 477 |
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops); |
4aa656364 perf session: Mov... |
478 479 |
if (session == NULL) return -ENOMEM; |
e727ca73f perf kmem: Resolv... |
480 481 |
if (perf_session__create_kernel_maps(session) < 0) goto out_delete; |
d549c7690 perf session: Rem... |
482 483 |
if (!perf_session__has_traces(session, "kmem record")) goto out_delete; |
ba77c9e11 perf: Add 'perf k... |
484 |
setup_pager(); |
4aa656364 perf session: Mov... |
485 486 487 |
err = perf_session__process_events(session, &event_ops); if (err != 0) goto out_delete; |
ba77c9e11 perf: Add 'perf k... |
488 |
sort_result(); |
4aa656364 perf session: Mov... |
489 490 491 492 |
print_result(session); out_delete: perf_session__delete(session); return err; |
ba77c9e11 perf: Add 'perf k... |
493 494 495 |
} static const char * const kmem_usage[] = { |
90b86a9f7 perf kmem: Show u... |
496 |
"perf kmem [<options>] {record|stat}", |
ba77c9e11 perf: Add 'perf k... |
497 498 |
NULL }; |
ba77c9e11 perf: Add 'perf k... |
499 500 501 502 503 504 505 506 |
static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->ptr < r->ptr) return -1; else if (l->ptr > r->ptr) return 1; return 0; } |
29b3e1528 perf kmem: Defaul... |
507 508 509 510 |
static struct sort_dimension ptr_sort_dimension = { .name = "ptr", .cmp = ptr_cmp, }; |
ba77c9e11 perf: Add 'perf k... |
511 512 513 514 515 516 517 518 |
static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->call_site < r->call_site) return -1; else if (l->call_site > r->call_site) return 1; return 0; } |
29b3e1528 perf kmem: Defaul... |
519 520 521 522 |
static struct sort_dimension callsite_sort_dimension = { .name = "callsite", .cmp = callsite_cmp, }; |
f3ced7cdb perf kmem: Add --... |
523 524 525 526 527 528 529 530 |
static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->hit < r->hit) return -1; else if (l->hit > r->hit) return 1; return 0; } |
29b3e1528 perf kmem: Defaul... |
531 532 533 534 |
static struct sort_dimension hit_sort_dimension = { .name = "hit", .cmp = hit_cmp, }; |
ba77c9e11 perf: Add 'perf k... |
535 536 537 538 539 540 541 542 |
static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->bytes_alloc < r->bytes_alloc) return -1; else if (l->bytes_alloc > r->bytes_alloc) return 1; return 0; } |
29b3e1528 perf kmem: Defaul... |
543 544 545 546 |
static struct sort_dimension bytes_sort_dimension = { .name = "bytes", .cmp = bytes_cmp, }; |
f3ced7cdb perf kmem: Add --... |
547 548 549 550 551 552 553 554 555 556 557 558 559 |
static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) { double x, y; x = fragmentation(l->bytes_req, l->bytes_alloc); y = fragmentation(r->bytes_req, r->bytes_alloc); if (x < y) return -1; else if (x > y) return 1; return 0; } |
29b3e1528 perf kmem: Defaul... |
560 561 562 563 |
static struct sort_dimension frag_sort_dimension = { .name = "frag", .cmp = frag_cmp, }; |
079d3f653 perf kmem: Measur... |
564 565 566 567 568 569 570 571 572 573 574 575 576 |
static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r) { if (l->pingpong < r->pingpong) return -1; else if (l->pingpong > r->pingpong) return 1; return 0; } static struct sort_dimension pingpong_sort_dimension = { .name = "pingpong", .cmp = pingpong_cmp, }; |
29b3e1528 perf kmem: Defaul... |
577 578 579 580 581 582 |
static struct sort_dimension *avail_sorts[] = { &ptr_sort_dimension, &callsite_sort_dimension, &hit_sort_dimension, &bytes_sort_dimension, &frag_sort_dimension, |
079d3f653 perf kmem: Measur... |
583 |
&pingpong_sort_dimension, |
29b3e1528 perf kmem: Defaul... |
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
}; #define NUM_AVAIL_SORTS \ (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *)) static int sort_dimension__add(const char *tok, struct list_head *list) { struct sort_dimension *sort; int i; for (i = 0; i < NUM_AVAIL_SORTS; i++) { if (!strcmp(avail_sorts[i]->name, tok)) { sort = malloc(sizeof(*sort)); if (!sort) die("malloc"); memcpy(sort, avail_sorts[i], sizeof(*sort)); list_add_tail(&sort->list, list); return 0; } } return -1; } static int setup_sorting(struct list_head *sort_list, const char *arg) { char *tok; char *str = strdup(arg); if (!str) die("strdup"); while (true) { tok = strsep(&str, ","); if (!tok) break; if (sort_dimension__add(tok, sort_list) < 0) { error("Unknown --sort key: '%s'", tok); return -1; } } free(str); return 0; } |
ba77c9e11 perf: Add 'perf k... |
629 630 631 |
static int parse_sort_opt(const struct option *opt __used, const char *arg, int unset __used) { |
ba77c9e11 perf: Add 'perf k... |
632 633 |
if (!arg) return -1; |
ba77c9e11 perf: Add 'perf k... |
634 |
if (caller_flag > alloc_flag) |
29b3e1528 perf kmem: Defaul... |
635 |
return setup_sorting(&caller_sort, arg); |
ba77c9e11 perf: Add 'perf k... |
636 |
else |
29b3e1528 perf kmem: Defaul... |
637 |
return setup_sorting(&alloc_sort, arg); |
ba77c9e11 perf: Add 'perf k... |
638 639 640 |
return 0; } |
90b86a9f7 perf kmem: Show u... |
641 |
static int parse_caller_opt(const struct option *opt __used, |
793124169 perf kmem: Fix un... |
642 |
const char *arg __used, int unset __used) |
ba77c9e11 perf: Add 'perf k... |
643 |
{ |
90b86a9f7 perf kmem: Show u... |
644 645 646 |
caller_flag = (alloc_flag + 1); return 0; } |
ba77c9e11 perf: Add 'perf k... |
647 |
|
90b86a9f7 perf kmem: Show u... |
648 |
static int parse_alloc_opt(const struct option *opt __used, |
793124169 perf kmem: Fix un... |
649 |
const char *arg __used, int unset __used) |
90b86a9f7 perf kmem: Show u... |
650 651 |
{ alloc_flag = (caller_flag + 1); |
ba77c9e11 perf: Add 'perf k... |
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
return 0; } static int parse_line_opt(const struct option *opt __used, const char *arg, int unset __used) { int lines; if (!arg) return -1; lines = strtoul(arg, NULL, 10); if (caller_flag > alloc_flag) caller_lines = lines; else alloc_lines = lines; return 0; } static const struct option kmem_options[] = { OPT_STRING('i', "input", &input_name, "file", "input file name"), |
90b86a9f7 perf kmem: Show u... |
676 677 678 679 680 681 |
OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, "show per-callsite statistics", parse_caller_opt), OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, "show per-allocation statistics", parse_alloc_opt), |
29b3e1528 perf kmem: Defaul... |
682 |
OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", |
079d3f653 perf kmem: Measur... |
683 |
"sort by keys: ptr, call_site, bytes, hit, pingpong, frag", |
ba77c9e11 perf: Add 'perf k... |
684 685 |
parse_sort_opt), OPT_CALLBACK('l', "line", NULL, "num", |
90b86a9f7 perf kmem: Show u... |
686 |
"show n lines", |
ba77c9e11 perf: Add 'perf k... |
687 |
parse_line_opt), |
7707b6b6f perf kmem: Add ne... |
688 |
OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), |
ba77c9e11 perf: Add 'perf k... |
689 690 691 692 693 694 695 |
OPT_END() }; static const char *record_args[] = { "record", "-a", "-R", |
ba77c9e11 perf: Add 'perf k... |
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
"-f", "-c", "1", "-e", "kmem:kmalloc", "-e", "kmem:kmalloc_node", "-e", "kmem:kfree", "-e", "kmem:kmem_cache_alloc", "-e", "kmem:kmem_cache_alloc_node", "-e", "kmem:kmem_cache_free", }; static int __cmd_record(int argc, const char **argv) { unsigned int rec_argc, i, j; const char **rec_argv; rec_argc = ARRAY_SIZE(record_args) + argc - 1; rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
ce47dc56a perf tools: Catch... |
713 714 |
if (rec_argv == NULL) return -ENOMEM; |
ba77c9e11 perf: Add 'perf k... |
715 716 717 718 719 720 721 722 723 724 725 |
for (i = 0; i < ARRAY_SIZE(record_args); i++) rec_argv[i] = strdup(record_args[i]); for (j = 1; j < (unsigned int)argc; j++, i++) rec_argv[i] = argv[j]; return cmd_record(i, rec_argv, NULL); } int cmd_kmem(int argc, const char **argv, const char *prefix __used) { |
ba77c9e11 perf: Add 'perf k... |
726 |
argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); |
90b86a9f7 perf kmem: Show u... |
727 |
if (!argc) |
ba77c9e11 perf: Add 'perf k... |
728 |
usage_with_options(kmem_usage, kmem_options); |
655000e7c perf symbols: Ado... |
729 |
symbol__init(); |
90b86a9f7 perf kmem: Show u... |
730 731 732 733 734 735 736 737 738 |
if (!strncmp(argv[0], "rec", 3)) { return __cmd_record(argc, argv); } else if (!strcmp(argv[0], "stat")) { setup_cpunode_map(); if (list_empty(&caller_sort)) setup_sorting(&caller_sort, default_sort_order); if (list_empty(&alloc_sort)) setup_sorting(&alloc_sort, default_sort_order); |
ba77c9e11 perf: Add 'perf k... |
739 |
|
90b86a9f7 perf kmem: Show u... |
740 |
return __cmd_kmem(); |
b00eca8cd perf kmem: Print ... |
741 742 |
} else usage_with_options(kmem_usage, kmem_options); |
7d0d39459 perf kmem: Collec... |
743 |
|
90b86a9f7 perf kmem: Show u... |
744 |
return 0; |
ba77c9e11 perf: Add 'perf k... |
745 |
} |