diff options
Diffstat (limited to 'tools')
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 | ||