perf tools: some fixes and tweaks
Adrian Hunter
reviewerv13 cover perf tools: some fixes and tweaks
Hi
Here are some fixes and tweaks to perf tools (version 13).
Changes in V13:
perf tools: allow non-matching sample types
Moved to be the last patch
perf tools: add pid to struct thread
Dropped since its been applied
perf tools: add support for PERF_SAMPLE_IDENTFIER
Subsumed most of 'perf tools: allow non-matching sample types'
Changes in V12:
perf tools: re-implement debug print function for linking python/perf.so
Dropped since its been applied
perf tools: add debug prints
Dropped since its been applied
perf tools: allow non-matching sample types
Do not call perf_evlist__set_id_pos() when adding events other than the first Do not use matching_sample_types
perf: make events stream always parsable
Added Peter's missing Ack
Added Stephane's Tested-by
perf tools: add missing 'abi' member to 'struct regs_dump'
Added Jiri's Ack
Changes in V11:
perf tools: re-implement debug print function for linking python/perf.so
New patch split from "perf tools: add debug prints"
perf tools: add debug prints
Changed to use graph_dotted_line
Moved python/link changes to separate patch
Added Namhyung's Ack
perf tools: change machine__findnew_thread() to set thread pid
Added explanation of main thread lookup to commit message
perf tools: tidy up sample parsing overflow checking
Added Jiri's Ack
perf tools: remove unnecessary callchain validation
Added Namhyung's Ack
perf tools: remove references to struct ip_event
Added Namhyung's Ack
perf tools: move perf_evlist__config() to a new source file
Added Namhyung's Ack
perf tools: add missing 'abi' member to 'struct regs_dump'
New patch
perf tools: expand perf_event__synthesize_sample()
Adjusted for new 'abi' member of 'struct regs_dump'
perf tools: add a function to calculate sample event size
Adjusted for new 'abi' member of 'struct regs_dump'
perf tools: add a sample parsing test
Adjusted for new 'abi' member of 'struct regs_dump'
Changes in V10:
Re-based on:
perf/core branch of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git
commit 207353be1574027c151609a31167ac5919a056c8: perf tools: Remove filter parameter of thread__find_addr_map()
perf tools: add debug prints
Changed to use macros
perf tools: add pid to struct thread
Added David's Ack
perf tools: change machine__findnew_thread() to set thread pid
Added David's Ack
perf tools: remove references to struct ip_event
Also remove from hists_link.c
perf tools: move struct ip_event
Dropped since it is covered by "perf tools: remove references to struct ip_event"
perf tools: add a sample parsing test
Fix missing sample comparison for PERF_SAMPLE_READ
Changes in V9:
perf: Update perf_event_type documentation
Dropped since its been applied
perf tools: tidy up sample parsing overflow checking
Changed to use a single overflow function Updated for PERF_SAMPLE_READ
perf: make events stream always parsable
Added more about sample parsing to the commit message
perf tools: add support for PERF_SAMPLE_IDENTFIER
When selecting PERF_SAMPLE_IDENTFIER, ensure PERF_SAMPLE_ID is deselected
perf tools: expand perf_event__synthesize_sample()
Updated for PERF_SAMPLE_READ
perf tools: add a function to calculate sample event size
Updated for PERF_SAMPLE_READ
perf tools: add a sample parsing test
Updated for PERF_SAMPLE_READ
Changes in V8:
perf tools: add debug prints
Fixed Python link errors
perf tools: move perf_evlist__config() to a new source file
New Patch to avoid Python link errors
perf tools: add support for PERF_SAMPLE_IDENTFIER
Adjustments due to patch above
Changes in V7:
perf: Update perf_event_type documentation
Proposed new patch from Peter Zijlstra
perf: make events stream always parsable
Adjustments due to patch above
perf tools: tidy up sample parsing overflow checking
Change to a single overflow function Amend comment
perf tools: add a function to calculate sample event size
New patch
perf tools: add a sample parsing test
Amended to use sample event size calculation
Changes in V6:
Some checkpatch fixes
perf: make events stream always parsable
Add sample format comments
Changes in V5:
Re-based to Arnaldo's tree and dropped already applied patches:
perf tools: remove unused parameter
perf tools: fix missing tool parameter
perf tools: fix missing 'finished_round'
perf tools: fix parse_events_terms() segfault on error path perf tools: fix new_term() missing free on error path perf tools: add const specifier to perf_pmu__find name parameter perf tools: tidy duplicated munmap code
perf tools: validate perf event header size
perf tools: add debug prints
Changed to perf_event_attr__fprintf()
perf tools: add pid to struct thread
Always set the pid, even if a pid is already set
perf tools: change machine__findnew_thread() to set thread pid
Replaces: perf tools: change "machine" functions to set thread pid
perf tools: add support for PERF_SAMPLE_IDENTFIER
Only use PERF_SAMPLE_IDENTFIER if sample types are different
perf tools: expand perf_event__synthesize_sample()
New patch in preparation of a sample parsing test
perf tools: add a sample parsing test
New patch
Changes in V4:
I added kernel support for matching sample types via PERF_SAMPLE_IDENTIFIER. perf tools support for that required first fixing some other things.
perf tools: fix parse_events_terms() freeing local variable on error path
Dropped - covered by David Ahern
perf tools: struct thread has a tid not a pid
Added ack by David Ahern
perf tools: add pid to struct thread
Remove unused function
perf tools: fix missing increment in sample parsing
New patch
perf tools: tidy up sample parsing overflow checking
New patch
perf tools: remove unnecessary callchain validation
New patch
perf tools: remove references to struct ip_event
New patch
perf tools: move struct ip_event
New patch
perf: make events stream always parsable
New patch
perf tools: add support for PERF_SAMPLE_IDENTFIER
New patch
Changes in V3:
perf tools: add pid to struct thread
Split into 2 patches
perf tools: fix ppid in thread__fork()
Dropped for now
Changes in V2:
perf tools: fix missing tool parameter
Fixed one extra occurrence
perf tools: fix parse_events_terms() freeing local variable on error path
Made "freeing" code into a new function
perf tools: validate perf event header size
Corrected byte-swapping
perf tools: allow non-matching sample types
Added comments
Fixed id_pos calculation
id_pos/is_pos updated whenever sample_type changes Removed perf_evlist__sample_type()
Added __perf_evlist__combined_sample_type()
Added perf_evlist__combined_sample_type()
Added perf_evlist__make_sample_types_compatible()
Added ack's to patches acked by Jiri Olsa
Adrian Hunter (12):
perf tools: change machine__findnew_thread() to set thread pid perf tools: tidy up sample parsing overflow checking perf tools: remove unnecessary callchain validation perf tools: remove references to struct ip_event
perf: make events stream always parsable
perf tools: move perf_evlist__config() to a new source file perf tools: add support for PERF_SAMPLE_IDENTFIER perf tools: add missing 'abi' member to 'struct regs_dump' perf tools: expand perf_event__synthesize_sample() perf tools: add a function to calculate sample event size perf tools: add a sample parsing test
perf tools: allow non-matching sample types
include/uapi/linux/perf_event.h | 27 ++- kernel/events/core.c | 11 +- tools/perf/Makefile | 2 + tools/perf/builtin-inject.c | 8 +- tools/perf/builtin-kmem.c | 3 +- tools/perf/builtin-kvm.c | 2 +- tools/perf/builtin-lock.c | 3 +- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 20 +- tools/perf/builtin-script.c | 3 +- tools/perf/builtin-top.c | 11 +- tools/perf/builtin-trace.c | 10 +- tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/code-reading.c | 4 +- tools/perf/tests/hists_link.c | 23 +-- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/sample-parsing.c | 316 +++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/build-id.c | 11 +- tools/perf/util/callchain.c | 8 - tools/perf/util/callchain.h | 5 - tools/perf/util/event.c | 5 +- tools/perf/util/event.h | 34 ++-- tools/perf/util/evlist.c | 142 ++++++++++--- tools/perf/util/evlist.h | 9 +- tools/perf/util/evsel.c | 405 +++++++++++++++++++++++++++++++++----- tools/perf/util/evsel.h | 14 +- tools/perf/util/machine.c | 22 ++- tools/perf/util/machine.h | 3 +- tools/perf/util/record.c | 111 +++++++++++ tools/perf/util/session.c | 32 +-- 32 files changed, 1066 insertions(+), 189 deletions(-) create mode 100644 tools/perf/tests/sample-parsing.c create mode 100644 tools/perf/util/record.c
Regards
Adrian
Adrian Hunter
reviewerPATCH v13 1/12 perf tools: change machine__findnew_thread() to set thread pid
Add a new parameter for 'pid' to machine__findnew_thread(). Change callers to pass 'pid' when it is known.
Note that callers sometimes want to find the main thread which has the memory maps. The main thread has tid == pid so the usage in that case is:
machine__findnew_thread(machine, pid, pid)
whereas the usage to find the specific thread is:
machine__findnew_thread(machine, pid, tid)
--- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kmem.c | 3 ++- tools/perf/builtin-kvm.c | 2 +- tools/perf/builtin-lock.c | 3 ++- tools/perf/builtin-sched.c | 20 +++++++++++--------- tools/perf/builtin-script.c | 3 ++- tools/perf/builtin-trace.c | 10 +++++++--- tools/perf/tests/code-reading.c | 4 ++-- tools/perf/tests/hists_link.c | 3 ++- tools/perf/util/build-id.c | 7 +++++-- tools/perf/util/event.c | 3 ++- tools/perf/util/machine.c | 22 +++++++++++++++------- tools/perf/util/machine.h | 3 ++- tools/perf/util/session.c | 2 +- 14 files changed, 55 insertions(+), 32 deletions(-)
tools/perf/builtin-inject.c +1 -1
@@ -198,7 +198,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; - thread =machine__findnew_thread (machine, event->ip.pid); + thread =machine__findnew_thread (machine, event->ip.pid, event->ip.pid);if (thread ==NULL ) {pr_err ("problem processing %d event, skipping it.\n" , event->header.type);
tools/perf/builtin-kmem.c +2 -1
@@ -305,7 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.pid, + event->ip.pid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-kvm.c +1 -1
@@ -815,7 +815,7 @@ static int process_sample_event(struct perf_tool *tool,if (skip_sample (kvm, sample))return 0 ; - thread =machine__findnew_thread (machine, sample->tid); + thread =machine__findnew_thread (machine, sample->pid, sample->tid);if (thread ==NULL ) {pr_debug ("problem processing %d event, skipping it.\n" , event->header.type);
tools/perf/builtin-lock.c +2 -1
@@ -805,7 +805,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, sample->tid); + struct thread *thread = machine__findnew_thread(machine, sample->pid, + sample->tid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-sched.c +11 -9
@@ -724,8 +724,10 @@ static int replay_fork_event(struct perf_sched *sched, {struct thread *child, *parent; - child =machine__findnew_thread (machine, event->fork.tid); - parent =machine__findnew_thread (machine, event->fork.ptid); + child =machine__findnew_thread (machine, event->fork.pid, + event->fork.tid); + parent =machine__findnew_thread (machine, event->fork.ppid, + event->fork.ptid);if (child ==NULL || parent ==NULL ) { 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,return -1 ; } - sched_out =machine__findnew_thread (machine, prev_pid); - sched_in =machine__findnew_thread (machine, next_pid); + sched_out =machine__findnew_thread (machine,0 , prev_pid); + sched_in =machine__findnew_thread (machine,0 , next_pid); out_events =thread_atoms_search (&sched->atom_root, sched_out, &sched->cmp_pid);if (!out_events) {
@@ -978,7 +980,7 @@ static int latency_runtime_event(struct perf_sched *sched, {const u32 pid =perf_evsel__intval (evsel, sample,"pid" );const u64 runtime =perf_evsel__intval (evsel, sample,"runtime" ); -struct thread *thread =machine__findnew_thread (machine, pid); +struct thread *thread =machine__findnew_thread (machine,0 , pid);struct work_atoms *atoms =thread_atoms_search (&sched->atom_root, thread, &sched->cmp_pid);u64 timestamp = sample->time;int cpu = sample->cpu;
@@ -1016,7 +1018,7 @@ static int latency_wakeup_event(struct perf_sched *sched,if (!success)return 0 ; - wakee =machine__findnew_thread (machine, pid); + wakee =machine__findnew_thread (machine,0 , pid); atoms =thread_atoms_search (&sched->atom_root, wakee, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, wakee))
@@ -1070,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,if (sched->profile_cpu ==-1 )return 0 ; - migrant =machine__findnew_thread (machine, pid); + migrant =machine__findnew_thread (machine,0 , pid); atoms =thread_atoms_search (&sched->atom_root, migrant, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, migrant))
@@ -1289,8 +1291,8 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,return -1 ; } - sched_out =machine__findnew_thread (machine, prev_pid); - sched_in =machine__findnew_thread (machine, next_pid); + sched_out =machine__findnew_thread (machine,0 , prev_pid); + sched_in =machine__findnew_thread (machine,0 , next_pid); sched->curr_thread[this_cpu] = sched_in;
tools/perf/builtin-script.c +2 -1
@@ -501,7 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, struct machine *machine) {struct addr_location al; -struct thread *thread =machine__findnew_thread (machine, event->ip.tid); +struct thread *thread =machine__findnew_thread (machine, event->ip.pid, + event->ip.tid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-trace.c +7 -3
@@ -518,7 +518,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,if (sc->filtered)return 0 ; - thread =machine__findnew_thread (&trace->host, sample->tid); + thread =machine__findnew_thread (&trace->host, sample->pid, + sample->tid); ttrace =thread__trace (thread, trace->output);if (ttrace ==NULL )return -1 ;
@@ -569,7 +570,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,if (sc->filtered)return 0 ; - thread =machine__findnew_thread (&trace->host, sample->tid); + thread =machine__findnew_thread (&trace->host, sample->pid, + sample->tid); ttrace =thread__trace (thread, trace->output);if (ttrace ==NULL )return -1 ;
@@ -625,7 +627,9 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs {u64 runtime =perf_evsel__intval (evsel, sample,"runtime" );double runtime_ms = (double )runtime /NSEC_PER_MSEC ; -struct thread *thread =machine__findnew_thread (&trace->host, sample->tid); +struct thread *thread =machine__findnew_thread (&trace->host, + sample->pid, + sample->tid);struct thread_trace *ttrace =thread__trace (thread, trace->output);if (ttrace ==NULL )
tools/perf/tests/code-reading.c +2 -2
@@ -257,7 +257,7 @@ static int process_sample_event(struct machine *machine,return -1 ; } - thread =machine__findnew_thread (machine, sample.pid); + thread =machine__findnew_thread (machine, sample.pid, sample.pid);if (!thread) {pr_debug ("machine__findnew_thread failed\n" );return -1 ;
@@ -446,7 +446,7 @@ static int do_test_code_reading(bool try_kcore) goto out_err; } - thread =machine__findnew_thread (machine, pid); + thread =machine__findnew_thread (machine, pid, pid);if (!thread) {pr_debug ("machine__findnew_thread failed\n" ); goto out_err;
tools/perf/tests/hists_link.c +2 -1
@@ -88,7 +88,8 @@ static struct machine *setup_fake_machine(struct machines *machines)for (i =0 ; i <ARRAY_SIZE (fake_threads); i++) {struct thread *thread; - thread =machine__findnew_thread (machine, fake_threads[i].pid); + thread =machine__findnew_thread (machine, fake_threads[i].pid, + fake_threads[i].pid);if (thread ==NULL ) goto out;
tools/perf/util/build-id.c +5 -2
@@ -24,7 +24,8 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, {struct addr_location al;u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, event->ip.pid, + event->ip.pid);if (thread ==NULL ) { pr_err("problem processing %d event, skipping it.\n",
@@ -47,7 +48,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, __maybe_unused, struct machine *machine) { -struct thread *thread =machine__findnew_thread (machine, event->fork.tid); +struct thread *thread =machine__findnew_thread (machine, + event->fork.pid, + event->fork.tid);dump_printf ("(%d:%d):(%d:%d)\n" , event->fork.pid, event->fork.tid, event->fork.ppid, event->fork.ptid);
tools/perf/util/event.c +2 -1
@@ -686,7 +686,8 @@ int perf_event__preprocess_sample(const union perf_event *event, struct perf_sample *sample) {u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, event->ip.pid, + event->ip.pid);if (thread ==NULL )return -1 ;
tools/perf/util/machine.c +15 -7
@@ -32,7 +32,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)return -ENOMEM ;if (pid !=HOST_KERNEL_ID ) { -struct thread *thread =machine__findnew_thread (machine, pid); +struct thread *thread =machine__findnew_thread (machine,0 , + pid);char comm[64 ];if (thread ==NULL )
@@ -302,9 +303,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,return th; } -struct thread *machine__findnew_thread (struct machine *machine,pid_t tid) +struct thread *machine__findnew_thread (struct machine *machine,pid_t pid, +pid_t tid) { -return __machine__findnew_thread (machine,0 , tid, true); +return __machine__findnew_thread (machine, pid, tid, true); }struct 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)int machine__process_comm_event (struct machine *machine,union perf_event *event) { -struct thread *thread =machine__findnew_thread (machine, event->comm.tid); +struct thread *thread =machine__findnew_thread (machine, + event->comm.pid, + event->comm.tid);if (dump_trace)perf_event__fprintf_comm (event, stdout);
@@ -1012,7 +1016,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *eventreturn 0 ; } - thread =machine__findnew_thread (machine, event->mmap.pid); + thread =machine__findnew_thread (machine, event->mmap.pid, + event->mmap.pid);if (thread ==NULL ) goto out_problem;
@@ -1051,13 +1056,16 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)int machine__process_fork_event (struct machine *machine,union perf_event *event) {struct thread *thread =machine__find_thread (machine, event->fork.tid); -struct thread *parent =machine__findnew_thread (machine, event->fork.ptid); +struct thread *parent =machine__findnew_thread (machine, + event->fork.ppid, + event->fork.ptid);/* if a thread currently exists for the thread id remove it */ if (thread !=NULL )machine__remove_thread (machine, thread); - thread =machine__findnew_thread (machine, event->fork.tid); + thread =machine__findnew_thread (machine, event->fork.pid, + event->fork.tid);if (dump_trace)perf_event__fprintf_task (event, stdout);
tools/perf/util/machine.h +2 -1
@@ -106,7 +106,8 @@ static inline bool machine__is_host(struct machine *machine)return machine ? machine->pid ==HOST_KERNEL_ID : false; } -struct thread *machine__findnew_thread (struct machine *machine,pid_t tid); +struct thread *machine__findnew_thread (struct machine *machine,pid_t pid, +pid_t tid);size_t machine__fprintf (struct machine *machine,FILE *fp);
tools/perf/util/session.c +1 -1
@@ -1099,7 +1099,7 @@ void perf_event_header__bswap(struct perf_event_header *self)struct thread *perf_session__findnew (struct perf_session *session,pid_t pid) { -return machine__findnew_thread (&session->machines.host, pid); +return machine__findnew_thread (&session->machines.host,0 , pid); }static struct thread *perf_session__register_idle_thread (struct perf_session *self)
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: change machine__findnew_thread() to set thread pid
perf tools: change machine__findnew_thread() to set thread pid
Commit-ID: 314add6b1f045b59ca39683bd0cbc5310cd203f2 Gitweb: http://git.kernel.org/tip/314add6b1f045b59ca39683bd0cbc5310cd203f2 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:03 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 11:51:31 -0300
perf tools: change machine__findnew_thread() to set thread pid
Add a new parameter for 'pid' to machine__findnew_thread(). Change callers to pass 'pid' when it is known.
Note that callers sometimes want to find the main thread which has the memory maps. The main thread has tid == pid so the usage in that case is:
machine__findnew_thread(machine, pid, pid)
whereas the usage to find the specific thread is:
machine__findnew_thread(machine, pid, tid)
--- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kmem.c | 3 ++- tools/perf/builtin-kvm.c | 2 +- tools/perf/builtin-lock.c | 3 ++- tools/perf/builtin-sched.c | 20 +++++++++++--------- tools/perf/builtin-script.c | 3 ++- tools/perf/builtin-trace.c | 10 +++++++--- tools/perf/tests/code-reading.c | 4 ++-- tools/perf/tests/hists_link.c | 3 ++- tools/perf/util/build-id.c | 7 +++++-- tools/perf/util/event.c | 3 ++- tools/perf/util/machine.c | 22 +++++++++++++++------- tools/perf/util/machine.h | 3 ++- tools/perf/util/session.c | 2 +- 14 files changed, 55 insertions(+), 32 deletions(-)
tools/perf/builtin-inject.c +1 -1
@@ -198,7 +198,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; - thread =machine__findnew_thread (machine, event->ip.pid); + thread =machine__findnew_thread (machine, event->ip.pid, event->ip.pid);if (thread ==NULL ) {pr_err ("problem processing %d event, skipping it.\n" , event->header.type);
tools/perf/builtin-kmem.c +2 -1
@@ -305,7 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.pid, + event->ip.pid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-kvm.c +1 -1
@@ -815,7 +815,7 @@ static int process_sample_event(struct perf_tool *tool,if (skip_sample (kvm, sample))return 0 ; - thread =machine__findnew_thread (machine, sample->tid); + thread =machine__findnew_thread (machine, sample->pid, sample->tid);if (thread ==NULL ) {pr_debug ("problem processing %d event, skipping it.\n" , event->header.type);
tools/perf/builtin-lock.c +2 -1
@@ -805,7 +805,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, sample->tid); + struct thread *thread = machine__findnew_thread(machine, sample->pid, + sample->tid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-sched.c +11 -9
@@ -724,8 +724,10 @@ static int replay_fork_event(struct perf_sched *sched, {struct thread *child, *parent; - child =machine__findnew_thread (machine, event->fork.tid); - parent =machine__findnew_thread (machine, event->fork.ptid); + child =machine__findnew_thread (machine, event->fork.pid, + event->fork.tid); + parent =machine__findnew_thread (machine, event->fork.ppid, + event->fork.ptid);if (child ==NULL || parent ==NULL ) { 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,return -1 ; } - sched_out =machine__findnew_thread (machine, prev_pid); - sched_in =machine__findnew_thread (machine, next_pid); + sched_out =machine__findnew_thread (machine,0 , prev_pid); + sched_in =machine__findnew_thread (machine,0 , next_pid); out_events =thread_atoms_search (&sched->atom_root, sched_out, &sched->cmp_pid);if (!out_events) {
@@ -978,7 +980,7 @@ static int latency_runtime_event(struct perf_sched *sched, {const u32 pid =perf_evsel__intval (evsel, sample,"pid" );const u64 runtime =perf_evsel__intval (evsel, sample,"runtime" ); -struct thread *thread =machine__findnew_thread (machine, pid); +struct thread *thread =machine__findnew_thread (machine,0 , pid);struct work_atoms *atoms =thread_atoms_search (&sched->atom_root, thread, &sched->cmp_pid);u64 timestamp = sample->time;int cpu = sample->cpu;
@@ -1016,7 +1018,7 @@ static int latency_wakeup_event(struct perf_sched *sched,if (!success)return 0 ; - wakee =machine__findnew_thread (machine, pid); + wakee =machine__findnew_thread (machine,0 , pid); atoms =thread_atoms_search (&sched->atom_root, wakee, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, wakee))
@@ -1070,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,if (sched->profile_cpu ==-1 )return 0 ; - migrant =machine__findnew_thread (machine, pid); + migrant =machine__findnew_thread (machine,0 , pid); atoms =thread_atoms_search (&sched->atom_root, migrant, &sched->cmp_pid);if (!atoms) {if (thread_atoms_insert (sched, migrant))
@@ -1289,8 +1291,8 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,return -1 ; } - sched_out =machine__findnew_thread (machine, prev_pid); - sched_in =machine__findnew_thread (machine, next_pid); + sched_out =machine__findnew_thread (machine,0 , prev_pid); + sched_in =machine__findnew_thread (machine,0 , next_pid); sched->curr_thread[this_cpu] = sched_in;
tools/perf/builtin-script.c +2 -1
@@ -501,7 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, struct machine *machine) {struct addr_location al; -struct thread *thread =machine__findnew_thread (machine, event->ip.tid); +struct thread *thread =machine__findnew_thread (machine, event->ip.pid, + event->ip.tid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-trace.c +7 -3
@@ -521,7 +521,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,if (sc->filtered)return 0 ; - thread =machine__findnew_thread (&trace->host, sample->tid); + thread =machine__findnew_thread (&trace->host, sample->pid, + sample->tid); ttrace =thread__trace (thread, trace->output);if (ttrace ==NULL )return -1 ;
@@ -572,7 +573,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,if (sc->filtered)return 0 ; - thread =machine__findnew_thread (&trace->host, sample->tid); + thread =machine__findnew_thread (&trace->host, sample->pid, + sample->tid); ttrace =thread__trace (thread, trace->output);if (ttrace ==NULL )return -1 ;
@@ -628,7 +630,9 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs {u64 runtime =perf_evsel__intval (evsel, sample,"runtime" );double runtime_ms = (double )runtime /NSEC_PER_MSEC ; -struct thread *thread =machine__findnew_thread (&trace->host, sample->tid); +struct thread *thread =machine__findnew_thread (&trace->host, + sample->pid, + sample->tid);struct thread_trace *ttrace =thread__trace (thread, trace->output);if (ttrace ==NULL )
tools/perf/tests/code-reading.c +2 -2
@@ -257,7 +257,7 @@ static int process_sample_event(struct machine *machine,return -1 ; } - thread =machine__findnew_thread (machine, sample.pid); + thread =machine__findnew_thread (machine, sample.pid, sample.pid);if (!thread) {pr_debug ("machine__findnew_thread failed\n" );return -1 ;
@@ -446,7 +446,7 @@ static int do_test_code_reading(bool try_kcore) goto out_err; } - thread =machine__findnew_thread (machine, pid); + thread =machine__findnew_thread (machine, pid, pid);if (!thread) {pr_debug ("machine__findnew_thread failed\n" ); goto out_err;
tools/perf/tests/hists_link.c +2 -1
@@ -88,7 +88,8 @@ static struct machine *setup_fake_machine(struct machines *machines)for (i =0 ; i <ARRAY_SIZE (fake_threads); i++) {struct thread *thread; - thread =machine__findnew_thread (machine, fake_threads[i].pid); + thread =machine__findnew_thread (machine, fake_threads[i].pid, + fake_threads[i].pid);if (thread ==NULL ) goto out;
tools/perf/util/build-id.c +5 -2
@@ -24,7 +24,8 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, {struct addr_location al;u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, event->ip.pid, + event->ip.pid);if (thread ==NULL ) { pr_err("problem processing %d event, skipping it.\n",
@@ -47,7 +48,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, __maybe_unused, struct machine *machine) { -struct thread *thread =machine__findnew_thread (machine, event->fork.tid); +struct thread *thread =machine__findnew_thread (machine, + event->fork.pid, + event->fork.tid);dump_printf ("(%d:%d):(%d:%d)\n" , event->fork.pid, event->fork.tid, event->fork.ppid, event->fork.ptid);
tools/perf/util/event.c +2 -1
@@ -686,7 +686,8 @@ int perf_event__preprocess_sample(const union perf_event *event, struct perf_sample *sample) {u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, event->ip.pid, + event->ip.pid);if (thread ==NULL )return -1 ;
tools/perf/util/machine.c +15 -7
@@ -32,7 +32,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)return -ENOMEM ;if (pid !=HOST_KERNEL_ID ) { -struct thread *thread =machine__findnew_thread (machine, pid); +struct thread *thread =machine__findnew_thread (machine,0 , + pid);char comm[64 ];if (thread ==NULL )
@@ -302,9 +303,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,return th; } -struct thread *machine__findnew_thread (struct machine *machine,pid_t tid) +struct thread *machine__findnew_thread (struct machine *machine,pid_t pid, +pid_t tid) { -return __machine__findnew_thread (machine,0 , tid, true); +return __machine__findnew_thread (machine, pid, tid, true); }struct 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)int machine__process_comm_event (struct machine *machine,union perf_event *event) { -struct thread *thread =machine__findnew_thread (machine, event->comm.tid); +struct thread *thread =machine__findnew_thread (machine, + event->comm.pid, + event->comm.tid);if (dump_trace)perf_event__fprintf_comm (event, stdout);
@@ -1012,7 +1016,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *eventreturn 0 ; } - thread =machine__findnew_thread (machine, event->mmap.pid); + thread =machine__findnew_thread (machine, event->mmap.pid, + event->mmap.pid);if (thread ==NULL ) goto out_problem;
@@ -1051,13 +1056,16 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)int machine__process_fork_event (struct machine *machine,union perf_event *event) {struct thread *thread =machine__find_thread (machine, event->fork.tid); -struct thread *parent =machine__findnew_thread (machine, event->fork.ptid); +struct thread *parent =machine__findnew_thread (machine, + event->fork.ppid, + event->fork.ptid);/* if a thread currently exists for the thread id remove it */ if (thread !=NULL )machine__remove_thread (machine, thread); - thread =machine__findnew_thread (machine, event->fork.tid); + thread =machine__findnew_thread (machine, event->fork.pid, + event->fork.tid);if (dump_trace)perf_event__fprintf_task (event, stdout);
tools/perf/util/machine.h +2 -1
@@ -106,7 +106,8 @@ static inline bool machine__is_host(struct machine *machine)return machine ? machine->pid ==HOST_KERNEL_ID : false; } -struct thread *machine__findnew_thread (struct machine *machine,pid_t tid); +struct thread *machine__findnew_thread (struct machine *machine,pid_t pid, +pid_t tid);size_t machine__fprintf (struct machine *machine,FILE *fp);
tools/perf/util/session.c +1 -1
@@ -1099,7 +1099,7 @@ void perf_event_header__bswap(struct perf_event_header *self)struct thread *perf_session__findnew (struct perf_session *session,pid_t pid) { -return machine__findnew_thread (&session->machines.host, pid); +return machine__findnew_thread (&session->machines.host,0 , pid); }static struct thread *perf_session__register_idle_thread (struct perf_session *self)
Adrian Hunter
reviewerPATCH v13 2/12 perf tools: tidy up sample parsing overflow checking
In reply to Adrian HunterThe size of data retrieved from a sample event must be validated to ensure it does not go past the end of the event. That was being done sporadically and without considering integer overflows.
--- tools/perf/util/evsel.c | 112 ++++++++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 41 deletions(-)
tools/perf/util/evsel.c +71 -41
@@ -1131,24 +1131,30 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,return 0 ; } -static bool sample_overlap (const union perf_event *event, -const void *offset,u64 size) +static inline bool overflow (const void *endp,u16 max_size,const void *offset, +u64 size) { -const void *base = event; +return size > max_size || offset + size > endp; +} -if (offset + size > base + event->header.size) -return true; +#define OVERFLOW_CHECK (offset, size, max_size) \ + do { \ + if (overflow(endp, (max_size), (offset), (size))) \ + return -EFAULT; \ + } while (0) -return false; -} +#define OVERFLOW_CHECK_u64 (offset) \ + OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))int perf_evsel__parse_sample (struct perf_evsel *evsel,union perf_event *event,struct perf_sample *data) {u64 type = evsel->attr.sample_type; -u64 regs_user = evsel->attr.sample_regs_user;bool swapped = evsel->needs_swap;const u64 *array; +u16 max_size = event->header.size; +const void *endp = (void *)event + max_size; +u64 sz;/* * used for cross-endian analysis. See git commit 65014ab3
@@ -1170,6 +1176,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array = event->sample.array; +/* +* The evsel's sample_size is based on PERF_SAMPLE_MASK which includes +* up to PERF_SAMPLE_PERIOD. After that overflow() must be used to +* check the format does not go past the end of the event. +*/ if (evsel->sample_size +sizeof (event->header) > event->header.size)return -EFAULT ;
@@ -1235,6 +1246,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_READ ) {u64 read_format = evsel->attr.read_format; +OVERFLOW_CHECK_u64 (array);if (read_format &PERF_FORMAT_GROUP ) data->read.group.nr = *array;else
@@ -1243,41 +1255,51 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++;if (read_format &PERF_FORMAT_TOTAL_TIME_ENABLED ) { +OVERFLOW_CHECK_u64 (array); data->read.time_enabled = *array; array++; }if (read_format &PERF_FORMAT_TOTAL_TIME_RUNNING ) { +OVERFLOW_CHECK_u64 (array); data->read.time_running = *array; array++; }/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ if (read_format &PERF_FORMAT_GROUP ) { - data->read.group.values = (struct sample_read_value *) array; - array = (void *) array + data->read.group.nr * -sizeof (struct sample_read_value ); +const u64 max_group_nr =UINT64_MAX / +sizeof (struct sample_read_value ); + +if (data->read.group.nr > max_group_nr) +return -EFAULT ; + sz = data->read.group.nr * +sizeof (struct sample_read_value ); +OVERFLOW_CHECK (array, sz, max_size); + data->read.group.values = + (struct sample_read_value *)array; + array = (void *)array + sz; }else { +OVERFLOW_CHECK_u64 (array); data->read.one.id = *array; array++; } }if (type &PERF_SAMPLE_CALLCHAIN ) { -if (sample_overlap (event, array,sizeof (data->callchain->nr))) -return -EFAULT ; - - data->callchain = (struct ip_callchain *)array; +const u64 max_callchain_nr =UINT64_MAX /sizeof (u64); -if (sample_overlap (event, array, data->callchain->nr)) +OVERFLOW_CHECK_u64 (array); + data->callchain = (struct ip_callchain *)array++; +if (data->callchain->nr > max_callchain_nr)return -EFAULT ; - - array +=1 + data->callchain->nr; + sz = data->callchain->nr *sizeof (u64); +OVERFLOW_CHECK (array, sz, max_size); + array = (void *)array + sz; }if (type &PERF_SAMPLE_RAW ) { -const u64 *pdata; - +OVERFLOW_CHECK_u64 (array); u.val64 = *array;if (WARN_ONCE (swapped,"Endianness of raw data not corrected!\n" )) {
@@ -1286,65 +1308,73 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, u.val32[0 ] =bswap_32 (u.val32[0 ]); u.val32[1 ] =bswap_32 (u.val32[1 ]); } - -if (sample_overlap (event, array,sizeof (u32))) -return -EFAULT ; - data->raw_size = u.val32[0 ]; - pdata = (void *) array +sizeof (u32); - -if (sample_overlap (event, pdata, data->raw_size)) -return -EFAULT ; + array = (void *)array +sizeof (u32); - data->raw_data = (void *) pdata; - - array = (void *)array + data->raw_size +sizeof (u32); +OVERFLOW_CHECK (array, data->raw_size, max_size); + data->raw_data = (void *)array; + array = (void *)array + data->raw_size; }if (type &PERF_SAMPLE_BRANCH_STACK ) { -u64 sz; +const u64 max_branch_nr =UINT64_MAX / +sizeof (struct branch_entry ); - data->branch_stack = (struct branch_stack *)array; - array++;/* nr */ +OVERFLOW_CHECK_u64 (array); + data->branch_stack = (struct branch_stack *)array++; +if (data->branch_stack->nr > max_branch_nr) +return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); - sz /=sizeof (u64); - array += sz; +OVERFLOW_CHECK (array, sz, max_size); + array = (void *)array + sz; }if (type &PERF_SAMPLE_REGS_USER ) { +u64 avail; +/* First u64 tells us if we have any regs in sample. */ -u64 avail = *array++; +OVERFLOW_CHECK_u64 (array); + avail = *array++;if (avail) { +u64 regs_user = evsel->attr.sample_regs_user; + + sz =hweight_long (regs_user) *sizeof (u64); +OVERFLOW_CHECK (array, sz, max_size); data->user_regs.regs = (u64 *)array; - array +=hweight_long (regs_user); + array = (void *)array + sz; } }if (type &PERF_SAMPLE_STACK_USER ) { -u64 size = *array++; +OVERFLOW_CHECK_u64 (array); + sz = *array++; data->user_stack.offset = ((char *)(array -1 ) - (char *) event); -if (!size) { +if (!sz) { data->user_stack.size =0 ; }else { +OVERFLOW_CHECK (array, sz, max_size); data->user_stack.data = (char *)array; - array += size /sizeof (*array); + array = (void *)array + sz; +OVERFLOW_CHECK_u64 (array); data->user_stack.size = *array++; } } data->weight =0 ;if (type &PERF_SAMPLE_WEIGHT ) { +OVERFLOW_CHECK_u64 (array); data->weight = *array; array++; } data->data_src =PERF_MEM_DATA_SRC_NONE ;if (type &PERF_SAMPLE_DATA_SRC ) { +OVERFLOW_CHECK_u64 (array); data->data_src = *array; array++; }
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evsel: Tidy up sample parsing overflow checking
perf evsel: Tidy up sample parsing overflow checking
Commit-ID: 03b6ea9b91e0914caa847a1ade759af549555298 Gitweb: http://git.kernel.org/tip/03b6ea9b91e0914caa847a1ade759af549555298 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:04 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 15:10:02 -0300
perf evsel: Tidy up sample parsing overflow checking
The size of data retrieved from a sample event must be validated to ensure it does not go past the end of the event. That was being done sporadically and without considering integer overflows.
--- tools/perf/util/evsel.c | 112 ++++++++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 41 deletions(-)
tools/perf/util/evsel.c +71 -41
@@ -1131,24 +1131,30 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,return 0 ; } -static bool sample_overlap (const union perf_event *event, -const void *offset,u64 size) +static inline bool overflow (const void *endp,u16 max_size,const void *offset, +u64 size) { -const void *base = event; +return size > max_size || offset + size > endp; +} -if (offset + size > base + event->header.size) -return true; +#define OVERFLOW_CHECK (offset, size, max_size) \ + do { \ + if (overflow(endp, (max_size), (offset), (size))) \ + return -EFAULT; \ + } while (0) -return false; -} +#define OVERFLOW_CHECK_u64 (offset) \ + OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))int perf_evsel__parse_sample (struct perf_evsel *evsel,union perf_event *event,struct perf_sample *data) {u64 type = evsel->attr.sample_type; -u64 regs_user = evsel->attr.sample_regs_user;bool swapped = evsel->needs_swap;const u64 *array; +u16 max_size = event->header.size; +const void *endp = (void *)event + max_size; +u64 sz;/* * used for cross-endian analysis. See git commit 65014ab3
@@ -1170,6 +1176,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array = event->sample.array; +/* +* The evsel's sample_size is based on PERF_SAMPLE_MASK which includes +* up to PERF_SAMPLE_PERIOD. After that overflow() must be used to +* check the format does not go past the end of the event. +*/ if (evsel->sample_size +sizeof (event->header) > event->header.size)return -EFAULT ;
@@ -1235,6 +1246,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_READ ) {u64 read_format = evsel->attr.read_format; +OVERFLOW_CHECK_u64 (array);if (read_format &PERF_FORMAT_GROUP ) data->read.group.nr = *array;else
@@ -1243,41 +1255,51 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++;if (read_format &PERF_FORMAT_TOTAL_TIME_ENABLED ) { +OVERFLOW_CHECK_u64 (array); data->read.time_enabled = *array; array++; }if (read_format &PERF_FORMAT_TOTAL_TIME_RUNNING ) { +OVERFLOW_CHECK_u64 (array); data->read.time_running = *array; array++; }/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ if (read_format &PERF_FORMAT_GROUP ) { - data->read.group.values = (struct sample_read_value *) array; - array = (void *) array + data->read.group.nr * -sizeof (struct sample_read_value ); +const u64 max_group_nr =UINT64_MAX / +sizeof (struct sample_read_value ); + +if (data->read.group.nr > max_group_nr) +return -EFAULT ; + sz = data->read.group.nr * +sizeof (struct sample_read_value ); +OVERFLOW_CHECK (array, sz, max_size); + data->read.group.values = + (struct sample_read_value *)array; + array = (void *)array + sz; }else { +OVERFLOW_CHECK_u64 (array); data->read.one.id = *array; array++; } }if (type &PERF_SAMPLE_CALLCHAIN ) { -if (sample_overlap (event, array,sizeof (data->callchain->nr))) -return -EFAULT ; - - data->callchain = (struct ip_callchain *)array; +const u64 max_callchain_nr =UINT64_MAX /sizeof (u64); -if (sample_overlap (event, array, data->callchain->nr)) +OVERFLOW_CHECK_u64 (array); + data->callchain = (struct ip_callchain *)array++; +if (data->callchain->nr > max_callchain_nr)return -EFAULT ; - - array +=1 + data->callchain->nr; + sz = data->callchain->nr *sizeof (u64); +OVERFLOW_CHECK (array, sz, max_size); + array = (void *)array + sz; }if (type &PERF_SAMPLE_RAW ) { -const u64 *pdata; - +OVERFLOW_CHECK_u64 (array); u.val64 = *array;if (WARN_ONCE (swapped,"Endianness of raw data not corrected!\n" )) {
@@ -1286,65 +1308,73 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, u.val32[0 ] =bswap_32 (u.val32[0 ]); u.val32[1 ] =bswap_32 (u.val32[1 ]); } - -if (sample_overlap (event, array,sizeof (u32))) -return -EFAULT ; - data->raw_size = u.val32[0 ]; - pdata = (void *) array +sizeof (u32); - -if (sample_overlap (event, pdata, data->raw_size)) -return -EFAULT ; + array = (void *)array +sizeof (u32); - data->raw_data = (void *) pdata; - - array = (void *)array + data->raw_size +sizeof (u32); +OVERFLOW_CHECK (array, data->raw_size, max_size); + data->raw_data = (void *)array; + array = (void *)array + data->raw_size; }if (type &PERF_SAMPLE_BRANCH_STACK ) { -u64 sz; +const u64 max_branch_nr =UINT64_MAX / +sizeof (struct branch_entry ); - data->branch_stack = (struct branch_stack *)array; - array++;/* nr */ +OVERFLOW_CHECK_u64 (array); + data->branch_stack = (struct branch_stack *)array++; +if (data->branch_stack->nr > max_branch_nr) +return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); - sz /=sizeof (u64); - array += sz; +OVERFLOW_CHECK (array, sz, max_size); + array = (void *)array + sz; }if (type &PERF_SAMPLE_REGS_USER ) { +u64 avail; +/* First u64 tells us if we have any regs in sample. */ -u64 avail = *array++; +OVERFLOW_CHECK_u64 (array); + avail = *array++;if (avail) { +u64 regs_user = evsel->attr.sample_regs_user; + + sz =hweight_long (regs_user) *sizeof (u64); +OVERFLOW_CHECK (array, sz, max_size); data->user_regs.regs = (u64 *)array; - array +=hweight_long (regs_user); + array = (void *)array + sz; } }if (type &PERF_SAMPLE_STACK_USER ) { -u64 size = *array++; +OVERFLOW_CHECK_u64 (array); + sz = *array++; data->user_stack.offset = ((char *)(array -1 ) - (char *) event); -if (!size) { +if (!sz) { data->user_stack.size =0 ; }else { +OVERFLOW_CHECK (array, sz, max_size); data->user_stack.data = (char *)array; - array += size /sizeof (*array); + array = (void *)array + sz; +OVERFLOW_CHECK_u64 (array); data->user_stack.size = *array++; } } data->weight =0 ;if (type &PERF_SAMPLE_WEIGHT ) { +OVERFLOW_CHECK_u64 (array); data->weight = *array; array++; } data->data_src =PERF_MEM_DATA_SRC_NONE ;if (type &PERF_SAMPLE_DATA_SRC ) { +OVERFLOW_CHECK_u64 (array); data->data_src = *array; array++; }
Adrian Hunter
reviewerPATCH v13 3/12 perf tools: remove unnecessary callchain validation
In reply to Adrian HunterNow that the sample parsing correctly checks data sizes there is no reason for it to be done again for callchains.
--- tools/perf/util/callchain.c | 8 -------- tools/perf/util/callchain.h | 5 ----- tools/perf/util/session.c | 20 -------------------- 3 files changed, 33 deletions(-)
tools/perf/util/callchain.c +0 -8
@@ -21,14 +21,6 @@ __threadstruct callchain_cursor callchain_cursor; -bool ip_callchain__valid (struct ip_callchain *chain, -const union perf_event *event) -{ -unsigned int chain_size = event->header.size; - chain_size -= (unsigned long )&event->ip.__more_data - (unsigned long )event; -return chain->nr *sizeof (u64) <= chain_size; -} -#define chain_for_each_child (child, parent) \ list_for_each_entry(child, &parent->children, siblings)
tools/perf/util/callchain.h +0 -5
@@ -109,11 +109,6 @@ int callchain_append(struct callchain_root *root,int callchain_merge (struct callchain_cursor *cursor,struct callchain_root *dst,struct callchain_root *src); -struct ip_callchain ; -union perf_event ; - -bool ip_callchain__valid (struct ip_callchain *chain, -const union perf_event *event);/* * Initialize a cursor before adding entries inside, but keep * the previously allocated entries as a cache.
tools/perf/util/session.c +0 -20
@@ -997,22 +997,6 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__preprocess_sample (struct perf_session *session, -union perf_event *event,struct perf_sample *sample) -{ -if (event->header.type !=PERF_RECORD_SAMPLE || - !(perf_evlist__sample_type (session->evlist) &PERF_SAMPLE_CALLCHAIN )) -return 0 ; - -if (!ip_callchain__valid (sample->callchain, event)) { -pr_debug ("call-chain problem with event, skipping it.\n" ); - ++session->stats.nr_invalid_chains; - session->stats.total_invalid_chains += sample->period; -return -EINVAL ; - } -return 0 ; -} -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset) {
@@ -1075,10 +1059,6 @@ static int perf_session__process_event(struct perf_session *session,if (ret)return ret; -/* Preprocess sample records - precheck callchains */ -if (perf_session__preprocess_sample (session, event, &sample)) -return 0 ; -if (tool->ordered_samples) { ret =perf_session_queue_event (session, event, &sample, file_offset);
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf callchain: Remove unnecessary validation
perf callchain: Remove unnecessary validation
Commit-ID: 07940293ba7a43070cdebda952b0e6025d80a383 Gitweb: http://git.kernel.org/tip/07940293ba7a43070cdebda952b0e6025d80a383 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:05 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 15:11:29 -0300
perf callchain: Remove unnecessary validation
Now that the sample parsing correctly checks data sizes there is no reason for it to be done again for callchains.
--- tools/perf/util/callchain.c | 8 -------- tools/perf/util/callchain.h | 5 ----- tools/perf/util/session.c | 20 -------------------- 3 files changed, 33 deletions(-)
tools/perf/util/callchain.c +0 -8
@@ -21,14 +21,6 @@ __threadstruct callchain_cursor callchain_cursor; -bool ip_callchain__valid (struct ip_callchain *chain, -const union perf_event *event) -{ -unsigned int chain_size = event->header.size; - chain_size -= (unsigned long )&event->ip.__more_data - (unsigned long )event; -return chain->nr *sizeof (u64) <= chain_size; -} -#define chain_for_each_child (child, parent) \ list_for_each_entry(child, &parent->children, siblings)
tools/perf/util/callchain.h +0 -5
@@ -109,11 +109,6 @@ int callchain_append(struct callchain_root *root,int callchain_merge (struct callchain_cursor *cursor,struct callchain_root *dst,struct callchain_root *src); -struct ip_callchain ; -union perf_event ; - -bool ip_callchain__valid (struct ip_callchain *chain, -const union perf_event *event);/* * Initialize a cursor before adding entries inside, but keep * the previously allocated entries as a cache.
tools/perf/util/session.c +0 -20
@@ -997,22 +997,6 @@ static int perf_session_deliver_event(struct perf_session *session, } } -static int perf_session__preprocess_sample (struct perf_session *session, -union perf_event *event,struct perf_sample *sample) -{ -if (event->header.type !=PERF_RECORD_SAMPLE || - !(perf_evlist__sample_type (session->evlist) &PERF_SAMPLE_CALLCHAIN )) -return 0 ; - -if (!ip_callchain__valid (sample->callchain, event)) { -pr_debug ("call-chain problem with event, skipping it.\n" ); - ++session->stats.nr_invalid_chains; - session->stats.total_invalid_chains += sample->period; -return -EINVAL ; - } -return 0 ; -} -static int perf_session__process_user_event (struct perf_session *session,union perf_event *event,struct perf_tool *tool,u64 file_offset) {
@@ -1075,10 +1059,6 @@ static int perf_session__process_event(struct perf_session *session,if (ret)return ret; -/* Preprocess sample records - precheck callchains */ -if (perf_session__preprocess_sample (session, event, &sample)) -return 0 ; -if (tool->ordered_samples) { ret =perf_session_queue_event (session, event, &sample, file_offset);
Adrian Hunter
reviewerPATCH v13 4/12 perf tools: remove references to struct ip_event
In reply to Adrian Hunterstruct ip_event assumes fixed positions for ip, pid and tid. That is no longer true with the addition of PERF_SAMPLE_IDENTIFIER. The information is anyway in struct sample, so use that instead.
--- tools/perf/builtin-inject.c | 4 ++-- tools/perf/builtin-kmem.c | 4 ++-- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-script.c | 4 ++-- tools/perf/builtin-top.c | 11 ++++++----- tools/perf/tests/hists_link.c | 20 ++++++++------------ tools/perf/util/build-id.c | 8 ++++---- tools/perf/util/event.c | 6 +++--- tools/perf/util/event.h | 11 ----------- tools/perf/util/evsel.c | 4 ++-- tools/perf/util/session.c | 8 +++++--- 11 files changed, 35 insertions(+), 47 deletions(-)
tools/perf/builtin-inject.c +2 -2
@@ -198,7 +198,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; - thread =machine__findnew_thread (machine, event->ip.pid, event->ip.pid); + thread =machine__findnew_thread (machine, sample->pid, sample->pid);if (thread ==NULL ) {pr_err ("problem processing %d event, skipping it.\n" , event->header.type);
@@ -206,7 +206,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, }thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - event->ip.ip, &al); + sample->ip, &al);if (al.map !=NULL ) {if (!al.map->dso->hit) {
tools/perf/builtin-kmem.c +2 -2
@@ -305,8 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, event->ip.pid, - event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, sample->pid, + sample->pid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-mem.c +1 -1
@@ -94,7 +94,7 @@ dump_raw_samples(struct perf_tool *tool, symbol_conf.field_sep, sample->tid, symbol_conf.field_sep, - event->ip.ip, + sample->ip, symbol_conf.field_sep, sample->addr, symbol_conf.field_sep,
tools/perf/builtin-script.c +2 -2
@@ -501,8 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, struct machine *machine) {struct addr_location al; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid, - event->ip.tid); +struct thread *thread =machine__findnew_thread (machine, sample->pid, + sample->tid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-top.c +6 -5
@@ -689,7 +689,7 @@ static void perf_event__process_sample(struct perf_tool *tool, { struct perf_top *top = container_of(tool, struct perf_top, tool);struct symbol *parent =NULL ; -u64 ip = event->ip.ip; +u64 ip = sample->ip;struct addr_location al;int err;
@@ -699,10 +699,10 @@ static void perf_event__process_sample(struct perf_tool *tool,if (!seen) seen =intlist__new (NULL ); -if (!intlist__has_entry (seen, event->ip.pid)) { +if (!intlist__has_entry (seen, sample->pid)) {pr_err ("Can't find guest [%d]'s kernel information\n" , - event->ip.pid); -intlist__add (seen, event->ip.pid); + sample->pid); +intlist__add (seen, sample->pid); }return ; }
@@ -836,7 +836,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)break ;case PERF_RECORD_MISC_GUEST_KERNEL : ++top->guest_kernel_samples; - machine =perf_session__find_machine (session, event->ip.pid); + machine =perf_session__find_machine (session, + sample.pid);break ;case PERF_RECORD_MISC_GUEST_USER : ++top->guest_us_samples;
tools/perf/tests/hists_link.c +8 -12
@@ -211,15 +211,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)list_for_each_entry (evsel, &evlist->entries, node) {for (k =0 ; k <ARRAY_SIZE (fake_common_samples); k++) {const union perf_event event = { - .ip = { - .header = { - .misc =PERF_RECORD_MISC_USER , - }, - .pid = fake_common_samples[k].pid, - .ip = fake_common_samples[k].ip, + .header = { + .misc =PERF_RECORD_MISC_USER , }, }; + sample.pid = fake_common_samples[k].pid; + sample.ip = fake_common_samples[k].ip;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 ) goto out;
@@ -235,15 +233,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)for (k =0 ; k <ARRAY_SIZE (fake_samples[i]); k++) {const union perf_event event = { - .ip = { - .header = { - .misc =PERF_RECORD_MISC_USER , - }, - .pid = fake_samples[i][k].pid, - .ip = fake_samples[i][k].ip, + .header = { + .misc =PERF_RECORD_MISC_USER , }, }; + sample.pid = fake_samples[i][k].pid; + sample.ip = fake_samples[i][k].ip;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 ) goto out;
tools/perf/util/build-id.c +4 -4
@@ -18,14 +18,14 @@int build_id__mark_dso_hit (struct perf_tool *tool__maybe_unused ,union perf_event *event, -struct perf_sample *sample__maybe_unused , +struct perf_sample *sample,struct perf_evsel *evsel__maybe_unused ,struct machine *machine) {struct addr_location al;u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid, - event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, sample->pid, + sample->pid);if (thread ==NULL ) { pr_err("problem processing %d event, skipping it.\n",
@@ -34,7 +34,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, }thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - event->ip.ip, &al); + sample->ip, &al);if (al.map !=NULL ) al.map->dso->hit =1 ;
tools/perf/util/event.c +3 -3
@@ -686,8 +686,8 @@ int perf_event__preprocess_sample(const union perf_event *event, struct perf_sample *sample) {u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid, - event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, sample->pid, + sample->pid);if (thread ==NULL )return -1 ;
@@ -709,7 +709,7 @@ int perf_event__preprocess_sample(const union perf_event *event,machine__create_kernel_maps (machine);thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - event->ip.ip, al); + sample->ip, al);dump_printf (" ...... dso: %s\n" , al->map ? al->map->dso->long_name : al->level =='H' ?"[hypervisor]" :"<not found>" );
tools/perf/util/event.h +0 -11
@@ -8,16 +8,6 @@#include "map.h" #include "build-id.h" -/* -* PERF_SAMPLE_IP | PERF_SAMPLE_TID | * -*/ -struct ip_event { -struct perf_event_header header; -u64 ip; -u32 pid, tid; -unsigned char __more_data[]; -}; -struct mmap_event {struct perf_event_header header;u32 pid, tid;
@@ -166,7 +156,6 @@ struct tracing_data_event {union perf_event {struct perf_event_header header; -struct ip_event ip;struct mmap_event mmap;struct comm_event comm;struct fork_event fork;
tools/perf/util/evsel.c +2 -2
@@ -1185,7 +1185,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,return -EFAULT ;if (type &PERF_SAMPLE_IP ) { - data->ip = event->ip.ip; + data->ip = *array; array++; }
@@ -1397,7 +1397,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, array = event->sample.array;if (type &PERF_SAMPLE_IP ) { - event->ip.ip = sample->ip; + *array = sample->ip; array++; }
tools/perf/util/session.c +5 -3
@@ -840,7 +840,8 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,static struct machine *perf_session__find_machine_for_cpumode (struct perf_session *session, -union perf_event *event) +union perf_event *event, +struct perf_sample *sample) {const u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ;
@@ -852,7 +853,7 @@ static struct machine *if (event->header.type ==PERF_RECORD_MMAP ) pid = event->mmap.pid;else - pid = event->ip.pid; + pid = sample->pid;return perf_session__findnew_machine (session, pid); }
@@ -958,7 +959,8 @@ static int perf_session_deliver_event(struct perf_session *session,hists__inc_nr_events (&evsel->hists, event->header.type); } - machine =perf_session__find_machine_for_cpumode (session, event); + machine =perf_session__find_machine_for_cpumode (session, event, + sample);switch (event->header.type) {case PERF_RECORD_SAMPLE :
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Remove references to struct ip_event
perf tools: Remove references to struct ip_event
Commit-ID: ef89325f773bc9f2f4e6019bd7f3d968ba85df9a Gitweb: http://git.kernel.org/tip/ef89325f773bc9f2f4e6019bd7f3d968ba85df9a Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:06 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 15:29:28 -0300
perf tools: Remove references to struct ip_event
The ip_event struct assumes fixed positions for ip, pid and tid. That is no longer true with the addition of PERF_SAMPLE_IDENTIFIER. The information is anyway in struct sample, so use that instead.
--- tools/perf/builtin-inject.c | 4 ++-- tools/perf/builtin-kmem.c | 4 ++-- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-script.c | 4 ++-- tools/perf/builtin-top.c | 11 ++++++----- tools/perf/tests/hists_link.c | 20 ++++++++------------ tools/perf/util/build-id.c | 8 ++++---- tools/perf/util/event.c | 6 +++--- tools/perf/util/event.h | 11 ----------- tools/perf/util/evsel.c | 4 ++-- tools/perf/util/session.c | 8 +++++--- 11 files changed, 35 insertions(+), 47 deletions(-)
tools/perf/builtin-inject.c +2 -2
@@ -198,7 +198,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; - thread =machine__findnew_thread (machine, event->ip.pid, event->ip.pid); + thread =machine__findnew_thread (machine, sample->pid, sample->pid);if (thread ==NULL ) {pr_err ("problem processing %d event, skipping it.\n" , event->header.type);
@@ -206,7 +206,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, }thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - event->ip.ip, &al); + sample->ip, &al);if (al.map !=NULL ) {if (!al.map->dso->hit) {
tools/perf/builtin-kmem.c +2 -2
@@ -305,8 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,struct perf_evsel *evsel, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, event->ip.pid, - event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, sample->pid, + sample->pid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-mem.c +1 -1
@@ -94,7 +94,7 @@ dump_raw_samples(struct perf_tool *tool, symbol_conf.field_sep, sample->tid, symbol_conf.field_sep, - event->ip.ip, + sample->ip, symbol_conf.field_sep, sample->addr, symbol_conf.field_sep,
tools/perf/builtin-script.c +2 -2
@@ -501,8 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, struct machine *machine) {struct addr_location al; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid, - event->ip.tid); +struct thread *thread =machine__findnew_thread (machine, sample->pid, + sample->tid);if (thread ==NULL ) { pr_debug("problem processing %d event, skipping it.\n",
tools/perf/builtin-top.c +6 -5
@@ -689,7 +689,7 @@ static void perf_event__process_sample(struct perf_tool *tool, { struct perf_top *top = container_of(tool, struct perf_top, tool);struct symbol *parent =NULL ; -u64 ip = event->ip.ip; +u64 ip = sample->ip;struct addr_location al;int err;
@@ -699,10 +699,10 @@ static void perf_event__process_sample(struct perf_tool *tool,if (!seen) seen =intlist__new (NULL ); -if (!intlist__has_entry (seen, event->ip.pid)) { +if (!intlist__has_entry (seen, sample->pid)) {pr_err ("Can't find guest [%d]'s kernel information\n" , - event->ip.pid); -intlist__add (seen, event->ip.pid); + sample->pid); +intlist__add (seen, sample->pid); }return ; }
@@ -836,7 +836,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)break ;case PERF_RECORD_MISC_GUEST_KERNEL : ++top->guest_kernel_samples; - machine =perf_session__find_machine (session, event->ip.pid); + machine =perf_session__find_machine (session, + sample.pid);break ;case PERF_RECORD_MISC_GUEST_USER : ++top->guest_us_samples;
tools/perf/tests/hists_link.c +8 -12
@@ -211,15 +211,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)list_for_each_entry (evsel, &evlist->entries, node) {for (k =0 ; k <ARRAY_SIZE (fake_common_samples); k++) {const union perf_event event = { - .ip = { - .header = { - .misc =PERF_RECORD_MISC_USER , - }, - .pid = fake_common_samples[k].pid, - .ip = fake_common_samples[k].ip, + .header = { + .misc =PERF_RECORD_MISC_USER , }, }; + sample.pid = fake_common_samples[k].pid; + sample.ip = fake_common_samples[k].ip;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 ) goto out;
@@ -235,15 +233,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)for (k =0 ; k <ARRAY_SIZE (fake_samples[i]); k++) {const union perf_event event = { - .ip = { - .header = { - .misc =PERF_RECORD_MISC_USER , - }, - .pid = fake_samples[i][k].pid, - .ip = fake_samples[i][k].ip, + .header = { + .misc =PERF_RECORD_MISC_USER , }, }; + sample.pid = fake_samples[i][k].pid; + sample.ip = fake_samples[i][k].ip;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 ) goto out;
tools/perf/util/build-id.c +4 -4
@@ -18,14 +18,14 @@int build_id__mark_dso_hit (struct perf_tool *tool__maybe_unused ,union perf_event *event, -struct perf_sample *sample__maybe_unused , +struct perf_sample *sample,struct perf_evsel *evsel__maybe_unused ,struct machine *machine) {struct addr_location al;u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid, - event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, sample->pid, + sample->pid);if (thread ==NULL ) { pr_err("problem processing %d event, skipping it.\n",
@@ -34,7 +34,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, }thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - event->ip.ip, &al); + sample->ip, &al);if (al.map !=NULL ) al.map->dso->hit =1 ;
tools/perf/util/event.c +3 -3
@@ -686,8 +686,8 @@ int perf_event__preprocess_sample(const union perf_event *event, struct perf_sample *sample) {u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -struct thread *thread =machine__findnew_thread (machine, event->ip.pid, - event->ip.pid); +struct thread *thread =machine__findnew_thread (machine, sample->pid, + sample->pid);if (thread ==NULL )return -1 ;
@@ -709,7 +709,7 @@ int perf_event__preprocess_sample(const union perf_event *event,machine__create_kernel_maps (machine);thread__find_addr_map (thread, machine, cpumode,MAP__FUNCTION , - event->ip.ip, al); + sample->ip, al);dump_printf (" ...... dso: %s\n" , al->map ? al->map->dso->long_name : al->level =='H' ?"[hypervisor]" :"<not found>" );
tools/perf/util/event.h +0 -11
@@ -8,16 +8,6 @@#include "map.h" #include "build-id.h" -/* -* PERF_SAMPLE_IP | PERF_SAMPLE_TID | * -*/ -struct ip_event { -struct perf_event_header header; -u64 ip; -u32 pid, tid; -unsigned char __more_data[]; -}; -struct mmap_event {struct perf_event_header header;u32 pid, tid;
@@ -166,7 +156,6 @@ struct tracing_data_event {union perf_event {struct perf_event_header header; -struct ip_event ip;struct mmap_event mmap;struct comm_event comm;struct fork_event fork;
tools/perf/util/evsel.c +2 -2
@@ -1185,7 +1185,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,return -EFAULT ;if (type &PERF_SAMPLE_IP ) { - data->ip = event->ip.ip; + data->ip = *array; array++; }
@@ -1397,7 +1397,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, array = event->sample.array;if (type &PERF_SAMPLE_IP ) { - event->ip.ip = sample->ip; + *array = sample->ip; array++; }
tools/perf/util/session.c +5 -3
@@ -840,7 +840,8 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,static struct machine *perf_session__find_machine_for_cpumode (struct perf_session *session, -union perf_event *event) +union perf_event *event, +struct perf_sample *sample) {const u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ;
@@ -852,7 +853,7 @@ static struct machine *if (event->header.type ==PERF_RECORD_MMAP ) pid = event->mmap.pid;else - pid = event->ip.pid; + pid = sample->pid;return perf_session__findnew_machine (session, pid); }
@@ -958,7 +959,8 @@ static int perf_session_deliver_event(struct perf_session *session,hists__inc_nr_events (&evsel->hists, event->header.type); } - machine =perf_session__find_machine_for_cpumode (session, event); + machine =perf_session__find_machine_for_cpumode (session, event, + sample);switch (event->header.type) {case PERF_RECORD_SAMPLE :
Adrian Hunter
reviewerPATCH v13 5/12 perf: make events stream always parsable
In reply to Adrian HunterThe event stream is not always parsable because the format of a sample is dependent on the sample_type of the selected event. When there is more than one selected event and the sample_types are not the same then parsing becomes problematic. A sample can be matched to its selected event using the ID that is allocated when the event is opened. Unfortunately, to get the ID from the sample means first parsing it.
This patch adds a new sample format bit PERF_SAMPLE_IDENTIFER that puts the ID at a fixed position so that the ID can be retrieved without parsing the sample. For sample events, that is the first position immediately after the header. For non-sample events, that is the last position.
In this respect parsing samples requires that the sample_type and ID values are recorded. For example, perf tools records struct perf_event_attr and the IDs within the perf.data file. Those must be read first before it is possible to parse samples found later in the perf.data file.
--- include/uapi/linux/perf_event.h | 27 ++++++++++++++++++++------- kernel/events/core.c | 11 ++++++++++- 2 files changed, 30 insertions(+), 8 deletions(-)
include/uapi/linux/perf_event.h +20 -7
@@ -134,8 +134,9 @@ enum perf_event_sample_format {PERF_SAMPLE_STACK_USER =1U <<13 ,PERF_SAMPLE_WEIGHT =1U <<14 ,PERF_SAMPLE_DATA_SRC =1U <<15 , +PERF_SAMPLE_IDENTIFIER =1U <<16 , - PERF_SAMPLE_MAX = 1U << 16, /* non-ABI */ + PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */ };/*
@@ -492,12 +493,12 @@ enum perf_event_type {/* * If perf_event_attr.sample_id_all is set then all event types will * have the sample_type selected fields related to where/when -* (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID) -* described in PERF_RECORD_SAMPLE below, it will be stashed just after -* the perf_event_header and the fields already present for the existing -* fields, i.e. at the end of the payload. That way a newer perf.data -* file will be supported by older perf tools, with these new optional -* fields being ignored. +* (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU, +* IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed +* just after the perf_event_header and the fields already present for +* the existing fields, i.e. at the end of the payload. That way a newer +* perf.data file will be supported by older perf tools, with these new +* optional fields being ignored. * * struct sample_id { * { u32 pid, tid; } && PERF_SAMPLE_TID
@@ -505,7 +506,12 @@ enum perf_event_type {* { u64 id; } && PERF_SAMPLE_ID * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID * { u32 cpu, res; } && PERF_SAMPLE_CPU +* { u64 id; } && PERF_SAMPLE_IDENTIFIER * } && perf_event_attr::sample_id_all +* +* Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The +* advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed +* relative to header.size. */ /*
@@ -594,6 +600,13 @@ enum perf_event_type {* struct { * struct perf_event_header header; * +* # +* # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. +* # The advantage of PERF_SAMPLE_IDENTIFIER is that its position +* # is fixed relative to header. +* # +* +* { u64 id; } && PERF_SAMPLE_IDENTIFIER * { u64 ip; } && PERF_SAMPLE_IP * { u32 pid, tid; } && PERF_SAMPLE_TID * { u64 time; } && PERF_SAMPLE_TIME
kernel/events/core.c +10 -1
@@ -1213,6 +1213,9 @@ static void perf_event__id_header_size(struct perf_event *event)if (sample_type &PERF_SAMPLE_TIME ) size +=sizeof (data->time); +if (sample_type &PERF_SAMPLE_IDENTIFIER ) + size +=sizeof (data->id); +if (sample_type &PERF_SAMPLE_ID ) size +=sizeof (data->id);
@@ -4280,7 +4283,7 @@ static void __perf_event_header__init_id(struct perf_event_header *header,if (sample_type &PERF_SAMPLE_TIME ) data->time =perf_clock (); -if (sample_type &PERF_SAMPLE_ID ) +if (sample_type & (PERF_SAMPLE_ID |PERF_SAMPLE_IDENTIFIER )) data->id =primary_event_id (event);if (sample_type &PERF_SAMPLE_STREAM_ID )
@@ -4319,6 +4322,9 @@ static void __perf_event__output_id_sample(struct perf_output_handle *handle,if (sample_type &PERF_SAMPLE_CPU )perf_output_put (handle, data->cpu_entry); + +if (sample_type &PERF_SAMPLE_IDENTIFIER ) +perf_output_put (handle, data->id); } void perf_event__output_id_sample(struct perf_event *event,
@@ -4432,6 +4438,9 @@ void perf_output_sample(struct perf_output_handle *handle,perf_output_put (handle, *header); +if (sample_type &PERF_SAMPLE_IDENTIFIER ) +perf_output_put (handle, data->id); +if (sample_type &PERF_SAMPLE_IP )perf_output_put (handle, data->ip);
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf: make events stream always parsable
perf: make events stream always parsable
Commit-ID: ff3d527cebc1fa3707c617bfe9e74f53fcfb0955 Gitweb: http://git.kernel.org/tip/ff3d527cebc1fa3707c617bfe9e74f53fcfb0955 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:07 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 15:40:03 -0300
perf: make events stream always parsable
The event stream is not always parsable because the format of a sample is dependent on the sample_type of the selected event. When there is more than one selected event and the sample_types are not the same then parsing becomes problematic. A sample can be matched to its selected event using the ID that is allocated when the event is opened. Unfortunately, to get the ID from the sample means first parsing it.
This patch adds a new sample format bit PERF_SAMPLE_IDENTIFER that puts the ID at a fixed position so that the ID can be retrieved without parsing the sample. For sample events, that is the first position immediately after the header. For non-sample events, that is the last position.
In this respect parsing samples requires that the sample_type and ID values are recorded. For example, perf tools records struct perf_event_attr and the IDs within the perf.data file. Those must be read first before it is possible to parse samples found later in the perf.data file.
--- include/uapi/linux/perf_event.h | 27 ++++++++++++++++++++------- kernel/events/core.c | 11 ++++++++++- 2 files changed, 30 insertions(+), 8 deletions(-)
include/uapi/linux/perf_event.h +20 -7
@@ -134,8 +134,9 @@ enum perf_event_sample_format {PERF_SAMPLE_STACK_USER =1U <<13 ,PERF_SAMPLE_WEIGHT =1U <<14 ,PERF_SAMPLE_DATA_SRC =1U <<15 , +PERF_SAMPLE_IDENTIFIER =1U <<16 , - PERF_SAMPLE_MAX = 1U << 16, /* non-ABI */ + PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */ };/*
@@ -492,12 +493,12 @@ enum perf_event_type {/* * If perf_event_attr.sample_id_all is set then all event types will * have the sample_type selected fields related to where/when -* (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID) -* described in PERF_RECORD_SAMPLE below, it will be stashed just after -* the perf_event_header and the fields already present for the existing -* fields, i.e. at the end of the payload. That way a newer perf.data -* file will be supported by older perf tools, with these new optional -* fields being ignored. +* (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU, +* IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed +* just after the perf_event_header and the fields already present for +* the existing fields, i.e. at the end of the payload. That way a newer +* perf.data file will be supported by older perf tools, with these new +* optional fields being ignored. * * struct sample_id { * { u32 pid, tid; } && PERF_SAMPLE_TID
@@ -505,7 +506,12 @@ enum perf_event_type {* { u64 id; } && PERF_SAMPLE_ID * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID * { u32 cpu, res; } && PERF_SAMPLE_CPU +* { u64 id; } && PERF_SAMPLE_IDENTIFIER * } && perf_event_attr::sample_id_all +* +* Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The +* advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed +* relative to header.size. */ /*
@@ -594,6 +600,13 @@ enum perf_event_type {* struct { * struct perf_event_header header; * +* # +* # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. +* # The advantage of PERF_SAMPLE_IDENTIFIER is that its position +* # is fixed relative to header. +* # +* +* { u64 id; } && PERF_SAMPLE_IDENTIFIER * { u64 ip; } && PERF_SAMPLE_IP * { u32 pid, tid; } && PERF_SAMPLE_TID * { u64 time; } && PERF_SAMPLE_TIME
kernel/events/core.c +10 -1
@@ -1213,6 +1213,9 @@ static void perf_event__id_header_size(struct perf_event *event)if (sample_type &PERF_SAMPLE_TIME ) size +=sizeof (data->time); +if (sample_type &PERF_SAMPLE_IDENTIFIER ) + size +=sizeof (data->id); +if (sample_type &PERF_SAMPLE_ID ) size +=sizeof (data->id);
@@ -4280,7 +4283,7 @@ static void __perf_event_header__init_id(struct perf_event_header *header,if (sample_type &PERF_SAMPLE_TIME ) data->time =perf_clock (); -if (sample_type &PERF_SAMPLE_ID ) +if (sample_type & (PERF_SAMPLE_ID |PERF_SAMPLE_IDENTIFIER )) data->id =primary_event_id (event);if (sample_type &PERF_SAMPLE_STREAM_ID )
@@ -4319,6 +4322,9 @@ static void __perf_event__output_id_sample(struct perf_output_handle *handle,if (sample_type &PERF_SAMPLE_CPU )perf_output_put (handle, data->cpu_entry); + +if (sample_type &PERF_SAMPLE_IDENTIFIER ) +perf_output_put (handle, data->id); } void perf_event__output_id_sample(struct perf_event *event,
@@ -4432,6 +4438,9 @@ void perf_output_sample(struct perf_output_handle *handle,perf_output_put (handle, *header); +if (sample_type &PERF_SAMPLE_IDENTIFIER ) +perf_output_put (handle, data->id); +if (sample_type &PERF_SAMPLE_IP )perf_output_put (handle, data->ip);
Adrian Hunter
reviewerPATCH v13 6/12 perf tools: move perf_evlist__config() to a new source file
In reply to Adrian Hunterperf_evlist__config() must be moved to a separate source file to avoid Python link errors when adding support for PERF_SAMPLE_IDENTIFIER.
It is appropriate to do this because perf_evlist__config() is a helper function for event recording. It is used by tools to apply recording options to perf_evlist. It is not used by the Python API.
--- tools/perf/Makefile | 1 + tools/perf/util/evlist.c | 22 ---------------------- tools/perf/util/record.c | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 tools/perf/util/record.c
tools/perf/Makefile +1 -0
@@ -360,6 +360,7 @@ LIB_OBJS += $(OUTPUT)util/rblist.o LIB_OBJS += $(OUTPUT)util/intlist.o LIB_OBJS += $(OUTPUT)util/vdso.o LIB_OBJS += $(OUTPUT)util/stat.o +LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/evlist.c +0 -22
@@ -49,28 +49,6 @@ struct perf_evlist *perf_evlist__new(void)return evlist; } -void perf_evlist__config (struct perf_evlist *evlist, -struct perf_record_opts *opts) -{ -struct perf_evsel *evsel; -/* -* Set the evsel leader links before we configure attributes, -* since some might depend on this info. -*/ -if (opts->group) -perf_evlist__set_leader (evlist); - -if (evlist->cpus->map[0 ] <0 ) - opts->no_inherit = true; - -list_for_each_entry (evsel, &evlist->entries, node) { -perf_evsel__config (evsel, opts); - -if (evlist->nr_entries >1 ) -perf_evsel__set_sample_id (evsel); - } -} -static void perf_evlist__purge (struct perf_evlist *evlist) {struct perf_evsel *pos, *n;
tools/perf/util/record.c new file +25 -0
@@ -0,0 +1,25 @@ +#include "evlist.h" +#include "evsel.h" +#include "cpumap.h" + +void perf_evlist__config (struct perf_evlist *evlist, +struct perf_record_opts *opts) +{ +struct perf_evsel *evsel; +/* +* Set the evsel leader links before we configure attributes, +* since some might depend on this info. +*/ +if (opts->group) +perf_evlist__set_leader (evlist); + +if (evlist->cpus->map[0 ] <0 ) + opts->no_inherit = true; + +list_for_each_entry (evsel, &evlist->entries, node) { +perf_evsel__config (evsel, opts); + +if (evlist->nr_entries >1 ) +perf_evsel__set_sample_id (evsel); + } +}
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evlist: Move perf_evlist__config() to a new source file
perf evlist: Move perf_evlist__config() to a new source file
Commit-ID: faf967068e8c4d8df52f01f9361241101b3065a0 Gitweb: http://git.kernel.org/tip/faf967068e8c4d8df52f01f9361241101b3065a0 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:08 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 15:49:10 -0300
perf evlist: Move perf_evlist__config() to a new source file
perf_evlist__config() must be moved to a separate source file to avoid Python link errors when adding support for PERF_SAMPLE_IDENTIFIER.
It is appropriate to do this because perf_evlist__config() is a helper function for event recording. It is used by tools to apply recording options to perf_evlist. It is not used by the Python API.
--- tools/perf/Makefile | 1 + tools/perf/util/evlist.c | 22 ---------------------- tools/perf/util/record.c | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 22 deletions(-)
tools/perf/Makefile +1 -0
@@ -360,6 +360,7 @@ LIB_OBJS += $(OUTPUT)util/rblist.o LIB_OBJS += $(OUTPUT)util/intlist.o LIB_OBJS += $(OUTPUT)util/vdso.o LIB_OBJS += $(OUTPUT)util/stat.o +LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/evlist.c +0 -22
@@ -49,28 +49,6 @@ struct perf_evlist *perf_evlist__new(void)return evlist; } -void perf_evlist__config (struct perf_evlist *evlist, -struct perf_record_opts *opts) -{ -struct perf_evsel *evsel; -/* -* Set the evsel leader links before we configure attributes, -* since some might depend on this info. -*/ -if (opts->group) -perf_evlist__set_leader (evlist); - -if (evlist->cpus->map[0 ] <0 ) - opts->no_inherit = true; - -list_for_each_entry (evsel, &evlist->entries, node) { -perf_evsel__config (evsel, opts); - -if (evlist->nr_entries >1 ) -perf_evsel__set_sample_id (evsel); - } -} -static void perf_evlist__purge (struct perf_evlist *evlist) {struct perf_evsel *pos, *n;
tools/perf/util/record.c new file +25 -0
@@ -0,0 +1,25 @@ +#include "evlist.h" +#include "evsel.h" +#include "cpumap.h" + +void perf_evlist__config (struct perf_evlist *evlist, +struct perf_record_opts *opts) +{ +struct perf_evsel *evsel; +/* +* Set the evsel leader links before we configure attributes, +* since some might depend on this info. +*/ +if (opts->group) +perf_evlist__set_leader (evlist); + +if (evlist->cpus->map[0 ] <0 ) + opts->no_inherit = true; + +list_for_each_entry (evsel, &evlist->entries, node) { +perf_evsel__config (evsel, opts); + +if (evlist->nr_entries >1 ) +perf_evsel__set_sample_id (evsel); + } +}
Adrian Hunter
reviewerPATCH v13 7/12 perf tools: add support for PERF_SAMPLE_IDENTFIER
In reply to Adrian HunterEnable parsing of samples with sample format bit PERF_SAMPLE_IDENTFIER. In addition, if the kernel supports it, prefer it to selecting PERF_SAMPLE_ID thereby allowing non-matching sample types.
--- tools/perf/builtin-report.c | 2 +- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/util/event.h | 3 +- tools/perf/util/evlist.c | 111 +++++++++++++++++++++++++++++++++++++++--- tools/perf/util/evlist.h | 8 ++- tools/perf/util/evsel.c | 101 ++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 14 +++++- tools/perf/util/record.c | 89 +++++++++++++++++++++++++++++++-- tools/perf/util/session.c | 2 +- 9 files changed, 310 insertions(+), 22 deletions(-)
tools/perf/builtin-report.c +1 -1
@@ -365,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,static int perf_report__setup_sample_type (struct perf_report *rep) {struct perf_session *self = rep->session; -u64 sample_type =perf_evlist__sample_type (self->evlist); +u64 sample_type =perf_evlist__combined_sample_type (self->evlist);if (!self->fd_pipe && !(sample_type &PERF_SAMPLE_CALLCHAIN )) {if (sort__has_parent) {
tools/perf/tests/mmap-basic.c +1 -1
@@ -72,7 +72,7 @@ int test__basic_mmap(void) } evsels[i]->attr.wakeup_events =1 ; -perf_evsel__set_sample_id (evsels[i]); +perf_evsel__set_sample_id (evsels[i], false);perf_evlist__add (evlist, evsels[i]);
tools/perf/util/event.h +2 -1
@@ -53,7 +53,8 @@ struct read_event { (PERF_SAMPLE_IP |PERF_SAMPLE_TID | \PERF_SAMPLE_TIME |PERF_SAMPLE_ADDR | \PERF_SAMPLE_ID |PERF_SAMPLE_STREAM_ID | \ - PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) +PERF_SAMPLE_CPU |PERF_SAMPLE_PERIOD | \ + PERF_SAMPLE_IDENTIFIER)struct sample_event {struct perf_event_header header;
tools/perf/util/evlist.c +103 -8
163 lines not on this page · raw message
tools/perf/util/evlist.h +7 -1
@@ -32,6 +32,9 @@ struct perf_evlist {int nr_fds;int nr_mmaps;int mmap_len; +int id_pos; +int is_pos; +u64 combined_sample_type;struct {int cork_fd;pid_t pid;
@@ -85,6 +88,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);int perf_evlist__open (struct perf_evlist *evlist);void perf_evlist__close (struct perf_evlist *evlist); +void perf_evlist__set_id_pos (struct perf_evlist *evlist); +bool perf_can_sample_identifier (void );void perf_evlist__config (struct perf_evlist *evlist,struct perf_record_opts *opts);
@@ -121,7 +126,8 @@ void __perf_evlist__set_leader(struct list_head *list);void perf_evlist__set_leader (struct perf_evlist *evlist);u64 perf_evlist__read_format (struct perf_evlist *evlist); -u64 perf_evlist__sample_type (struct perf_evlist *evlist); +u64 __perf_evlist__combined_sample_type (struct perf_evlist *evlist); +u64 perf_evlist__combined_sample_type (struct perf_evlist *evlist);bool perf_evlist__sample_id_all (struct perf_evlist *evlist);u16 perf_evlist__id_hdr_size (struct perf_evlist *evlist);
tools/perf/util/evsel.c +96 -5
171 lines not on this page · raw message
tools/perf/util/evsel.h +13 -1
@@ -48,6 +48,12 @@ struct perf_sample_id {* @name - Can be set to retain the original event name passed by the user, * so that when showing results in tools such as 'perf stat', we * show the name used, not some alias. +* @id_pos: the position of the event id (PERF_SAMPLE_ID or +* PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of +* struct sample_event +* @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or +* PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all +* is used there is an id sample appended to non-sample events */ struct perf_evsel {struct list_head node;
@@ -74,6 +80,8 @@ struct perf_evsel { } handler;struct cpu_map *cpus;unsigned int sample_size; +int id_pos; +int is_pos;bool supported;bool needs_swap;/* parse modifier helper */
@@ -104,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel);void perf_evsel__config (struct perf_evsel *evsel,struct perf_record_opts *opts); +int __perf_evsel__sample_size (u64 sample_type); +void perf_evsel__calc_id_pos (struct perf_evsel *evsel); +bool perf_evsel__is_cache_op_valid (u8 type,u8 op);#define PERF_EVSEL__MAX_ALIASES 8
@@ -142,7 +153,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,#define perf_evsel__reset_sample_bit (evsel, bit) \ __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) -void perf_evsel__set_sample_id (struct perf_evsel *evsel); +void perf_evsel__set_sample_id (struct perf_evsel *evsel, +bool use_sample_identifier);int perf_evsel__set_filter (struct perf_evsel *evsel,int ncpus,int nthreads,const char *filter);
tools/perf/util/record.c +86 -3
107 lines not on this page · raw message
tools/perf/util/session.c +1 -1
@@ -739,7 +739,7 @@ static void perf_session__print_tstamp(struct perf_session *session,union perf_event *event, struct perf_sample *sample) { - u64 sample_type = perf_evlist__sample_type(session->evlist); + u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);if (event->header.type !=PERF_RECORD_SAMPLE && !perf_evlist__sample_id_all (session->evlist)) {
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add support for PERF_SAMPLE_IDENTIFIER
perf tools: Add support for PERF_SAMPLE_IDENTIFIER
Commit-ID: 75562573bab35b129cfd342fc2bcf89da84a6644 Gitweb: http://git.kernel.org/tip/75562573bab35b129cfd342fc2bcf89da84a6644 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:09 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 16:09:31 -0300
perf tools: Add support for PERF_SAMPLE_IDENTIFIER
Enable parsing of samples with sample format bit PERF_SAMPLE_IDENTIFIER. In addition, if the kernel supports it, prefer it to selecting PERF_SAMPLE_ID thereby allowing non-matching sample types.
--- tools/perf/builtin-report.c | 2 +- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/util/event.h | 3 +- tools/perf/util/evlist.c | 111 +++++++++++++++++++++++++++++++++++++++--- tools/perf/util/evlist.h | 8 ++- tools/perf/util/evsel.c | 101 ++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 14 +++++- tools/perf/util/record.c | 89 +++++++++++++++++++++++++++++++-- tools/perf/util/session.c | 2 +- 9 files changed, 310 insertions(+), 22 deletions(-)
tools/perf/builtin-report.c +1 -1
@@ -365,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,static int perf_report__setup_sample_type (struct perf_report *rep) {struct perf_session *self = rep->session; -u64 sample_type =perf_evlist__sample_type (self->evlist); +u64 sample_type =perf_evlist__combined_sample_type (self->evlist);if (!self->fd_pipe && !(sample_type &PERF_SAMPLE_CALLCHAIN )) {if (sort__has_parent) {
tools/perf/tests/mmap-basic.c +1 -1
@@ -72,7 +72,7 @@ int test__basic_mmap(void) } evsels[i]->attr.wakeup_events =1 ; -perf_evsel__set_sample_id (evsels[i]); +perf_evsel__set_sample_id (evsels[i], false);perf_evlist__add (evlist, evsels[i]);
tools/perf/util/event.h +2 -1
@@ -53,7 +53,8 @@ struct read_event { (PERF_SAMPLE_IP |PERF_SAMPLE_TID | \PERF_SAMPLE_TIME |PERF_SAMPLE_ADDR | \PERF_SAMPLE_ID |PERF_SAMPLE_STREAM_ID | \ - PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) +PERF_SAMPLE_CPU |PERF_SAMPLE_PERIOD | \ + PERF_SAMPLE_IDENTIFIER)struct sample_event {struct perf_event_header header;
tools/perf/util/evlist.c +103 -8
163 lines not on this page · raw message
tools/perf/util/evlist.h +7 -1
@@ -32,6 +32,9 @@ struct perf_evlist {int nr_fds;int nr_mmaps;int mmap_len; +int id_pos; +int is_pos; +u64 combined_sample_type;struct {int cork_fd;pid_t pid;
@@ -85,6 +88,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);int perf_evlist__open (struct perf_evlist *evlist);void perf_evlist__close (struct perf_evlist *evlist); +void perf_evlist__set_id_pos (struct perf_evlist *evlist); +bool perf_can_sample_identifier (void );void perf_evlist__config (struct perf_evlist *evlist,struct perf_record_opts *opts);
@@ -121,7 +126,8 @@ void __perf_evlist__set_leader(struct list_head *list);void perf_evlist__set_leader (struct perf_evlist *evlist);u64 perf_evlist__read_format (struct perf_evlist *evlist); -u64 perf_evlist__sample_type (struct perf_evlist *evlist); +u64 __perf_evlist__combined_sample_type (struct perf_evlist *evlist); +u64 perf_evlist__combined_sample_type (struct perf_evlist *evlist);bool perf_evlist__sample_id_all (struct perf_evlist *evlist);u16 perf_evlist__id_hdr_size (struct perf_evlist *evlist);
tools/perf/util/evsel.c +96 -5
171 lines not on this page · raw message
tools/perf/util/evsel.h +13 -1
@@ -48,6 +48,12 @@ struct perf_sample_id {* @name - Can be set to retain the original event name passed by the user, * so that when showing results in tools such as 'perf stat', we * show the name used, not some alias. +* @id_pos: the position of the event id (PERF_SAMPLE_ID or +* PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of +* struct sample_event +* @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or +* PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all +* is used there is an id sample appended to non-sample events */ struct perf_evsel {struct list_head node;
@@ -74,6 +80,8 @@ struct perf_evsel { } handler;struct cpu_map *cpus;unsigned int sample_size; +int id_pos; +int is_pos;bool supported;bool needs_swap;/* parse modifier helper */
@@ -104,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel);void perf_evsel__config (struct perf_evsel *evsel,struct perf_record_opts *opts); +int __perf_evsel__sample_size (u64 sample_type); +void perf_evsel__calc_id_pos (struct perf_evsel *evsel); +bool perf_evsel__is_cache_op_valid (u8 type,u8 op);#define PERF_EVSEL__MAX_ALIASES 8
@@ -142,7 +153,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,#define perf_evsel__reset_sample_bit (evsel, bit) \ __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) -void perf_evsel__set_sample_id (struct perf_evsel *evsel); +void perf_evsel__set_sample_id (struct perf_evsel *evsel, +bool use_sample_identifier);int perf_evsel__set_filter (struct perf_evsel *evsel,int ncpus,int nthreads,const char *filter);
tools/perf/util/record.c +86 -3
107 lines not on this page · raw message
tools/perf/util/session.c +1 -1
@@ -739,7 +739,7 @@ static void perf_session__print_tstamp(struct perf_session *session,union perf_event *event, struct perf_sample *sample) { - u64 sample_type = perf_evlist__sample_type(session->evlist); + u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);if (event->header.type !=PERF_RECORD_SAMPLE && !perf_evlist__sample_id_all (session->evlist)) {
Adrian Hunter
reviewerPATCH v13 8/12 perf tools: add missing 'abi' member to 'struct regs_dump'
In reply to Adrian HunterAnd store the parsed value there. Note that the 'abi' is 0 (no registers), 1 (32-bit registers) or 2 (64-bit registers), but the registers are anyway copied one-by-one as 64-bit values onto the event i.e. see 'perf_output_sample_regs()'
--- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/event.h +1 -0
@@ -62,6 +62,7 @@ struct sample_event { };struct regs_dump { +u64 abi;u64 *regs; };
tools/perf/util/evsel.c +3 -4
@@ -1416,13 +1416,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, }if (type &PERF_SAMPLE_REGS_USER ) { -u64 avail; -/* First u64 tells us if we have any regs in sample. */ OVERFLOW_CHECK_u64 (array); - avail = *array++; + data->user_regs.abi = *array; + array++; -if (avail) { +if (data->user_regs.abi) {u64 regs_user = evsel->attr.sample_regs_user; sz =hweight_long (regs_user) *sizeof (u64);
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add missing 'abi' member to ' struct regs_dump'
perf tools: Add missing 'abi' member to 'struct regs_dump'
Commit-ID: 5b95a4a3b52a1de84022dfaf580df4b5251f4a15 Gitweb: http://git.kernel.org/tip/5b95a4a3b52a1de84022dfaf580df4b5251f4a15 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:10 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 16:10:58 -0300
perf tools: Add missing 'abi' member to 'struct regs_dump'
And store the parsed value there. Note that the 'abi' is 0 (no registers), 1 (32-bit registers) or 2 (64-bit registers), but the registers are anyway copied one-by-one as 64-bit values onto the event i.e. see 'perf_output_sample_regs()'
--- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/event.h +1 -0
@@ -62,6 +62,7 @@ struct sample_event { };struct regs_dump { +u64 abi;u64 *regs; };
tools/perf/util/evsel.c +3 -4
@@ -1416,13 +1416,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, }if (type &PERF_SAMPLE_REGS_USER ) { -u64 avail; -/* First u64 tells us if we have any regs in sample. */ OVERFLOW_CHECK_u64 (array); - avail = *array++; + data->user_regs.abi = *array; + array++; -if (avail) { +if (data->user_regs.abi) {u64 regs_user = evsel->attr.sample_regs_user; sz =hweight_long (regs_user) *sizeof (u64);
Adrian Hunter
reviewerPATCH v13 9/12 perf tools: expand perf_event__synthesize_sample()
In reply to Adrian HunterExpand perf_event__synthesize_sample() to handle all sample format bits.
--- tools/perf/builtin-inject.c | 4 +- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 95 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 3 deletions(-)
tools/perf/builtin-inject.c +3 -1
@@ -301,7 +301,9 @@ found: sample_sw.period = sample->period; sample_sw.time = sample->time;perf_event__synthesize_sample (event_sw, evsel->attr.sample_type, - &sample_sw, false); + evsel->attr.sample_regs_user, + evsel->attr.read_format, &sample_sw, + false);build_id__mark_dso_hit (tool, event_sw, &sample_sw, evsel, machine);return perf_event__repipe (tool, event_sw, &sample_sw, machine); }
tools/perf/util/event.h +1 -0
@@ -230,6 +230,7 @@ int perf_event__preprocess_sample(const union perf_event *self,const char *perf_event__name (unsigned int id);int perf_event__synthesize_sample (union perf_event *event,u64 type, +u64 sample_regs_user,u64 read_format,const struct perf_sample *sample,bool swapped);
tools/perf/util/evsel.c +93 -2
117 lines not on this page · raw message
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Expand perf_event__synthesize_sample( )
perf tools: Expand perf_event__synthesize_sample()
Commit-ID: d03f2170546d2f0c236a42706d211e15ffb64184 Gitweb: http://git.kernel.org/tip/d03f2170546d2f0c236a42706d211e15ffb64184 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:11 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 16:14:20 -0300
perf tools: Expand perf_event__synthesize_sample()
Expand perf_event__synthesize_sample() to handle all sample format bits.
--- tools/perf/builtin-inject.c | 4 +- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 95 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 3 deletions(-)
tools/perf/builtin-inject.c +3 -1
@@ -301,7 +301,9 @@ found: sample_sw.period = sample->period; sample_sw.time = sample->time;perf_event__synthesize_sample (event_sw, evsel->attr.sample_type, - &sample_sw, false); + evsel->attr.sample_regs_user, + evsel->attr.read_format, &sample_sw, + false);build_id__mark_dso_hit (tool, event_sw, &sample_sw, evsel, machine);return perf_event__repipe (tool, event_sw, &sample_sw, machine); }
tools/perf/util/event.h +1 -0
@@ -230,6 +230,7 @@ int perf_event__preprocess_sample(const union perf_event *self,const char *perf_event__name (unsigned int id);int perf_event__synthesize_sample (union perf_event *event,u64 type, +u64 sample_regs_user,u64 read_format,const struct perf_sample *sample,bool swapped);
tools/perf/util/evsel.c +93 -2
117 lines not on this page · raw message
Adrian Hunter
reviewerPATCH v13 10/12 perf tools: add a function to calculate sample event size
In reply to Adrian HunterAdd perf_event__sample_event_size() which can be used when synthesizing sample events to determine how big the resulting event will be, and therefore how much memory to allocate.
--- tools/perf/util/event.h | 2 ++ tools/perf/util/evsel.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+)
tools/perf/util/event.h +2 -0
@@ -229,6 +229,8 @@ int perf_event__preprocess_sample(const union perf_event *self,const char *perf_event__name (unsigned int id); +size_t perf_event__sample_event_size (const struct perf_sample *sample,u64 type, +u64 sample_regs_user,u64 read_format); int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 sample_regs_user, u64 read_format, const struct perf_sample *sample,
tools/perf/util/evsel.c +92 -0
98 lines not on this page · raw message
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add a function to calculate sample event size
perf tools: Add a function to calculate sample event size
Commit-ID: b1cf6f65aa7096984836addab7cec6b5b6d4393a Gitweb: http://git.kernel.org/tip/b1cf6f65aa7096984836addab7cec6b5b6d4393a Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:12 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 16:44:26 -0300
perf tools: Add a function to calculate sample event size
Add perf_event__sample_event_size() which can be used when synthesizing sample events to determine how big the resulting event will be, and therefore how much memory to allocate.
--- tools/perf/util/event.h | 2 ++ tools/perf/util/evsel.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+)
tools/perf/util/event.h +2 -0
@@ -229,6 +229,8 @@ int perf_event__preprocess_sample(const union perf_event *self,const char *perf_event__name (unsigned int id); +size_t perf_event__sample_event_size (const struct perf_sample *sample,u64 type, +u64 sample_regs_user,u64 read_format); int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 sample_regs_user, u64 read_format, const struct perf_sample *sample,
tools/perf/util/evsel.c +92 -0
98 lines not on this page · raw message
Adrian Hunter
reviewerPATCH v13 11/12 perf tools: add a sample parsing test
In reply to Adrian HunterAdd a test that checks that sample parsing is correctly implemented.
--- tools/perf/Makefile | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/sample-parsing.c | 316 ++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 4 files changed, 322 insertions(+) create mode 100644 tools/perf/tests/sample-parsing.c
tools/perf/Makefile +1 -0
@@ -439,6 +439,7 @@ PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) ifneq ($(OUTPUT),) CFLAGS += -I$(OUTPUT) endif +LIB_OBJS += $(OUTPUT)tests/sample-parsing.o ifdef NO_LIBELF EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
tools/perf/tests/builtin-test.c +4 -0
@@ -104,6 +104,10 @@ static struct test { .func = test__code_reading, }, { + .desc = "Test sample parsing", + .func = test__sample_parsing, + }, + { .func = NULL, }, };
tools/perf/tests/sample-parsing.c new file +316 -0
316 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -37,5 +37,6 @@ int test__task_exit(void);int test__sw_clock_freq (void );int test__perf_time_to_tsc (void );int test__code_reading (void ); +int test__sample_parsing (void );#endif /* TESTS_H */
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tests: Add a sample parsing test
perf tests: Add a sample parsing test
Commit-ID: 045f8cd8542d2fcd424a32fa10fcd3dd29c6d374 Gitweb: http://git.kernel.org/tip/045f8cd8542d2fcd424a32fa10fcd3dd29c6d374 Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 27 Aug 2013 11:23:13 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Thu, 29 Aug 2013 16:46:58 -0300
perf tests: Add a sample parsing test
Add a test that checks that sample parsing is correctly implemented.
--- tools/perf/Makefile | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/sample-parsing.c | 316 ++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 4 files changed, 322 insertions(+)
tools/perf/Makefile +1 -0
@@ -439,6 +439,7 @@ PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) ifneq ($(OUTPUT),) CFLAGS += -I$(OUTPUT) endif +LIB_OBJS += $(OUTPUT)tests/sample-parsing.o ifdef NO_LIBELF EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
tools/perf/tests/builtin-test.c +4 -0
@@ -104,6 +104,10 @@ static struct test { .func = test__code_reading, }, { + .desc = "Test sample parsing", + .func = test__sample_parsing, + }, + { .func = NULL, }, };
tools/perf/tests/sample-parsing.c new file +316 -0
316 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -37,5 +37,6 @@ int test__task_exit(void);int test__sw_clock_freq (void );int test__perf_time_to_tsc (void );int test__code_reading (void ); +int test__sample_parsing (void );#endif /* TESTS_H */
Adrian Hunter
reviewerPATCH v13 12/12 perf tools: allow non-matching sample types
In reply to Adrian HunterFor kernels that do not support PERF_SAMPLE_IDENTIFIER, sample types need not be identical to determine the sample id from the event. Only the position of the sample id needs to be the same.
Compatible sample types are ones in which the bits defined by PERF_COMPAT_MASK are the same. 'perf_evlist__config()' forces sample types to be compatible on that basis.
--- tools/perf/util/event.h | 16 ++++++++++++++++ tools/perf/util/evlist.c | 25 +++++++++++++++++++++++++ tools/perf/util/evlist.h | 1 + tools/perf/util/record.c | 5 ++++- 4 files changed, 46 insertions(+), 1 deletion(-)
tools/perf/util/event.h +16 -0
@@ -56,6 +56,22 @@ struct read_event { PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \ PERF_SAMPLE_IDENTIFIER) +/* +* Events have compatible sample types if the following bits all have the same +* value. This is because the order of sample members is fixed. For sample +* events the order is: PERF_SAMPLE_IP, PERF_SAMPLE_TID, PERF_SAMPLE_TIME, +* PERF_SAMPLE_ADDR, PERF_SAMPLE_ID. For non-sample events the sample members +* are accessed in reverse order. The order is: PERF_SAMPLE_ID, +* PERF_SAMPLE_STREAM_ID, PERF_SAMPLE_CPU. PERF_SAMPLE_IDENTIFIER is added for +* completeness but it should not be used with PERF_SAMPLE_ID. Sample types +* that include PERF_SAMPLE_IDENTIFIER are always compatible. +*/ +#define PERF_COMPAT_MASK \ + (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ + PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ + PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ + PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER) +struct sample_event {struct perf_event_header header;u64 array[];
tools/perf/util/evlist.c +25 -0
@@ -64,6 +64,31 @@ void perf_evlist__set_id_pos(struct perf_evlist *evlist) evlist->is_pos = first->is_pos; } +/** +* perf_evlist__make_sample_types_compatible - make sample types compatible. +* @evlist: selected event list +* +* Events with compatible sample types all have the same id_pos and is_pos. +* This can be achieved by matching the bits of PERF_COMPAT_MASK. +*/ +void perf_evlist__make_sample_types_compatible (struct perf_evlist *evlist) +{ +struct perf_evsel *evsel; +u64 compat =0 ; + +list_for_each_entry (evsel, &evlist->entries, node) + compat |= evsel->attr.sample_type &PERF_COMPAT_MASK ; + +list_for_each_entry (evsel, &evlist->entries, node) { + evsel->attr.sample_type |= compat; + evsel->sample_size = +__perf_evsel__sample_size (evsel->attr.sample_type); +perf_evsel__calc_id_pos (evsel); + } + +perf_evlist__set_id_pos (evlist); +} +static void perf_evlist__purge (struct perf_evlist *evlist) {struct perf_evsel *pos, *n;
tools/perf/util/evlist.h +1 -0
@@ -89,6 +89,7 @@ int perf_evlist__open(struct perf_evlist *evlist);void perf_evlist__close (struct perf_evlist *evlist);void perf_evlist__set_id_pos (struct perf_evlist *evlist); +void perf_evlist__make_sample_types_compatible (struct perf_evlist *evlist);bool perf_can_sample_identifier (void );void perf_evlist__config (struct perf_evlist *evlist,struct perf_record_opts *opts);
tools/perf/util/record.c +4 -1
@@ -104,5 +104,8 @@ void perf_evlist__config(struct perf_evlist *evlist,perf_evsel__set_sample_id (evsel, use_sample_identifier); } -perf_evlist__set_id_pos (evlist); +if (use_sample_identifier) +perf_evlist__set_id_pos (evlist); +else +perf_evlist__make_sample_types_compatible (evlist); }
Signature · 1 line
1.7.11.7