diff options
Diffstat (limited to 'tools/perf')
24 files changed, 578 insertions, 352 deletions
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt index 44b0ce35c28a..eac4d852e7cd 100644 --- a/tools/perf/Documentation/perf-kmem.txt +++ b/tools/perf/Documentation/perf-kmem.txt | |||
| @@ -8,16 +8,16 @@ perf-kmem - Tool to trace/measure kernel memory(slab) properties | |||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf kmem' {record} [<options>] | 11 | 'perf kmem' {record|stat} [<options>] |
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | There's two variants of perf kmem: | 15 | There are two variants of perf kmem: |
| 16 | 16 | ||
| 17 | 'perf kmem record <command>' to record the kmem events | 17 | 'perf kmem record <command>' to record the kmem events |
| 18 | of an arbitrary workload. | 18 | of an arbitrary workload. |
| 19 | 19 | ||
| 20 | 'perf kmem' to report kernel memory statistics. | 20 | 'perf kmem stat' to report kernel memory statistics. |
| 21 | 21 | ||
| 22 | OPTIONS | 22 | OPTIONS |
| 23 | ------- | 23 | ------- |
| @@ -25,8 +25,11 @@ OPTIONS | |||
| 25 | --input=<file>:: | 25 | --input=<file>:: |
| 26 | Select the input file (default: perf.data) | 26 | Select the input file (default: perf.data) |
| 27 | 27 | ||
| 28 | --stat=<caller|alloc>:: | 28 | --caller:: |
| 29 | Select per callsite or per allocation statistics | 29 | Show per-callsite statistics |
| 30 | |||
| 31 | --alloc:: | ||
| 32 | Show per-allocation statistics | ||
| 30 | 33 | ||
| 31 | -s <key[,key2...]>:: | 34 | -s <key[,key2...]>:: |
| 32 | --sort=<key[,key2...]>:: | 35 | --sort=<key[,key2...]>:: |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 9270594e6dfd..8fa6bf99fcb5 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
| @@ -8,10 +8,13 @@ perf-probe - Define new dynamic tracepoints | |||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...] | 11 | 'perf probe' [options] --add='PROBE' [...] |
| 12 | or | 12 | or |
| 13 | 'perf probe' [options] 'PROBE' ['PROBE' ...] | 13 | 'perf probe' [options] PROBE |
| 14 | 14 | or | |
| 15 | 'perf probe' [options] --del='[GROUP:]EVENT' [...] | ||
| 16 | or | ||
| 17 | 'perf probe' --list | ||
| 15 | 18 | ||
| 16 | DESCRIPTION | 19 | DESCRIPTION |
| 17 | ----------- | 20 | ----------- |
| @@ -31,8 +34,16 @@ OPTIONS | |||
| 31 | Be more verbose (show parsed arguments, etc). | 34 | Be more verbose (show parsed arguments, etc). |
| 32 | 35 | ||
| 33 | -a:: | 36 | -a:: |
| 34 | --add:: | 37 | --add=:: |
| 35 | Define a probe point (see PROBE SYNTAX for detail) | 38 | Define a probe event (see PROBE SYNTAX for detail). |
| 39 | |||
| 40 | -d:: | ||
| 41 | --del=:: | ||
| 42 | Delete a probe event. | ||
| 43 | |||
| 44 | -l:: | ||
| 45 | --list:: | ||
| 46 | List up current probe events. | ||
| 36 | 47 | ||
| 37 | PROBE SYNTAX | 48 | PROBE SYNTAX |
| 38 | ------------ | 49 | ------------ |
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 7dee9d19ab7a..dcb6143a0002 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
| @@ -19,7 +19,7 @@ static char const *input_name = "perf.data"; | |||
| 19 | static int force; | 19 | static int force; |
| 20 | 20 | ||
| 21 | static const char *const buildid_list_usage[] = { | 21 | static const char *const buildid_list_usage[] = { |
| 22 | "perf report [<options>]", | 22 | "perf buildid-list [<options>]", |
| 23 | NULL | 23 | NULL |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
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 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index a58e11b7ea80..5a47c1e11f77 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include "perf.h" | 35 | #include "perf.h" |
| 36 | #include "builtin.h" | 36 | #include "builtin.h" |
| 37 | #include "util/util.h" | 37 | #include "util/util.h" |
| 38 | #include "util/strlist.h" | ||
| 38 | #include "util/event.h" | 39 | #include "util/event.h" |
| 39 | #include "util/debug.h" | 40 | #include "util/debug.h" |
| 40 | #include "util/parse-options.h" | 41 | #include "util/parse-options.h" |
| @@ -43,11 +44,12 @@ | |||
| 43 | #include "util/probe-event.h" | 44 | #include "util/probe-event.h" |
| 44 | 45 | ||
| 45 | /* Default vmlinux search paths */ | 46 | /* Default vmlinux search paths */ |
| 46 | #define NR_SEARCH_PATH 3 | 47 | #define NR_SEARCH_PATH 4 |
| 47 | const char *default_search_path[NR_SEARCH_PATH] = { | 48 | const char *default_search_path[NR_SEARCH_PATH] = { |
| 48 | "/lib/modules/%s/build/vmlinux", /* Custom build kernel */ | 49 | "/lib/modules/%s/build/vmlinux", /* Custom build kernel */ |
| 49 | "/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */ | 50 | "/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */ |
| 50 | "/boot/vmlinux-debug-%s", /* Ubuntu */ | 51 | "/boot/vmlinux-debug-%s", /* Ubuntu */ |
| 52 | "./vmlinux", /* CWD */ | ||
| 51 | }; | 53 | }; |
| 52 | 54 | ||
| 53 | #define MAX_PATH_LEN 256 | 55 | #define MAX_PATH_LEN 256 |
| @@ -60,6 +62,7 @@ static struct { | |||
| 60 | int need_dwarf; | 62 | int need_dwarf; |
| 61 | int nr_probe; | 63 | int nr_probe; |
| 62 | struct probe_point probes[MAX_PROBES]; | 64 | struct probe_point probes[MAX_PROBES]; |
| 65 | struct strlist *dellist; | ||
| 63 | } session; | 66 | } session; |
| 64 | 67 | ||
| 65 | static bool listing; | 68 | static bool listing; |
| @@ -79,6 +82,25 @@ static void parse_probe_event(const char *str) | |||
| 79 | pr_debug("%d arguments\n", pp->nr_args); | 82 | pr_debug("%d arguments\n", pp->nr_args); |
| 80 | } | 83 | } |
| 81 | 84 | ||
| 85 | static void parse_probe_event_argv(int argc, const char **argv) | ||
| 86 | { | ||
| 87 | int i, len; | ||
| 88 | char *buf; | ||
| 89 | |||
| 90 | /* Bind up rest arguments */ | ||
| 91 | len = 0; | ||
| 92 | for (i = 0; i < argc; i++) | ||
| 93 | len += strlen(argv[i]) + 1; | ||
| 94 | buf = zalloc(len + 1); | ||
| 95 | if (!buf) | ||
| 96 | die("Failed to allocate memory for binding arguments."); | ||
| 97 | len = 0; | ||
| 98 | for (i = 0; i < argc; i++) | ||
| 99 | len += sprintf(&buf[len], "%s ", argv[i]); | ||
| 100 | parse_probe_event(buf); | ||
| 101 | free(buf); | ||
| 102 | } | ||
| 103 | |||
| 82 | static int opt_add_probe_event(const struct option *opt __used, | 104 | static int opt_add_probe_event(const struct option *opt __used, |
| 83 | const char *str, int unset __used) | 105 | const char *str, int unset __used) |
| 84 | { | 106 | { |
| @@ -87,6 +109,17 @@ static int opt_add_probe_event(const struct option *opt __used, | |||
| 87 | return 0; | 109 | return 0; |
| 88 | } | 110 | } |
| 89 | 111 | ||
| 112 | static int opt_del_probe_event(const struct option *opt __used, | ||
| 113 | const char *str, int unset __used) | ||
| 114 | { | ||
| 115 | if (str) { | ||
| 116 | if (!session.dellist) | ||
| 117 | session.dellist = strlist__new(true, NULL); | ||
| 118 | strlist__add(session.dellist, str); | ||
| 119 | } | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 90 | #ifndef NO_LIBDWARF | 123 | #ifndef NO_LIBDWARF |
| 91 | static int open_default_vmlinux(void) | 124 | static int open_default_vmlinux(void) |
| 92 | { | 125 | { |
| @@ -121,6 +154,7 @@ static int open_default_vmlinux(void) | |||
| 121 | static const char * const probe_usage[] = { | 154 | static const char * const probe_usage[] = { |
| 122 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 155 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
| 123 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 156 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
| 157 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | ||
| 124 | "perf probe --list", | 158 | "perf probe --list", |
| 125 | NULL | 159 | NULL |
| 126 | }; | 160 | }; |
| @@ -132,7 +166,9 @@ static const struct option options[] = { | |||
| 132 | OPT_STRING('k', "vmlinux", &session.vmlinux, "file", | 166 | OPT_STRING('k', "vmlinux", &session.vmlinux, "file", |
| 133 | "vmlinux/module pathname"), | 167 | "vmlinux/module pathname"), |
| 134 | #endif | 168 | #endif |
| 135 | OPT_BOOLEAN('l', "list", &listing, "list up current probes"), | 169 | OPT_BOOLEAN('l', "list", &listing, "list up current probe events"), |
| 170 | OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", | ||
| 171 | opt_del_probe_event), | ||
| 136 | OPT_CALLBACK('a', "add", NULL, | 172 | OPT_CALLBACK('a', "add", NULL, |
| 137 | #ifdef NO_LIBDWARF | 173 | #ifdef NO_LIBDWARF |
| 138 | "FUNC[+OFFS|%return] [ARG ...]", | 174 | "FUNC[+OFFS|%return] [ARG ...]", |
| @@ -160,7 +196,7 @@ static const struct option options[] = { | |||
| 160 | 196 | ||
| 161 | int cmd_probe(int argc, const char **argv, const char *prefix __used) | 197 | int cmd_probe(int argc, const char **argv, const char *prefix __used) |
| 162 | { | 198 | { |
| 163 | int i, j, ret; | 199 | int i, ret; |
| 164 | #ifndef NO_LIBDWARF | 200 | #ifndef NO_LIBDWARF |
| 165 | int fd; | 201 | int fd; |
| 166 | #endif | 202 | #endif |
| @@ -168,40 +204,52 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 168 | 204 | ||
| 169 | argc = parse_options(argc, argv, options, probe_usage, | 205 | argc = parse_options(argc, argv, options, probe_usage, |
| 170 | PARSE_OPT_STOP_AT_NON_OPTION); | 206 | PARSE_OPT_STOP_AT_NON_OPTION); |
| 171 | for (i = 0; i < argc; i++) | 207 | if (argc > 0) |
| 172 | parse_probe_event(argv[i]); | 208 | parse_probe_event_argv(argc, argv); |
| 173 | 209 | ||
| 174 | if ((session.nr_probe == 0 && !listing) || | 210 | if ((session.nr_probe == 0 && !session.dellist && !listing)) |
| 175 | (session.nr_probe != 0 && listing)) | ||
| 176 | usage_with_options(probe_usage, options); | 211 | usage_with_options(probe_usage, options); |
| 177 | 212 | ||
| 178 | if (listing) { | 213 | if (listing) { |
| 214 | if (session.nr_probe != 0 || session.dellist) { | ||
| 215 | pr_warning(" Error: Don't use --list with" | ||
| 216 | " --add/--del.\n"); | ||
| 217 | usage_with_options(probe_usage, options); | ||
| 218 | } | ||
| 179 | show_perf_probe_events(); | 219 | show_perf_probe_events(); |
| 180 | return 0; | 220 | return 0; |
| 181 | } | 221 | } |
| 182 | 222 | ||
| 223 | if (session.dellist) { | ||
| 224 | del_trace_kprobe_events(session.dellist); | ||
| 225 | strlist__delete(session.dellist); | ||
| 226 | if (session.nr_probe == 0) | ||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 183 | if (session.need_dwarf) | 230 | if (session.need_dwarf) |
| 184 | #ifdef NO_LIBDWARF | 231 | #ifdef NO_LIBDWARF |
| 185 | die("Debuginfo-analysis is not supported"); | 232 | die("Debuginfo-analysis is not supported"); |
| 186 | #else /* !NO_LIBDWARF */ | 233 | #else /* !NO_LIBDWARF */ |
| 187 | pr_debug("Some probes require debuginfo.\n"); | 234 | pr_debug("Some probes require debuginfo.\n"); |
| 188 | 235 | ||
| 189 | if (session.vmlinux) | 236 | if (session.vmlinux) { |
| 237 | pr_debug("Try to open %s.", session.vmlinux); | ||
| 190 | fd = open(session.vmlinux, O_RDONLY); | 238 | fd = open(session.vmlinux, O_RDONLY); |
| 191 | else | 239 | } else |
| 192 | fd = open_default_vmlinux(); | 240 | fd = open_default_vmlinux(); |
| 193 | if (fd < 0) { | 241 | if (fd < 0) { |
| 194 | if (session.need_dwarf) | 242 | if (session.need_dwarf) |
| 195 | die("Could not open vmlinux/module file."); | 243 | die("Could not open debuginfo file."); |
| 196 | 244 | ||
| 197 | pr_warning("Could not open vmlinux/module file." | 245 | pr_debug("Could not open vmlinux/module file." |
| 198 | " Try to use symbols.\n"); | 246 | " Try to use symbols.\n"); |
| 199 | goto end_dwarf; | 247 | goto end_dwarf; |
| 200 | } | 248 | } |
| 201 | 249 | ||
| 202 | /* Searching probe points */ | 250 | /* Searching probe points */ |
| 203 | for (j = 0; j < session.nr_probe; j++) { | 251 | for (i = 0; i < session.nr_probe; i++) { |
| 204 | pp = &session.probes[j]; | 252 | pp = &session.probes[i]; |
| 205 | if (pp->found) | 253 | if (pp->found) |
| 206 | continue; | 254 | continue; |
| 207 | 255 | ||
| @@ -223,8 +271,8 @@ end_dwarf: | |||
| 223 | #endif /* !NO_LIBDWARF */ | 271 | #endif /* !NO_LIBDWARF */ |
| 224 | 272 | ||
| 225 | /* Synthesize probes without dwarf */ | 273 | /* Synthesize probes without dwarf */ |
| 226 | for (j = 0; j < session.nr_probe; j++) { | 274 | for (i = 0; i < session.nr_probe; i++) { |
| 227 | pp = &session.probes[j]; | 275 | pp = &session.probes[i]; |
| 228 | if (pp->found) /* This probe is already found. */ | 276 | if (pp->found) /* This probe is already found. */ |
| 229 | continue; | 277 | continue; |
| 230 | 278 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 383c4ab4f9af..2b9eb3a553ed 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -605,44 +605,41 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
| 605 | 605 | ||
| 606 | static int process_sample_event(event_t *event) | 606 | static int process_sample_event(event_t *event) |
| 607 | { | 607 | { |
| 608 | u64 ip = event->ip.ip; | 608 | struct sample_data data; |
| 609 | u64 period = 1; | ||
| 610 | void *more_data = event->ip.__more_data; | ||
| 611 | struct ip_callchain *chain = NULL; | ||
| 612 | int cpumode; | 609 | int cpumode; |
| 613 | struct addr_location al; | 610 | struct addr_location al; |
| 614 | struct thread *thread = threads__findnew(event->ip.pid); | 611 | struct thread *thread; |
| 615 | 612 | ||
| 616 | if (sample_type & PERF_SAMPLE_PERIOD) { | 613 | memset(&data, 0, sizeof(data)); |
| 617 | period = *(u64 *)more_data; | 614 | data.period = 1; |
| 618 | more_data += sizeof(u64); | 615 | |
| 619 | } | 616 | event__parse_sample(event, sample_type, &data); |
| 620 | 617 | ||
| 621 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 618 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
| 622 | event->header.misc, | 619 | event->header.misc, |
| 623 | event->ip.pid, event->ip.tid, | 620 | data.pid, data.tid, |
| 624 | (void *)(long)ip, | 621 | (void *)(long)data.ip, |
| 625 | (long long)period); | 622 | (long long)data.period); |
| 626 | 623 | ||
| 627 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { | 624 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { |
| 628 | unsigned int i; | 625 | unsigned int i; |
| 629 | 626 | ||
| 630 | chain = (void *)more_data; | 627 | dump_printf("... chain: nr:%Lu\n", data.callchain->nr); |
| 631 | |||
| 632 | dump_printf("... chain: nr:%Lu\n", chain->nr); | ||
| 633 | 628 | ||
| 634 | if (validate_chain(chain, event) < 0) { | 629 | if (validate_chain(data.callchain, event) < 0) { |
| 635 | pr_debug("call-chain problem with event, " | 630 | pr_debug("call-chain problem with event, " |
| 636 | "skipping it.\n"); | 631 | "skipping it.\n"); |
| 637 | return 0; | 632 | return 0; |
| 638 | } | 633 | } |
| 639 | 634 | ||
| 640 | if (dump_trace) { | 635 | if (dump_trace) { |
| 641 | for (i = 0; i < chain->nr; i++) | 636 | for (i = 0; i < data.callchain->nr; i++) |
| 642 | dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); | 637 | dump_printf("..... %2d: %016Lx\n", |
| 638 | i, data.callchain->ips[i]); | ||
| 643 | } | 639 | } |
| 644 | } | 640 | } |
| 645 | 641 | ||
| 642 | thread = threads__findnew(data.pid); | ||
| 646 | if (thread == NULL) { | 643 | if (thread == NULL) { |
| 647 | pr_debug("problem processing %d event, skipping it.\n", | 644 | pr_debug("problem processing %d event, skipping it.\n", |
| 648 | event->header.type); | 645 | event->header.type); |
| @@ -657,7 +654,7 @@ static int process_sample_event(event_t *event) | |||
| 657 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 654 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 658 | 655 | ||
| 659 | thread__find_addr_location(thread, cpumode, | 656 | thread__find_addr_location(thread, cpumode, |
| 660 | MAP__FUNCTION, ip, &al, NULL); | 657 | MAP__FUNCTION, data.ip, &al, NULL); |
| 661 | /* | 658 | /* |
| 662 | * We have to do this here as we may have a dso with no symbol hit that | 659 | * We have to do this here as we may have a dso with no symbol hit that |
| 663 | * has a name longer than the ones with symbols sampled. | 660 | * has a name longer than the ones with symbols sampled. |
| @@ -675,12 +672,12 @@ static int process_sample_event(event_t *event) | |||
| 675 | if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) | 672 | if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) |
| 676 | return 0; | 673 | return 0; |
| 677 | 674 | ||
| 678 | if (hist_entry__add(&al, chain, period)) { | 675 | if (hist_entry__add(&al, data.callchain, data.period)) { |
| 679 | pr_debug("problem incrementing symbol count, skipping event\n"); | 676 | pr_debug("problem incrementing symbol count, skipping event\n"); |
| 680 | return -1; | 677 | return -1; |
| 681 | } | 678 | } |
| 682 | 679 | ||
| 683 | event__stats.total += period; | 680 | event__stats.total += data.period; |
| 684 | 681 | ||
| 685 | return 0; | 682 | return 0; |
| 686 | } | 683 | } |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 26b782f26ee1..7cca7c15b40a 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include "util/debug.h" | 13 | #include "util/debug.h" |
| 14 | #include "util/data_map.h" | 14 | #include "util/data_map.h" |
| 15 | 15 | ||
| 16 | #include <sys/types.h> | ||
| 17 | #include <sys/prctl.h> | 16 | #include <sys/prctl.h> |
| 18 | 17 | ||
| 19 | #include <semaphore.h> | 18 | #include <semaphore.h> |
| @@ -141,6 +140,7 @@ struct work_atoms { | |||
| 141 | struct thread *thread; | 140 | struct thread *thread; |
| 142 | struct rb_node node; | 141 | struct rb_node node; |
| 143 | u64 max_lat; | 142 | u64 max_lat; |
| 143 | u64 max_lat_at; | ||
| 144 | u64 total_lat; | 144 | u64 total_lat; |
| 145 | u64 nb_atoms; | 145 | u64 nb_atoms; |
| 146 | u64 total_runtime; | 146 | u64 total_runtime; |
| @@ -414,34 +414,33 @@ static u64 get_cpu_usage_nsec_parent(void) | |||
| 414 | return sum; | 414 | return sum; |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | static u64 get_cpu_usage_nsec_self(void) | 417 | static int self_open_counters(void) |
| 418 | { | 418 | { |
| 419 | char filename [] = "/proc/1234567890/sched"; | 419 | struct perf_event_attr attr; |
| 420 | unsigned long msecs, nsecs; | 420 | int fd; |
| 421 | char *line = NULL; | ||
| 422 | u64 total = 0; | ||
| 423 | size_t len = 0; | ||
| 424 | ssize_t chars; | ||
| 425 | FILE *file; | ||
| 426 | int ret; | ||
| 427 | 421 | ||
| 428 | sprintf(filename, "/proc/%d/sched", getpid()); | 422 | memset(&attr, 0, sizeof(attr)); |
| 429 | file = fopen(filename, "r"); | ||
| 430 | BUG_ON(!file); | ||
| 431 | 423 | ||
| 432 | while ((chars = getline(&line, &len, file)) != -1) { | 424 | attr.type = PERF_TYPE_SOFTWARE; |
| 433 | ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", | 425 | attr.config = PERF_COUNT_SW_TASK_CLOCK; |
| 434 | &msecs, &nsecs); | 426 | |
| 435 | if (ret == 2) { | 427 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); |
| 436 | total = msecs*1e6 + nsecs; | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | } | ||
| 440 | if (line) | ||
| 441 | free(line); | ||
| 442 | fclose(file); | ||
| 443 | 428 | ||
| 444 | return total; | 429 | if (fd < 0) |
| 430 | die("Error: sys_perf_event_open() syscall returned" | ||
| 431 | "with %d (%s)\n", fd, strerror(errno)); | ||
| 432 | return fd; | ||
| 433 | } | ||
| 434 | |||
| 435 | static u64 get_cpu_usage_nsec_self(int fd) | ||
| 436 | { | ||
| 437 | u64 runtime; | ||
| 438 | int ret; | ||
| 439 | |||
| 440 | ret = read(fd, &runtime, sizeof(runtime)); | ||
| 441 | BUG_ON(ret != sizeof(runtime)); | ||
| 442 | |||
| 443 | return runtime; | ||
| 445 | } | 444 | } |
| 446 | 445 | ||
| 447 | static void *thread_func(void *ctx) | 446 | static void *thread_func(void *ctx) |
| @@ -450,9 +449,11 @@ static void *thread_func(void *ctx) | |||
| 450 | u64 cpu_usage_0, cpu_usage_1; | 449 | u64 cpu_usage_0, cpu_usage_1; |
| 451 | unsigned long i, ret; | 450 | unsigned long i, ret; |
| 452 | char comm2[22]; | 451 | char comm2[22]; |
| 452 | int fd; | ||
| 453 | 453 | ||
| 454 | sprintf(comm2, ":%s", this_task->comm); | 454 | sprintf(comm2, ":%s", this_task->comm); |
| 455 | prctl(PR_SET_NAME, comm2); | 455 | prctl(PR_SET_NAME, comm2); |
| 456 | fd = self_open_counters(); | ||
| 456 | 457 | ||
| 457 | again: | 458 | again: |
| 458 | ret = sem_post(&this_task->ready_for_work); | 459 | ret = sem_post(&this_task->ready_for_work); |
| @@ -462,16 +463,15 @@ again: | |||
| 462 | ret = pthread_mutex_unlock(&start_work_mutex); | 463 | ret = pthread_mutex_unlock(&start_work_mutex); |
| 463 | BUG_ON(ret); | 464 | BUG_ON(ret); |
| 464 | 465 | ||
| 465 | cpu_usage_0 = get_cpu_usage_nsec_self(); | 466 | cpu_usage_0 = get_cpu_usage_nsec_self(fd); |
| 466 | 467 | ||
| 467 | for (i = 0; i < this_task->nr_events; i++) { | 468 | for (i = 0; i < this_task->nr_events; i++) { |
| 468 | this_task->curr_event = i; | 469 | this_task->curr_event = i; |
| 469 | process_sched_event(this_task, this_task->atoms[i]); | 470 | process_sched_event(this_task, this_task->atoms[i]); |
| 470 | } | 471 | } |
| 471 | 472 | ||
| 472 | cpu_usage_1 = get_cpu_usage_nsec_self(); | 473 | cpu_usage_1 = get_cpu_usage_nsec_self(fd); |
| 473 | this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; | 474 | this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; |
| 474 | |||
| 475 | ret = sem_post(&this_task->work_done_sem); | 475 | ret = sem_post(&this_task->work_done_sem); |
| 476 | BUG_ON(ret); | 476 | BUG_ON(ret); |
| 477 | 477 | ||
| @@ -628,11 +628,6 @@ static void test_calibrations(void) | |||
| 628 | printf("the sleep test took %Ld nsecs\n", T1-T0); | 628 | printf("the sleep test took %Ld nsecs\n", T1-T0); |
| 629 | } | 629 | } |
| 630 | 630 | ||
| 631 | struct raw_event_sample { | ||
| 632 | u32 size; | ||
| 633 | char data[0]; | ||
| 634 | }; | ||
| 635 | |||
| 636 | #define FILL_FIELD(ptr, field, event, data) \ | 631 | #define FILL_FIELD(ptr, field, event, data) \ |
| 637 | ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) | 632 | ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) |
| 638 | 633 | ||
| @@ -1019,8 +1014,10 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) | |||
| 1019 | 1014 | ||
| 1020 | delta = atom->sched_in_time - atom->wake_up_time; | 1015 | delta = atom->sched_in_time - atom->wake_up_time; |
| 1021 | atoms->total_lat += delta; | 1016 | atoms->total_lat += delta; |
| 1022 | if (delta > atoms->max_lat) | 1017 | if (delta > atoms->max_lat) { |
| 1023 | atoms->max_lat = delta; | 1018 | atoms->max_lat = delta; |
| 1019 | atoms->max_lat_at = timestamp; | ||
| 1020 | } | ||
| 1024 | atoms->nb_atoms++; | 1021 | atoms->nb_atoms++; |
| 1025 | } | 1022 | } |
| 1026 | 1023 | ||
| @@ -1216,10 +1213,11 @@ static void output_lat_thread(struct work_atoms *work_list) | |||
| 1216 | 1213 | ||
| 1217 | avg = work_list->total_lat / work_list->nb_atoms; | 1214 | avg = work_list->total_lat / work_list->nb_atoms; |
| 1218 | 1215 | ||
| 1219 | printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", | 1216 | printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n", |
| 1220 | (double)work_list->total_runtime / 1e6, | 1217 | (double)work_list->total_runtime / 1e6, |
| 1221 | work_list->nb_atoms, (double)avg / 1e6, | 1218 | work_list->nb_atoms, (double)avg / 1e6, |
| 1222 | (double)work_list->max_lat / 1e6); | 1219 | (double)work_list->max_lat / 1e6, |
| 1220 | (double)work_list->max_lat_at / 1e9); | ||
| 1223 | } | 1221 | } |
| 1224 | 1222 | ||
| 1225 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) | 1223 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
| @@ -1356,7 +1354,7 @@ static void sort_lat(void) | |||
| 1356 | static struct trace_sched_handler *trace_handler; | 1354 | static struct trace_sched_handler *trace_handler; |
| 1357 | 1355 | ||
| 1358 | static void | 1356 | static void |
| 1359 | process_sched_wakeup_event(struct raw_event_sample *raw, | 1357 | process_sched_wakeup_event(void *data, |
| 1360 | struct event *event, | 1358 | struct event *event, |
| 1361 | int cpu __used, | 1359 | int cpu __used, |
| 1362 | u64 timestamp __used, | 1360 | u64 timestamp __used, |
| @@ -1364,13 +1362,13 @@ process_sched_wakeup_event(struct raw_event_sample *raw, | |||
| 1364 | { | 1362 | { |
| 1365 | struct trace_wakeup_event wakeup_event; | 1363 | struct trace_wakeup_event wakeup_event; |
| 1366 | 1364 | ||
| 1367 | FILL_COMMON_FIELDS(wakeup_event, event, raw->data); | 1365 | FILL_COMMON_FIELDS(wakeup_event, event, data); |
| 1368 | 1366 | ||
| 1369 | FILL_ARRAY(wakeup_event, comm, event, raw->data); | 1367 | FILL_ARRAY(wakeup_event, comm, event, data); |
| 1370 | FILL_FIELD(wakeup_event, pid, event, raw->data); | 1368 | FILL_FIELD(wakeup_event, pid, event, data); |
| 1371 | FILL_FIELD(wakeup_event, prio, event, raw->data); | 1369 | FILL_FIELD(wakeup_event, prio, event, data); |
| 1372 | FILL_FIELD(wakeup_event, success, event, raw->data); | 1370 | FILL_FIELD(wakeup_event, success, event, data); |
| 1373 | FILL_FIELD(wakeup_event, cpu, event, raw->data); | 1371 | FILL_FIELD(wakeup_event, cpu, event, data); |
| 1374 | 1372 | ||
| 1375 | if (trace_handler->wakeup_event) | 1373 | if (trace_handler->wakeup_event) |
| 1376 | trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); | 1374 | trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); |
| @@ -1469,7 +1467,7 @@ map_switch_event(struct trace_switch_event *switch_event, | |||
| 1469 | 1467 | ||
| 1470 | 1468 | ||
| 1471 | static void | 1469 | static void |
| 1472 | process_sched_switch_event(struct raw_event_sample *raw, | 1470 | process_sched_switch_event(void *data, |
| 1473 | struct event *event, | 1471 | struct event *event, |
| 1474 | int this_cpu, | 1472 | int this_cpu, |
| 1475 | u64 timestamp __used, | 1473 | u64 timestamp __used, |
| @@ -1477,15 +1475,15 @@ process_sched_switch_event(struct raw_event_sample *raw, | |||
| 1477 | { | 1475 | { |
| 1478 | struct trace_switch_event switch_event; | 1476 | struct trace_switch_event switch_event; |
| 1479 | 1477 | ||
| 1480 | FILL_COMMON_FIELDS(switch_event, event, raw->data); | 1478 | FILL_COMMON_FIELDS(switch_event, event, data); |
| 1481 | 1479 | ||
| 1482 | FILL_ARRAY(switch_event, prev_comm, event, raw->data); | 1480 | FILL_ARRAY(switch_event, prev_comm, event, data); |
| 1483 | FILL_FIELD(switch_event, prev_pid, event, raw->data); | 1481 | FILL_FIELD(switch_event, prev_pid, event, data); |
| 1484 | FILL_FIELD(switch_event, prev_prio, event, raw->data); | 1482 | FILL_FIELD(switch_event, prev_prio, event, data); |
| 1485 | FILL_FIELD(switch_event, prev_state, event, raw->data); | 1483 | FILL_FIELD(switch_event, prev_state, event, data); |
| 1486 | FILL_ARRAY(switch_event, next_comm, event, raw->data); | 1484 | FILL_ARRAY(switch_event, next_comm, event, data); |
| 1487 | FILL_FIELD(switch_event, next_pid, event, raw->data); | 1485 | FILL_FIELD(switch_event, next_pid, event, data); |
| 1488 | FILL_FIELD(switch_event, next_prio, event, raw->data); | 1486 | FILL_FIELD(switch_event, next_prio, event, data); |
| 1489 | 1487 | ||
| 1490 | if (curr_pid[this_cpu] != (u32)-1) { | 1488 | if (curr_pid[this_cpu] != (u32)-1) { |
| 1491 | /* | 1489 | /* |
| @@ -1502,7 +1500,7 @@ process_sched_switch_event(struct raw_event_sample *raw, | |||
| 1502 | } | 1500 | } |
| 1503 | 1501 | ||
| 1504 | static void | 1502 | static void |
| 1505 | process_sched_runtime_event(struct raw_event_sample *raw, | 1503 | process_sched_runtime_event(void *data, |
| 1506 | struct event *event, | 1504 | struct event *event, |
| 1507 | int cpu __used, | 1505 | int cpu __used, |
| 1508 | u64 timestamp __used, | 1506 | u64 timestamp __used, |
| @@ -1510,17 +1508,17 @@ process_sched_runtime_event(struct raw_event_sample *raw, | |||
| 1510 | { | 1508 | { |
| 1511 | struct trace_runtime_event runtime_event; | 1509 | struct trace_runtime_event runtime_event; |
| 1512 | 1510 | ||
| 1513 | FILL_ARRAY(runtime_event, comm, event, raw->data); | 1511 | FILL_ARRAY(runtime_event, comm, event, data); |
| 1514 | FILL_FIELD(runtime_event, pid, event, raw->data); | 1512 | FILL_FIELD(runtime_event, pid, event, data); |
| 1515 | FILL_FIELD(runtime_event, runtime, event, raw->data); | 1513 | FILL_FIELD(runtime_event, runtime, event, data); |
| 1516 | FILL_FIELD(runtime_event, vruntime, event, raw->data); | 1514 | FILL_FIELD(runtime_event, vruntime, event, data); |
| 1517 | 1515 | ||
| 1518 | if (trace_handler->runtime_event) | 1516 | if (trace_handler->runtime_event) |
| 1519 | trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); | 1517 | trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); |
| 1520 | } | 1518 | } |
| 1521 | 1519 | ||
| 1522 | static void | 1520 | static void |
| 1523 | process_sched_fork_event(struct raw_event_sample *raw, | 1521 | process_sched_fork_event(void *data, |
| 1524 | struct event *event, | 1522 | struct event *event, |
| 1525 | int cpu __used, | 1523 | int cpu __used, |
| 1526 | u64 timestamp __used, | 1524 | u64 timestamp __used, |
| @@ -1528,12 +1526,12 @@ process_sched_fork_event(struct raw_event_sample *raw, | |||
| 1528 | { | 1526 | { |
| 1529 | struct trace_fork_event fork_event; | 1527 | struct trace_fork_event fork_event; |
| 1530 | 1528 | ||
| 1531 | FILL_COMMON_FIELDS(fork_event, event, raw->data); | 1529 | FILL_COMMON_FIELDS(fork_event, event, data); |
| 1532 | 1530 | ||
| 1533 | FILL_ARRAY(fork_event, parent_comm, event, raw->data); | 1531 | FILL_ARRAY(fork_event, parent_comm, event, data); |
| 1534 | FILL_FIELD(fork_event, parent_pid, event, raw->data); | 1532 | FILL_FIELD(fork_event, parent_pid, event, data); |
| 1535 | FILL_ARRAY(fork_event, child_comm, event, raw->data); | 1533 | FILL_ARRAY(fork_event, child_comm, event, data); |
| 1536 | FILL_FIELD(fork_event, child_pid, event, raw->data); | 1534 | FILL_FIELD(fork_event, child_pid, event, data); |
| 1537 | 1535 | ||
| 1538 | if (trace_handler->fork_event) | 1536 | if (trace_handler->fork_event) |
| 1539 | trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); | 1537 | trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); |
| @@ -1550,7 +1548,7 @@ process_sched_exit_event(struct event *event, | |||
| 1550 | } | 1548 | } |
| 1551 | 1549 | ||
| 1552 | static void | 1550 | static void |
| 1553 | process_sched_migrate_task_event(struct raw_event_sample *raw, | 1551 | process_sched_migrate_task_event(void *data, |
| 1554 | struct event *event, | 1552 | struct event *event, |
| 1555 | int cpu __used, | 1553 | int cpu __used, |
| 1556 | u64 timestamp __used, | 1554 | u64 timestamp __used, |
| @@ -1558,80 +1556,66 @@ process_sched_migrate_task_event(struct raw_event_sample *raw, | |||
| 1558 | { | 1556 | { |
| 1559 | struct trace_migrate_task_event migrate_task_event; | 1557 | struct trace_migrate_task_event migrate_task_event; |
| 1560 | 1558 | ||
| 1561 | FILL_COMMON_FIELDS(migrate_task_event, event, raw->data); | 1559 | FILL_COMMON_FIELDS(migrate_task_event, event, data); |
| 1562 | 1560 | ||
| 1563 | FILL_ARRAY(migrate_task_event, comm, event, raw->data); | 1561 | FILL_ARRAY(migrate_task_event, comm, event, data); |
| 1564 | FILL_FIELD(migrate_task_event, pid, event, raw->data); | 1562 | FILL_FIELD(migrate_task_event, pid, event, data); |
| 1565 | FILL_FIELD(migrate_task_event, prio, event, raw->data); | 1563 | FILL_FIELD(migrate_task_event, prio, event, data); |
| 1566 | FILL_FIELD(migrate_task_event, cpu, event, raw->data); | 1564 | FILL_FIELD(migrate_task_event, cpu, event, data); |
| 1567 | 1565 | ||
| 1568 | if (trace_handler->migrate_task_event) | 1566 | if (trace_handler->migrate_task_event) |
| 1569 | trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); | 1567 | trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); |
| 1570 | } | 1568 | } |
| 1571 | 1569 | ||
| 1572 | static void | 1570 | static void |
| 1573 | process_raw_event(event_t *raw_event __used, void *more_data, | 1571 | process_raw_event(event_t *raw_event __used, void *data, |
| 1574 | int cpu, u64 timestamp, struct thread *thread) | 1572 | int cpu, u64 timestamp, struct thread *thread) |
| 1575 | { | 1573 | { |
| 1576 | struct raw_event_sample *raw = more_data; | ||
| 1577 | struct event *event; | 1574 | struct event *event; |
| 1578 | int type; | 1575 | int type; |
| 1579 | 1576 | ||
| 1580 | type = trace_parse_common_type(raw->data); | 1577 | |
| 1578 | type = trace_parse_common_type(data); | ||
| 1581 | event = trace_find_event(type); | 1579 | event = trace_find_event(type); |
| 1582 | 1580 | ||
| 1583 | if (!strcmp(event->name, "sched_switch")) | 1581 | if (!strcmp(event->name, "sched_switch")) |
| 1584 | process_sched_switch_event(raw, event, cpu, timestamp, thread); | 1582 | process_sched_switch_event(data, event, cpu, timestamp, thread); |
| 1585 | if (!strcmp(event->name, "sched_stat_runtime")) | 1583 | if (!strcmp(event->name, "sched_stat_runtime")) |
| 1586 | process_sched_runtime_event(raw, event, cpu, timestamp, thread); | 1584 | process_sched_runtime_event(data, event, cpu, timestamp, thread); |
| 1587 | if (!strcmp(event->name, "sched_wakeup")) | 1585 | if (!strcmp(event->name, "sched_wakeup")) |
| 1588 | process_sched_wakeup_event(raw, event, cpu, timestamp, thread); | 1586 | process_sched_wakeup_event(data, event, cpu, timestamp, thread); |
| 1589 | if (!strcmp(event->name, "sched_wakeup_new")) | 1587 | if (!strcmp(event->name, "sched_wakeup_new")) |
| 1590 | process_sched_wakeup_event(raw, event, cpu, timestamp, thread); | 1588 | process_sched_wakeup_event(data, event, cpu, timestamp, thread); |
| 1591 | if (!strcmp(event->name, "sched_process_fork")) | 1589 | if (!strcmp(event->name, "sched_process_fork")) |
| 1592 | process_sched_fork_event(raw, event, cpu, timestamp, thread); | 1590 | process_sched_fork_event(data, event, cpu, timestamp, thread); |
| 1593 | if (!strcmp(event->name, "sched_process_exit")) | 1591 | if (!strcmp(event->name, "sched_process_exit")) |
| 1594 | process_sched_exit_event(event, cpu, timestamp, thread); | 1592 | process_sched_exit_event(event, cpu, timestamp, thread); |
| 1595 | if (!strcmp(event->name, "sched_migrate_task")) | 1593 | if (!strcmp(event->name, "sched_migrate_task")) |
| 1596 | process_sched_migrate_task_event(raw, event, cpu, timestamp, thread); | 1594 | process_sched_migrate_task_event(data, event, cpu, timestamp, thread); |
| 1597 | } | 1595 | } |
| 1598 | 1596 | ||
| 1599 | static int process_sample_event(event_t *event) | 1597 | static int process_sample_event(event_t *event) |
| 1600 | { | 1598 | { |
| 1599 | struct sample_data data; | ||
| 1601 | struct thread *thread; | 1600 | struct thread *thread; |
| 1602 | u64 ip = event->ip.ip; | ||
| 1603 | u64 timestamp = -1; | ||
| 1604 | u32 cpu = -1; | ||
| 1605 | u64 period = 1; | ||
| 1606 | void *more_data = event->ip.__more_data; | ||
| 1607 | 1601 | ||
| 1608 | if (!(sample_type & PERF_SAMPLE_RAW)) | 1602 | if (!(sample_type & PERF_SAMPLE_RAW)) |
| 1609 | return 0; | 1603 | return 0; |
| 1610 | 1604 | ||
| 1611 | thread = threads__findnew(event->ip.pid); | 1605 | memset(&data, 0, sizeof(data)); |
| 1606 | data.time = -1; | ||
| 1607 | data.cpu = -1; | ||
| 1608 | data.period = -1; | ||
| 1612 | 1609 | ||
| 1613 | if (sample_type & PERF_SAMPLE_TIME) { | 1610 | event__parse_sample(event, sample_type, &data); |
| 1614 | timestamp = *(u64 *)more_data; | ||
| 1615 | more_data += sizeof(u64); | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | if (sample_type & PERF_SAMPLE_CPU) { | ||
| 1619 | cpu = *(u32 *)more_data; | ||
| 1620 | more_data += sizeof(u32); | ||
| 1621 | more_data += sizeof(u32); /* reserved */ | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | if (sample_type & PERF_SAMPLE_PERIOD) { | ||
| 1625 | period = *(u64 *)more_data; | ||
| 1626 | more_data += sizeof(u64); | ||
| 1627 | } | ||
| 1628 | 1611 | ||
| 1629 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 1612 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
| 1630 | event->header.misc, | 1613 | event->header.misc, |
| 1631 | event->ip.pid, event->ip.tid, | 1614 | data.pid, data.tid, |
| 1632 | (void *)(long)ip, | 1615 | (void *)(long)data.ip, |
| 1633 | (long long)period); | 1616 | (long long)data.period); |
| 1634 | 1617 | ||
| 1618 | thread = threads__findnew(data.pid); | ||
| 1635 | if (thread == NULL) { | 1619 | if (thread == NULL) { |
| 1636 | pr_debug("problem processing %d event, skipping it.\n", | 1620 | pr_debug("problem processing %d event, skipping it.\n", |
| 1637 | event->header.type); | 1621 | event->header.type); |
| @@ -1640,10 +1624,10 @@ static int process_sample_event(event_t *event) | |||
| 1640 | 1624 | ||
| 1641 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1625 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
| 1642 | 1626 | ||
| 1643 | if (profile_cpu != -1 && profile_cpu != (int) cpu) | 1627 | if (profile_cpu != -1 && profile_cpu != (int)data.cpu) |
| 1644 | return 0; | 1628 | return 0; |
| 1645 | 1629 | ||
| 1646 | process_raw_event(event, more_data, cpu, timestamp, thread); | 1630 | process_raw_event(event, data.raw_data, data.cpu, data.time, thread); |
| 1647 | 1631 | ||
| 1648 | return 0; | 1632 | return 0; |
| 1649 | } | 1633 | } |
| @@ -1724,9 +1708,9 @@ static void __cmd_lat(void) | |||
| 1724 | read_events(); | 1708 | read_events(); |
| 1725 | sort_lat(); | 1709 | sort_lat(); |
| 1726 | 1710 | ||
| 1727 | printf("\n -----------------------------------------------------------------------------------------\n"); | 1711 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); |
| 1728 | printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); | 1712 | printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n"); |
| 1729 | printf(" -----------------------------------------------------------------------------------------\n"); | 1713 | printf(" ---------------------------------------------------------------------------------------------------------------\n"); |
| 1730 | 1714 | ||
| 1731 | next = rb_first(&sorted_atom_root); | 1715 | next = rb_first(&sorted_atom_root); |
| 1732 | 1716 | ||
| @@ -1902,13 +1886,18 @@ static int __cmd_record(int argc, const char **argv) | |||
| 1902 | 1886 | ||
| 1903 | int cmd_sched(int argc, const char **argv, const char *prefix __used) | 1887 | int cmd_sched(int argc, const char **argv, const char *prefix __used) |
| 1904 | { | 1888 | { |
| 1905 | symbol__init(0); | ||
| 1906 | |||
| 1907 | argc = parse_options(argc, argv, sched_options, sched_usage, | 1889 | argc = parse_options(argc, argv, sched_options, sched_usage, |
| 1908 | PARSE_OPT_STOP_AT_NON_OPTION); | 1890 | PARSE_OPT_STOP_AT_NON_OPTION); |
| 1909 | if (!argc) | 1891 | if (!argc) |
| 1910 | usage_with_options(sched_usage, sched_options); | 1892 | usage_with_options(sched_usage, sched_options); |
| 1911 | 1893 | ||
| 1894 | /* | ||
| 1895 | * Aliased to 'perf trace' for now: | ||
| 1896 | */ | ||
| 1897 | if (!strcmp(argv[0], "trace")) | ||
| 1898 | return cmd_trace(argc, argv, prefix); | ||
| 1899 | |||
| 1900 | symbol__init(0); | ||
| 1912 | if (!strncmp(argv[0], "rec", 3)) { | 1901 | if (!strncmp(argv[0], "rec", 3)) { |
| 1913 | return __cmd_record(argc, argv); | 1902 | return __cmd_record(argc, argv); |
| 1914 | } else if (!strncmp(argv[0], "lat", 3)) { | 1903 | } else if (!strncmp(argv[0], "lat", 3)) { |
| @@ -1932,11 +1921,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used) | |||
| 1932 | usage_with_options(replay_usage, replay_options); | 1921 | usage_with_options(replay_usage, replay_options); |
| 1933 | } | 1922 | } |
| 1934 | __cmd_replay(); | 1923 | __cmd_replay(); |
| 1935 | } else if (!strcmp(argv[0], "trace")) { | ||
| 1936 | /* | ||
| 1937 | * Aliased to 'perf trace' for now: | ||
| 1938 | */ | ||
| 1939 | return cmd_trace(argc, argv, prefix); | ||
| 1940 | } else { | 1924 | } else { |
| 1941 | usage_with_options(sched_usage, sched_options); | 1925 | usage_with_options(sched_usage, sched_options); |
| 1942 | } | 1926 | } |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index cb58b6605fcc..f472df9561ee 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
| @@ -302,12 +302,11 @@ process_exit_event(event_t *event) | |||
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | struct trace_entry { | 304 | struct trace_entry { |
| 305 | u32 size; | ||
| 306 | unsigned short type; | 305 | unsigned short type; |
| 307 | unsigned char flags; | 306 | unsigned char flags; |
| 308 | unsigned char preempt_count; | 307 | unsigned char preempt_count; |
| 309 | int pid; | 308 | int pid; |
| 310 | int tgid; | 309 | int lock_depth; |
| 311 | }; | 310 | }; |
| 312 | 311 | ||
| 313 | struct power_entry { | 312 | struct power_entry { |
| @@ -484,43 +483,22 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
| 484 | static int | 483 | static int |
| 485 | process_sample_event(event_t *event) | 484 | process_sample_event(event_t *event) |
| 486 | { | 485 | { |
| 487 | int cursor = 0; | 486 | struct sample_data data; |
| 488 | u64 addr = 0; | ||
| 489 | u64 stamp = 0; | ||
| 490 | u32 cpu = 0; | ||
| 491 | u32 pid = 0; | ||
| 492 | struct trace_entry *te; | 487 | struct trace_entry *te; |
| 493 | 488 | ||
| 494 | if (sample_type & PERF_SAMPLE_IP) | 489 | memset(&data, 0, sizeof(data)); |
| 495 | cursor++; | ||
| 496 | |||
| 497 | if (sample_type & PERF_SAMPLE_TID) { | ||
| 498 | pid = event->sample.array[cursor]>>32; | ||
| 499 | cursor++; | ||
| 500 | } | ||
| 501 | if (sample_type & PERF_SAMPLE_TIME) { | ||
| 502 | stamp = event->sample.array[cursor++]; | ||
| 503 | 490 | ||
| 504 | if (!first_time || first_time > stamp) | 491 | event__parse_sample(event, sample_type, &data); |
| 505 | first_time = stamp; | ||
| 506 | if (last_time < stamp) | ||
| 507 | last_time = stamp; | ||
| 508 | 492 | ||
| 493 | if (sample_type & PERF_SAMPLE_TIME) { | ||
| 494 | if (!first_time || first_time > data.time) | ||
| 495 | first_time = data.time; | ||
| 496 | if (last_time < data.time) | ||
| 497 | last_time = data.time; | ||
| 509 | } | 498 | } |
| 510 | if (sample_type & PERF_SAMPLE_ADDR) | ||
| 511 | addr = event->sample.array[cursor++]; | ||
| 512 | if (sample_type & PERF_SAMPLE_ID) | ||
| 513 | cursor++; | ||
| 514 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 515 | cursor++; | ||
| 516 | if (sample_type & PERF_SAMPLE_CPU) | ||
| 517 | cpu = event->sample.array[cursor++] & 0xFFFFFFFF; | ||
| 518 | if (sample_type & PERF_SAMPLE_PERIOD) | ||
| 519 | cursor++; | ||
| 520 | |||
| 521 | te = (void *)&event->sample.array[cursor]; | ||
| 522 | 499 | ||
| 523 | if (sample_type & PERF_SAMPLE_RAW && te->size > 0) { | 500 | te = (void *)data.raw_data; |
| 501 | if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { | ||
| 524 | char *event_str; | 502 | char *event_str; |
| 525 | struct power_entry *pe; | 503 | struct power_entry *pe; |
| 526 | 504 | ||
| @@ -532,19 +510,19 @@ process_sample_event(event_t *event) | |||
| 532 | return 0; | 510 | return 0; |
| 533 | 511 | ||
| 534 | if (strcmp(event_str, "power:power_start") == 0) | 512 | if (strcmp(event_str, "power:power_start") == 0) |
| 535 | c_state_start(cpu, stamp, pe->value); | 513 | c_state_start(data.cpu, data.time, pe->value); |
| 536 | 514 | ||
| 537 | if (strcmp(event_str, "power:power_end") == 0) | 515 | if (strcmp(event_str, "power:power_end") == 0) |
| 538 | c_state_end(cpu, stamp); | 516 | c_state_end(data.cpu, data.time); |
| 539 | 517 | ||
| 540 | if (strcmp(event_str, "power:power_frequency") == 0) | 518 | if (strcmp(event_str, "power:power_frequency") == 0) |
| 541 | p_state_change(cpu, stamp, pe->value); | 519 | p_state_change(data.cpu, data.time, pe->value); |
| 542 | 520 | ||
| 543 | if (strcmp(event_str, "sched:sched_wakeup") == 0) | 521 | if (strcmp(event_str, "sched:sched_wakeup") == 0) |
| 544 | sched_wakeup(cpu, stamp, pid, te); | 522 | sched_wakeup(data.cpu, data.time, data.pid, te); |
| 545 | 523 | ||
| 546 | if (strcmp(event_str, "sched:sched_switch") == 0) | 524 | if (strcmp(event_str, "sched:sched_switch") == 0) |
| 547 | sched_switch(cpu, stamp, te); | 525 | sched_switch(data.cpu, data.time, te); |
| 548 | } | 526 | } |
| 549 | return 0; | 527 | return 0; |
| 550 | } | 528 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index abb914aa7be6..c2fcc34486f5 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -66,58 +66,40 @@ static u64 sample_type; | |||
| 66 | 66 | ||
| 67 | static int process_sample_event(event_t *event) | 67 | static int process_sample_event(event_t *event) |
| 68 | { | 68 | { |
| 69 | u64 ip = event->ip.ip; | 69 | struct sample_data data; |
| 70 | u64 timestamp = -1; | 70 | struct thread *thread; |
| 71 | u32 cpu = -1; | ||
| 72 | u64 period = 1; | ||
| 73 | void *more_data = event->ip.__more_data; | ||
| 74 | struct thread *thread = threads__findnew(event->ip.pid); | ||
| 75 | |||
| 76 | if (sample_type & PERF_SAMPLE_TIME) { | ||
| 77 | timestamp = *(u64 *)more_data; | ||
| 78 | more_data += sizeof(u64); | ||
| 79 | } | ||
| 80 | 71 | ||
| 81 | if (sample_type & PERF_SAMPLE_CPU) { | 72 | memset(&data, 0, sizeof(data)); |
| 82 | cpu = *(u32 *)more_data; | 73 | data.time = -1; |
| 83 | more_data += sizeof(u32); | 74 | data.cpu = -1; |
| 84 | more_data += sizeof(u32); /* reserved */ | 75 | data.period = 1; |
| 85 | } | ||
| 86 | 76 | ||
| 87 | if (sample_type & PERF_SAMPLE_PERIOD) { | 77 | event__parse_sample(event, sample_type, &data); |
| 88 | period = *(u64 *)more_data; | ||
| 89 | more_data += sizeof(u64); | ||
| 90 | } | ||
| 91 | 78 | ||
| 92 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 79 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
| 93 | event->header.misc, | 80 | event->header.misc, |
| 94 | event->ip.pid, event->ip.tid, | 81 | data.pid, data.tid, |
| 95 | (void *)(long)ip, | 82 | (void *)(long)data.ip, |
| 96 | (long long)period); | 83 | (long long)data.period); |
| 97 | 84 | ||
| 85 | thread = threads__findnew(event->ip.pid); | ||
| 98 | if (thread == NULL) { | 86 | if (thread == NULL) { |
| 99 | pr_debug("problem processing %d event, skipping it.\n", | 87 | pr_debug("problem processing %d event, skipping it.\n", |
| 100 | event->header.type); | 88 | event->header.type); |
| 101 | return -1; | 89 | return -1; |
| 102 | } | 90 | } |
| 103 | 91 | ||
| 104 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | ||
| 105 | |||
| 106 | if (sample_type & PERF_SAMPLE_RAW) { | 92 | if (sample_type & PERF_SAMPLE_RAW) { |
| 107 | struct { | ||
| 108 | u32 size; | ||
| 109 | char data[0]; | ||
| 110 | } *raw = more_data; | ||
| 111 | |||
| 112 | /* | 93 | /* |
| 113 | * FIXME: better resolve from pid from the struct trace_entry | 94 | * FIXME: better resolve from pid from the struct trace_entry |
| 114 | * field, although it should be the same than this perf | 95 | * field, although it should be the same than this perf |
| 115 | * event pid | 96 | * event pid |
| 116 | */ | 97 | */ |
| 117 | scripting_ops->process_event(cpu, raw->data, raw->size, | 98 | scripting_ops->process_event(data.cpu, data.raw_data, |
| 118 | timestamp, thread->comm); | 99 | data.raw_size, |
| 100 | data.time, thread->comm); | ||
| 119 | } | 101 | } |
| 120 | event__stats.total += period; | 102 | event__stats.total += data.period; |
| 121 | 103 | ||
| 122 | return 0; | 104 | return 0; |
| 123 | } | 105 | } |
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index ca0bedf637c2..59b65d0bd7c1 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c | |||
| @@ -100,11 +100,11 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | int perf_header__read_build_ids(int input, off_t offset, off_t size) | 103 | int perf_header__read_build_ids(int input, u64 offset, u64 size) |
| 104 | { | 104 | { |
| 105 | struct build_id_event bev; | 105 | struct build_id_event bev; |
| 106 | char filename[PATH_MAX]; | 106 | char filename[PATH_MAX]; |
| 107 | off_t limit = offset + size; | 107 | u64 limit = offset + size; |
| 108 | int err = -1; | 108 | int err = -1; |
| 109 | 109 | ||
| 110 | while (offset < limit) { | 110 | while (offset < limit) { |
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index 3180ff7e3633..258a87bcc4fb 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h | |||
| @@ -27,6 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, | |||
| 27 | int full_paths, | 27 | int full_paths, |
| 28 | int *cwdlen, | 28 | int *cwdlen, |
| 29 | char **cwd); | 29 | char **cwd); |
| 30 | int perf_header__read_build_ids(int input, off_t offset, off_t file_size); | 30 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); |
| 31 | 31 | ||
| 32 | #endif | 32 | #endif |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 414b89d1bde9..4dcecafa85dc 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -310,3 +310,70 @@ int event__preprocess_sample(const event_t *self, struct addr_location *al, | |||
| 310 | al->level == 'H' ? "[hypervisor]" : "<not found>"); | 310 | al->level == 'H' ? "[hypervisor]" : "<not found>"); |
| 311 | return 0; | 311 | return 0; |
| 312 | } | 312 | } |
| 313 | |||
| 314 | int event__parse_sample(event_t *event, u64 type, struct sample_data *data) | ||
| 315 | { | ||
| 316 | u64 *array = event->sample.array; | ||
| 317 | |||
| 318 | if (type & PERF_SAMPLE_IP) { | ||
| 319 | data->ip = event->ip.ip; | ||
| 320 | array++; | ||
| 321 | } | ||
| 322 | |||
| 323 | if (type & PERF_SAMPLE_TID) { | ||
| 324 | u32 *p = (u32 *)array; | ||
| 325 | data->pid = p[0]; | ||
| 326 | data->tid = p[1]; | ||
| 327 | array++; | ||
| 328 | } | ||
| 329 | |||
| 330 | if (type & PERF_SAMPLE_TIME) { | ||
| 331 | data->time = *array; | ||
| 332 | array++; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (type & PERF_SAMPLE_ADDR) { | ||
| 336 | data->addr = *array; | ||
| 337 | array++; | ||
| 338 | } | ||
| 339 | |||
| 340 | if (type & PERF_SAMPLE_ID) { | ||
| 341 | data->id = *array; | ||
| 342 | array++; | ||
| 343 | } | ||
| 344 | |||
| 345 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
| 346 | data->stream_id = *array; | ||
| 347 | array++; | ||
| 348 | } | ||
| 349 | |||
| 350 | if (type & PERF_SAMPLE_CPU) { | ||
| 351 | u32 *p = (u32 *)array; | ||
| 352 | data->cpu = *p; | ||
| 353 | array++; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (type & PERF_SAMPLE_PERIOD) { | ||
| 357 | data->period = *array; | ||
| 358 | array++; | ||
| 359 | } | ||
| 360 | |||
| 361 | if (type & PERF_SAMPLE_READ) { | ||
| 362 | pr_debug("PERF_SAMPLE_READ is unsuported for now\n"); | ||
| 363 | return -1; | ||
| 364 | } | ||
| 365 | |||
| 366 | if (type & PERF_SAMPLE_CALLCHAIN) { | ||
| 367 | data->callchain = (struct ip_callchain *)array; | ||
| 368 | array += 1 + data->callchain->nr; | ||
| 369 | } | ||
| 370 | |||
| 371 | if (type & PERF_SAMPLE_RAW) { | ||
| 372 | u32 *p = (u32 *)array; | ||
| 373 | data->raw_size = *p; | ||
| 374 | p++; | ||
| 375 | data->raw_data = p; | ||
| 376 | } | ||
| 377 | |||
| 378 | return 0; | ||
| 379 | } | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index a4cc8105cf67..c7a78eef8e52 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -56,11 +56,25 @@ struct read_event { | |||
| 56 | u64 id; | 56 | u64 id; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | struct sample_event{ | 59 | struct sample_event { |
| 60 | struct perf_event_header header; | 60 | struct perf_event_header header; |
| 61 | u64 array[]; | 61 | u64 array[]; |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | struct sample_data { | ||
| 65 | u64 ip; | ||
| 66 | u32 pid, tid; | ||
| 67 | u64 time; | ||
| 68 | u64 addr; | ||
| 69 | u64 id; | ||
| 70 | u64 stream_id; | ||
| 71 | u32 cpu; | ||
| 72 | u64 period; | ||
| 73 | struct ip_callchain *callchain; | ||
| 74 | u32 raw_size; | ||
| 75 | void *raw_data; | ||
| 76 | }; | ||
| 77 | |||
| 64 | #define BUILD_ID_SIZE 20 | 78 | #define BUILD_ID_SIZE 20 |
| 65 | 79 | ||
| 66 | struct build_id_event { | 80 | struct build_id_event { |
| @@ -155,5 +169,6 @@ int event__process_task(event_t *self); | |||
| 155 | struct addr_location; | 169 | struct addr_location; |
| 156 | int event__preprocess_sample(const event_t *self, struct addr_location *al, | 170 | int event__preprocess_sample(const event_t *self, struct addr_location *al, |
| 157 | symbol_filter_t filter); | 171 | symbol_filter_t filter); |
| 172 | int event__parse_sample(event_t *event, u64 type, struct sample_data *data); | ||
| 158 | 173 | ||
| 159 | #endif /* __PERF_RECORD_H */ | 174 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 4805e6dfd23c..59a9c0b3033e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -187,7 +187,9 @@ static int do_write(int fd, const void *buf, size_t size) | |||
| 187 | 187 | ||
| 188 | static int __dsos__write_buildid_table(struct list_head *head, int fd) | 188 | static int __dsos__write_buildid_table(struct list_head *head, int fd) |
| 189 | { | 189 | { |
| 190 | #define NAME_ALIGN 64 | ||
| 190 | struct dso *pos; | 191 | struct dso *pos; |
| 192 | static const char zero_buf[NAME_ALIGN]; | ||
| 191 | 193 | ||
| 192 | list_for_each_entry(pos, head, node) { | 194 | list_for_each_entry(pos, head, node) { |
| 193 | int err; | 195 | int err; |
| @@ -197,14 +199,17 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd) | |||
| 197 | if (!pos->has_build_id) | 199 | if (!pos->has_build_id) |
| 198 | continue; | 200 | continue; |
| 199 | len = pos->long_name_len + 1; | 201 | len = pos->long_name_len + 1; |
| 200 | len = ALIGN(len, 64); | 202 | len = ALIGN(len, NAME_ALIGN); |
| 201 | memset(&b, 0, sizeof(b)); | 203 | memset(&b, 0, sizeof(b)); |
| 202 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 204 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
| 203 | b.header.size = sizeof(b) + len; | 205 | b.header.size = sizeof(b) + len; |
| 204 | err = do_write(fd, &b, sizeof(b)); | 206 | err = do_write(fd, &b, sizeof(b)); |
| 205 | if (err < 0) | 207 | if (err < 0) |
| 206 | return err; | 208 | return err; |
| 207 | err = do_write(fd, pos->long_name, len); | 209 | err = do_write(fd, pos->long_name, pos->long_name_len + 1); |
| 210 | if (err < 0) | ||
| 211 | return err; | ||
| 212 | err = do_write(fd, zero_buf, len - pos->long_name_len - 1); | ||
| 208 | if (err < 0) | 213 | if (err < 0) |
| 209 | return err; | 214 | return err; |
| 210 | } | 215 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 9e5dbd66d34d..e5bc0fb016b2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
| 197 | if (id == config) { | 197 | if (id == config) { |
| 198 | closedir(evt_dir); | 198 | closedir(evt_dir); |
| 199 | closedir(sys_dir); | 199 | closedir(sys_dir); |
| 200 | path = zalloc(sizeof(path)); | 200 | path = zalloc(sizeof(*path)); |
| 201 | path->system = malloc(MAX_EVENT_LENGTH); | 201 | path->system = malloc(MAX_EVENT_LENGTH); |
| 202 | if (!path->system) { | 202 | if (!path->system) { |
| 203 | free(path); | 203 | free(path); |
| @@ -467,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags) | |||
| 467 | while ((evt_ent = readdir(evt_dir))) { | 467 | while ((evt_ent = readdir(evt_dir))) { |
| 468 | char event_opt[MAX_EVOPT_LEN + 1]; | 468 | char event_opt[MAX_EVOPT_LEN + 1]; |
| 469 | int len; | 469 | int len; |
| 470 | unsigned int rem = MAX_EVOPT_LEN; | ||
| 471 | 470 | ||
| 472 | if (!strcmp(evt_ent->d_name, ".") | 471 | if (!strcmp(evt_ent->d_name, ".") |
| 473 | || !strcmp(evt_ent->d_name, "..") | 472 | || !strcmp(evt_ent->d_name, "..") |
| @@ -475,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags) | |||
| 475 | || !strcmp(evt_ent->d_name, "filter")) | 474 | || !strcmp(evt_ent->d_name, "filter")) |
| 476 | continue; | 475 | continue; |
| 477 | 476 | ||
| 478 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, | 477 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, |
| 479 | evt_ent->d_name); | 478 | evt_ent->d_name, flags ? ":" : "", |
| 479 | flags ?: ""); | ||
| 480 | if (len < 0) | 480 | if (len < 0) |
| 481 | return EVT_FAILED; | 481 | return EVT_FAILED; |
| 482 | 482 | ||
| 483 | rem -= len; | ||
| 484 | if (flags) { | ||
| 485 | if (rem < strlen(flags) + 1) | ||
| 486 | return EVT_FAILED; | ||
| 487 | |||
| 488 | strcat(event_opt, ":"); | ||
| 489 | strcat(event_opt, flags); | ||
| 490 | } | ||
| 491 | |||
| 492 | if (parse_events(NULL, event_opt, 0)) | 483 | if (parse_events(NULL, event_opt, 0)) |
| 493 | return EVT_FAILED; | 484 | return EVT_FAILED; |
| 494 | } | 485 | } |
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 6d8af48c925e..efebd5b476b3 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
| @@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr, | |||
| 430 | pos = fprintf(stderr, " "); | 430 | pos = fprintf(stderr, " "); |
| 431 | if (opts->short_name) | 431 | if (opts->short_name) |
| 432 | pos += fprintf(stderr, "-%c", opts->short_name); | 432 | pos += fprintf(stderr, "-%c", opts->short_name); |
| 433 | else | ||
| 434 | pos += fprintf(stderr, " "); | ||
| 435 | |||
| 433 | if (opts->long_name && opts->short_name) | 436 | if (opts->long_name && opts->short_name) |
| 434 | pos += fprintf(stderr, ", "); | 437 | pos += fprintf(stderr, ", "); |
| 435 | if (opts->long_name) | 438 | if (opts->long_name) |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index cd7fbda5e2a5..d14a4585bcaf 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -48,6 +48,9 @@ | |||
| 48 | 48 | ||
| 49 | /* If there is no space to write, returns -E2BIG. */ | 49 | /* If there is no space to write, returns -E2BIG. */ |
| 50 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 50 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
| 51 | __attribute__((format(printf, 3, 4))); | ||
| 52 | |||
| 53 | static int e_snprintf(char *str, size_t size, const char *format, ...) | ||
| 51 | { | 54 | { |
| 52 | int ret; | 55 | int ret; |
| 53 | va_list ap; | 56 | va_list ap; |
| @@ -258,7 +261,7 @@ int synthesize_perf_probe_event(struct probe_point *pp) | |||
| 258 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, | 261 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, |
| 259 | offs, pp->retprobe ? "%return" : "", line); | 262 | offs, pp->retprobe ? "%return" : "", line); |
| 260 | else | 263 | else |
| 261 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line); | 264 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); |
| 262 | if (ret <= 0) | 265 | if (ret <= 0) |
| 263 | goto error; | 266 | goto error; |
| 264 | len = ret; | 267 | len = ret; |
| @@ -373,14 +376,32 @@ static void clear_probe_point(struct probe_point *pp) | |||
| 373 | free(pp->args); | 376 | free(pp->args); |
| 374 | for (i = 0; i < pp->found; i++) | 377 | for (i = 0; i < pp->found; i++) |
| 375 | free(pp->probes[i]); | 378 | free(pp->probes[i]); |
| 376 | memset(pp, 0, sizeof(pp)); | 379 | memset(pp, 0, sizeof(*pp)); |
| 380 | } | ||
| 381 | |||
| 382 | /* Show an event */ | ||
| 383 | static void show_perf_probe_event(const char *group, const char *event, | ||
| 384 | const char *place, struct probe_point *pp) | ||
| 385 | { | ||
| 386 | int i; | ||
| 387 | char buf[128]; | ||
| 388 | |||
| 389 | e_snprintf(buf, 128, "%s:%s", group, event); | ||
| 390 | printf(" %-40s (on %s", buf, place); | ||
| 391 | |||
| 392 | if (pp->nr_args > 0) { | ||
| 393 | printf(" with"); | ||
| 394 | for (i = 0; i < pp->nr_args; i++) | ||
| 395 | printf(" %s", pp->args[i]); | ||
| 396 | } | ||
| 397 | printf(")\n"); | ||
| 377 | } | 398 | } |
| 378 | 399 | ||
| 379 | /* List up current perf-probe events */ | 400 | /* List up current perf-probe events */ |
| 380 | void show_perf_probe_events(void) | 401 | void show_perf_probe_events(void) |
| 381 | { | 402 | { |
| 382 | unsigned int i; | 403 | unsigned int i; |
| 383 | int fd; | 404 | int fd, nr; |
| 384 | char *group, *event; | 405 | char *group, *event; |
| 385 | struct probe_point pp; | 406 | struct probe_point pp; |
| 386 | struct strlist *rawlist; | 407 | struct strlist *rawlist; |
| @@ -393,8 +414,13 @@ void show_perf_probe_events(void) | |||
| 393 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { | 414 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { |
| 394 | ent = strlist__entry(rawlist, i); | 415 | ent = strlist__entry(rawlist, i); |
| 395 | parse_trace_kprobe_event(ent->s, &group, &event, &pp); | 416 | parse_trace_kprobe_event(ent->s, &group, &event, &pp); |
| 417 | /* Synthesize only event probe point */ | ||
| 418 | nr = pp.nr_args; | ||
| 419 | pp.nr_args = 0; | ||
| 396 | synthesize_perf_probe_event(&pp); | 420 | synthesize_perf_probe_event(&pp); |
| 397 | printf("[%s:%s]\t%s\n", group, event, pp.probes[0]); | 421 | pp.nr_args = nr; |
| 422 | /* Show an event */ | ||
| 423 | show_perf_probe_event(group, event, pp.probes[0], &pp); | ||
| 398 | free(group); | 424 | free(group); |
| 399 | free(event); | 425 | free(event); |
| 400 | clear_probe_point(&pp); | 426 | clear_probe_point(&pp); |
| @@ -404,21 +430,28 @@ void show_perf_probe_events(void) | |||
| 404 | } | 430 | } |
| 405 | 431 | ||
| 406 | /* Get current perf-probe event names */ | 432 | /* Get current perf-probe event names */ |
| 407 | static struct strlist *get_perf_event_names(int fd) | 433 | static struct strlist *get_perf_event_names(int fd, bool include_group) |
| 408 | { | 434 | { |
| 409 | unsigned int i; | 435 | unsigned int i; |
| 410 | char *group, *event; | 436 | char *group, *event; |
| 437 | char buf[128]; | ||
| 411 | struct strlist *sl, *rawlist; | 438 | struct strlist *sl, *rawlist; |
| 412 | struct str_node *ent; | 439 | struct str_node *ent; |
| 413 | 440 | ||
| 414 | rawlist = get_trace_kprobe_event_rawlist(fd); | 441 | rawlist = get_trace_kprobe_event_rawlist(fd); |
| 415 | 442 | ||
| 416 | sl = strlist__new(false, NULL); | 443 | sl = strlist__new(true, NULL); |
| 417 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { | 444 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { |
| 418 | ent = strlist__entry(rawlist, i); | 445 | ent = strlist__entry(rawlist, i); |
| 419 | parse_trace_kprobe_event(ent->s, &group, &event, NULL); | 446 | parse_trace_kprobe_event(ent->s, &group, &event, NULL); |
| 420 | strlist__add(sl, event); | 447 | if (include_group) { |
| 448 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
| 449 | die("Failed to copy group:event name."); | ||
| 450 | strlist__add(sl, buf); | ||
| 451 | } else | ||
| 452 | strlist__add(sl, event); | ||
| 421 | free(group); | 453 | free(group); |
| 454 | free(event); | ||
| 422 | } | 455 | } |
| 423 | 456 | ||
| 424 | strlist__delete(rawlist); | 457 | strlist__delete(rawlist); |
| @@ -426,24 +459,30 @@ static struct strlist *get_perf_event_names(int fd) | |||
| 426 | return sl; | 459 | return sl; |
| 427 | } | 460 | } |
| 428 | 461 | ||
| 429 | static int write_trace_kprobe_event(int fd, const char *buf) | 462 | static void write_trace_kprobe_event(int fd, const char *buf) |
| 430 | { | 463 | { |
| 431 | int ret; | 464 | int ret; |
| 432 | 465 | ||
| 466 | pr_debug("Writing event: %s\n", buf); | ||
| 433 | ret = write(fd, buf, strlen(buf)); | 467 | ret = write(fd, buf, strlen(buf)); |
| 434 | if (ret <= 0) | 468 | if (ret <= 0) |
| 435 | die("Failed to create event."); | 469 | die("Failed to write event: %s", strerror(errno)); |
| 436 | else | ||
| 437 | printf("Added new event: %s\n", buf); | ||
| 438 | |||
| 439 | return ret; | ||
| 440 | } | 470 | } |
| 441 | 471 | ||
| 442 | static void get_new_event_name(char *buf, size_t len, const char *base, | 472 | static void get_new_event_name(char *buf, size_t len, const char *base, |
| 443 | struct strlist *namelist) | 473 | struct strlist *namelist) |
| 444 | { | 474 | { |
| 445 | int i, ret; | 475 | int i, ret; |
| 446 | for (i = 0; i < MAX_EVENT_INDEX; i++) { | 476 | |
| 477 | /* Try no suffix */ | ||
| 478 | ret = e_snprintf(buf, len, "%s", base); | ||
| 479 | if (ret < 0) | ||
| 480 | die("snprintf() failed: %s", strerror(-ret)); | ||
| 481 | if (!strlist__has_entry(namelist, buf)) | ||
| 482 | return; | ||
| 483 | |||
| 484 | /* Try to add suffix */ | ||
| 485 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | ||
| 447 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 486 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
| 448 | if (ret < 0) | 487 | if (ret < 0) |
| 449 | die("snprintf() failed: %s", strerror(-ret)); | 488 | die("snprintf() failed: %s", strerror(-ret)); |
| @@ -464,7 +503,7 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) | |||
| 464 | 503 | ||
| 465 | fd = open_kprobe_events(O_RDWR, O_APPEND); | 504 | fd = open_kprobe_events(O_RDWR, O_APPEND); |
| 466 | /* Get current event names */ | 505 | /* Get current event names */ |
| 467 | namelist = get_perf_event_names(fd); | 506 | namelist = get_perf_event_names(fd, false); |
| 468 | 507 | ||
| 469 | for (j = 0; j < nr_probes; j++) { | 508 | for (j = 0; j < nr_probes; j++) { |
| 470 | pp = probes + j; | 509 | pp = probes + j; |
| @@ -476,9 +515,73 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) | |||
| 476 | PERFPROBE_GROUP, event, | 515 | PERFPROBE_GROUP, event, |
| 477 | pp->probes[i]); | 516 | pp->probes[i]); |
| 478 | write_trace_kprobe_event(fd, buf); | 517 | write_trace_kprobe_event(fd, buf); |
| 518 | printf("Added new event:\n"); | ||
| 519 | /* Get the first parameter (probe-point) */ | ||
| 520 | sscanf(pp->probes[i], "%s", buf); | ||
| 521 | show_perf_probe_event(PERFPROBE_GROUP, event, | ||
| 522 | buf, pp); | ||
| 479 | /* Add added event name to namelist */ | 523 | /* Add added event name to namelist */ |
| 480 | strlist__add(namelist, event); | 524 | strlist__add(namelist, event); |
| 481 | } | 525 | } |
| 482 | } | 526 | } |
| 527 | /* Show how to use the event. */ | ||
| 528 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | ||
| 529 | printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); | ||
| 530 | |||
| 531 | strlist__delete(namelist); | ||
| 532 | close(fd); | ||
| 533 | } | ||
| 534 | |||
| 535 | static void del_trace_kprobe_event(int fd, const char *group, | ||
| 536 | const char *event, struct strlist *namelist) | ||
| 537 | { | ||
| 538 | char buf[128]; | ||
| 539 | |||
| 540 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
| 541 | die("Failed to copy event."); | ||
| 542 | if (!strlist__has_entry(namelist, buf)) { | ||
| 543 | pr_warning("Warning: event \"%s\" is not found.\n", buf); | ||
| 544 | return; | ||
| 545 | } | ||
| 546 | /* Convert from perf-probe event to trace-kprobe event */ | ||
| 547 | if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0) | ||
| 548 | die("Failed to copy event."); | ||
| 549 | |||
| 550 | write_trace_kprobe_event(fd, buf); | ||
| 551 | printf("Remove event: %s:%s\n", group, event); | ||
| 552 | } | ||
| 553 | |||
| 554 | void del_trace_kprobe_events(struct strlist *dellist) | ||
| 555 | { | ||
| 556 | int fd; | ||
| 557 | unsigned int i; | ||
| 558 | const char *group, *event; | ||
| 559 | char *p, *str; | ||
| 560 | struct str_node *ent; | ||
| 561 | struct strlist *namelist; | ||
| 562 | |||
| 563 | fd = open_kprobe_events(O_RDWR, O_APPEND); | ||
| 564 | /* Get current event names */ | ||
| 565 | namelist = get_perf_event_names(fd, true); | ||
| 566 | |||
| 567 | for (i = 0; i < strlist__nr_entries(dellist); i++) { | ||
| 568 | ent = strlist__entry(dellist, i); | ||
| 569 | str = strdup(ent->s); | ||
| 570 | if (!str) | ||
| 571 | die("Failed to copy event."); | ||
| 572 | p = strchr(str, ':'); | ||
| 573 | if (p) { | ||
| 574 | group = str; | ||
| 575 | *p = '\0'; | ||
| 576 | event = p + 1; | ||
| 577 | } else { | ||
| 578 | group = PERFPROBE_GROUP; | ||
| 579 | event = str; | ||
| 580 | } | ||
| 581 | del_trace_kprobe_event(fd, group, event, namelist); | ||
| 582 | free(str); | ||
| 583 | } | ||
| 584 | strlist__delete(namelist); | ||
| 483 | close(fd); | 585 | close(fd); |
| 484 | } | 586 | } |
| 587 | |||
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 0c6fe56fe38a..f752159124ae 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
| @@ -10,6 +10,7 @@ extern void parse_trace_kprobe_event(const char *str, char **group, | |||
| 10 | char **event, struct probe_point *pp); | 10 | char **event, struct probe_point *pp); |
| 11 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); | 11 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); |
| 12 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); | 12 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); |
| 13 | extern void del_trace_kprobe_events(struct strlist *dellist); | ||
| 13 | extern void show_perf_probe_events(void); | 14 | extern void show_perf_probe_events(void); |
| 14 | 15 | ||
| 15 | /* Maximum index number of event-name postfix */ | 16 | /* Maximum index number of event-name postfix */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 293cdfc1b8ca..4585f1d86792 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -106,7 +106,7 @@ static int strtailcmp(const char *s1, const char *s2) | |||
| 106 | { | 106 | { |
| 107 | int i1 = strlen(s1); | 107 | int i1 = strlen(s1); |
| 108 | int i2 = strlen(s2); | 108 | int i2 = strlen(s2); |
| 109 | while (--i1 > 0 && --i2 > 0) { | 109 | while (--i1 >= 0 && --i2 >= 0) { |
| 110 | if (s1[i1] != s2[i2]) | 110 | if (s1[i1] != s2[i2]) |
| 111 | return s1[i1] - s2[i2]; | 111 | return s1[i1] - s2[i2]; |
| 112 | } | 112 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index fffcb937cdcb..e7508ad3450f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -938,8 +938,9 @@ static bool __dsos__read_build_ids(struct list_head *head) | |||
| 938 | 938 | ||
| 939 | bool dsos__read_build_ids(void) | 939 | bool dsos__read_build_ids(void) |
| 940 | { | 940 | { |
| 941 | return __dsos__read_build_ids(&dsos__kernel) || | 941 | bool kbuildids = __dsos__read_build_ids(&dsos__kernel), |
| 942 | __dsos__read_build_ids(&dsos__user); | 942 | ubuildids = __dsos__read_build_ids(&dsos__user); |
| 943 | return kbuildids || ubuildids; | ||
| 943 | } | 944 | } |
| 944 | 945 | ||
| 945 | /* | 946 | /* |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0302405aa2ca..c5c32be040bf 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
| @@ -177,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused) | |||
| 177 | func_count++; | 177 | func_count++; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); | 180 | func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1)); |
| 181 | 181 | ||
| 182 | i = 0; | 182 | i = 0; |
| 183 | while (list) { | 183 | while (list) { |
| @@ -1477,7 +1477,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok) | |||
| 1477 | goto out_free; | 1477 | goto out_free; |
| 1478 | 1478 | ||
| 1479 | field = malloc_or_die(sizeof(*field)); | 1479 | field = malloc_or_die(sizeof(*field)); |
| 1480 | memset(field, 0, sizeof(field)); | 1480 | memset(field, 0, sizeof(*field)); |
| 1481 | 1481 | ||
| 1482 | value = arg_eval(arg); | 1482 | value = arg_eval(arg); |
| 1483 | field->value = strdup(value); | 1483 | field->value = strdup(value); |
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c index 51e833fd58c3..a5ffe60db5d6 100644 --- a/tools/perf/util/trace-event-perl.c +++ b/tools/perf/util/trace-event-perl.c | |||
| @@ -32,9 +32,6 @@ | |||
| 32 | 32 | ||
| 33 | void xs_init(pTHX); | 33 | void xs_init(pTHX); |
| 34 | 34 | ||
| 35 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | ||
| 36 | void boot_DynaLoader(pTHX_ CV *cv); | ||
| 37 | |||
| 38 | void xs_init(pTHX) | 35 | void xs_init(pTHX) |
| 39 | { | 36 | { |
| 40 | const char *file = __FILE__; | 37 | const char *file = __FILE__; |
| @@ -573,26 +570,72 @@ struct scripting_ops perl_scripting_ops = { | |||
| 573 | .generate_script = perl_generate_script, | 570 | .generate_script = perl_generate_script, |
| 574 | }; | 571 | }; |
| 575 | 572 | ||
| 576 | #ifdef NO_LIBPERL | 573 | static void print_unsupported_msg(void) |
| 577 | void setup_perl_scripting(void) | ||
| 578 | { | 574 | { |
| 579 | fprintf(stderr, "Perl scripting not supported." | 575 | fprintf(stderr, "Perl scripting not supported." |
| 580 | " Install libperl and rebuild perf to enable it. e.g. " | 576 | " Install libperl and rebuild perf to enable it.\n" |
| 581 | "apt-get install libperl-dev (ubuntu), yum install " | 577 | "For example:\n # apt-get install libperl-dev (ubuntu)" |
| 582 | "perl-ExtUtils-Embed (Fedora), etc.\n"); | 578 | "\n # yum install perl-ExtUtils-Embed (Fedora)" |
| 579 | "\n etc.\n"); | ||
| 583 | } | 580 | } |
| 584 | #else | 581 | |
| 585 | void setup_perl_scripting(void) | 582 | static int perl_start_script_unsupported(const char *script __unused) |
| 583 | { | ||
| 584 | print_unsupported_msg(); | ||
| 585 | |||
| 586 | return -1; | ||
| 587 | } | ||
| 588 | |||
| 589 | static int perl_stop_script_unsupported(void) | ||
| 590 | { | ||
| 591 | return 0; | ||
| 592 | } | ||
| 593 | |||
| 594 | static void perl_process_event_unsupported(int cpu __unused, | ||
| 595 | void *data __unused, | ||
| 596 | int size __unused, | ||
| 597 | unsigned long long nsecs __unused, | ||
| 598 | char *comm __unused) | ||
| 599 | { | ||
| 600 | } | ||
| 601 | |||
| 602 | static int perl_generate_script_unsupported(const char *outfile __unused) | ||
| 603 | { | ||
| 604 | print_unsupported_msg(); | ||
| 605 | |||
| 606 | return -1; | ||
| 607 | } | ||
| 608 | |||
| 609 | struct scripting_ops perl_scripting_unsupported_ops = { | ||
| 610 | .name = "Perl", | ||
| 611 | .start_script = perl_start_script_unsupported, | ||
| 612 | .stop_script = perl_stop_script_unsupported, | ||
| 613 | .process_event = perl_process_event_unsupported, | ||
| 614 | .generate_script = perl_generate_script_unsupported, | ||
| 615 | }; | ||
| 616 | |||
| 617 | static void register_perl_scripting(struct scripting_ops *scripting_ops) | ||
| 586 | { | 618 | { |
| 587 | int err; | 619 | int err; |
| 588 | err = script_spec_register("Perl", &perl_scripting_ops); | 620 | err = script_spec_register("Perl", scripting_ops); |
| 589 | if (err) | 621 | if (err) |
| 590 | die("error registering Perl script extension"); | 622 | die("error registering Perl script extension"); |
| 591 | 623 | ||
| 592 | err = script_spec_register("pl", &perl_scripting_ops); | 624 | err = script_spec_register("pl", scripting_ops); |
| 593 | if (err) | 625 | if (err) |
| 594 | die("error registering pl script extension"); | 626 | die("error registering pl script extension"); |
| 595 | 627 | ||
| 596 | scripting_context = malloc(sizeof(struct scripting_context)); | 628 | scripting_context = malloc(sizeof(struct scripting_context)); |
| 597 | } | 629 | } |
| 630 | |||
| 631 | #ifdef NO_LIBPERL | ||
| 632 | void setup_perl_scripting(void) | ||
| 633 | { | ||
| 634 | register_perl_scripting(&perl_scripting_unsupported_ops); | ||
| 635 | } | ||
| 636 | #else | ||
| 637 | void setup_perl_scripting(void) | ||
| 638 | { | ||
| 639 | register_perl_scripting(&perl_scripting_ops); | ||
| 640 | } | ||
| 598 | #endif | 641 | #endif |
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h index 8fe0d866fe1a..e88fb26137bb 100644 --- a/tools/perf/util/trace-event-perl.h +++ b/tools/perf/util/trace-event-perl.h | |||
| @@ -34,9 +34,13 @@ typedef int INTERP; | |||
| 34 | #define dXSUB_SYS | 34 | #define dXSUB_SYS |
| 35 | #define pTHX_ | 35 | #define pTHX_ |
| 36 | static inline void newXS(const char *a, void *b, const char *c) {} | 36 | static inline void newXS(const char *a, void *b, const char *c) {} |
| 37 | static void boot_Perf__Trace__Context(pTHX_ CV *cv) {} | ||
| 38 | static void boot_DynaLoader(pTHX_ CV *cv) {} | ||
| 37 | #else | 39 | #else |
| 38 | #include <EXTERN.h> | 40 | #include <EXTERN.h> |
| 39 | #include <perl.h> | 41 | #include <perl.h> |
| 42 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | ||
| 43 | void boot_DynaLoader(pTHX_ CV *cv); | ||
| 40 | typedef PerlInterpreter * INTERP; | 44 | typedef PerlInterpreter * INTERP; |
| 41 | #endif | 45 | #endif |
| 42 | 46 | ||
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 342dfdd43f87..1744422cafcb 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
| @@ -145,8 +145,9 @@ static void read_proc_kallsyms(void) | |||
| 145 | if (!size) | 145 | if (!size) |
| 146 | return; | 146 | return; |
| 147 | 147 | ||
| 148 | buf = malloc_or_die(size); | 148 | buf = malloc_or_die(size + 1); |
| 149 | read_or_die(buf, size); | 149 | read_or_die(buf, size); |
| 150 | buf[size] = '\0'; | ||
| 150 | 151 | ||
| 151 | parse_proc_kallsyms(buf, size); | 152 | parse_proc_kallsyms(buf, size); |
| 152 | 153 | ||
