aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-08-31 04:05:48 -0400
committerIngo Molnar <mingo@kernel.org>2013-08-31 04:05:48 -0400
commitea79ca0de05198159bcb8a45479122a75e4a5861 (patch)
tree0288b2e20a404a96e4727b0c4590e97a58baac21 /tools
parent00e4cb1ced1b17c35465defafe86d156cbd7544e (diff)
parentf2935f3e585226b8203ec3861907e1cb16ad3d6a (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: * Tidy up sample parsing validation, from Adrian Hunter. * Make events stream always parsable by adding a new sample_type bit: PERF_SAMPLE_IDENTIFIER, that when requested will be always aat a fixed position in all PERF_RECORD_ records, from Adrian Hunter. * Add a sample parsing test, from Adrian Hunter. * Add option to 'perf trace' to analyze events in a file versus live, so that one can do: [root@zoo ~]# perf record -a -e raw_syscalls:* sleep 1 [ perf record: Woken up 0 times to write data ] [ perf record: Captured and wrote 25.150 MB perf.data (~1098836 samples) ] [root@zoo ~]# perf trace -i perf.data -e futex --duration 1 17.799 ( 1.020 ms): 7127 futex(uaddr: 0x7fff3f6c6674, op: 393, val: 1, utime: 0x7fff3f6c6470, ua 113.344 (95.429 ms): 7127 futex(uaddr: 0x7fff3f6c6674, op: 393, val: 1, utime: 0x7fff3f6c6470, uaddr2: 0x7fff3f6c6648, val3: 4294967 133.778 ( 1.042 ms): 18004 futex(uaddr: 0x7fff3f6c6674, op: 393, val: 1, utime: 0x7fff3f6c6470, uaddr2: 0x7fff3f6c6648, val3: 429496 [root@zoo ~]# From David Ahern. * Honor target pid / tid options in 'perf trace' when analyzing a file, from David Ahern. * Handle missing HUGEPAGE defines in the mmap beautifier in 'perf trace', from David Ahern. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-trace.txt4
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/builtin-inject.c8
-rw-r--r--tools/perf/builtin-kmem.c3
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-lock.c3
-rw-r--r--tools/perf/builtin-mem.c2
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/builtin-sched.c20
-rw-r--r--tools/perf/builtin-script.c3
-rw-r--r--tools/perf/builtin-top.c11
-rw-r--r--tools/perf/builtin-trace.c157
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/code-reading.c4
-rw-r--r--tools/perf/tests/hists_link.c23
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/tests/sample-parsing.c316
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/util/build-id.c11
-rw-r--r--tools/perf/util/callchain.c8
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h18
-rw-r--r--tools/perf/util/evlist.c140
-rw-r--r--tools/perf/util/evlist.h12
-rw-r--r--tools/perf/util/evsel.c405
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/machine.c22
-rw-r--r--tools/perf/util/machine.h3
-rw-r--r--tools/perf/util/record.c108
-rw-r--r--tools/perf/util/session.c32
31 files changed, 1163 insertions, 187 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index fe19811faf90..daccd2c0a48f 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -74,6 +74,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
74--sched: 74--sched:
75 Accrue thread runtime and provide a summary at the end of the session. 75 Accrue thread runtime and provide a summary at the end of the session.
76 76
77-i
78--input
79 Process events from a given perf data file.
80
77SEE ALSO 81SEE ALSO
78-------- 82--------
79linkperf:perf-record[1], linkperf:perf-script[1] 83linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7d30a7ddcc88..ecebfd00295e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -360,6 +360,7 @@ LIB_OBJS += $(OUTPUT)util/rblist.o
360LIB_OBJS += $(OUTPUT)util/intlist.o 360LIB_OBJS += $(OUTPUT)util/intlist.o
361LIB_OBJS += $(OUTPUT)util/vdso.o 361LIB_OBJS += $(OUTPUT)util/vdso.o
362LIB_OBJS += $(OUTPUT)util/stat.o 362LIB_OBJS += $(OUTPUT)util/stat.o
363LIB_OBJS += $(OUTPUT)util/record.o
363 364
364LIB_OBJS += $(OUTPUT)ui/setup.o 365LIB_OBJS += $(OUTPUT)ui/setup.o
365LIB_OBJS += $(OUTPUT)ui/helpline.o 366LIB_OBJS += $(OUTPUT)ui/helpline.o
@@ -438,6 +439,7 @@ PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
438ifneq ($(OUTPUT),) 439ifneq ($(OUTPUT),)
439 CFLAGS += -I$(OUTPUT) 440 CFLAGS += -I$(OUTPUT)
440endif 441endif
442LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
441 443
442ifdef NO_LIBELF 444ifdef NO_LIBELF
443EXTLIBS := $(filter-out -lelf,$(EXTLIBS)) 445EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 1d8de2e4a407..9b336fdb6f71 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -198,7 +198,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
198 198
199 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 199 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
200 200
201 thread = machine__findnew_thread(machine, event->ip.pid); 201 thread = machine__findnew_thread(machine, sample->pid, sample->pid);
202 if (thread == NULL) { 202 if (thread == NULL) {
203 pr_err("problem processing %d event, skipping it.\n", 203 pr_err("problem processing %d event, skipping it.\n",
204 event->header.type); 204 event->header.type);
@@ -206,7 +206,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
206 } 206 }
207 207
208 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 208 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
209 event->ip.ip, &al); 209 sample->ip, &al);
210 210
211 if (al.map != NULL) { 211 if (al.map != NULL) {
212 if (!al.map->dso->hit) { 212 if (!al.map->dso->hit) {
@@ -301,7 +301,9 @@ found:
301 sample_sw.period = sample->period; 301 sample_sw.period = sample->period;
302 sample_sw.time = sample->time; 302 sample_sw.time = sample->time;
303 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, 303 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
304 &sample_sw, false); 304 evsel->attr.sample_regs_user,
305 evsel->attr.read_format, &sample_sw,
306 false);
305 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); 307 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
306 return perf_event__repipe(tool, event_sw, &sample_sw, machine); 308 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
307} 309}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index b49f5c58e152..c2dff9cb1f2c 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -305,7 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
305 struct perf_evsel *evsel, 305 struct perf_evsel *evsel,
306 struct machine *machine) 306 struct machine *machine)
307{ 307{
308 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 308 struct thread *thread = machine__findnew_thread(machine, sample->pid,
309 sample->pid);
309 310
310 if (thread == NULL) { 311 if (thread == NULL) {
311 pr_debug("problem processing %d event, skipping it.\n", 312 pr_debug("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 6cd4de59be21..47b35407c2f2 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -815,7 +815,7 @@ static int process_sample_event(struct perf_tool *tool,
815 if (skip_sample(kvm, sample)) 815 if (skip_sample(kvm, sample))
816 return 0; 816 return 0;
817 817
818 thread = machine__findnew_thread(machine, sample->tid); 818 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
819 if (thread == NULL) { 819 if (thread == NULL) {
820 pr_debug("problem processing %d event, skipping it.\n", 820 pr_debug("problem processing %d event, skipping it.\n",
821 event->header.type); 821 event->header.type);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 76543a4a7a30..ee33ba2f05dd 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -805,7 +805,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
805 struct perf_evsel *evsel, 805 struct perf_evsel *evsel,
806 struct machine *machine) 806 struct machine *machine)
807{ 807{
808 struct thread *thread = machine__findnew_thread(machine, sample->tid); 808 struct thread *thread = machine__findnew_thread(machine, sample->pid,
809 sample->tid);
809 810
810 if (thread == NULL) { 811 if (thread == NULL) {
811 pr_debug("problem processing %d event, skipping it.\n", 812 pr_debug("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 706a1faa9559..791b432df847 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -94,7 +94,7 @@ dump_raw_samples(struct perf_tool *tool,
94 symbol_conf.field_sep, 94 symbol_conf.field_sep,
95 sample->tid, 95 sample->tid,
96 symbol_conf.field_sep, 96 symbol_conf.field_sep,
97 event->ip.ip, 97 sample->ip,
98 symbol_conf.field_sep, 98 symbol_conf.field_sep,
99 sample->addr, 99 sample->addr,
100 symbol_conf.field_sep, 100 symbol_conf.field_sep,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 958a56a0e39e..9725aa375414 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -365,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,
365static int perf_report__setup_sample_type(struct perf_report *rep) 365static int perf_report__setup_sample_type(struct perf_report *rep)
366{ 366{
367 struct perf_session *self = rep->session; 367 struct perf_session *self = rep->session;
368 u64 sample_type = perf_evlist__sample_type(self->evlist); 368 u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
369 369
370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
371 if (sort__has_parent) { 371 if (sort__has_parent) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index f809cc7fb7d9..d8c51b2f263f 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -724,8 +724,10 @@ static int replay_fork_event(struct perf_sched *sched,
724{ 724{
725 struct thread *child, *parent; 725 struct thread *child, *parent;
726 726
727 child = machine__findnew_thread(machine, event->fork.tid); 727 child = machine__findnew_thread(machine, event->fork.pid,
728 parent = machine__findnew_thread(machine, event->fork.ptid); 728 event->fork.tid);
729 parent = machine__findnew_thread(machine, event->fork.ppid,
730 event->fork.ptid);
729 731
730 if (child == NULL || parent == NULL) { 732 if (child == NULL || parent == NULL) {
731 pr_debug("thread does not exist on fork event: child %p, parent %p\n", 733 pr_debug("thread does not exist on fork event: child %p, parent %p\n",
@@ -934,8 +936,8 @@ static int latency_switch_event(struct perf_sched *sched,
934 return -1; 936 return -1;
935 } 937 }
936 938
937 sched_out = machine__findnew_thread(machine, prev_pid); 939 sched_out = machine__findnew_thread(machine, 0, prev_pid);
938 sched_in = machine__findnew_thread(machine, next_pid); 940 sched_in = machine__findnew_thread(machine, 0, next_pid);
939 941
940 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 942 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
941 if (!out_events) { 943 if (!out_events) {
@@ -978,7 +980,7 @@ static int latency_runtime_event(struct perf_sched *sched,
978{ 980{
979 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 981 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
980 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 982 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
981 struct thread *thread = machine__findnew_thread(machine, pid); 983 struct thread *thread = machine__findnew_thread(machine, 0, pid);
982 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 984 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
983 u64 timestamp = sample->time; 985 u64 timestamp = sample->time;
984 int cpu = sample->cpu; 986 int cpu = sample->cpu;
@@ -1016,7 +1018,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
1016 if (!success) 1018 if (!success)
1017 return 0; 1019 return 0;
1018 1020
1019 wakee = machine__findnew_thread(machine, pid); 1021 wakee = machine__findnew_thread(machine, 0, pid);
1020 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1022 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1021 if (!atoms) { 1023 if (!atoms) {
1022 if (thread_atoms_insert(sched, wakee)) 1024 if (thread_atoms_insert(sched, wakee))
@@ -1070,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1070 if (sched->profile_cpu == -1) 1072 if (sched->profile_cpu == -1)
1071 return 0; 1073 return 0;
1072 1074
1073 migrant = machine__findnew_thread(machine, pid); 1075 migrant = machine__findnew_thread(machine, 0, pid);
1074 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1076 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1075 if (!atoms) { 1077 if (!atoms) {
1076 if (thread_atoms_insert(sched, migrant)) 1078 if (thread_atoms_insert(sched, migrant))
@@ -1289,8 +1291,8 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1289 return -1; 1291 return -1;
1290 } 1292 }
1291 1293
1292 sched_out = machine__findnew_thread(machine, prev_pid); 1294 sched_out = machine__findnew_thread(machine, 0, prev_pid);
1293 sched_in = machine__findnew_thread(machine, next_pid); 1295 sched_in = machine__findnew_thread(machine, 0, next_pid);
1294 1296
1295 sched->curr_thread[this_cpu] = sched_in; 1297 sched->curr_thread[this_cpu] = sched_in;
1296 1298
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 2ad9d5b6fb3c..93a34cef9676 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -501,7 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
501 struct machine *machine) 501 struct machine *machine)
502{ 502{
503 struct addr_location al; 503 struct addr_location al;
504 struct thread *thread = machine__findnew_thread(machine, event->ip.tid); 504 struct thread *thread = machine__findnew_thread(machine, sample->pid,
505 sample->tid);
505 506
506 if (thread == NULL) { 507 if (thread == NULL) {
507 pr_debug("problem processing %d event, skipping it.\n", 508 pr_debug("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e37521fc715a..212214162bb2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -689,7 +689,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
689{ 689{
690 struct perf_top *top = container_of(tool, struct perf_top, tool); 690 struct perf_top *top = container_of(tool, struct perf_top, tool);
691 struct symbol *parent = NULL; 691 struct symbol *parent = NULL;
692 u64 ip = event->ip.ip; 692 u64 ip = sample->ip;
693 struct addr_location al; 693 struct addr_location al;
694 int err; 694 int err;
695 695
@@ -699,10 +699,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
699 if (!seen) 699 if (!seen)
700 seen = intlist__new(NULL); 700 seen = intlist__new(NULL);
701 701
702 if (!intlist__has_entry(seen, event->ip.pid)) { 702 if (!intlist__has_entry(seen, sample->pid)) {
703 pr_err("Can't find guest [%d]'s kernel information\n", 703 pr_err("Can't find guest [%d]'s kernel information\n",
704 event->ip.pid); 704 sample->pid);
705 intlist__add(seen, event->ip.pid); 705 intlist__add(seen, sample->pid);
706 } 706 }
707 return; 707 return;
708 } 708 }
@@ -836,7 +836,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
836 break; 836 break;
837 case PERF_RECORD_MISC_GUEST_KERNEL: 837 case PERF_RECORD_MISC_GUEST_KERNEL:
838 ++top->guest_kernel_samples; 838 ++top->guest_kernel_samples;
839 machine = perf_session__find_machine(session, event->ip.pid); 839 machine = perf_session__find_machine(session,
840 sample.pid);
840 break; 841 break;
841 case PERF_RECORD_MISC_GUEST_USER: 842 case PERF_RECORD_MISC_GUEST_USER:
842 ++top->guest_us_samples; 843 ++top->guest_us_samples;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index b72afc73f9a7..69a065e51135 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -4,9 +4,11 @@
4#include "util/debug.h" 4#include "util/debug.h"
5#include "util/evlist.h" 5#include "util/evlist.h"
6#include "util/machine.h" 6#include "util/machine.h"
7#include "util/session.h"
7#include "util/thread.h" 8#include "util/thread.h"
8#include "util/parse-options.h" 9#include "util/parse-options.h"
9#include "util/strlist.h" 10#include "util/strlist.h"
11#include "util/intlist.h"
10#include "util/thread_map.h" 12#include "util/thread_map.h"
11 13
12#include <libaudit.h> 14#include <libaudit.h>
@@ -69,7 +71,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, unsigned
69 P_MMAP_FLAG(FILE); 71 P_MMAP_FLAG(FILE);
70 P_MMAP_FLAG(FIXED); 72 P_MMAP_FLAG(FIXED);
71 P_MMAP_FLAG(GROWSDOWN); 73 P_MMAP_FLAG(GROWSDOWN);
74#ifdef MAP_HUGETLB
72 P_MMAP_FLAG(HUGETLB); 75 P_MMAP_FLAG(HUGETLB);
76#endif
73 P_MMAP_FLAG(LOCKED); 77 P_MMAP_FLAG(LOCKED);
74 P_MMAP_FLAG(NONBLOCK); 78 P_MMAP_FLAG(NONBLOCK);
75 P_MMAP_FLAG(NORESERVE); 79 P_MMAP_FLAG(NORESERVE);
@@ -108,8 +112,12 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, uns
108#endif 112#endif
109 P_MADV_BHV(MERGEABLE); 113 P_MADV_BHV(MERGEABLE);
110 P_MADV_BHV(UNMERGEABLE); 114 P_MADV_BHV(UNMERGEABLE);
115#ifdef MADV_HUGEPAGE
111 P_MADV_BHV(HUGEPAGE); 116 P_MADV_BHV(HUGEPAGE);
117#endif
118#ifdef MADV_NOHUGEPAGE
112 P_MADV_BHV(NOHUGEPAGE); 119 P_MADV_BHV(NOHUGEPAGE);
120#endif
113#ifdef MADV_DONTDUMP 121#ifdef MADV_DONTDUMP
114 P_MADV_BHV(DONTDUMP); 122 P_MADV_BHV(DONTDUMP);
115#endif 123#endif
@@ -258,6 +266,8 @@ struct trace {
258 unsigned long nr_events; 266 unsigned long nr_events;
259 struct strlist *ev_qualifier; 267 struct strlist *ev_qualifier;
260 bool not_ev_qualifier; 268 bool not_ev_qualifier;
269 struct intlist *tid_list;
270 struct intlist *pid_list;
261 bool sched; 271 bool sched;
262 bool multiple_threads; 272 bool multiple_threads;
263 double duration_filter; 273 double duration_filter;
@@ -521,7 +531,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
521 if (sc->filtered) 531 if (sc->filtered)
522 return 0; 532 return 0;
523 533
524 thread = machine__findnew_thread(&trace->host, sample->tid); 534 thread = machine__findnew_thread(&trace->host, sample->pid,
535 sample->tid);
525 ttrace = thread__trace(thread, trace->output); 536 ttrace = thread__trace(thread, trace->output);
526 if (ttrace == NULL) 537 if (ttrace == NULL)
527 return -1; 538 return -1;
@@ -572,7 +583,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
572 if (sc->filtered) 583 if (sc->filtered)
573 return 0; 584 return 0;
574 585
575 thread = machine__findnew_thread(&trace->host, sample->tid); 586 thread = machine__findnew_thread(&trace->host, sample->pid,
587 sample->tid);
576 ttrace = thread__trace(thread, trace->output); 588 ttrace = thread__trace(thread, trace->output);
577 if (ttrace == NULL) 589 if (ttrace == NULL)
578 return -1; 590 return -1;
@@ -628,7 +640,9 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
628{ 640{
629 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 641 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
630 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 642 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
631 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 643 struct thread *thread = machine__findnew_thread(&trace->host,
644 sample->pid,
645 sample->tid);
632 struct thread_trace *ttrace = thread__trace(thread, trace->output); 646 struct thread_trace *ttrace = thread__trace(thread, trace->output);
633 647
634 if (ttrace == NULL) 648 if (ttrace == NULL)
@@ -648,6 +662,72 @@ out_dump:
648 return 0; 662 return 0;
649} 663}
650 664
665static bool skip_sample(struct trace *trace, struct perf_sample *sample)
666{
667 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
668 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
669 return false;
670
671 if (trace->pid_list || trace->tid_list)
672 return true;
673
674 return false;
675}
676
677static int trace__process_sample(struct perf_tool *tool,
678 union perf_event *event __maybe_unused,
679 struct perf_sample *sample,
680 struct perf_evsel *evsel,
681 struct machine *machine __maybe_unused)
682{
683 struct trace *trace = container_of(tool, struct trace, tool);
684 int err = 0;
685
686 tracepoint_handler handler = evsel->handler.func;
687
688 if (skip_sample(trace, sample))
689 return 0;
690
691 if (trace->base_time == 0)
692 trace->base_time = sample->time;
693
694 if (handler)
695 handler(trace, evsel, sample);
696
697 return err;
698}
699
700static bool
701perf_session__has_tp(struct perf_session *session, const char *name)
702{
703 struct perf_evsel *evsel;
704
705 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
706
707 return evsel != NULL;
708}
709
710static int parse_target_str(struct trace *trace)
711{
712 if (trace->opts.target.pid) {
713 trace->pid_list = intlist__new(trace->opts.target.pid);
714 if (trace->pid_list == NULL) {
715 pr_err("Error parsing process id string\n");
716 return -EINVAL;
717 }
718 }
719
720 if (trace->opts.target.tid) {
721 trace->tid_list = intlist__new(trace->opts.target.tid);
722 if (trace->tid_list == NULL) {
723 pr_err("Error parsing thread id string\n");
724 return -EINVAL;
725 }
726 }
727
728 return 0;
729}
730
651static int trace__run(struct trace *trace, int argc, const char **argv) 731static int trace__run(struct trace *trace, int argc, const char **argv)
652{ 732{
653 struct perf_evlist *evlist = perf_evlist__new(); 733 struct perf_evlist *evlist = perf_evlist__new();
@@ -787,6 +867,69 @@ out:
787 return err; 867 return err;
788} 868}
789 869
870static int trace__replay(struct trace *trace)
871{
872 const struct perf_evsel_str_handler handlers[] = {
873 { "raw_syscalls:sys_enter", trace__sys_enter, },
874 { "raw_syscalls:sys_exit", trace__sys_exit, },
875 };
876
877 struct perf_session *session;
878 int err = -1;
879
880 trace->tool.sample = trace__process_sample;
881 trace->tool.mmap = perf_event__process_mmap;
882 trace->tool.comm = perf_event__process_comm;
883 trace->tool.exit = perf_event__process_exit;
884 trace->tool.fork = perf_event__process_fork;
885 trace->tool.attr = perf_event__process_attr;
886 trace->tool.tracing_data = perf_event__process_tracing_data;
887 trace->tool.build_id = perf_event__process_build_id;
888
889 trace->tool.ordered_samples = true;
890 trace->tool.ordering_requires_timestamps = true;
891
892 /* add tid to output */
893 trace->multiple_threads = true;
894
895 if (symbol__init() < 0)
896 return -1;
897
898 session = perf_session__new(input_name, O_RDONLY, 0, false,
899 &trace->tool);
900 if (session == NULL)
901 return -ENOMEM;
902
903 err = perf_session__set_tracepoints_handlers(session, handlers);
904 if (err)
905 goto out;
906
907 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
908 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
909 goto out;
910 }
911
912 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
913 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
914 goto out;
915 }
916
917 err = parse_target_str(trace);
918 if (err != 0)
919 goto out;
920
921 setup_pager();
922
923 err = perf_session__process_events(session, &trace->tool);
924 if (err)
925 pr_err("Failed to process events, error %d", err);
926
927out:
928 perf_session__delete(session);
929
930 return err;
931}
932
790static size_t trace__fprintf_threads_header(FILE *fp) 933static size_t trace__fprintf_threads_header(FILE *fp)
791{ 934{
792 size_t printed; 935 size_t printed;
@@ -888,6 +1031,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
888 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 1031 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
889 "list of events to trace"), 1032 "list of events to trace"),
890 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1033 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1034 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
891 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", 1035 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
892 "trace events on existing process id"), 1036 "trace events on existing process id"),
893 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", 1037 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
@@ -896,7 +1040,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
896 "system-wide collection from all CPUs"), 1040 "system-wide collection from all CPUs"),
897 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", 1041 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
898 "list of cpus to monitor"), 1042 "list of cpus to monitor"),
899 OPT_BOOLEAN('i', "no-inherit", &trace.opts.no_inherit, 1043 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
900 "child tasks do not inherit counters"), 1044 "child tasks do not inherit counters"),
901 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, 1045 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
902 "number of mmap data pages"), 1046 "number of mmap data pages"),
@@ -954,7 +1098,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
954 if (!argc && perf_target__none(&trace.opts.target)) 1098 if (!argc && perf_target__none(&trace.opts.target))
955 trace.opts.target.system_wide = true; 1099 trace.opts.target.system_wide = true;
956 1100
957 err = trace__run(&trace, argc, argv); 1101 if (input_name)
1102 err = trace__replay(&trace);
1103 else
1104 err = trace__run(&trace, argc, argv);
958 1105
959 if (trace.sched && !err) 1106 if (trace.sched && !err)
960 trace__fprintf_thread_summary(&trace, trace.output); 1107 trace__fprintf_thread_summary(&trace, trace.output);
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index f5af19244a05..8ad9415dd847 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -104,6 +104,10 @@ static struct test {
104 .func = test__code_reading, 104 .func = test__code_reading,
105 }, 105 },
106 { 106 {
107 .desc = "Test sample parsing",
108 .func = test__sample_parsing,
109 },
110 {
107 .func = NULL, 111 .func = NULL,
108 }, 112 },
109}; 113};
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index df9afd9cab4c..6fb781d5586c 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -257,7 +257,7 @@ static int process_sample_event(struct machine *machine,
257 return -1; 257 return -1;
258 } 258 }
259 259
260 thread = machine__findnew_thread(machine, sample.pid); 260 thread = machine__findnew_thread(machine, sample.pid, sample.pid);
261 if (!thread) { 261 if (!thread) {
262 pr_debug("machine__findnew_thread failed\n"); 262 pr_debug("machine__findnew_thread failed\n");
263 return -1; 263 return -1;
@@ -446,7 +446,7 @@ static int do_test_code_reading(bool try_kcore)
446 goto out_err; 446 goto out_err;
447 } 447 }
448 448
449 thread = machine__findnew_thread(machine, pid); 449 thread = machine__findnew_thread(machine, pid, pid);
450 if (!thread) { 450 if (!thread) {
451 pr_debug("machine__findnew_thread failed\n"); 451 pr_debug("machine__findnew_thread failed\n");
452 goto out_err; 452 goto out_err;
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 50bfb01183ea..4228ffc0d968 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -88,7 +88,8 @@ static struct machine *setup_fake_machine(struct machines *machines)
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { 88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread; 89 struct thread *thread;
90 90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid); 91 thread = machine__findnew_thread(machine, fake_threads[i].pid,
92 fake_threads[i].pid);
92 if (thread == NULL) 93 if (thread == NULL)
93 goto out; 94 goto out;
94 95
@@ -210,15 +211,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
210 list_for_each_entry(evsel, &evlist->entries, node) { 211 list_for_each_entry(evsel, &evlist->entries, node) {
211 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
212 const union perf_event event = { 213 const union perf_event event = {
213 .ip = { 214 .header = {
214 .header = { 215 .misc = PERF_RECORD_MISC_USER,
215 .misc = PERF_RECORD_MISC_USER,
216 },
217 .pid = fake_common_samples[k].pid,
218 .ip = fake_common_samples[k].ip,
219 }, 216 },
220 }; 217 };
221 218
219 sample.pid = fake_common_samples[k].pid;
220 sample.ip = fake_common_samples[k].ip;
222 if (perf_event__preprocess_sample(&event, machine, &al, 221 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample) < 0) 222 &sample) < 0)
224 goto out; 223 goto out;
@@ -234,15 +233,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
234 233
235 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { 234 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
236 const union perf_event event = { 235 const union perf_event event = {
237 .ip = { 236 .header = {
238 .header = { 237 .misc = PERF_RECORD_MISC_USER,
239 .misc = PERF_RECORD_MISC_USER,
240 },
241 .pid = fake_samples[i][k].pid,
242 .ip = fake_samples[i][k].ip,
243 }, 238 },
244 }; 239 };
245 240
241 sample.pid = fake_samples[i][k].pid;
242 sample.ip = fake_samples[i][k].ip;
246 if (perf_event__preprocess_sample(&event, machine, &al, 243 if (perf_event__preprocess_sample(&event, machine, &al,
247 &sample) < 0) 244 &sample) < 0)
248 goto out; 245 goto out;
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 5b1b5aba722b..c4185b9aeb80 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -72,7 +72,7 @@ int test__basic_mmap(void)
72 } 72 }
73 73
74 evsels[i]->attr.wakeup_events = 1; 74 evsels[i]->attr.wakeup_events = 1;
75 perf_evsel__set_sample_id(evsels[i]); 75 perf_evsel__set_sample_id(evsels[i], false);
76 76
77 perf_evlist__add(evlist, evsels[i]); 77 perf_evlist__add(evlist, evsels[i]);
78 78
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
new file mode 100644
index 000000000000..77f598dbd97a
--- /dev/null
+++ b/tools/perf/tests/sample-parsing.c
@@ -0,0 +1,316 @@
1#include <stdbool.h>
2#include <inttypes.h>
3
4#include "util.h"
5#include "event.h"
6#include "evsel.h"
7
8#include "tests.h"
9
10#define COMP(m) do { \
11 if (s1->m != s2->m) { \
12 pr_debug("Samples differ at '"#m"'\n"); \
13 return false; \
14 } \
15} while (0)
16
17#define MCOMP(m) do { \
18 if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) { \
19 pr_debug("Samples differ at '"#m"'\n"); \
20 return false; \
21 } \
22} while (0)
23
24static bool samples_same(const struct perf_sample *s1,
25 const struct perf_sample *s2, u64 type, u64 regs_user,
26 u64 read_format)
27{
28 size_t i;
29
30 if (type & PERF_SAMPLE_IDENTIFIER)
31 COMP(id);
32
33 if (type & PERF_SAMPLE_IP)
34 COMP(ip);
35
36 if (type & PERF_SAMPLE_TID) {
37 COMP(pid);
38 COMP(tid);
39 }
40
41 if (type & PERF_SAMPLE_TIME)
42 COMP(time);
43
44 if (type & PERF_SAMPLE_ADDR)
45 COMP(addr);
46
47 if (type & PERF_SAMPLE_ID)
48 COMP(id);
49
50 if (type & PERF_SAMPLE_STREAM_ID)
51 COMP(stream_id);
52
53 if (type & PERF_SAMPLE_CPU)
54 COMP(cpu);
55
56 if (type & PERF_SAMPLE_PERIOD)
57 COMP(period);
58
59 if (type & PERF_SAMPLE_READ) {
60 if (read_format & PERF_FORMAT_GROUP)
61 COMP(read.group.nr);
62 else
63 COMP(read.one.value);
64 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
65 COMP(read.time_enabled);
66 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
67 COMP(read.time_running);
68 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
69 if (read_format & PERF_FORMAT_GROUP) {
70 for (i = 0; i < s1->read.group.nr; i++)
71 MCOMP(read.group.values[i]);
72 } else {
73 COMP(read.one.id);
74 }
75 }
76
77 if (type & PERF_SAMPLE_CALLCHAIN) {
78 COMP(callchain->nr);
79 for (i = 0; i < s1->callchain->nr; i++)
80 COMP(callchain->ips[i]);
81 }
82
83 if (type & PERF_SAMPLE_RAW) {
84 COMP(raw_size);
85 if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
86 pr_debug("Samples differ at 'raw_data'\n");
87 return false;
88 }
89 }
90
91 if (type & PERF_SAMPLE_BRANCH_STACK) {
92 COMP(branch_stack->nr);
93 for (i = 0; i < s1->branch_stack->nr; i++)
94 MCOMP(branch_stack->entries[i]);
95 }
96
97 if (type & PERF_SAMPLE_REGS_USER) {
98 size_t sz = hweight_long(regs_user) * sizeof(u64);
99
100 COMP(user_regs.abi);
101 if (s1->user_regs.abi &&
102 (!s1->user_regs.regs || !s2->user_regs.regs ||
103 memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
104 pr_debug("Samples differ at 'user_regs'\n");
105 return false;
106 }
107 }
108
109 if (type & PERF_SAMPLE_STACK_USER) {
110 COMP(user_stack.size);
111 if (memcmp(s1->user_stack.data, s1->user_stack.data,
112 s1->user_stack.size)) {
113 pr_debug("Samples differ at 'user_stack'\n");
114 return false;
115 }
116 }
117
118 if (type & PERF_SAMPLE_WEIGHT)
119 COMP(weight);
120
121 if (type & PERF_SAMPLE_DATA_SRC)
122 COMP(data_src);
123
124 return true;
125}
126
127static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
128{
129 struct perf_evsel evsel = {
130 .needs_swap = false,
131 .attr = {
132 .sample_type = sample_type,
133 .sample_regs_user = sample_regs_user,
134 .read_format = read_format,
135 },
136 };
137 union perf_event *event;
138 union {
139 struct ip_callchain callchain;
140 u64 data[64];
141 } callchain = {
142 /* 3 ips */
143 .data = {3, 201, 202, 203},
144 };
145 union {
146 struct branch_stack branch_stack;
147 u64 data[64];
148 } branch_stack = {
149 /* 1 branch_entry */
150 .data = {1, 211, 212, 213},
151 };
152 u64 user_regs[64];
153 const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
154 const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
155 struct perf_sample sample = {
156 .ip = 101,
157 .pid = 102,
158 .tid = 103,
159 .time = 104,
160 .addr = 105,
161 .id = 106,
162 .stream_id = 107,
163 .period = 108,
164 .weight = 109,
165 .cpu = 110,
166 .raw_size = sizeof(raw_data),
167 .data_src = 111,
168 .raw_data = (void *)raw_data,
169 .callchain = &callchain.callchain,
170 .branch_stack = &branch_stack.branch_stack,
171 .user_regs = {
172 .abi = PERF_SAMPLE_REGS_ABI_64,
173 .regs = user_regs,
174 },
175 .user_stack = {
176 .size = sizeof(data),
177 .data = (void *)data,
178 },
179 .read = {
180 .time_enabled = 0x030a59d664fca7deULL,
181 .time_running = 0x011b6ae553eb98edULL,
182 },
183 };
184 struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
185 struct perf_sample sample_out;
186 size_t i, sz, bufsz;
187 int err, ret = -1;
188
189 for (i = 0; i < sizeof(user_regs); i++)
190 *(i + (u8 *)user_regs) = i & 0xfe;
191
192 if (read_format & PERF_FORMAT_GROUP) {
193 sample.read.group.nr = 4;
194 sample.read.group.values = values;
195 } else {
196 sample.read.one.value = 0x08789faeb786aa87ULL;
197 sample.read.one.id = 99;
198 }
199
200 sz = perf_event__sample_event_size(&sample, sample_type,
201 sample_regs_user, read_format);
202 bufsz = sz + 4096; /* Add a bit for overrun checking */
203 event = malloc(bufsz);
204 if (!event) {
205 pr_debug("malloc failed\n");
206 return -1;
207 }
208
209 memset(event, 0xff, bufsz);
210 event->header.type = PERF_RECORD_SAMPLE;
211 event->header.misc = 0;
212 event->header.size = sz;
213
214 err = perf_event__synthesize_sample(event, sample_type,
215 sample_regs_user, read_format,
216 &sample, false);
217 if (err) {
218 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
219 "perf_event__synthesize_sample", sample_type, err);
220 goto out_free;
221 }
222
223 /* The data does not contain 0xff so we use that to check the size */
224 for (i = bufsz; i > 0; i--) {
225 if (*(i - 1 + (u8 *)event) != 0xff)
226 break;
227 }
228 if (i != sz) {
229 pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
230 i, sz);
231 goto out_free;
232 }
233
234 evsel.sample_size = __perf_evsel__sample_size(sample_type);
235
236 err = perf_evsel__parse_sample(&evsel, event, &sample_out);
237 if (err) {
238 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
239 "perf_evsel__parse_sample", sample_type, err);
240 goto out_free;
241 }
242
243 if (!samples_same(&sample, &sample_out, sample_type,
244 sample_regs_user, read_format)) {
245 pr_debug("parsing failed for sample_type %#"PRIx64"\n",
246 sample_type);
247 goto out_free;
248 }
249
250 ret = 0;
251out_free:
252 free(event);
253 if (ret && read_format)
254 pr_debug("read_format %#"PRIx64"\n", read_format);
255 return ret;
256}
257
258/**
259 * test__sample_parsing - test sample parsing.
260 *
261 * This function implements a test that synthesizes a sample event, parses it
262 * and then checks that the parsed sample matches the original sample. The test
263 * checks sample format bits separately and together. If the test passes %0 is
264 * returned, otherwise %-1 is returned.
265 */
266int test__sample_parsing(void)
267{
268 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
269 u64 sample_type;
270 u64 sample_regs_user;
271 size_t i;
272 int err;
273
274 /*
275 * Fail the test if it has not been updated when new sample format bits
276 * were added.
277 */
278 if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) {
279 pr_debug("sample format has changed - test needs updating\n");
280 return -1;
281 }
282
283 /* Test each sample format bit separately */
284 for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
285 sample_type <<= 1) {
286 /* Test read_format variations */
287 if (sample_type == PERF_SAMPLE_READ) {
288 for (i = 0; i < ARRAY_SIZE(rf); i++) {
289 err = do_test(sample_type, 0, rf[i]);
290 if (err)
291 return err;
292 }
293 continue;
294 }
295
296 if (sample_type == PERF_SAMPLE_REGS_USER)
297 sample_regs_user = 0x3fff;
298 else
299 sample_regs_user = 0;
300
301 err = do_test(sample_type, sample_regs_user, 0);
302 if (err)
303 return err;
304 }
305
306 /* Test all sample format bits together */
307 sample_type = PERF_SAMPLE_MAX - 1;
308 sample_regs_user = 0x3fff;
309 for (i = 0; i < ARRAY_SIZE(rf); i++) {
310 err = do_test(sample_type, sample_regs_user, rf[i]);
311 if (err)
312 return err;
313 }
314
315 return 0;
316}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index c748f532b20f..83d5b71a3ce4 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -37,5 +37,6 @@ int test__task_exit(void);
37int test__sw_clock_freq(void); 37int test__sw_clock_freq(void);
38int test__perf_time_to_tsc(void); 38int test__perf_time_to_tsc(void);
39int test__code_reading(void); 39int test__code_reading(void);
40int test__sample_parsing(void);
40 41
41#endif /* TESTS_H */ 42#endif /* TESTS_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5295625c0c00..fb584092eb88 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -18,13 +18,14 @@
18 18
19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
20 union perf_event *event, 20 union perf_event *event,
21 struct perf_sample *sample __maybe_unused, 21 struct perf_sample *sample,
22 struct perf_evsel *evsel __maybe_unused, 22 struct perf_evsel *evsel __maybe_unused,
23 struct machine *machine) 23 struct machine *machine)
24{ 24{
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 27 struct thread *thread = machine__findnew_thread(machine, sample->pid,
28 sample->pid);
28 29
29 if (thread == NULL) { 30 if (thread == NULL) {
30 pr_err("problem processing %d event, skipping it.\n", 31 pr_err("problem processing %d event, skipping it.\n",
@@ -33,7 +34,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
33 } 34 }
34 35
35 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 36 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
36 event->ip.ip, &al); 37 sample->ip, &al);
37 38
38 if (al.map != NULL) 39 if (al.map != NULL)
39 al.map->dso->hit = 1; 40 al.map->dso->hit = 1;
@@ -47,7 +48,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
47 __maybe_unused, 48 __maybe_unused,
48 struct machine *machine) 49 struct machine *machine)
49{ 50{
50 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 51 struct thread *thread = machine__findnew_thread(machine,
52 event->fork.pid,
53 event->fork.tid);
51 54
52 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 55 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
53 event->fork.ppid, event->fork.ptid); 56 event->fork.ppid, event->fork.ptid);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 4fee33b229b0..482f68081cd8 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -21,14 +21,6 @@
21 21
22__thread struct callchain_cursor callchain_cursor; 22__thread struct callchain_cursor callchain_cursor;
23 23
24bool ip_callchain__valid(struct ip_callchain *chain,
25 const union perf_event *event)
26{
27 unsigned int chain_size = event->header.size;
28 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
29 return chain->nr * sizeof(u64) <= chain_size;
30}
31
32#define chain_for_each_child(child, parent) \ 24#define chain_for_each_child(child, parent) \
33 list_for_each_entry(child, &parent->children, siblings) 25 list_for_each_entry(child, &parent->children, siblings)
34 26
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 812d5a0ff2bc..2b585bc308cf 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -109,11 +109,6 @@ int callchain_append(struct callchain_root *root,
109int callchain_merge(struct callchain_cursor *cursor, 109int callchain_merge(struct callchain_cursor *cursor,
110 struct callchain_root *dst, struct callchain_root *src); 110 struct callchain_root *dst, struct callchain_root *src);
111 111
112struct ip_callchain;
113union perf_event;
114
115bool ip_callchain__valid(struct ip_callchain *chain,
116 const union perf_event *event);
117/* 112/*
118 * Initialize a cursor before adding entries inside, but keep 113 * Initialize a cursor before adding entries inside, but keep
119 * the previously allocated entries as a cache. 114 * the previously allocated entries as a cache.
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 49713ae46551..8d51f21107aa 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -686,7 +686,8 @@ int perf_event__preprocess_sample(const union perf_event *event,
686 struct perf_sample *sample) 686 struct perf_sample *sample)
687{ 687{
688 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 688 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
689 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 689 struct thread *thread = machine__findnew_thread(machine, sample->pid,
690 sample->pid);
690 691
691 if (thread == NULL) 692 if (thread == NULL)
692 return -1; 693 return -1;
@@ -708,7 +709,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
708 machine__create_kernel_maps(machine); 709 machine__create_kernel_maps(machine);
709 710
710 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 711 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
711 event->ip.ip, al); 712 sample->ip, al);
712 dump_printf(" ...... dso: %s\n", 713 dump_printf(" ...... dso: %s\n",
713 al->map ? al->map->dso->long_name : 714 al->map ? al->map->dso->long_name :
714 al->level == 'H' ? "[hypervisor]" : "<not found>"); 715 al->level == 'H' ? "[hypervisor]" : "<not found>");
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 15db071d96b5..93130d856bf0 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -8,16 +8,6 @@
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10 10
11/*
12 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
13 */
14struct ip_event {
15 struct perf_event_header header;
16 u64 ip;
17 u32 pid, tid;
18 unsigned char __more_data[];
19};
20
21struct mmap_event { 11struct mmap_event {
22 struct perf_event_header header; 12 struct perf_event_header header;
23 u32 pid, tid; 13 u32 pid, tid;
@@ -63,7 +53,8 @@ struct read_event {
63 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ 53 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
64 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ 54 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
65 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ 55 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
66 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) 56 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
57 PERF_SAMPLE_IDENTIFIER)
67 58
68struct sample_event { 59struct sample_event {
69 struct perf_event_header header; 60 struct perf_event_header header;
@@ -71,6 +62,7 @@ struct sample_event {
71}; 62};
72 63
73struct regs_dump { 64struct regs_dump {
65 u64 abi;
74 u64 *regs; 66 u64 *regs;
75}; 67};
76 68
@@ -166,7 +158,6 @@ struct tracing_data_event {
166 158
167union perf_event { 159union perf_event {
168 struct perf_event_header header; 160 struct perf_event_header header;
169 struct ip_event ip;
170 struct mmap_event mmap; 161 struct mmap_event mmap;
171 struct comm_event comm; 162 struct comm_event comm;
172 struct fork_event fork; 163 struct fork_event fork;
@@ -238,7 +229,10 @@ int perf_event__preprocess_sample(const union perf_event *self,
238 229
239const char *perf_event__name(unsigned int id); 230const char *perf_event__name(unsigned int id);
240 231
232size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
233 u64 sample_regs_user, u64 read_format);
241int perf_event__synthesize_sample(union perf_event *event, u64 type, 234int perf_event__synthesize_sample(union perf_event *event, u64 type,
235 u64 sample_regs_user, u64 read_format,
242 const struct perf_sample *sample, 236 const struct perf_sample *sample,
243 bool swapped); 237 bool swapped);
244 238
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1f5105ac5c85..5df4ca91bed3 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -49,26 +49,19 @@ struct perf_evlist *perf_evlist__new(void)
49 return evlist; 49 return evlist;
50} 50}
51 51
52void perf_evlist__config(struct perf_evlist *evlist, 52/**
53 struct perf_record_opts *opts) 53 * perf_evlist__set_id_pos - set the positions of event ids.
54 * @evlist: selected event list
55 *
56 * Events with compatible sample types all have the same id_pos
57 * and is_pos. For convenience, put a copy on evlist.
58 */
59void perf_evlist__set_id_pos(struct perf_evlist *evlist)
54{ 60{
55 struct perf_evsel *evsel; 61 struct perf_evsel *first = perf_evlist__first(evlist);
56 /*
57 * Set the evsel leader links before we configure attributes,
58 * since some might depend on this info.
59 */
60 if (opts->group)
61 perf_evlist__set_leader(evlist);
62
63 if (evlist->cpus->map[0] < 0)
64 opts->no_inherit = true;
65
66 list_for_each_entry(evsel, &evlist->entries, node) {
67 perf_evsel__config(evsel, opts);
68 62
69 if (evlist->nr_entries > 1) 63 evlist->id_pos = first->id_pos;
70 perf_evsel__set_sample_id(evsel); 64 evlist->is_pos = first->is_pos;
71 }
72} 65}
73 66
74static void perf_evlist__purge(struct perf_evlist *evlist) 67static void perf_evlist__purge(struct perf_evlist *evlist)
@@ -101,15 +94,20 @@ void perf_evlist__delete(struct perf_evlist *evlist)
101void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 94void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
102{ 95{
103 list_add_tail(&entry->node, &evlist->entries); 96 list_add_tail(&entry->node, &evlist->entries);
104 ++evlist->nr_entries; 97 if (!evlist->nr_entries++)
98 perf_evlist__set_id_pos(evlist);
105} 99}
106 100
107void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 101void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
108 struct list_head *list, 102 struct list_head *list,
109 int nr_entries) 103 int nr_entries)
110{ 104{
105 bool set_id_pos = !evlist->nr_entries;
106
111 list_splice_tail(list, &evlist->entries); 107 list_splice_tail(list, &evlist->entries);
112 evlist->nr_entries += nr_entries; 108 evlist->nr_entries += nr_entries;
109 if (set_id_pos)
110 perf_evlist__set_id_pos(evlist);
113} 111}
114 112
115void __perf_evlist__set_leader(struct list_head *list) 113void __perf_evlist__set_leader(struct list_head *list)
@@ -210,6 +208,21 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
210 return NULL; 208 return NULL;
211} 209}
212 210
211struct perf_evsel *
212perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
213 const char *name)
214{
215 struct perf_evsel *evsel;
216
217 list_for_each_entry(evsel, &evlist->entries, node) {
218 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) &&
219 (strcmp(evsel->name, name) == 0))
220 return evsel;
221 }
222
223 return NULL;
224}
225
213int perf_evlist__add_newtp(struct perf_evlist *evlist, 226int perf_evlist__add_newtp(struct perf_evlist *evlist,
214 const char *sys, const char *name, void *handler) 227 const char *sys, const char *name, void *handler)
215{ 228{
@@ -371,6 +384,55 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
371 return NULL; 384 return NULL;
372} 385}
373 386
387static int perf_evlist__event2id(struct perf_evlist *evlist,
388 union perf_event *event, u64 *id)
389{
390 const u64 *array = event->sample.array;
391 ssize_t n;
392
393 n = (event->header.size - sizeof(event->header)) >> 3;
394
395 if (event->header.type == PERF_RECORD_SAMPLE) {
396 if (evlist->id_pos >= n)
397 return -1;
398 *id = array[evlist->id_pos];
399 } else {
400 if (evlist->is_pos > n)
401 return -1;
402 n -= evlist->is_pos;
403 *id = array[n];
404 }
405 return 0;
406}
407
408static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
409 union perf_event *event)
410{
411 struct hlist_head *head;
412 struct perf_sample_id *sid;
413 int hash;
414 u64 id;
415
416 if (evlist->nr_entries == 1)
417 return perf_evlist__first(evlist);
418
419 if (perf_evlist__event2id(evlist, event, &id))
420 return NULL;
421
422 /* Synthesized events have an id of zero */
423 if (!id)
424 return perf_evlist__first(evlist);
425
426 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
427 head = &evlist->heads[hash];
428
429 hlist_for_each_entry(sid, head, node) {
430 if (sid->id == id)
431 return sid->evsel;
432 }
433 return NULL;
434}
435
374union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 436union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
375{ 437{
376 struct perf_mmap *md = &evlist->mmap[idx]; 438 struct perf_mmap *md = &evlist->mmap[idx];
@@ -681,20 +743,40 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
681 743
682bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) 744bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
683{ 745{
684 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; 746 struct perf_evsel *pos;
685 747
686 list_for_each_entry_continue(pos, &evlist->entries, node) { 748 if (evlist->nr_entries == 1)
687 if (first->attr.sample_type != pos->attr.sample_type) 749 return true;
750
751 if (evlist->id_pos < 0 || evlist->is_pos < 0)
752 return false;
753
754 list_for_each_entry(pos, &evlist->entries, node) {
755 if (pos->id_pos != evlist->id_pos ||
756 pos->is_pos != evlist->is_pos)
688 return false; 757 return false;
689 } 758 }
690 759
691 return true; 760 return true;
692} 761}
693 762
694u64 perf_evlist__sample_type(struct perf_evlist *evlist) 763u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
695{ 764{
696 struct perf_evsel *first = perf_evlist__first(evlist); 765 struct perf_evsel *evsel;
697 return first->attr.sample_type; 766
767 if (evlist->combined_sample_type)
768 return evlist->combined_sample_type;
769
770 list_for_each_entry(evsel, &evlist->entries, node)
771 evlist->combined_sample_type |= evsel->attr.sample_type;
772
773 return evlist->combined_sample_type;
774}
775
776u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist)
777{
778 evlist->combined_sample_type = 0;
779 return __perf_evlist__combined_sample_type(evlist);
698} 780}
699 781
700bool perf_evlist__valid_read_format(struct perf_evlist *evlist) 782bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
@@ -749,6 +831,9 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
749 831
750 if (sample_type & PERF_SAMPLE_CPU) 832 if (sample_type & PERF_SAMPLE_CPU)
751 size += sizeof(data->cpu) * 2; 833 size += sizeof(data->cpu) * 2;
834
835 if (sample_type & PERF_SAMPLE_IDENTIFIER)
836 size += sizeof(data->id);
752out: 837out:
753 return size; 838 return size;
754} 839}
@@ -907,7 +992,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
907int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, 992int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
908 struct perf_sample *sample) 993 struct perf_sample *sample)
909{ 994{
910 struct perf_evsel *evsel = perf_evlist__first(evlist); 995 struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
996
997 if (!evsel)
998 return -EFAULT;
911 return perf_evsel__parse_sample(evsel, event, sample); 999 return perf_evsel__parse_sample(evsel, event, sample);
912} 1000}
913 1001
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 327ababa67b6..841a39405f6a 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -32,6 +32,9 @@ struct perf_evlist {
32 int nr_fds; 32 int nr_fds;
33 int nr_mmaps; 33 int nr_mmaps;
34 int mmap_len; 34 int mmap_len;
35 int id_pos;
36 int is_pos;
37 u64 combined_sample_type;
35 struct { 38 struct {
36 int cork_fd; 39 int cork_fd;
37 pid_t pid; 40 pid_t pid;
@@ -71,6 +74,10 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
71struct perf_evsel * 74struct perf_evsel *
72perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); 75perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
73 76
77struct perf_evsel *
78perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
79 const char *name);
80
74void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 81void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
75 int cpu, int thread, u64 id); 82 int cpu, int thread, u64 id);
76 83
@@ -85,6 +92,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
85int perf_evlist__open(struct perf_evlist *evlist); 92int perf_evlist__open(struct perf_evlist *evlist);
86void perf_evlist__close(struct perf_evlist *evlist); 93void perf_evlist__close(struct perf_evlist *evlist);
87 94
95void perf_evlist__set_id_pos(struct perf_evlist *evlist);
96bool perf_can_sample_identifier(void);
88void perf_evlist__config(struct perf_evlist *evlist, 97void perf_evlist__config(struct perf_evlist *evlist,
89 struct perf_record_opts *opts); 98 struct perf_record_opts *opts);
90 99
@@ -121,7 +130,8 @@ void __perf_evlist__set_leader(struct list_head *list);
121void perf_evlist__set_leader(struct perf_evlist *evlist); 130void perf_evlist__set_leader(struct perf_evlist *evlist);
122 131
123u64 perf_evlist__read_format(struct perf_evlist *evlist); 132u64 perf_evlist__read_format(struct perf_evlist *evlist);
124u64 perf_evlist__sample_type(struct perf_evlist *evlist); 133u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist);
134u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist);
125bool perf_evlist__sample_id_all(struct perf_evlist *evlist); 135bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
126u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); 136u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
127 137
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 47cbe1e58b73..e8745fb635a7 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -31,7 +31,7 @@ static struct {
31 31
32#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 32#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
33 33
34static int __perf_evsel__sample_size(u64 sample_type) 34int __perf_evsel__sample_size(u64 sample_type)
35{ 35{
36 u64 mask = sample_type & PERF_SAMPLE_MASK; 36 u64 mask = sample_type & PERF_SAMPLE_MASK;
37 int size = 0; 37 int size = 0;
@@ -47,6 +47,72 @@ static int __perf_evsel__sample_size(u64 sample_type)
47 return size; 47 return size;
48} 48}
49 49
50/**
51 * __perf_evsel__calc_id_pos - calculate id_pos.
52 * @sample_type: sample type
53 *
54 * This function returns the position of the event id (PERF_SAMPLE_ID or
55 * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct
56 * sample_event.
57 */
58static int __perf_evsel__calc_id_pos(u64 sample_type)
59{
60 int idx = 0;
61
62 if (sample_type & PERF_SAMPLE_IDENTIFIER)
63 return 0;
64
65 if (!(sample_type & PERF_SAMPLE_ID))
66 return -1;
67
68 if (sample_type & PERF_SAMPLE_IP)
69 idx += 1;
70
71 if (sample_type & PERF_SAMPLE_TID)
72 idx += 1;
73
74 if (sample_type & PERF_SAMPLE_TIME)
75 idx += 1;
76
77 if (sample_type & PERF_SAMPLE_ADDR)
78 idx += 1;
79
80 return idx;
81}
82
83/**
84 * __perf_evsel__calc_is_pos - calculate is_pos.
85 * @sample_type: sample type
86 *
87 * This function returns the position (counting backwards) of the event id
88 * (PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if
89 * sample_id_all is used there is an id sample appended to non-sample events.
90 */
91static int __perf_evsel__calc_is_pos(u64 sample_type)
92{
93 int idx = 1;
94
95 if (sample_type & PERF_SAMPLE_IDENTIFIER)
96 return 1;
97
98 if (!(sample_type & PERF_SAMPLE_ID))
99 return -1;
100
101 if (sample_type & PERF_SAMPLE_CPU)
102 idx += 1;
103
104 if (sample_type & PERF_SAMPLE_STREAM_ID)
105 idx += 1;
106
107 return idx;
108}
109
110void perf_evsel__calc_id_pos(struct perf_evsel *evsel)
111{
112 evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type);
113 evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type);
114}
115
50void hists__init(struct hists *hists) 116void hists__init(struct hists *hists)
51{ 117{
52 memset(hists, 0, sizeof(*hists)); 118 memset(hists, 0, sizeof(*hists));
@@ -63,6 +129,7 @@ void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
63 if (!(evsel->attr.sample_type & bit)) { 129 if (!(evsel->attr.sample_type & bit)) {
64 evsel->attr.sample_type |= bit; 130 evsel->attr.sample_type |= bit;
65 evsel->sample_size += sizeof(u64); 131 evsel->sample_size += sizeof(u64);
132 perf_evsel__calc_id_pos(evsel);
66 } 133 }
67} 134}
68 135
@@ -72,12 +139,19 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
72 if (evsel->attr.sample_type & bit) { 139 if (evsel->attr.sample_type & bit) {
73 evsel->attr.sample_type &= ~bit; 140 evsel->attr.sample_type &= ~bit;
74 evsel->sample_size -= sizeof(u64); 141 evsel->sample_size -= sizeof(u64);
142 perf_evsel__calc_id_pos(evsel);
75 } 143 }
76} 144}
77 145
78void perf_evsel__set_sample_id(struct perf_evsel *evsel) 146void perf_evsel__set_sample_id(struct perf_evsel *evsel,
147 bool can_sample_identifier)
79{ 148{
80 perf_evsel__set_sample_bit(evsel, ID); 149 if (can_sample_identifier) {
150 perf_evsel__reset_sample_bit(evsel, ID);
151 perf_evsel__set_sample_bit(evsel, IDENTIFIER);
152 } else {
153 perf_evsel__set_sample_bit(evsel, ID);
154 }
81 evsel->attr.read_format |= PERF_FORMAT_ID; 155 evsel->attr.read_format |= PERF_FORMAT_ID;
82} 156}
83 157
@@ -90,6 +164,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
90 INIT_LIST_HEAD(&evsel->node); 164 INIT_LIST_HEAD(&evsel->node);
91 hists__init(&evsel->hists); 165 hists__init(&evsel->hists);
92 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 166 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
167 perf_evsel__calc_id_pos(evsel);
93} 168}
94 169
95struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 170struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -509,7 +584,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
509 * We need ID even in case of single event, because 584 * We need ID even in case of single event, because
510 * PERF_SAMPLE_READ process ID specific data. 585 * PERF_SAMPLE_READ process ID specific data.
511 */ 586 */
512 perf_evsel__set_sample_id(evsel); 587 perf_evsel__set_sample_id(evsel, false);
513 588
514 /* 589 /*
515 * Apply group format only if we belong to group 590 * Apply group format only if we belong to group
@@ -1088,6 +1163,11 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
1088 array += ((event->header.size - 1163 array += ((event->header.size -
1089 sizeof(event->header)) / sizeof(u64)) - 1; 1164 sizeof(event->header)) / sizeof(u64)) - 1;
1090 1165
1166 if (type & PERF_SAMPLE_IDENTIFIER) {
1167 sample->id = *array;
1168 array--;
1169 }
1170
1091 if (type & PERF_SAMPLE_CPU) { 1171 if (type & PERF_SAMPLE_CPU) {
1092 u.val64 = *array; 1172 u.val64 = *array;
1093 if (swapped) { 1173 if (swapped) {
@@ -1131,24 +1211,30 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
1131 return 0; 1211 return 0;
1132} 1212}
1133 1213
1134static bool sample_overlap(const union perf_event *event, 1214static inline bool overflow(const void *endp, u16 max_size, const void *offset,
1135 const void *offset, u64 size) 1215 u64 size)
1136{ 1216{
1137 const void *base = event; 1217 return size > max_size || offset + size > endp;
1218}
1138 1219
1139 if (offset + size > base + event->header.size) 1220#define OVERFLOW_CHECK(offset, size, max_size) \
1140 return true; 1221 do { \
1222 if (overflow(endp, (max_size), (offset), (size))) \
1223 return -EFAULT; \
1224 } while (0)
1141 1225
1142 return false; 1226#define OVERFLOW_CHECK_u64(offset) \
1143} 1227 OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))
1144 1228
1145int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 1229int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1146 struct perf_sample *data) 1230 struct perf_sample *data)
1147{ 1231{
1148 u64 type = evsel->attr.sample_type; 1232 u64 type = evsel->attr.sample_type;
1149 u64 regs_user = evsel->attr.sample_regs_user;
1150 bool swapped = evsel->needs_swap; 1233 bool swapped = evsel->needs_swap;
1151 const u64 *array; 1234 const u64 *array;
1235 u16 max_size = event->header.size;
1236 const void *endp = (void *)event + max_size;
1237 u64 sz;
1152 1238
1153 /* 1239 /*
1154 * used for cross-endian analysis. See git commit 65014ab3 1240 * used for cross-endian analysis. See git commit 65014ab3
@@ -1170,11 +1256,22 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1170 1256
1171 array = event->sample.array; 1257 array = event->sample.array;
1172 1258
1259 /*
1260 * The evsel's sample_size is based on PERF_SAMPLE_MASK which includes
1261 * up to PERF_SAMPLE_PERIOD. After that overflow() must be used to
1262 * check the format does not go past the end of the event.
1263 */
1173 if (evsel->sample_size + sizeof(event->header) > event->header.size) 1264 if (evsel->sample_size + sizeof(event->header) > event->header.size)
1174 return -EFAULT; 1265 return -EFAULT;
1175 1266
1267 data->id = -1ULL;
1268 if (type & PERF_SAMPLE_IDENTIFIER) {
1269 data->id = *array;
1270 array++;
1271 }
1272
1176 if (type & PERF_SAMPLE_IP) { 1273 if (type & PERF_SAMPLE_IP) {
1177 data->ip = event->ip.ip; 1274 data->ip = *array;
1178 array++; 1275 array++;
1179 } 1276 }
1180 1277
@@ -1203,7 +1300,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1203 array++; 1300 array++;
1204 } 1301 }
1205 1302
1206 data->id = -1ULL;
1207 if (type & PERF_SAMPLE_ID) { 1303 if (type & PERF_SAMPLE_ID) {
1208 data->id = *array; 1304 data->id = *array;
1209 array++; 1305 array++;
@@ -1235,6 +1331,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1235 if (type & PERF_SAMPLE_READ) { 1331 if (type & PERF_SAMPLE_READ) {
1236 u64 read_format = evsel->attr.read_format; 1332 u64 read_format = evsel->attr.read_format;
1237 1333
1334 OVERFLOW_CHECK_u64(array);
1238 if (read_format & PERF_FORMAT_GROUP) 1335 if (read_format & PERF_FORMAT_GROUP)
1239 data->read.group.nr = *array; 1336 data->read.group.nr = *array;
1240 else 1337 else
@@ -1243,41 +1340,51 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1243 array++; 1340 array++;
1244 1341
1245 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1342 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
1343 OVERFLOW_CHECK_u64(array);
1246 data->read.time_enabled = *array; 1344 data->read.time_enabled = *array;
1247 array++; 1345 array++;
1248 } 1346 }
1249 1347
1250 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 1348 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
1349 OVERFLOW_CHECK_u64(array);
1251 data->read.time_running = *array; 1350 data->read.time_running = *array;
1252 array++; 1351 array++;
1253 } 1352 }
1254 1353
1255 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1354 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1256 if (read_format & PERF_FORMAT_GROUP) { 1355 if (read_format & PERF_FORMAT_GROUP) {
1257 data->read.group.values = (struct sample_read_value *) array; 1356 const u64 max_group_nr = UINT64_MAX /
1258 array = (void *) array + data->read.group.nr * 1357 sizeof(struct sample_read_value);
1259 sizeof(struct sample_read_value); 1358
1359 if (data->read.group.nr > max_group_nr)
1360 return -EFAULT;
1361 sz = data->read.group.nr *
1362 sizeof(struct sample_read_value);
1363 OVERFLOW_CHECK(array, sz, max_size);
1364 data->read.group.values =
1365 (struct sample_read_value *)array;
1366 array = (void *)array + sz;
1260 } else { 1367 } else {
1368 OVERFLOW_CHECK_u64(array);
1261 data->read.one.id = *array; 1369 data->read.one.id = *array;
1262 array++; 1370 array++;
1263 } 1371 }
1264 } 1372 }
1265 1373
1266 if (type & PERF_SAMPLE_CALLCHAIN) { 1374 if (type & PERF_SAMPLE_CALLCHAIN) {
1267 if (sample_overlap(event, array, sizeof(data->callchain->nr))) 1375 const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
1268 return -EFAULT;
1269
1270 data->callchain = (struct ip_callchain *)array;
1271 1376
1272 if (sample_overlap(event, array, data->callchain->nr)) 1377 OVERFLOW_CHECK_u64(array);
1378 data->callchain = (struct ip_callchain *)array++;
1379 if (data->callchain->nr > max_callchain_nr)
1273 return -EFAULT; 1380 return -EFAULT;
1274 1381 sz = data->callchain->nr * sizeof(u64);
1275 array += 1 + data->callchain->nr; 1382 OVERFLOW_CHECK(array, sz, max_size);
1383 array = (void *)array + sz;
1276 } 1384 }
1277 1385
1278 if (type & PERF_SAMPLE_RAW) { 1386 if (type & PERF_SAMPLE_RAW) {
1279 const u64 *pdata; 1387 OVERFLOW_CHECK_u64(array);
1280
1281 u.val64 = *array; 1388 u.val64 = *array;
1282 if (WARN_ONCE(swapped, 1389 if (WARN_ONCE(swapped,
1283 "Endianness of raw data not corrected!\n")) { 1390 "Endianness of raw data not corrected!\n")) {
@@ -1286,65 +1393,71 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1286 u.val32[0] = bswap_32(u.val32[0]); 1393 u.val32[0] = bswap_32(u.val32[0]);
1287 u.val32[1] = bswap_32(u.val32[1]); 1394 u.val32[1] = bswap_32(u.val32[1]);
1288 } 1395 }
1289
1290 if (sample_overlap(event, array, sizeof(u32)))
1291 return -EFAULT;
1292
1293 data->raw_size = u.val32[0]; 1396 data->raw_size = u.val32[0];
1294 pdata = (void *) array + sizeof(u32); 1397 array = (void *)array + sizeof(u32);
1295
1296 if (sample_overlap(event, pdata, data->raw_size))
1297 return -EFAULT;
1298
1299 data->raw_data = (void *) pdata;
1300 1398
1301 array = (void *)array + data->raw_size + sizeof(u32); 1399 OVERFLOW_CHECK(array, data->raw_size, max_size);
1400 data->raw_data = (void *)array;
1401 array = (void *)array + data->raw_size;
1302 } 1402 }
1303 1403
1304 if (type & PERF_SAMPLE_BRANCH_STACK) { 1404 if (type & PERF_SAMPLE_BRANCH_STACK) {
1305 u64 sz; 1405 const u64 max_branch_nr = UINT64_MAX /
1406 sizeof(struct branch_entry);
1306 1407
1307 data->branch_stack = (struct branch_stack *)array; 1408 OVERFLOW_CHECK_u64(array);
1308 array++; /* nr */ 1409 data->branch_stack = (struct branch_stack *)array++;
1309 1410
1411 if (data->branch_stack->nr > max_branch_nr)
1412 return -EFAULT;
1310 sz = data->branch_stack->nr * sizeof(struct branch_entry); 1413 sz = data->branch_stack->nr * sizeof(struct branch_entry);
1311 sz /= sizeof(u64); 1414 OVERFLOW_CHECK(array, sz, max_size);
1312 array += sz; 1415 array = (void *)array + sz;
1313 } 1416 }
1314 1417
1315 if (type & PERF_SAMPLE_REGS_USER) { 1418 if (type & PERF_SAMPLE_REGS_USER) {
1316 /* First u64 tells us if we have any regs in sample. */ 1419 OVERFLOW_CHECK_u64(array);
1317 u64 avail = *array++; 1420 data->user_regs.abi = *array;
1421 array++;
1422
1423 if (data->user_regs.abi) {
1424 u64 regs_user = evsel->attr.sample_regs_user;
1318 1425
1319 if (avail) { 1426 sz = hweight_long(regs_user) * sizeof(u64);
1427 OVERFLOW_CHECK(array, sz, max_size);
1320 data->user_regs.regs = (u64 *)array; 1428 data->user_regs.regs = (u64 *)array;
1321 array += hweight_long(regs_user); 1429 array = (void *)array + sz;
1322 } 1430 }
1323 } 1431 }
1324 1432
1325 if (type & PERF_SAMPLE_STACK_USER) { 1433 if (type & PERF_SAMPLE_STACK_USER) {
1326 u64 size = *array++; 1434 OVERFLOW_CHECK_u64(array);
1435 sz = *array++;
1327 1436
1328 data->user_stack.offset = ((char *)(array - 1) 1437 data->user_stack.offset = ((char *)(array - 1)
1329 - (char *) event); 1438 - (char *) event);
1330 1439
1331 if (!size) { 1440 if (!sz) {
1332 data->user_stack.size = 0; 1441 data->user_stack.size = 0;
1333 } else { 1442 } else {
1443 OVERFLOW_CHECK(array, sz, max_size);
1334 data->user_stack.data = (char *)array; 1444 data->user_stack.data = (char *)array;
1335 array += size / sizeof(*array); 1445 array = (void *)array + sz;
1446 OVERFLOW_CHECK_u64(array);
1336 data->user_stack.size = *array++; 1447 data->user_stack.size = *array++;
1337 } 1448 }
1338 } 1449 }
1339 1450
1340 data->weight = 0; 1451 data->weight = 0;
1341 if (type & PERF_SAMPLE_WEIGHT) { 1452 if (type & PERF_SAMPLE_WEIGHT) {
1453 OVERFLOW_CHECK_u64(array);
1342 data->weight = *array; 1454 data->weight = *array;
1343 array++; 1455 array++;
1344 } 1456 }
1345 1457
1346 data->data_src = PERF_MEM_DATA_SRC_NONE; 1458 data->data_src = PERF_MEM_DATA_SRC_NONE;
1347 if (type & PERF_SAMPLE_DATA_SRC) { 1459 if (type & PERF_SAMPLE_DATA_SRC) {
1460 OVERFLOW_CHECK_u64(array);
1348 data->data_src = *array; 1461 data->data_src = *array;
1349 array++; 1462 array++;
1350 } 1463 }
@@ -1352,12 +1465,105 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1352 return 0; 1465 return 0;
1353} 1466}
1354 1467
1468size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1469 u64 sample_regs_user, u64 read_format)
1470{
1471 size_t sz, result = sizeof(struct sample_event);
1472
1473 if (type & PERF_SAMPLE_IDENTIFIER)
1474 result += sizeof(u64);
1475
1476 if (type & PERF_SAMPLE_IP)
1477 result += sizeof(u64);
1478
1479 if (type & PERF_SAMPLE_TID)
1480 result += sizeof(u64);
1481
1482 if (type & PERF_SAMPLE_TIME)
1483 result += sizeof(u64);
1484
1485 if (type & PERF_SAMPLE_ADDR)
1486 result += sizeof(u64);
1487
1488 if (type & PERF_SAMPLE_ID)
1489 result += sizeof(u64);
1490
1491 if (type & PERF_SAMPLE_STREAM_ID)
1492 result += sizeof(u64);
1493
1494 if (type & PERF_SAMPLE_CPU)
1495 result += sizeof(u64);
1496
1497 if (type & PERF_SAMPLE_PERIOD)
1498 result += sizeof(u64);
1499
1500 if (type & PERF_SAMPLE_READ) {
1501 result += sizeof(u64);
1502 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
1503 result += sizeof(u64);
1504 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
1505 result += sizeof(u64);
1506 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1507 if (read_format & PERF_FORMAT_GROUP) {
1508 sz = sample->read.group.nr *
1509 sizeof(struct sample_read_value);
1510 result += sz;
1511 } else {
1512 result += sizeof(u64);
1513 }
1514 }
1515
1516 if (type & PERF_SAMPLE_CALLCHAIN) {
1517 sz = (sample->callchain->nr + 1) * sizeof(u64);
1518 result += sz;
1519 }
1520
1521 if (type & PERF_SAMPLE_RAW) {
1522 result += sizeof(u32);
1523 result += sample->raw_size;
1524 }
1525
1526 if (type & PERF_SAMPLE_BRANCH_STACK) {
1527 sz = sample->branch_stack->nr * sizeof(struct branch_entry);
1528 sz += sizeof(u64);
1529 result += sz;
1530 }
1531
1532 if (type & PERF_SAMPLE_REGS_USER) {
1533 if (sample->user_regs.abi) {
1534 result += sizeof(u64);
1535 sz = hweight_long(sample_regs_user) * sizeof(u64);
1536 result += sz;
1537 } else {
1538 result += sizeof(u64);
1539 }
1540 }
1541
1542 if (type & PERF_SAMPLE_STACK_USER) {
1543 sz = sample->user_stack.size;
1544 result += sizeof(u64);
1545 if (sz) {
1546 result += sz;
1547 result += sizeof(u64);
1548 }
1549 }
1550
1551 if (type & PERF_SAMPLE_WEIGHT)
1552 result += sizeof(u64);
1553
1554 if (type & PERF_SAMPLE_DATA_SRC)
1555 result += sizeof(u64);
1556
1557 return result;
1558}
1559
1355int perf_event__synthesize_sample(union perf_event *event, u64 type, 1560int perf_event__synthesize_sample(union perf_event *event, u64 type,
1561 u64 sample_regs_user, u64 read_format,
1356 const struct perf_sample *sample, 1562 const struct perf_sample *sample,
1357 bool swapped) 1563 bool swapped)
1358{ 1564{
1359 u64 *array; 1565 u64 *array;
1360 1566 size_t sz;
1361 /* 1567 /*
1362 * used for cross-endian analysis. See git commit 65014ab3 1568 * used for cross-endian analysis. See git commit 65014ab3
1363 * for why this goofiness is needed. 1569 * for why this goofiness is needed.
@@ -1366,8 +1572,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1366 1572
1367 array = event->sample.array; 1573 array = event->sample.array;
1368 1574
1575 if (type & PERF_SAMPLE_IDENTIFIER) {
1576 *array = sample->id;
1577 array++;
1578 }
1579
1369 if (type & PERF_SAMPLE_IP) { 1580 if (type & PERF_SAMPLE_IP) {
1370 event->ip.ip = sample->ip; 1581 *array = sample->ip;
1371 array++; 1582 array++;
1372 } 1583 }
1373 1584
@@ -1425,6 +1636,97 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1425 array++; 1636 array++;
1426 } 1637 }
1427 1638
1639 if (type & PERF_SAMPLE_READ) {
1640 if (read_format & PERF_FORMAT_GROUP)
1641 *array = sample->read.group.nr;
1642 else
1643 *array = sample->read.one.value;
1644 array++;
1645
1646 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
1647 *array = sample->read.time_enabled;
1648 array++;
1649 }
1650
1651 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
1652 *array = sample->read.time_running;
1653 array++;
1654 }
1655
1656 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1657 if (read_format & PERF_FORMAT_GROUP) {
1658 sz = sample->read.group.nr *
1659 sizeof(struct sample_read_value);
1660 memcpy(array, sample->read.group.values, sz);
1661 array = (void *)array + sz;
1662 } else {
1663 *array = sample->read.one.id;
1664 array++;
1665 }
1666 }
1667
1668 if (type & PERF_SAMPLE_CALLCHAIN) {
1669 sz = (sample->callchain->nr + 1) * sizeof(u64);
1670 memcpy(array, sample->callchain, sz);
1671 array = (void *)array + sz;
1672 }
1673
1674 if (type & PERF_SAMPLE_RAW) {
1675 u.val32[0] = sample->raw_size;
1676 if (WARN_ONCE(swapped,
1677 "Endianness of raw data not corrected!\n")) {
1678 /*
1679 * Inverse of what is done in perf_evsel__parse_sample
1680 */
1681 u.val32[0] = bswap_32(u.val32[0]);
1682 u.val32[1] = bswap_32(u.val32[1]);
1683 u.val64 = bswap_64(u.val64);
1684 }
1685 *array = u.val64;
1686 array = (void *)array + sizeof(u32);
1687
1688 memcpy(array, sample->raw_data, sample->raw_size);
1689 array = (void *)array + sample->raw_size;
1690 }
1691
1692 if (type & PERF_SAMPLE_BRANCH_STACK) {
1693 sz = sample->branch_stack->nr * sizeof(struct branch_entry);
1694 sz += sizeof(u64);
1695 memcpy(array, sample->branch_stack, sz);
1696 array = (void *)array + sz;
1697 }
1698
1699 if (type & PERF_SAMPLE_REGS_USER) {
1700 if (sample->user_regs.abi) {
1701 *array++ = sample->user_regs.abi;
1702 sz = hweight_long(sample_regs_user) * sizeof(u64);
1703 memcpy(array, sample->user_regs.regs, sz);
1704 array = (void *)array + sz;
1705 } else {
1706 *array++ = 0;
1707 }
1708 }
1709
1710 if (type & PERF_SAMPLE_STACK_USER) {
1711 sz = sample->user_stack.size;
1712 *array++ = sz;
1713 if (sz) {
1714 memcpy(array, sample->user_stack.data, sz);
1715 array = (void *)array + sz;
1716 *array++ = sz;
1717 }
1718 }
1719
1720 if (type & PERF_SAMPLE_WEIGHT) {
1721 *array = sample->weight;
1722 array++;
1723 }
1724
1725 if (type & PERF_SAMPLE_DATA_SRC) {
1726 *array = sample->data_src;
1727 array++;
1728 }
1729
1428 return 0; 1730 return 0;
1429} 1731}
1430 1732
@@ -1554,6 +1856,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1554 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), 1856 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1555 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), 1857 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1556 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), 1858 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1859 bit_name(IDENTIFIER),
1557 { .name = NULL, } 1860 { .name = NULL, }
1558 }; 1861 };
1559#undef bit_name 1862#undef bit_name
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 532a5f925da0..4a7bdc713bab 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -48,6 +48,12 @@ struct perf_sample_id {
48 * @name - Can be set to retain the original event name passed by the user, 48 * @name - Can be set to retain the original event name passed by the user,
49 * so that when showing results in tools such as 'perf stat', we 49 * so that when showing results in tools such as 'perf stat', we
50 * show the name used, not some alias. 50 * show the name used, not some alias.
51 * @id_pos: the position of the event id (PERF_SAMPLE_ID or
52 * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of
53 * struct sample_event
54 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
55 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
56 * is used there is an id sample appended to non-sample events
51 */ 57 */
52struct perf_evsel { 58struct perf_evsel {
53 struct list_head node; 59 struct list_head node;
@@ -74,6 +80,8 @@ struct perf_evsel {
74 } handler; 80 } handler;
75 struct cpu_map *cpus; 81 struct cpu_map *cpus;
76 unsigned int sample_size; 82 unsigned int sample_size;
83 int id_pos;
84 int is_pos;
77 bool supported; 85 bool supported;
78 bool needs_swap; 86 bool needs_swap;
79 /* parse modifier helper */ 87 /* parse modifier helper */
@@ -104,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel);
104void perf_evsel__config(struct perf_evsel *evsel, 112void perf_evsel__config(struct perf_evsel *evsel,
105 struct perf_record_opts *opts); 113 struct perf_record_opts *opts);
106 114
115int __perf_evsel__sample_size(u64 sample_type);
116void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
117
107bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 118bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
108 119
109#define PERF_EVSEL__MAX_ALIASES 8 120#define PERF_EVSEL__MAX_ALIASES 8
@@ -142,7 +153,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
142#define perf_evsel__reset_sample_bit(evsel, bit) \ 153#define perf_evsel__reset_sample_bit(evsel, bit) \
143 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) 154 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
144 155
145void perf_evsel__set_sample_id(struct perf_evsel *evsel); 156void perf_evsel__set_sample_id(struct perf_evsel *evsel,
157 bool use_sample_identifier);
146 158
147int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 159int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
148 const char *filter); 160 const char *filter);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 59486c180626..1dca61f0512d 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -32,7 +32,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
32 return -ENOMEM; 32 return -ENOMEM;
33 33
34 if (pid != HOST_KERNEL_ID) { 34 if (pid != HOST_KERNEL_ID) {
35 struct thread *thread = machine__findnew_thread(machine, pid); 35 struct thread *thread = machine__findnew_thread(machine, 0,
36 pid);
36 char comm[64]; 37 char comm[64];
37 38
38 if (thread == NULL) 39 if (thread == NULL)
@@ -302,9 +303,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
302 return th; 303 return th;
303} 304}
304 305
305struct thread *machine__findnew_thread(struct machine *machine, pid_t tid) 306struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
307 pid_t tid)
306{ 308{
307 return __machine__findnew_thread(machine, 0, tid, true); 309 return __machine__findnew_thread(machine, pid, tid, true);
308} 310}
309 311
310struct thread *machine__find_thread(struct machine *machine, pid_t tid) 312struct thread *machine__find_thread(struct machine *machine, pid_t tid)
@@ -314,7 +316,9 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid)
314 316
315int machine__process_comm_event(struct machine *machine, union perf_event *event) 317int machine__process_comm_event(struct machine *machine, union perf_event *event)
316{ 318{
317 struct thread *thread = machine__findnew_thread(machine, event->comm.tid); 319 struct thread *thread = machine__findnew_thread(machine,
320 event->comm.pid,
321 event->comm.tid);
318 322
319 if (dump_trace) 323 if (dump_trace)
320 perf_event__fprintf_comm(event, stdout); 324 perf_event__fprintf_comm(event, stdout);
@@ -1012,7 +1016,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1012 return 0; 1016 return 0;
1013 } 1017 }
1014 1018
1015 thread = machine__findnew_thread(machine, event->mmap.pid); 1019 thread = machine__findnew_thread(machine, event->mmap.pid,
1020 event->mmap.pid);
1016 if (thread == NULL) 1021 if (thread == NULL)
1017 goto out_problem; 1022 goto out_problem;
1018 1023
@@ -1051,13 +1056,16 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
1051int machine__process_fork_event(struct machine *machine, union perf_event *event) 1056int machine__process_fork_event(struct machine *machine, union perf_event *event)
1052{ 1057{
1053 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1058 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1054 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); 1059 struct thread *parent = machine__findnew_thread(machine,
1060 event->fork.ppid,
1061 event->fork.ptid);
1055 1062
1056 /* if a thread currently exists for the thread id remove it */ 1063 /* if a thread currently exists for the thread id remove it */
1057 if (thread != NULL) 1064 if (thread != NULL)
1058 machine__remove_thread(machine, thread); 1065 machine__remove_thread(machine, thread);
1059 1066
1060 thread = machine__findnew_thread(machine, event->fork.tid); 1067 thread = machine__findnew_thread(machine, event->fork.pid,
1068 event->fork.tid);
1061 if (dump_trace) 1069 if (dump_trace)
1062 perf_event__fprintf_task(event, stdout); 1070 perf_event__fprintf_task(event, stdout);
1063 1071
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 603ffba999d9..0df925ba6a44 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -106,7 +106,8 @@ static inline bool machine__is_host(struct machine *machine)
106 return machine ? machine->pid == HOST_KERNEL_ID : false; 106 return machine ? machine->pid == HOST_KERNEL_ID : false;
107} 107}
108 108
109struct thread *machine__findnew_thread(struct machine *machine, pid_t tid); 109struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
110 pid_t tid);
110 111
111size_t machine__fprintf(struct machine *machine, FILE *fp); 112size_t machine__fprintf(struct machine *machine, FILE *fp);
112 113
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
new file mode 100644
index 000000000000..18d73aa2f0f8
--- /dev/null
+++ b/tools/perf/util/record.c
@@ -0,0 +1,108 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "cpumap.h"
4#include "parse-events.h"
5
6typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
7
8static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
9{
10 struct perf_evlist *evlist;
11 struct perf_evsel *evsel;
12 int err = -EAGAIN, fd;
13
14 evlist = perf_evlist__new();
15 if (!evlist)
16 return -ENOMEM;
17
18 if (parse_events(evlist, str))
19 goto out_delete;
20
21 evsel = perf_evlist__first(evlist);
22
23 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
24 if (fd < 0)
25 goto out_delete;
26 close(fd);
27
28 fn(evsel);
29
30 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
31 if (fd < 0) {
32 if (errno == EINVAL)
33 err = -EINVAL;
34 goto out_delete;
35 }
36 close(fd);
37 err = 0;
38
39out_delete:
40 perf_evlist__delete(evlist);
41 return err;
42}
43
44static bool perf_probe_api(setup_probe_fn_t fn)
45{
46 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
47 struct cpu_map *cpus;
48 int cpu, ret, i = 0;
49
50 cpus = cpu_map__new(NULL);
51 if (!cpus)
52 return false;
53 cpu = cpus->map[0];
54 cpu_map__delete(cpus);
55
56 do {
57 ret = perf_do_probe_api(fn, cpu, try[i++]);
58 if (!ret)
59 return true;
60 } while (ret == -EAGAIN && try[i]);
61
62 return false;
63}
64
65static void perf_probe_sample_identifier(struct perf_evsel *evsel)
66{
67 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
68}
69
70bool perf_can_sample_identifier(void)
71{
72 return perf_probe_api(perf_probe_sample_identifier);
73}
74
75void perf_evlist__config(struct perf_evlist *evlist,
76 struct perf_record_opts *opts)
77{
78 struct perf_evsel *evsel;
79 bool use_sample_identifier = false;
80
81 /*
82 * Set the evsel leader links before we configure attributes,
83 * since some might depend on this info.
84 */
85 if (opts->group)
86 perf_evlist__set_leader(evlist);
87
88 if (evlist->cpus->map[0] < 0)
89 opts->no_inherit = true;
90
91 list_for_each_entry(evsel, &evlist->entries, node)
92 perf_evsel__config(evsel, opts);
93
94 if (evlist->nr_entries > 1) {
95 struct perf_evsel *first = perf_evlist__first(evlist);
96
97 list_for_each_entry(evsel, &evlist->entries, node) {
98 if (evsel->attr.sample_type == first->attr.sample_type)
99 continue;
100 use_sample_identifier = perf_can_sample_identifier();
101 break;
102 }
103 list_for_each_entry(evsel, &evlist->entries, node)
104 perf_evsel__set_sample_id(evsel, use_sample_identifier);
105 }
106
107 perf_evlist__set_id_pos(evlist);
108}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index de16a7736859..07642a7b9346 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -739,7 +739,7 @@ static void perf_session__print_tstamp(struct perf_session *session,
739 union perf_event *event, 739 union perf_event *event,
740 struct perf_sample *sample) 740 struct perf_sample *sample)
741{ 741{
742 u64 sample_type = perf_evlist__sample_type(session->evlist); 742 u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);
743 743
744 if (event->header.type != PERF_RECORD_SAMPLE && 744 if (event->header.type != PERF_RECORD_SAMPLE &&
745 !perf_evlist__sample_id_all(session->evlist)) { 745 !perf_evlist__sample_id_all(session->evlist)) {
@@ -840,7 +840,8 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
840 840
841static struct machine * 841static struct machine *
842 perf_session__find_machine_for_cpumode(struct perf_session *session, 842 perf_session__find_machine_for_cpumode(struct perf_session *session,
843 union perf_event *event) 843 union perf_event *event,
844 struct perf_sample *sample)
844{ 845{
845 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 846 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
846 847
@@ -852,7 +853,7 @@ static struct machine *
852 if (event->header.type == PERF_RECORD_MMAP) 853 if (event->header.type == PERF_RECORD_MMAP)
853 pid = event->mmap.pid; 854 pid = event->mmap.pid;
854 else 855 else
855 pid = event->ip.pid; 856 pid = sample->pid;
856 857
857 return perf_session__findnew_machine(session, pid); 858 return perf_session__findnew_machine(session, pid);
858 } 859 }
@@ -958,7 +959,8 @@ static int perf_session_deliver_event(struct perf_session *session,
958 hists__inc_nr_events(&evsel->hists, event->header.type); 959 hists__inc_nr_events(&evsel->hists, event->header.type);
959 } 960 }
960 961
961 machine = perf_session__find_machine_for_cpumode(session, event); 962 machine = perf_session__find_machine_for_cpumode(session, event,
963 sample);
962 964
963 switch (event->header.type) { 965 switch (event->header.type) {
964 case PERF_RECORD_SAMPLE: 966 case PERF_RECORD_SAMPLE:
@@ -997,22 +999,6 @@ static int perf_session_deliver_event(struct perf_session *session,
997 } 999 }
998} 1000}
999 1001
1000static int perf_session__preprocess_sample(struct perf_session *session,
1001 union perf_event *event, struct perf_sample *sample)
1002{
1003 if (event->header.type != PERF_RECORD_SAMPLE ||
1004 !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
1005 return 0;
1006
1007 if (!ip_callchain__valid(sample->callchain, event)) {
1008 pr_debug("call-chain problem with event, skipping it.\n");
1009 ++session->stats.nr_invalid_chains;
1010 session->stats.total_invalid_chains += sample->period;
1011 return -EINVAL;
1012 }
1013 return 0;
1014}
1015
1016static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1002static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
1017 struct perf_tool *tool, u64 file_offset) 1003 struct perf_tool *tool, u64 file_offset)
1018{ 1004{
@@ -1075,10 +1061,6 @@ static int perf_session__process_event(struct perf_session *session,
1075 if (ret) 1061 if (ret)
1076 return ret; 1062 return ret;
1077 1063
1078 /* Preprocess sample records - precheck callchains */
1079 if (perf_session__preprocess_sample(session, event, &sample))
1080 return 0;
1081
1082 if (tool->ordered_samples) { 1064 if (tool->ordered_samples) {
1083 ret = perf_session_queue_event(session, event, &sample, 1065 ret = perf_session_queue_event(session, event, &sample,
1084 file_offset); 1066 file_offset);
@@ -1099,7 +1081,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
1099 1081
1100struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1082struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1101{ 1083{
1102 return machine__findnew_thread(&session->machines.host, pid); 1084 return machine__findnew_thread(&session->machines.host, 0, pid);
1103} 1085}
1104 1086
1105static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1087static struct thread *perf_session__register_idle_thread(struct perf_session *self)