diff options
Diffstat (limited to 'tools/perf/builtin-kmem.c')
-rw-r--r-- | tools/perf/builtin-kmem.c | 123 |
1 files changed, 56 insertions, 67 deletions
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 047fef74bd52..5f209514f657 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -57,11 +57,6 @@ static struct rb_root root_caller_sorted; | |||
57 | static unsigned long total_requested, total_allocated; | 57 | static unsigned long total_requested, total_allocated; |
58 | static unsigned long nr_allocs, nr_cross_allocs; | 58 | static unsigned long nr_allocs, nr_cross_allocs; |
59 | 59 | ||
60 | struct raw_event_sample { | ||
61 | u32 size; | ||
62 | char data[0]; | ||
63 | }; | ||
64 | |||
65 | #define PATH_SYS_NODE "/sys/devices/system/node" | 60 | #define PATH_SYS_NODE "/sys/devices/system/node" |
66 | 61 | ||
67 | static void init_cpunode_map(void) | 62 | static void init_cpunode_map(void) |
@@ -201,7 +196,7 @@ static void insert_caller_stat(unsigned long call_site, | |||
201 | } | 196 | } |
202 | } | 197 | } |
203 | 198 | ||
204 | static void process_alloc_event(struct raw_event_sample *raw, | 199 | static void process_alloc_event(void *data, |
205 | struct event *event, | 200 | struct event *event, |
206 | int cpu, | 201 | int cpu, |
207 | u64 timestamp __used, | 202 | u64 timestamp __used, |
@@ -214,10 +209,10 @@ static void process_alloc_event(struct raw_event_sample *raw, | |||
214 | int bytes_alloc; | 209 | int bytes_alloc; |
215 | int node1, node2; | 210 | int node1, node2; |
216 | 211 | ||
217 | ptr = raw_field_value(event, "ptr", raw->data); | 212 | ptr = raw_field_value(event, "ptr", data); |
218 | call_site = raw_field_value(event, "call_site", raw->data); | 213 | call_site = raw_field_value(event, "call_site", data); |
219 | bytes_req = raw_field_value(event, "bytes_req", raw->data); | 214 | bytes_req = raw_field_value(event, "bytes_req", data); |
220 | bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); | 215 | bytes_alloc = raw_field_value(event, "bytes_alloc", data); |
221 | 216 | ||
222 | insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); | 217 | insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); |
223 | insert_caller_stat(call_site, bytes_req, bytes_alloc); | 218 | insert_caller_stat(call_site, bytes_req, bytes_alloc); |
@@ -227,7 +222,7 @@ static void process_alloc_event(struct raw_event_sample *raw, | |||
227 | 222 | ||
228 | if (node) { | 223 | if (node) { |
229 | node1 = cpunode_map[cpu]; | 224 | node1 = cpunode_map[cpu]; |
230 | node2 = raw_field_value(event, "node", raw->data); | 225 | node2 = raw_field_value(event, "node", data); |
231 | if (node1 != node2) | 226 | if (node1 != node2) |
232 | nr_cross_allocs++; | 227 | nr_cross_allocs++; |
233 | } | 228 | } |
@@ -262,7 +257,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr, | |||
262 | return NULL; | 257 | return NULL; |
263 | } | 258 | } |
264 | 259 | ||
265 | static void process_free_event(struct raw_event_sample *raw, | 260 | static void process_free_event(void *data, |
266 | struct event *event, | 261 | struct event *event, |
267 | int cpu, | 262 | int cpu, |
268 | u64 timestamp __used, | 263 | u64 timestamp __used, |
@@ -271,7 +266,7 @@ static void process_free_event(struct raw_event_sample *raw, | |||
271 | unsigned long ptr; | 266 | unsigned long ptr; |
272 | struct alloc_stat *s_alloc, *s_caller; | 267 | struct alloc_stat *s_alloc, *s_caller; |
273 | 268 | ||
274 | ptr = raw_field_value(event, "ptr", raw->data); | 269 | ptr = raw_field_value(event, "ptr", data); |
275 | 270 | ||
276 | s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); | 271 | s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); |
277 | if (!s_alloc) | 272 | if (!s_alloc) |
@@ -289,66 +284,53 @@ static void process_free_event(struct raw_event_sample *raw, | |||
289 | } | 284 | } |
290 | 285 | ||
291 | static void | 286 | static void |
292 | process_raw_event(event_t *raw_event __used, void *more_data, | 287 | process_raw_event(event_t *raw_event __used, void *data, |
293 | int cpu, u64 timestamp, struct thread *thread) | 288 | int cpu, u64 timestamp, struct thread *thread) |
294 | { | 289 | { |
295 | struct raw_event_sample *raw = more_data; | ||
296 | struct event *event; | 290 | struct event *event; |
297 | int type; | 291 | int type; |
298 | 292 | ||
299 | type = trace_parse_common_type(raw->data); | 293 | type = trace_parse_common_type(data); |
300 | event = trace_find_event(type); | 294 | event = trace_find_event(type); |
301 | 295 | ||
302 | if (!strcmp(event->name, "kmalloc") || | 296 | if (!strcmp(event->name, "kmalloc") || |
303 | !strcmp(event->name, "kmem_cache_alloc")) { | 297 | !strcmp(event->name, "kmem_cache_alloc")) { |
304 | process_alloc_event(raw, event, cpu, timestamp, thread, 0); | 298 | process_alloc_event(data, event, cpu, timestamp, thread, 0); |
305 | return; | 299 | return; |
306 | } | 300 | } |
307 | 301 | ||
308 | if (!strcmp(event->name, "kmalloc_node") || | 302 | if (!strcmp(event->name, "kmalloc_node") || |
309 | !strcmp(event->name, "kmem_cache_alloc_node")) { | 303 | !strcmp(event->name, "kmem_cache_alloc_node")) { |
310 | process_alloc_event(raw, event, cpu, timestamp, thread, 1); | 304 | process_alloc_event(data, event, cpu, timestamp, thread, 1); |
311 | return; | 305 | return; |
312 | } | 306 | } |
313 | 307 | ||
314 | if (!strcmp(event->name, "kfree") || | 308 | if (!strcmp(event->name, "kfree") || |
315 | !strcmp(event->name, "kmem_cache_free")) { | 309 | !strcmp(event->name, "kmem_cache_free")) { |
316 | process_free_event(raw, event, cpu, timestamp, thread); | 310 | process_free_event(data, event, cpu, timestamp, thread); |
317 | return; | 311 | return; |
318 | } | 312 | } |
319 | } | 313 | } |
320 | 314 | ||
321 | static int process_sample_event(event_t *event) | 315 | static int process_sample_event(event_t *event) |
322 | { | 316 | { |
323 | u64 ip = event->ip.ip; | 317 | struct sample_data data; |
324 | u64 timestamp = -1; | 318 | struct thread *thread; |
325 | u32 cpu = -1; | ||
326 | u64 period = 1; | ||
327 | void *more_data = event->ip.__more_data; | ||
328 | struct thread *thread = threads__findnew(event->ip.pid); | ||
329 | 319 | ||
330 | if (sample_type & PERF_SAMPLE_TIME) { | 320 | memset(&data, 0, sizeof(data)); |
331 | timestamp = *(u64 *)more_data; | 321 | data.time = -1; |
332 | more_data += sizeof(u64); | 322 | data.cpu = -1; |
333 | } | 323 | data.period = 1; |
334 | |||
335 | if (sample_type & PERF_SAMPLE_CPU) { | ||
336 | cpu = *(u32 *)more_data; | ||
337 | more_data += sizeof(u32); | ||
338 | more_data += sizeof(u32); /* reserved */ | ||
339 | } | ||
340 | 324 | ||
341 | if (sample_type & PERF_SAMPLE_PERIOD) { | 325 | event__parse_sample(event, sample_type, &data); |
342 | period = *(u64 *)more_data; | ||
343 | more_data += sizeof(u64); | ||
344 | } | ||
345 | 326 | ||
346 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 327 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
347 | event->header.misc, | 328 | event->header.misc, |
348 | event->ip.pid, event->ip.tid, | 329 | data.pid, data.tid, |
349 | (void *)(long)ip, | 330 | (void *)(long)data.ip, |
350 | (long long)period); | 331 | (long long)data.period); |
351 | 332 | ||
333 | thread = threads__findnew(event->ip.pid); | ||
352 | if (thread == NULL) { | 334 | if (thread == NULL) { |
353 | pr_debug("problem processing %d event, skipping it.\n", | 335 | pr_debug("problem processing %d event, skipping it.\n", |
354 | event->header.type); | 336 | event->header.type); |
@@ -357,7 +339,8 @@ static int process_sample_event(event_t *event) | |||
357 | 339 | ||
358 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 340 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
359 | 341 | ||
360 | process_raw_event(event, more_data, cpu, timestamp, thread); | 342 | process_raw_event(event, data.raw_data, data.cpu, |
343 | data.time, thread); | ||
361 | 344 | ||
362 | return 0; | 345 | return 0; |
363 | } | 346 | } |
@@ -543,7 +526,7 @@ static int __cmd_kmem(void) | |||
543 | } | 526 | } |
544 | 527 | ||
545 | static const char * const kmem_usage[] = { | 528 | static const char * const kmem_usage[] = { |
546 | "perf kmem [<options>] {record}", | 529 | "perf kmem [<options>] {record|stat}", |
547 | NULL | 530 | NULL |
548 | }; | 531 | }; |
549 | 532 | ||
@@ -703,18 +686,17 @@ static int parse_sort_opt(const struct option *opt __used, | |||
703 | return 0; | 686 | return 0; |
704 | } | 687 | } |
705 | 688 | ||
706 | static int parse_stat_opt(const struct option *opt __used, | 689 | static int parse_caller_opt(const struct option *opt __used, |
707 | const char *arg, int unset __used) | 690 | const char *arg __used, int unset __used) |
708 | { | 691 | { |
709 | if (!arg) | 692 | caller_flag = (alloc_flag + 1); |
710 | return -1; | 693 | return 0; |
694 | } | ||
711 | 695 | ||
712 | if (strcmp(arg, "alloc") == 0) | 696 | static int parse_alloc_opt(const struct option *opt __used, |
713 | alloc_flag = (caller_flag + 1); | 697 | const char *arg __used, int unset __used) |
714 | else if (strcmp(arg, "caller") == 0) | 698 | { |
715 | caller_flag = (alloc_flag + 1); | 699 | alloc_flag = (caller_flag + 1); |
716 | else | ||
717 | return -1; | ||
718 | return 0; | 700 | return 0; |
719 | } | 701 | } |
720 | 702 | ||
@@ -739,14 +721,17 @@ static int parse_line_opt(const struct option *opt __used, | |||
739 | static const struct option kmem_options[] = { | 721 | static const struct option kmem_options[] = { |
740 | OPT_STRING('i', "input", &input_name, "file", | 722 | OPT_STRING('i', "input", &input_name, "file", |
741 | "input file name"), | 723 | "input file name"), |
742 | OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>", | 724 | OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, |
743 | "stat selector, Pass 'alloc' or 'caller'.", | 725 | "show per-callsite statistics", |
744 | parse_stat_opt), | 726 | parse_caller_opt), |
727 | OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, | ||
728 | "show per-allocation statistics", | ||
729 | parse_alloc_opt), | ||
745 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", | 730 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", |
746 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", | 731 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", |
747 | parse_sort_opt), | 732 | parse_sort_opt), |
748 | OPT_CALLBACK('l', "line", NULL, "num", | 733 | OPT_CALLBACK('l', "line", NULL, "num", |
749 | "show n lins", | 734 | "show n lines", |
750 | parse_line_opt), | 735 | parse_line_opt), |
751 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), | 736 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), |
752 | OPT_END() | 737 | OPT_END() |
@@ -790,18 +775,22 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used) | |||
790 | 775 | ||
791 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); | 776 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); |
792 | 777 | ||
793 | if (argc && !strncmp(argv[0], "rec", 3)) | 778 | if (!argc) |
794 | return __cmd_record(argc, argv); | ||
795 | else if (argc) | ||
796 | usage_with_options(kmem_usage, kmem_options); | 779 | usage_with_options(kmem_usage, kmem_options); |
797 | 780 | ||
798 | if (list_empty(&caller_sort)) | 781 | if (!strncmp(argv[0], "rec", 3)) { |
799 | setup_sorting(&caller_sort, default_sort_order); | 782 | return __cmd_record(argc, argv); |
800 | if (list_empty(&alloc_sort)) | 783 | } else if (!strcmp(argv[0], "stat")) { |
801 | setup_sorting(&alloc_sort, default_sort_order); | 784 | setup_cpunode_map(); |
785 | |||
786 | if (list_empty(&caller_sort)) | ||
787 | setup_sorting(&caller_sort, default_sort_order); | ||
788 | if (list_empty(&alloc_sort)) | ||
789 | setup_sorting(&alloc_sort, default_sort_order); | ||
802 | 790 | ||
803 | setup_cpunode_map(); | 791 | return __cmd_kmem(); |
792 | } | ||
804 | 793 | ||
805 | return __cmd_kmem(); | 794 | return 0; |
806 | } | 795 | } |
807 | 796 | ||