perf tools: Introduce an abstraction for Instruction Tracing
Adrian Hunter
reviewercover perf tools: Introduce an abstraction for Instruction Tracing
Hi
I have separated out some more preparatory patches for Intel PT. The first 3 patches are small fixes, but the rest introduce an abstraction for Instruction tracing.
The abstraction has two separate aspects:
1. recording Instruction Trace data
2. processing Instruction Trace data
Recording consists of mmapping a separate buffer and copying the data into the perf.data file. The buffer is an AUX area buffer although the details of the AUX area are not implemented because the kernel support is pending. The data is written preceded by a new user event PERF_RECORD_ITRACE. The data is too big to fit in the event but follows immediately afterward. Session processing has to skip to get to the next event header in a similar fashion to the existing PERF_RECORD_HEADER_TRACING_DATA event. The main recording patches are:
perf evlist: Add initial support for mmapping an Instruction Trace buffer perf tools: Add user events for Instruction Tracing
perf tools: Add support for Instruction Trace recording
perf record: Add basic Instruction Tracing support
Processing consists of providing hooks in session processing to enable an Instruction Trace decoder to see all the events and deliver synthesized events transparently into the event stream. The main processing patch is:
perf session: Add hooks to allow transparent decoding of Instruction Tracing data
Adrian Hunter (25):
perf tools: Do not poll events that use the system_wide flag
perf tools: Add perf-read-vdso32 and perf-read-vdsox32 to .gitignore perf tools: Only override the default :tid comm entry
perf header: Add Instruction Tracing feature
perf evlist: Add initial support for mmapping an Instruction Trace buffer perf tools: Add user events for Instruction Tracing
perf tools: Add support for Instruction Trace recording
perf record: Add basic Instruction Tracing support
perf record: Extend -m option for Instruction Tracing mmap pages perf tools: Add a user event for Instruction Tracing errors
perf session: Add hooks to allow transparent decoding of Instruction Tracing data perf session: Add Instruction Tracing options
perf itrace: Add helpers for Instruction Tracing errors
perf itrace: Add helpers for queuing Instruction Tracing data
perf itrace: Add a heap for sorting Instruction Tracing queues
perf itrace: Add processing for Instruction Tracing events
perf itrace: Add a hashtable for caching decoded instructions
perf tools: Add member to struct dso for an instruction cache
perf script: Add Instruction Tracing support
perf script: Always allow fields 'addr' and 'cpu' for itrace
perf report: Add Instruction Tracing support
perf inject: Re-pipe Instruction Tracing events
perf inject: Add Instruction Tracing support
perf tools: Add Instruction Tracing index
perf tools: Hit all build ids when Instruction Tracing
tools/perf/.gitignore | 2 + tools/perf/Documentation/perf-inject.txt | 27 + tools/perf/Documentation/perf-record.txt | 2 + tools/perf/Documentation/perf-report.txt | 28 + tools/perf/Documentation/perf-script.txt | 28 + tools/perf/Makefile.perf | 2 + tools/perf/builtin-buildid-list.c | 9 + tools/perf/builtin-inject.c | 157 +++- tools/perf/builtin-record.c | 173 +++- tools/perf/builtin-report.c | 12 + tools/perf/builtin-script.c | 39 +- tools/perf/perf.h | 2 + tools/perf/util/dso.c | 2 + tools/perf/util/dso.h | 3 + tools/perf/util/event.c | 3 + tools/perf/util/event.h | 38 + tools/perf/util/evlist.c | 80 +- tools/perf/util/evlist.h | 6 + tools/perf/util/header.c | 36 + tools/perf/util/header.h | 1 + tools/perf/util/itrace.c | 1255 ++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 447 +++++++++++ tools/perf/util/record.c | 11 +- tools/perf/util/session.c | 148 +++- tools/perf/util/session.h | 6 + tools/perf/util/thread.c | 5 +- tools/perf/util/tool.h | 10 +- 27 files changed, 2481 insertions(+), 51 deletions(-) create mode 100644 tools/perf/util/itrace.c create mode 100644 tools/perf/util/itrace.h
Regards
Adrian
Adrian Hunter
reviewerPATCH 1/25 perf tools: Do not poll events that use the system_wide flag
The system_wide flag causes a selected event to be opened always without a pid. Consequently it will never get a POLLHUP, but it is used for tracking in combination with other events, so it should not need to be polled anyway. Therefore don't add it for polling.
--- tools/perf/util/evlist.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
tools/perf/util/evlist.c +9 -1
@@ -816,7 +816,15 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,perf_evlist__mmap_get (evlist, idx); } -if (__perf_evlist__add_pollfd (evlist, fd, idx) <0 ) { +/* +* The system_wide flag causes a selected event to be opened +* always without a pid. Consequently it will never get a +* POLLHUP, but it is used for tracking in combination with +* other events, so it should not need to be polled anyway. +* Therefore don't add it for polling. +*/ +if (!evsel->system_wide && +__perf_evlist__add_pollfd (evlist, fd, idx) <0 ) {perf_evlist__mmap_put (evlist, idx);return -1 ; }
Signature · 1 line
1.9.1
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf evlist: Do not poll events that use the system_wide flag
perf evlist: Do not poll events that use the system_wide flag
Commit-ID: f90d194a867a5a1db51789b8c4e99bcd196be6bb Gitweb: http://git.kernel.org/tip/f90d194a867a5a1db51789b8c4e99bcd196be6bb Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 11 Nov 2014 16:16:39 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 19 Nov 2014 12:33:48 -0300
perf evlist: Do not poll events that use the system_wide flag
The system_wide flag causes a selected event to be opened always without a pid.
Consequently it will never get a POLLHUP, but it is used for tracking in combination with other events, so it should not need to be polled anyway.
Therefore don't add it for polling.
--- tools/perf/util/evlist.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
tools/perf/util/evlist.c +9 -1
@@ -816,7 +816,15 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,perf_evlist__mmap_get (evlist, idx); } -if (__perf_evlist__add_pollfd (evlist, fd, idx) <0 ) { +/* +* The system_wide flag causes a selected event to be opened +* always without a pid. Consequently it will never get a +* POLLHUP, but it is used for tracking in combination with +* other events, so it should not need to be polled anyway. +* Therefore don't add it for polling. +*/ +if (!evsel->system_wide && +__perf_evlist__add_pollfd (evlist, fd, idx) <0 ) {perf_evlist__mmap_put (evlist, idx);return -1 ; }
Adrian Hunter
reviewerPATCH 2/25 perf tools: Add perf-read-vdso32 and perf-read-vdsox32 to .gitignore
In reply to Adrian HunterRecently added executables Add perf-read-vdso32 and perf-read-vdsox32 need to be added to .gitignore.
--- tools/perf/.gitignore | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/.gitignore +2 -0
@@ -2,6 +2,8 @@ PERF-CFLAGS PERF-GUI-VARS PERF-VERSION-FILE perf +perf-read-vdso32 +perf-read-vdsox32 perf-help perf-record perf-report
Signature · 1 line
1.9.1
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add perf-read-vdso32 and perf-read-vdsox32 to .gitignore
perf tools: Add perf-read-vdso32 and perf-read-vdsox32 to .gitignore
Commit-ID: 4b34f19b66ad29f10af90ad396131adbd16d737f Gitweb: http://git.kernel.org/tip/4b34f19b66ad29f10af90ad396131adbd16d737f Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 11 Nov 2014 16:16:40 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 19 Nov 2014 12:34:24 -0300
perf tools: Add perf-read-vdso32 and perf-read-vdsox32 to .gitignore
Recently added executables Add perf-read-vdso32 and perf-read-vdsox32 need to be added to .gitignore.
--- tools/perf/.gitignore | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/.gitignore +2 -0
@@ -2,6 +2,8 @@ PERF-CFLAGS PERF-GUI-VARS PERF-VERSION-FILE perf +perf-read-vdso32 +perf-read-vdsox32 perf-help perf-record perf-report
Adrian Hunter
reviewerPATCH 3/25 perf tools: Only override the default :tid comm entry
In reply to Adrian HunterEvents may still be ordered even if there are no timestamps e.g. if the data is recorded per-thread.
Also synthesized COMM events have a timestamp of zero.
Consequently it is better to keep comm entries even if they have a timestamp of zero.
However, when a struct thread is created the command string is not known and a comm entry with a string of the form ":<tid>" is used. In that case thread->comm_set is false and the comm entry should be overridden.
--- tools/perf/util/thread.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
tools/perf/util/thread.c +2 -3
@@ -103,15 +103,14 @@ struct comm *thread__exec_comm(const struct thread *thread)return last; } -/* CHECKME: time should always be 0 if event aren't ordered */ int __thread__set_comm (struct thread *thread,const char *str,u64 timestamp,bool exec) {struct comm *new, *curr =thread__comm (thread);int err; -/* Override latest entry if it had no specific time coverage */ -if (!curr->start && !curr->exec) { +/* Override the default :tid entry */ +if (!thread->comm_set) { err =comm__override (curr, str, timestamp, exec);if (err)return err;
Signature · 1 line
1.9.1
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Only override the default : tid comm entry
perf tools: Only override the default :tid comm entry
Commit-ID: a84808083688d82d7f1e5786ccf5df0ff7d448cb Gitweb: http://git.kernel.org/tip/a84808083688d82d7f1e5786ccf5df0ff7d448cb Author: Adrian Hunter <[email protected]> AuthorDate: Tue, 11 Nov 2014 16:16:41 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Wed, 19 Nov 2014 12:37:26 -0300
perf tools: Only override the default :tid comm entry
Events may still be ordered even if there are no timestamps e.g. if the data is recorded per-thread.
Also synthesized COMM events have a timestamp of zero.
Consequently it is better to keep comm entries even if they have a timestamp of zero.
However, when a struct thread is created the command string is not known and a comm entry with a string of the form ":<tid>" is used.
In that case thread->comm_set is false and the comm entry should be overridden.
--- tools/perf/util/thread.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
tools/perf/util/thread.c +2 -3
@@ -103,15 +103,14 @@ struct comm *thread__exec_comm(const struct thread *thread)return last; } -/* CHECKME: time should always be 0 if event aren't ordered */ int __thread__set_comm (struct thread *thread,const char *str,u64 timestamp,bool exec) {struct comm *new, *curr =thread__comm (thread);int err; -/* Override latest entry if it had no specific time coverage */ -if (!curr->start && !curr->exec) { +/* Override the default :tid entry */ +if (!thread->comm_set) { err =comm__override (curr, str, timestamp, exec);if (err)return err;
Adrian Hunter
reviewerPATCH 4/25 perf header: Add Instruction Tracing feature
In reply to Adrian HunterAdd a feature to indicate that a perf.data file
contains Instruction Tracing data.
--- tools/perf/util/header.c | 14 ++++++++++++++ tools/perf/util/header.h | 1 + 2 files changed, 15 insertions(+)
tools/perf/util/header.c +14 -0
@@ -869,6 +869,13 @@ static int write_branch_stack(int fd __maybe_unused,return 0 ; } +static int write_itrace (int fd__maybe_unused , +struct perf_header *h__maybe_unused , +struct perf_evlist *evlist__maybe_unused ) +{ +return 0 ; +} +static void print_hostname (struct perf_header *ph,int fd__maybe_unused ,FILE *fp) {
@@ -1163,6 +1170,12 @@ static void print_branch_stack(struct perf_header *ph __maybe_unused,fprintf (fp,"# contains samples with branch stack\n" ); } +static void print_itrace (struct perf_header *ph__maybe_unused , +int fd__maybe_unused ,FILE *fp) +{ +fprintf (fp,"# contains Instruction Traces\n" ); +} +static void print_pmu_mappings (struct perf_header *ph,int fd__maybe_unused ,FILE *fp) {
@@ -1873,6 +1886,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {FEAT_OPA (HEADER_BRANCH_STACK , branch_stack),FEAT_OPP (HEADER_PMU_MAPPINGS , pmu_mappings),FEAT_OPP (HEADER_GROUP_DESC , group_desc), + FEAT_OPA(HEADER_ITRACE, itrace), }; struct header_print_data {
tools/perf/util/header.h +1 -0
@@ -30,6 +30,7 @@ enum {HEADER_BRANCH_STACK ,HEADER_PMU_MAPPINGS ,HEADER_GROUP_DESC , +HEADER_ITRACE ,HEADER_LAST_FEATURE , HEADER_FEAT_BITS = 256, };
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 5/25 perf evlist: Add initial support for mmapping an Instruction Trace buffer
In reply to Adrian HunterThis patch anticipates the addition to the kernel
of an "aux" buffer that can be mmapped separately
from the perf-events buffer.
The expectation is that this buffer can be configured to contain hardware-produced trace information for Instruction Tracing, hence the name "itrace". The first implementation will support Intel BTS and Intel PT.
One itrace buffer is mmapped per perf-events buffer. If the requested itrace buffer size is zero, which it will be until further support is added, then no itrace mmapping is attempted.
--- tools/perf/Makefile.perf | 2 + tools/perf/util/evlist.c | 60 +++++++++++++++++++++++++++-- tools/perf/util/evlist.h | 5 +++ tools/perf/util/itrace.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 tools/perf/util/itrace.c create mode 100644 tools/perf/util/itrace.h
tools/perf/Makefile.perf +2 -0
@@ -314,6 +314,7 @@ LIB_H += util/perf_regs.h LIB_H += util/unwind.h LIB_H += util/vdso.h LIB_H += util/tsc.h +LIB_H += util/itrace.h LIB_H += ui/helpline.h LIB_H += ui/progress.h LIB_H += ui/util.h
@@ -399,6 +400,7 @@ LIB_OBJS += $(OUTPUT)util/data.o LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)util/cloexec.o LIB_OBJS += $(OUTPUT)util/thread-stack.o +LIB_OBJS += $(OUTPUT)util/itrace.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/evlist.c +57 -3
124 lines not on this page · raw message
tools/perf/util/evlist.h +5 -0
@@ -8,6 +8,7 @@#include "event.h" #include "evsel.h" #include "util.h" +#include "itrace.h" #include <unistd.h> struct pollfd ;
@@ -28,6 +29,7 @@ struct perf_mmap {int mask;int refcnt;unsigned int prev; +struct itrace_mmap itrace_mmap;char event_copy[PERF_SAMPLE_MAX_SIZE ]; };
@@ -123,6 +125,9 @@ int perf_evlist__parse_mmap_pages(const struct option *opt,const char *str, int unset); +int perf_evlist__mmap_ex (struct perf_evlist *evlist,unsigned int pages, +bool overwrite,unsigned int itrace_pages, +bool itrace_overwrite);int perf_evlist__mmap (struct perf_evlist *evlist,unsigned int pages,bool overwrite);void perf_evlist__munmap (struct perf_evlist *evlist);
tools/perf/util/itrace.c new file +99 -0
99 lines not on this page · raw message
tools/perf/util/itrace.h new file +96 -0
96 lines not on this page · raw message
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 6/25 perf tools: Add user events for Instruction Tracing
In reply to Adrian HunterAdd two user events for Instruction Tracing.
PERF_RECORD_ITRACE_INFO contains metadata, consisting primarily the type of the Instruction Tracing data plus some amount of architecture-specific information. There should be only one PERF_RECORD_ITRACE_INFO event.
PERF_RECORD_ITRACE identifies Instruction Tracing data copied from the mmapped Instruction Tracing region. The actual data is not part of the event but immediately follows it.
--- tools/perf/util/event.c | 2 ++ tools/perf/util/event.h | 22 +++++++++++++++ tools/perf/util/session.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/tool.h | 9 ++++++- 4 files changed, 101 insertions(+), 1 deletion(-)
tools/perf/util/event.c +2 -0
@@ -29,6 +29,8 @@ static const char *perf_event__names[] = { [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", [PERF_RECORD_ID_INDEX] = "ID_INDEX", + [PERF_RECORD_ITRACE_INFO] = "ITRACE_INFO", + [PERF_RECORD_ITRACE] = "ITRACE", };const char *perf_event__name (unsigned int id)
tools/perf/util/event.h +22 -0
@@ -214,6 +214,8 @@ enum perf_user_event_type { /* above any possible kernel type */PERF_RECORD_HEADER_BUILD_ID =67 ,PERF_RECORD_FINISHED_ROUND =68 ,PERF_RECORD_ID_INDEX =69 , +PERF_RECORD_ITRACE_INFO =70 , +PERF_RECORD_ITRACE =71 , PERF_RECORD_HEADER_MAX };
@@ -279,6 +281,24 @@ struct id_index_event {struct id_index_entry entries[0 ]; }; +struct itrace_info_event { +struct perf_event_header header; +u32 type; +u32 reserved__;/* For alignment */ +u64 priv[]; +}; + +struct itrace_event { +struct perf_event_header header; +u64 size; +u64 offset; +u64 reference; +u32 idx; +u32 tid; +u32 cpu; +u32 reserved__;/* For alignment */ +}; +union perf_event {struct perf_event_header header;struct mmap_event mmap;
@@ -294,6 +314,8 @@ union perf_event {struct tracing_data_event tracing_data;struct build_id_event build_id;struct id_index_event id_index; +struct itrace_info_event itrace_info; +struct itrace_event itrace; };void perf_event__print_totals (void );
tools/perf/util/session.c +69 -0
99 lines not on this page · raw message
tools/perf/util/tool.h +8 -1
@@ -3,6 +3,8 @@#include <stdbool.h> +#include <linux/types.h> +struct perf_session ;union perf_event ;struct perf_evlist ;
@@ -25,6 +27,9 @@ typedef int (*event_attr_op)(struct perf_tool *tool,typedef int (*event_op2 )(struct perf_tool *tool,union perf_event *event,struct perf_session *session); +typedef s64 (*event_op3 )(struct perf_tool *tool,union perf_event *event, +struct perf_session *session); +struct perf_tool {event_sample sample, read;
@@ -40,7 +45,9 @@ struct perf_tool {event_op2 tracing_data;event_op2 finished_round, build_id, - id_index; + id_index, + itrace_info; +event_op3 itrace;bool ordered_events;bool ordering_requires_timestamps; };
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 7/25 perf tools: Add support for Instruction Trace recording
In reply to Adrian HunterAdd support for reading from the Instruction Tracing mmap and synthesizing Instruction Tracing events.
This patch introduces an abstraction for recording Instruction Trace data. Recording is initialized by itrace_record__init() which is a weak function to be implemented by the architecture to provide recording callbacks. Recording is mainly handled by itrace_mmap__read() and perf_event__synthesize_itrace() but there are callbacks for miscellaneous needs including validating and processing user options, populating private data in itrace_info_event, and freeing the structure when finished.
--- tools/perf/perf.h | 2 + tools/perf/util/itrace.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 59 +++++++++++++- tools/perf/util/record.c | 11 ++- 4 files changed, 265 insertions(+), 2 deletions(-)
tools/perf/perf.h +2 -0
@@ -52,8 +52,10 @@ struct record_opts {bool sample_weight;bool sample_time;bool period; +bool full_itrace;unsigned int freq;unsigned int mmap_pages; +unsigned int itrace_mmap_pages;unsigned int user_freq;u64 branch_stack;u64 default_interval;
tools/perf/util/itrace.c +195 -0
210 lines not on this page · raw message
tools/perf/util/itrace.h +58 -1
81 lines not on this page · raw message
tools/perf/util/record.c +10 -1
@@ -119,7 +119,16 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) evsel->attr.comm_exec =1 ; } -if (evlist->nr_entries >1 ) { +if (opts->full_itrace) { +/* +* Need to be able to synthesize and parse selected events with +* arbitrary sample types, which requires always being able to +* match the id. +*/ + use_sample_identifier = true; +evlist__for_each (evlist, evsel) +perf_evsel__set_sample_id (evsel, use_sample_identifier); + }else if (evlist->nr_entries >1 ) {struct perf_evsel *first =perf_evlist__first (evlist);evlist__for_each (evlist, evsel) {
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 8/25 perf record: Add basic Instruction Tracing support
In reply to Adrian HunterAmend the perf record tool to read the
Instruction Tracing mmap and synthesize
Instruction Tracing events.
--- tools/perf/builtin-record.c | 99 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 14 deletions(-)
tools/perf/builtin-record.c +85 -14
@@ -27,6 +27,7 @@#include "util/cpumap.h" #include "util/thread_map.h" #include "util/data.h" +#include "util/itrace.h" #include <unistd.h> #include <sched.h>
@@ -38,6 +39,7 @@ struct record {struct record_opts opts;u64 bytes_written;struct perf_data_file file; +struct itrace_record *itr;struct perf_evlist *evlist;struct perf_session *session;const char *progname;
@@ -110,6 +112,43 @@ out:return rc; } +static int record__process_itrace (struct perf_tool *tool, +union perf_event *event,void *data1, +size_t len1,void *data2,size_t len2) +{ + struct record *rec = container_of(tool, struct record, tool); +size_t padding; +u8 pad[8 ] = {0 }; + +/* event.itrace.size includes padding, see __itrace_mmap__read() */ + padding = (len1 + len2) &7 ; +if (padding) + padding =8 - padding; + +record__write (rec, event, event->header.size); +record__write (rec, data1, len1); +record__write (rec, data2, len2); +record__write (rec, &pad, padding); + +return 0 ; +} + +static int record__itrace_mmap_read (struct record *rec, +struct itrace_mmap *mm) +{ +int ret; + + ret =itrace_mmap__read (mm, rec->itr, &rec->tool, + record__process_itrace); +if (ret <0 ) +return ret; + +if (ret) + rec->samples++; + +return 0 ; +} +static volatile int done =0 ;static volatile int signr =-1 ;static volatile int child_finished =0 ;
@@ -168,13 +207,15 @@ try_again: goto out; } -if (perf_evlist__mmap (evlist, opts->mmap_pages, false) <0 ) { +if (perf_evlist__mmap_ex (evlist, opts->mmap_pages, false, + opts->itrace_mmap_pages, false) <0 ) {if (errno ==EPERM ) {pr_err ("Permission error mapping pages.\n" "Consider increasing " "/proc/sys/kernel/perf_event_mlock_kb,\n" "or try again with a smaller value of -m/--mmap_pages.\n" -"(current value: %u)\n" , opts->mmap_pages); +"(current value: %u,%u)\n" , + opts->mmap_pages, opts->itrace_mmap_pages); rc = -errno; }else { pr_err("failed to mmap with %d (%s)\n", errno,
@@ -257,12 +298,20 @@ static int record__mmap_read_all(struct record *rec)int rc =0 ;for (i =0 ; i < rec->evlist->nr_mmaps; i++) { +struct itrace_mmap *mm = &rec->evlist->mmap[i].itrace_mmap; +if (rec->evlist->mmap[i].base) {if (record__mmap_read (rec, i) !=0 ) { rc =-1 ; goto out; } } + +if (mm->base && +record__itrace_mmap_read (rec, mm) !=0 ) { + rc =-1 ; + goto out; + } }/*
@@ -292,6 +341,9 @@ static void record__init_features(struct record *rec)if (!rec->opts.branch_stack)perf_header__clear_feat (&session->header,HEADER_BRANCH_STACK ); + +if (!rec->opts.full_itrace) +perf_header__clear_feat (&session->header,HEADER_ITRACE ); }static volatile int workload_exec_errno;
@@ -407,6 +459,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } } +if (rec->opts.full_itrace) { + err =perf_event__synthesize_itrace_info (rec->itr, tool, + session, process_synthesized_event); +if (err) + goto out_delete_session; + } + err =perf_event__synthesize_kernel_mmap (tool, process_synthesized_event, machine);if (err <0 )
@@ -505,16 +564,17 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) }if (!quiet) { -fprintf (stderr,"[ perf record: Woken up %ld times to write data ]\n" , waking); - -/* -* Approximate RIP event size: 24 bytes. -*/ -fprintf (stderr, -"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64" samples) ]\n" , - (double )rec->bytes_written /1024.0 /1024.0 , - file->path, - rec->bytes_written /24 ); +fprintf (stderr,"[ perf record: Woken up %ld times to write data ]\n" , + waking); +fprintf (stderr,"[ perf record: Captured and wrote %.3f MB %s" , + (double )rec->bytes_written /1024.0 /1024.0 , file->path); +if (rec->opts.full_itrace) { +fprintf (stderr," ]\n" ); + }else { +/* Approximate RIP event size: 24 bytes */ +fprintf (stderr," (~%" PRIu64" samples) ]\n" , + rec->bytes_written /24 ); + } } out_child:
@@ -818,13 +878,18 @@ struct option *record_options = __record_options;int cmd_record (int argc,const char **argv,const char *prefix__maybe_unused ) { -int err = -ENOMEM ; +int err;struct record *rec = &record;char errbuf[BUFSIZ ]; + rec->itr =itrace_record__init (&err); +if (err) +return err; + + err = -ENOMEM ; rec->evlist =perf_evlist__new ();if (rec->evlist ==NULL ) -return -ENOMEM ; + goto out_itrace_free;perf_config (perf_record_config, rec);
@@ -884,6 +949,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)if (perf_evlist__create_maps (rec->evlist, &rec->opts.target) <0 )usage_with_options (record_usage, record_options); + err =itrace_record__options (rec->itr, rec->evlist, &rec->opts); +if (err) + goto out_symbol_exit; +if (record_opts__config (&rec->opts)) { err = -EINVAL ; goto out_symbol_exit;
@@ -893,5 +962,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) out_symbol_exit:perf_evlist__delete (rec->evlist);symbol__exit (); +out_itrace_free: +itrace_record__free (rec->itr);return err; }
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 9/25 perf record: Extend -m option for Instruction Tracing mmap pages
In reply to Adrian HunterExtend the -m option so that the number
of mmap pages for Instruction Tracing
can be specified.
--- tools/perf/Documentation/perf-record.txt | 2 ++ tools/perf/builtin-record.c | 49 ++++++++++++++++++++++++++++++-- tools/perf/util/evlist.c | 10 +++++-- tools/perf/util/evlist.h | 1 + 4 files changed, 56 insertions(+), 6 deletions(-)
tools/perf/Documentation/perf-record.txt +2 -0
@@ -91,6 +91,8 @@ OPTIONS Number of mmap data pages (must be a power of two) or size specification with appended unit character - B/K/M/G. The size is rounded up to have nearest pages power of two value. + Also, by adding a comma, the number of mmap pages for Instruction + Tracing can be specified. -g:: Enables call-graph (stack chain/backtrace) recording.
tools/perf/builtin-record.c +46 -3
61 lines not on this page · raw message
tools/perf/util/evlist.c +7 -3
@@ -984,10 +984,8 @@ static long parse_pages_arg(const char *str, unsigned long min,return pages; } -int perf_evlist__parse_mmap_pages (const struct option *opt,const char *str, -int unset__maybe_unused ) +int __perf_evlist__parse_mmap_pages (unsigned int *mmap_pages,const char *str) { -unsigned int *mmap_pages = opt->value;unsigned long max =UINT_MAX ;long pages;
@@ -1004,6 +1002,12 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,return 0 ; } +int perf_evlist__parse_mmap_pages (const struct option *opt,const char *str, +int unset__maybe_unused ) +{ +return __perf_evlist__parse_mmap_pages (opt->value, str); +} +/** * perf_evlist__mmap_ex - Create mmaps to receive events. * @evlist: list of events
tools/perf/util/evlist.h +1 -0
@@ -121,6 +121,7 @@ int perf_evlist__start_workload(struct perf_evlist *evlist);struct option ; +int __perf_evlist__parse_mmap_pages (unsigned int *mmap_pages,const char *str);int perf_evlist__parse_mmap_pages (const struct option *opt,const char *str,int unset);
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 10/25 perf tools: Add a user event for Instruction Tracing errors
In reply to Adrian HunterErrors encountered when decoding an Instruction Trace need to be reported to the user. However the "user" might be a script or another tool, so provide a new user event to capture those errors.
--- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 16 ++++++++++++++++ tools/perf/util/session.c | 25 +++++++++++++++++++++++++ tools/perf/util/tool.h | 3 ++- 4 files changed, 44 insertions(+), 1 deletion(-)
tools/perf/util/event.c +1 -0
@@ -31,6 +31,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_ID_INDEX] = "ID_INDEX", [PERF_RECORD_ITRACE_INFO] = "ITRACE_INFO", [PERF_RECORD_ITRACE] = "ITRACE", + [PERF_RECORD_ITRACE_ERROR] = "ITRACE_ERROR", };const char *perf_event__name (unsigned int id)
tools/perf/util/event.h +16 -0
@@ -216,6 +216,7 @@ enum perf_user_event_type { /* above any possible kernel type */PERF_RECORD_ID_INDEX =69 ,PERF_RECORD_ITRACE_INFO =70 ,PERF_RECORD_ITRACE =71 , +PERF_RECORD_ITRACE_ERROR =72 , PERF_RECORD_HEADER_MAX };
@@ -299,6 +300,20 @@ struct itrace_event {u32 reserved__;/* For alignment */ }; +#define MAX_ITRACE_ERROR_MSG 64 + +struct itrace_error_event { +struct perf_event_header header; +u32 type; +u32 code; +u32 cpu; +u32 pid; +u32 tid; +u32 reserved__;/* For alignment */ +u64 ip; +char msg[MAX_ITRACE_ERROR_MSG ]; +}; +union perf_event {struct perf_event_header header;struct mmap_event mmap;
@@ -316,6 +331,7 @@ union perf_event {struct id_index_event id_index;struct itrace_info_event itrace_info;struct itrace_event itrace; +struct itrace_error_event itrace_error; };void perf_event__print_totals (void );
tools/perf/util/session.c +25 -0
@@ -271,6 +271,15 @@ static s64 process_event_itrace_stub(struct perf_tool *tool __maybe_unused,return event->itrace.size; } +static +int process_event_itrace_error_stub (struct perf_tool *tool__maybe_unused , +union perf_event *event__maybe_unused , +struct perf_session *session__maybe_unused ) +{ +dump_printf (": unhandled!\n" ); +return 0 ; +} +void perf_tool__fill_defaults (struct perf_tool *tool) {if (tool->sample ==NULL )
@@ -311,6 +320,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->itrace_info = process_event_itrace_info_stub;if (tool->itrace ==NULL ) tool->itrace = process_event_itrace_stub; +if (tool->itrace_error ==NULL ) + tool->itrace_error = process_event_itrace_error_stub; }static void swap_sample_id_all (union perf_event *event,void *data)
@@ -514,6 +525,17 @@ static void perf_event__itrace_swap(union perf_event *event, event->itrace.cpu =bswap_32 (event->itrace.cpu); } +static void perf_event__itrace_error_swap (union perf_event *event, +bool sample_id_all__maybe_unused ) +{ + event->itrace_error.type =bswap_32 (event->itrace_error.type); + event->itrace_error.code =bswap_32 (event->itrace_error.code); + event->itrace_error.cpu =bswap_32 (event->itrace_error.cpu); + event->itrace_error.pid =bswap_32 (event->itrace_error.pid); + event->itrace_error.tid =bswap_32 (event->itrace_error.tid); + event->itrace_error.ip =bswap_64 (event->itrace_error.ip); +} +typedef void (*perf_event__swap_op )(union perf_event *event,bool sample_id_all);
@@ -535,6 +557,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_ID_INDEX] = perf_event__all64_swap, [PERF_RECORD_ITRACE_INFO] = perf_event__itrace_info_swap, [PERF_RECORD_ITRACE] = perf_event__itrace_swap, + [PERF_RECORD_ITRACE_ERROR] = perf_event__itrace_error_swap, [PERF_RECORD_HEADER_MAX] = NULL, };
@@ -971,6 +994,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,/* setup for reading amidst mmap */ lseek (fd, file_offset + event->header.size,SEEK_SET );return tool->itrace (tool, event, session); +case PERF_RECORD_ITRACE_ERROR : +return tool->itrace_error (tool, event, session);default :return -EINVAL ; }
tools/perf/util/tool.h +2 -1
@@ -46,7 +46,8 @@ struct perf_tool {event_op2 finished_round, build_id, id_index, - itrace_info; + itrace_info, + itrace_error;event_op3 itrace;bool ordered_events;bool ordering_requires_timestamps;
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 11/25 perf session: Add hooks to allow transparent decoding of Instruction Tracing data
In reply to Adrian HunterHook into session processing so that Instruction Trace decoding can synthesize events transparently to the tools.
The advantages of transparent decoding are that tools can be used directly with perf.data files containing Instruction Tracing data, which is easier for the user and more efficient than having a separate decoding tool.
This will work as follows:
1. Tools will feed itrace events to the decoder using perf_tool->itrace() (support for that still to come).
2. The decoder can process side-band events as needed due to the itrace->process_event() hook.
3. The decoder can deliver synthesized events into the event stream using perf_session__deliver_synth_event().
Note the expectation is that decoding will work on data that is time-ordered with respect to the per-cpu or per-thread contexts that were recorded.
--- tools/perf/util/itrace.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.c | 52 +++++++++++++++++++++++++++++++++++++----- tools/perf/util/session.h | 3 +++ 3 files changed, 106 insertions(+), 6 deletions(-)
tools/perf/util/itrace.h +57 -0
@@ -23,6 +23,7 @@#include <linux/types.h> #include "../perf.h" +#include "session.h" union perf_event ;struct perf_session ;
@@ -32,6 +33,26 @@ struct record_opts;struct itrace_info_event ;/** +* struct itrace - session callbacks to allow Instruction Trace data decoding. +* @process_event: lets the decoder see all session events +* @flush_events: process any remaining data +* @free_events: free resources associated with event processing +* @free: free resources associated with the session +* @error_count: number of errors +*/ +struct itrace { +int (*process_event)(struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool); +int (*flush_events)(struct perf_session *session, +struct perf_tool *tool); +void (*free_events)(struct perf_session *session); +void (*free)(struct perf_session *session); +unsigned long long error_count; +}; + +/** * struct itrace_mmap - records an mmap of the itrace buffer. * @base: address of mapped area * @userpg: pointer to buffer's perf_event_mmap_page
@@ -150,4 +171,40 @@ int perf_event__synthesize_itrace(struct perf_tool *tool, size_t size, u64 offset, u64 ref, int idx, u32 tid, u32 cpu); +static inline int itrace__process_event (struct perf_session *session, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool) +{ +if (!session->itrace) +return 0 ; + +return session->itrace->process_event (session, event, sample, tool); +} + +static inline int itrace__flush_events (struct perf_session *session, +struct perf_tool *tool) +{ +if (!session->itrace) +return 0 ; + +return session->itrace->flush_events (session, tool); +} + +static inline void itrace__free_events (struct perf_session *session) +{ +if (!session->itrace) +return ; + +return session->itrace->free_events (session); +} + +static inline void itrace__free (struct perf_session *session) +{ +if (!session->itrace) +return ; + +return session->itrace->free (session); +} +#endif
tools/perf/util/session.c +46 -6
114 lines not on this page · raw message
tools/perf/util/session.h +3 -0
@@ -15,10 +15,13 @@struct ip_callchain ;struct thread ; +struct itrace ; +struct perf_session {struct perf_header header;struct machines machines;struct perf_evlist *evlist; +struct itrace *itrace;struct trace_event tevent;struct events_stats stats;bool repipe;
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 12/25 perf session: Add Instruction Tracing options
In reply to Adrian HunterIt is assumed that Instruction Trace decoding will synthesize events for consumption by other tools. The nature of Instruction Tracing suggests the initial inclusion of options for "instructions" and "branches" events, but more could be added as needed.
--- tools/perf/util/itrace.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 43 +++++++++++++++ tools/perf/util/session.h | 2 + 3 files changed, 176 insertions(+)
tools/perf/util/itrace.c +131 -0
@@ -34,6 +34,7 @@#include "event.h" #include "debug.h" +#include "parse-options.h" int itrace_mmap__mmap (struct itrace_mmap *mm,struct itrace_mmap_params *mp,void *userpg,int fd)
@@ -205,6 +206,136 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,return process (tool, &ev,NULL ,NULL ); } +#define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS +#define PERF_ITRACE_DEFAULT_PERIOD 100000 +#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 +#define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 + +void itrace_synth_opts__set_default (struct itrace_synth_opts *synth_opts) +{ + synth_opts->instructions = true; + synth_opts->branches = true; + synth_opts->errors = true; + synth_opts->period_type =PERF_ITRACE_DEFAULT_PERIOD_TYPE ; + synth_opts->period =PERF_ITRACE_DEFAULT_PERIOD ; + synth_opts->callchain_sz =PERF_ITRACE_DEFAULT_CALLCHAIN_SZ ; +} + +int itrace_parse_synth_opts (const struct option *opt,const char *str, +int unset) +{ +struct itrace_synth_opts *synth_opts = opt->value; +const char *p; +char *endptr; + + synth_opts->set = true; + +if (unset) { + synth_opts->dont_decode = true; +return 0 ; + } + +if (!str) { +itrace_synth_opts__set_default (synth_opts); +return 0 ; + } + +for (p = str; *p;) { +switch (*p++) { +case 'i' : + synth_opts->instructions = true; +while (*p ==' ' || *p ==',' ) + p +=1 ; +if (isdigit (*p)) { + synth_opts->period =strtoull (p, &endptr,10 ); + p = endptr; +while (*p ==' ' || *p ==',' ) + p +=1 ; +switch (*p++) { +case 'i' : + synth_opts->period_type = +PERF_ITRACE_PERIOD_INSTRUCTIONS ; +break ; +case 't' : + synth_opts->period_type = +PERF_ITRACE_PERIOD_TICKS ; +break ; +case 'm' : + synth_opts->period *=1000 ; +/* Fall through */ +case 'u' : + synth_opts->period *=1000 ; +/* Fall through */ +case 'n' : +if (*p++ !='s' ) + goto out_err; + synth_opts->period_type = +PERF_ITRACE_PERIOD_NANOSECS ; +break ; +case '\0' : + goto out; +default : + goto out_err; + } + } +break ; +case 'b' : + synth_opts->branches = true; +break ; +case 'e' : + synth_opts->errors = true; +break ; +case 'd' : + synth_opts->log = true; +break ; +case 'c' : + synth_opts->branches = true; + synth_opts->calls = true; +break ; +case 'r' : + synth_opts->branches = true; + synth_opts->returns = true; +break ; +case 'g' : + synth_opts->instructions = true; + synth_opts->callchain = true; + synth_opts->callchain_sz = +PERF_ITRACE_DEFAULT_CALLCHAIN_SZ ; +while (*p ==' ' || *p ==',' ) + p +=1 ; +if (isdigit (*p)) { +unsigned int val; + + val =strtoul (p, &endptr,10 ); + p = endptr; +if (!val || val >PERF_ITRACE_MAX_CALLCHAIN_SZ ) + goto out_err; + synth_opts->callchain_sz = val; + } +break ; +case ' ' : +case ',' : +break ; +default : + goto out_err; + } + } +out: +if (synth_opts->instructions) { +if (!synth_opts->period_type) + synth_opts->period_type = +PERF_ITRACE_DEFAULT_PERIOD_TYPE ; +if (!synth_opts->period) + synth_opts->period =PERF_ITRACE_DEFAULT_PERIOD ; + } + +return 0 ; + +out_err: +pr_err ("Bad instruction trace options '%s'\n" , str); +return -EINVAL ; +} +int itrace_mmap__read (struct itrace_mmap *mm,struct itrace_record *itr,struct perf_tool *tool,process_itrace_t fn) {
tools/perf/util/itrace.h +43 -0
58 lines not on this page · raw message
tools/perf/util/session.h +2 -0
@@ -16,12 +16,14 @@ struct ip_callchain;struct thread ;struct itrace ; +struct itrace_synth_opts ;struct perf_session {struct perf_header header;struct machines machines;struct perf_evlist *evlist;struct itrace *itrace; +struct itrace_synth_opts *itrace_synth_opts;struct trace_event tevent;struct events_stats stats;bool repipe;
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 13/25 perf itrace: Add helpers for Instruction Tracing errors
In reply to Adrian HunterAdd functions to synthesize, count and print
Instruction Tracing error events.
--- tools/perf/util/itrace.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 16 ++++++++++++++ 2 files changed, 71 insertions(+)
tools/perf/util/itrace.c +55 -0
@@ -22,6 +22,7 @@#include <linux/types.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <errno.h>
@@ -33,6 +34,7 @@#include "itrace.h" #include "event.h" +#include "session.h" #include "debug.h" #include "parse-options.h"
@@ -157,6 +159,28 @@ struct itrace_record * __weak itrace_record__init(int *err)return NULL ; } +void itrace_synth_error (struct itrace_error_event *itrace_error,int type, +int code,int cpu,pid_t pid,pid_t tid,u64 ip, +const char *msg) +{ +size_t size; + +memset (itrace_error,0 ,sizeof (struct itrace_error_event )); + + itrace_error->header.type =PERF_RECORD_ITRACE_ERROR ; + itrace_error->type = type; + itrace_error->code = code; + itrace_error->cpu = cpu; + itrace_error->pid = pid; + itrace_error->tid = tid; + itrace_error->ip = ip; +strlcpy (itrace_error->msg, msg,MAX_ITRACE_ERROR_MSG ); + + size = (void *)itrace_error->msg - (void *)itrace_error + +strlen (itrace_error->msg) +1 ; + itrace_error->header.size =PERF_ALIGN (size,sizeof (u64)); +} + int perf_event__synthesize_itrace_info(struct itrace_record *itr, struct perf_tool *tool, struct perf_session *session,
@@ -336,6 +360,37 @@ out_err:return -EINVAL ; } +size_t perf_event__fprintf_itrace_error (union perf_event *event,FILE *fp) +{ +struct itrace_error_event *e = &event->itrace_error; +int ret; + + ret =fprintf (fp," Instruction trace error type %u" , e->type); + ret +=fprintf (fp," cpu %d pid %d tid %d ip %#" PRIx64" code %u: %s\n" , + e->cpu, e->pid, e->tid, e->ip, e->code, e->msg); +return ret; +} + +int perf_event__process_itrace_error (struct perf_tool *tool__maybe_unused , +union perf_event *event, +struct perf_session *session) +{ +if (session->itrace) + session->itrace->error_count +=1 ; + +perf_event__fprintf_itrace_error (event, stdout); +return 0 ; +} + +int perf_event__count_itrace_error (struct perf_tool *tool__maybe_unused , +union perf_event *event__maybe_unused , +struct perf_session *session) +{ +if (session->itrace) + session->itrace->error_count +=1 ; +return 0 ; +} +int itrace_mmap__read (struct itrace_mmap *mm,struct itrace_record *itr,struct perf_tool *tool,process_itrace_t fn) {
tools/perf/util/itrace.h +16 -0
@@ -33,6 +33,10 @@ struct option;struct record_opts ;struct itrace_info_event ; +enum itrace_error_type { +PERF_ITRACE_DECODER_ERROR =1 , +}; +enum itrace_period_type {PERF_ITRACE_PERIOD_INSTRUCTIONS ,PERF_ITRACE_PERIOD_TICKS ,
@@ -202,6 +206,10 @@ int itrace_record__info_fill(struct itrace_record *itr,void itrace_record__free (struct itrace_record *itr);u64 itrace_record__reference (struct itrace_record *itr); +void itrace_synth_error (struct itrace_error_event *itrace_error,int type, +int code,int cpu,pid_t pid,pid_t tid,u64 ip, +const char *msg); + int perf_event__synthesize_itrace_info(struct itrace_record *itr, struct perf_tool *tool, struct perf_session *session,
@@ -210,10 +218,18 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,perf_event__handler_t process, size_t size, u64 offset, u64 ref, int idx, u32 tid, u32 cpu); +int perf_event__process_itrace_error (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session); +int perf_event__count_itrace_error (struct perf_tool *tool__maybe_unused , +union perf_event *event__maybe_unused , +struct perf_session *session);int itrace_parse_synth_opts (const struct option *opt,const char *str,int unset);void itrace_synth_opts__set_default (struct itrace_synth_opts *synth_opts); +size_t perf_event__fprintf_itrace_error (union perf_event *event,FILE *fp); + static inline int itrace__process_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample,
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 14/25 perf itrace: Add helpers for queuing Instruction Tracing data
In reply to Adrian HunterProvide functions to queue Instruction Tracing data buffers for processing. A Instruction Trace decoder need not use the queues, however Intel BTS and Intel PT will use them.
There is one queue for each of the mmap buffers that were used for recording. Because those mmaps were associated with per-cpu or per-thread contexts, the data is time-ordered with respect to those contexts.
--- tools/perf/util/itrace.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 87 ++++++++++++++ 2 files changed, 391 insertions(+)
tools/perf/util/itrace.c +304 -0
@@ -20,11 +20,15 @@#include <linux/kernel.h> #include <linux/perf_event.h> #include <linux/types.h> +#include <linux/string.h> +#include <sys/param.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <limits.h> #include <errno.h> +#include <linux/list.h> #include "../perf.h" #include "util.h"
@@ -108,6 +112,241 @@ void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp, } } +#define ITRACE_INIT_NR_QUEUES 32 + +static struct itrace_queue *itrace_alloc_queue_array (unsigned int nr_queues) +{ +struct itrace_queue *queue_array; +unsigned int max_nr_queues, i; + + max_nr_queues =MIN (UINT_MAX ,SIZE_MAX ) /sizeof (struct itrace_queue ); +if (nr_queues > max_nr_queues) +return NULL ; + + queue_array =calloc (nr_queues,sizeof (struct itrace_queue )); +if (!queue_array) +return NULL ; + +for (i =0 ; i < nr_queues; i++) { +INIT_LIST_HEAD (&queue_array[i].head); + queue_array[i].priv =NULL ; + } + +return queue_array; +} + +int itrace_queues__init (struct itrace_queues *queues) +{ + queues->nr_queues =ITRACE_INIT_NR_QUEUES ; + queues->queue_array =itrace_alloc_queue_array (queues->nr_queues); +if (!queues->queue_array) +return -ENOMEM ; +return 0 ; +} + +static int itrace_queues__grow (struct itrace_queues *queues, +unsigned int new_nr_queues) +{ +unsigned int nr_queues = queues->nr_queues; +struct itrace_queue *queue_array; +unsigned int i; + +if (!nr_queues) + nr_queues =ITRACE_INIT_NR_QUEUES ; + +while (nr_queues && nr_queues < new_nr_queues) + nr_queues <<=1 ; + +if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues) +return -EINVAL ; + + queue_array =itrace_alloc_queue_array (nr_queues); +if (!queue_array) +return -ENOMEM ; + +for (i =0 ; i < queues->nr_queues; i++) { +list_splice_tail (&queues->queue_array[i].head, + &queue_array[i].head); + queue_array[i].priv = queues->queue_array[i].priv; + } + + queues->nr_queues = nr_queues; + queues->queue_array = queue_array; + +return 0 ; +} + +static void *itrace_copy_data (u64 size,struct perf_session *session) +{ +int fd =perf_data_file__fd (session->file); +void *p; +ssize_t ret; + +if (size >SSIZE_MAX ) +return NULL ; + + p =malloc (size); +if (!p) +return NULL ; + + ret =readn (fd, p, size); +if (ret != (ssize_t )size) { +free (p); +return NULL ; + } + +return p; +} + +static int itrace_queues__add_buffer (struct itrace_queues *queues, +unsigned int idx, +struct itrace_buffer *buffer) +{ +struct itrace_queue *queue; +int err; + +if (idx >= queues->nr_queues) { + err =itrace_queues__grow (queues, idx +1 ); +if (err) +return err; + } + + queue = &queues->queue_array[idx]; + +if (!queue->set) { + queue->set = true; + queue->tid = buffer->tid; + queue->cpu = buffer->cpu; + }else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) { +pr_err ("itrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n" , + queue->cpu, queue->tid, buffer->cpu, buffer->tid); +return -EINVAL ; + } + + buffer->buffer_nr = queues->next_buffer_nr++; + +list_add_tail (&buffer->list, &queue->head); + + queues->new_data = true; + queues->populated = true; + +return 0 ; +} + +/* Limit buffers to 32MiB on 32-bit */ +#define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024) + +static int itrace_queues__split_buffer (struct itrace_queues *queues, +unsigned int idx, +struct itrace_buffer *buffer) +{ +u64 sz = buffer->size; +bool consecutive = false; +struct itrace_buffer *b; +int err; + +while (sz >BUFFER_LIMIT_FOR_32_BIT ) { + b =memdup (buffer,sizeof (struct itrace_buffer )); +if (!b) +return -ENOMEM ; + b->size =BUFFER_LIMIT_FOR_32_BIT ; + b->consecutive = consecutive; + err =itrace_queues__add_buffer (queues, idx, b); +if (err) { +itrace_buffer__free (b); +return err; + } + buffer->data_offset +=BUFFER_LIMIT_FOR_32_BIT ; + sz -=BUFFER_LIMIT_FOR_32_BIT ; + consecutive = true; + } + + buffer->size = sz; + buffer->consecutive = consecutive; + +return 0 ; +} + +static int itrace_queues__add_event_buffer (struct itrace_queues *queues, +struct perf_session *session, +unsigned int idx, +struct itrace_buffer *buffer) +{ +if (session->one_mmap) { + buffer->data = buffer->data_offset - session->one_mmap_offset + + session->one_mmap_addr; + }else if (perf_data_file__is_pipe (session->file)) { + buffer->data =itrace_copy_data (buffer->size, session); +if (!buffer->data) +return -ENOMEM ; + buffer->data_needs_freeing = true; + }else if (BITS_PER_LONG ==32 && + buffer->size >BUFFER_LIMIT_FOR_32_BIT ) { +int err; + + err =itrace_queues__split_buffer (queues, idx, buffer); +if (err) +return err; + } + +return itrace_queues__add_buffer (queues, idx, buffer); +} + +int itrace_queues__add_event (struct itrace_queues *queues, +struct perf_session *session, +union perf_event *event,off_t data_offset, +struct itrace_buffer **buffer_ptr) +{ +struct itrace_buffer *buffer; +unsigned int idx; +int err; + + buffer =zalloc (sizeof (struct itrace_buffer )); +if (!buffer) +return -ENOMEM ; + + buffer->pid =-1 ; + buffer->tid = event->itrace.tid; + buffer->cpu = event->itrace.cpu; + buffer->data_offset = data_offset; + buffer->offset = event->itrace.offset; + buffer->reference = event->itrace.reference; + buffer->size = event->itrace.size; + idx = event->itrace.idx; + + err =itrace_queues__add_event_buffer (queues, session, idx, buffer); +if (err) + goto out_err; + +if (buffer_ptr) + *buffer_ptr = buffer; + +return 0 ; + +out_err: +itrace_buffer__free (buffer); +return err; +} + +void itrace_queues__free (struct itrace_queues *queues) +{ +unsigned int i; + +for (i =0 ; i < queues->nr_queues; i++) { +while (!list_empty (&queues->queue_array[i].head)) { +struct itrace_buffer *buffer; + + buffer =list_entry (queues->queue_array[i].head.next, + struct itrace_buffer, list); +list_del (&buffer->list); +itrace_buffer__free (buffer); + } + } + +zfree (&queues->queue_array); + queues->nr_queues =0 ; +} +size_t itrace_record__info_priv_size (struct itrace_record *itr) {if (itr)
@@ -159,6 +398,71 @@ struct itrace_record * __weak itrace_record__init(int *err)return NULL ; } +struct itrace_buffer *itrace_buffer__next (struct itrace_queue *queue, +struct itrace_buffer *buffer) +{ +if (buffer) { +if (list_is_last (&buffer->list, &queue->head)) +return NULL ; + return list_entry(buffer->list.next, struct itrace_buffer, + list); + }else { +if (list_empty (&queue->head)) +return NULL ; + return list_entry(queue->head.next, struct itrace_buffer, list); + } +} + +void *itrace_buffer__get_data (struct itrace_buffer *buffer,int fd) +{ +size_t adj = buffer->data_offset & (page_size -1 ); +size_t size = buffer->size + adj; +off_t file_offset = buffer->data_offset - adj; +void *addr; + +if (buffer->data) +return buffer->data; + + addr =mmap (NULL , size,PROT_READ ,MAP_SHARED , fd, file_offset); +if (addr ==MAP_FAILED ) +return NULL ; + + buffer->mmap_addr = addr; + buffer->mmap_size = size; + + buffer->data = addr + adj; + +return buffer->data; +} + +void itrace_buffer__put_data (struct itrace_buffer *buffer) +{ +if (!buffer->data || !buffer->mmap_addr) +return ; +munmap (buffer->mmap_addr, buffer->mmap_size); + buffer->mmap_addr =NULL ; + buffer->mmap_size =0 ; + buffer->data =NULL ; + buffer->use_data =NULL ; +} + +void itrace_buffer__drop_data (struct itrace_buffer *buffer) +{ +itrace_buffer__put_data (buffer); +if (buffer->data_needs_freeing) { + buffer->data_needs_freeing = false; +zfree (&buffer->data); + buffer->use_data =NULL ; + buffer->size =0 ; + } +} + +void itrace_buffer__free (struct itrace_buffer *buffer) +{ +itrace_buffer__drop_data (buffer); +free (buffer); +} +void itrace_synth_error (struct itrace_error_event *itrace_error,int type,int code,int cpu,pid_t pid,pid_t tid,u64 ip,const char *msg)
tools/perf/util/itrace.h +87 -0
105 lines not on this page · raw message
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 15/25 perf itrace: Add a heap for sorting Instruction Tracing queues
In reply to Adrian HunterIn order to process Instruction Tracing data in time order, the queue with data with the lowest timestamp must be processed first. Provide a heap to keep track of which queue that is.
As with the queues, a decoder does not have to use the heap, but Intel BTS and Intel PT will use it.
--- tools/perf/util/itrace.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 29 +++++++++++++++++ 2 files changed, 114 insertions(+)
tools/perf/util/itrace.c +85 -0
@@ -347,6 +347,91 @@ void itrace_queues__free(struct itrace_queues *queues) queues->nr_queues =0 ; } +static void itrace_heapify (struct itrace_heap_item *heap_array, +unsigned int pos,unsigned int queue_nr, +u64 ordinal) +{ +unsigned int parent; + +while (pos) { + parent = (pos -1 ) >>1 ; +if (heap_array[parent].ordinal <= ordinal) +break ; + heap_array[pos] = heap_array[parent]; + pos = parent; + } + heap_array[pos].queue_nr = queue_nr; + heap_array[pos].ordinal = ordinal; +} + +int itrace_heap__add (struct itrace_heap *heap,unsigned int queue_nr, +u64 ordinal) +{ +struct itrace_heap_item *heap_array; + +if (queue_nr >= heap->heap_sz) { +unsigned int heap_sz =ITRACE_INIT_NR_QUEUES ; + +while (heap_sz <= queue_nr) + heap_sz <<=1 ; + heap_array =realloc (heap->heap_array, + heap_sz *sizeof (struct itrace_heap_item )); +if (!heap_array) +return -ENOMEM ; + heap->heap_array = heap_array; + heap->heap_sz = heap_sz; + } + +itrace_heapify (heap->heap_array, heap->heap_cnt++, queue_nr, ordinal); + +return 0 ; +} + +void itrace_heap__free (struct itrace_heap *heap) +{ +zfree (&heap->heap_array); + heap->heap_cnt =0 ; + heap->heap_sz =0 ; +} + +void itrace_heap__pop (struct itrace_heap *heap) +{ +unsigned int pos, last, heap_cnt = heap->heap_cnt; +struct itrace_heap_item *heap_array; + +if (!heap_cnt) +return ; + + heap->heap_cnt -=1 ; + + heap_array = heap->heap_array; + + pos =0 ; +while (1 ) { +unsigned int left, right; + + left = (pos <<1 ) +1 ; +if (left >= heap_cnt) +break ; + right = left +1 ; +if (right >= heap_cnt) { + heap_array[pos] = heap_array[left]; +return ; + } +if (heap_array[left].ordinal < heap_array[right].ordinal) { + heap_array[pos] = heap_array[left]; + pos = left; + }else { + heap_array[pos] = heap_array[right]; + pos = right; + } + } + + last = heap_cnt -1 ; +itrace_heapify (heap_array, pos, heap_array[last].queue_nr, + heap_array[last].ordinal); +} +size_t itrace_record__info_priv_size (struct itrace_record *itr) {if (itr)
tools/perf/util/itrace.h +29 -0
@@ -172,6 +172,29 @@ struct itrace_queues { };/** +* struct itrace_heap_item - element of struct itrace_heap. +* @queue_nr: queue number +* @ordinal: value used for sorting (lowest ordinal is top of the heap) expected +* to be a timestamp +*/ +struct itrace_heap_item { +unsigned int queue_nr; +u64 ordinal; +}; + +/** +* struct itrace_heap - a heap suitable for sorting Instruction Tracing queues. +* @heap_array: the heap +* @heap_cnt: the number of elements in the heap +* @heap_sz: maximum number of elements (grows as needed) +*/ +struct itrace_heap { +struct itrace_heap_item *heap_array; +unsigned int heap_cnt; +unsigned int heap_sz; +}; + +/** * struct itrace_mmap - records an mmap of the itrace buffer. * @base: address of mapped area * @userpg: pointer to buffer's perf_event_mmap_page
@@ -280,6 +303,12 @@ void *itrace_buffer__get_data(struct itrace_buffer *buffer, int fd);void itrace_buffer__put_data (struct itrace_buffer *buffer);void itrace_buffer__drop_data (struct itrace_buffer *buffer);void itrace_buffer__free (struct itrace_buffer *buffer); + +int itrace_heap__add (struct itrace_heap *heap,unsigned int queue_nr, +u64 ordinal); +void itrace_heap__pop (struct itrace_heap *heap); +void itrace_heap__free (struct itrace_heap *heap); +struct itrace_record *itrace_record__init (int *err); int itrace_record__options(struct itrace_record *itr,
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 16/25 perf itrace: Add processing for Instruction Tracing events
In reply to Adrian HunterProvide hooks so that an Instruction Trace
decoder can process Instruction Tracing
events.
--- tools/perf/util/itrace.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 13 +++++++++++++ 2 files changed, 62 insertions(+)
tools/perf/util/itrace.c +49 -0
@@ -599,6 +599,28 @@ out_free:return err; } +static bool itrace__dont_decode (struct perf_session *session) +{ +return !session->itrace_synth_opts || + session->itrace_synth_opts->dont_decode; +} + +int perf_event__process_itrace_info (struct perf_tool *tool__maybe_unused , +union perf_event *event, +struct perf_session *session__maybe_unused ) +{ +enum itrace_type type = event->itrace_info.type; + +if (dump_trace) +fprintf (stdout," type: %u\n" , type); + +switch (type) { +case PERF_ITRACE_UNKNOWN : +default : +return -EINVAL ; + } +} + int perf_event__synthesize_itrace(struct perf_tool *tool, perf_event__handler_t process, size_t size, u64 offset, u64 ref, int idx,
@@ -619,6 +641,30 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,return process (tool, &ev,NULL ,NULL ); } +s64 perf_event__process_itrace (struct perf_tool *tool,union perf_event *event, +struct perf_session *session) +{ +s64 err; + +if (dump_trace) +fprintf (stdout," size: %#" PRIx64" offset: %#" PRIx64" ref: %#" PRIx64" idx: %u tid: %d cpu: %d\n" , + event->itrace.size, event->itrace.offset, + event->itrace.reference, event->itrace.idx, + event->itrace.tid, event->itrace.cpu); + +if (itrace__dont_decode (session)) +return event->itrace.size; + +if (!session->itrace || event->header.type !=PERF_RECORD_ITRACE ) +return -EINVAL ; + + err = session->itrace->process_itrace_event (session, event, tool); +if (err <0 ) +return err; + +return event->itrace.size; +} +#define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS#define PERF_ITRACE_DEFAULT_PERIOD 100000#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16
@@ -764,6 +810,9 @@ int perf_event__process_itrace_error(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_session *session) { + if (itrace__dont_decode(session)) + return 0; + if (session->itrace) session->itrace->error_count += 1;
tools/perf/util/itrace.h +13 -0
@@ -34,6 +34,10 @@ struct option;struct record_opts ;struct itrace_info_event ; +enum itrace_type { +PERF_ITRACE_UNKNOWN , +}; +enum itrace_error_type {PERF_ITRACE_DECODER_ERROR =1 , };
@@ -90,6 +94,9 @@ struct itrace {union perf_event *event, struct perf_sample *sample, struct perf_tool *tool); +int (*process_itrace_event)(struct perf_session *session, +union perf_event *event, +struct perf_tool *tool);int (*flush_events)(struct perf_session *session,struct perf_tool *tool);void (*free_events)(struct perf_session *session);
@@ -330,10 +337,16 @@ int perf_event__synthesize_itrace_info(struct itrace_record *itr,struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process); +int perf_event__process_itrace_info (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session);int perf_event__synthesize_itrace (struct perf_tool *tool,perf_event__handler_t process,size_t size,u64 offset,u64 ref,int idx,u32 tid,u32 cpu); +s64 perf_event__process_itrace (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session);int perf_event__process_itrace_error (struct perf_tool *tool,union perf_event *event,struct perf_session *session);
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 17/25 perf itrace: Add a hashtable for caching decoded instructions
In reply to Adrian HunterDecoding Instruction Trace data may involve walking object code. Rather than repetitively decoding the same instructions, a cache can be used to cache the results.
--- tools/perf/util/itrace.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 14 ++++++ 2 files changed, 137 insertions(+)
tools/perf/util/itrace.c +123 -0
@@ -37,6 +37,8 @@#include "thread_map.h" #include "itrace.h" +#include <linux/hash.h> +#include "event.h" #include "session.h" #include "debug.h"
@@ -916,3 +918,124 @@ int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,return 1 ; } + +/** +* struct itrace_cache - hash table to cache decoded instruction blocks +* @hashtable: the hashtable +* @sz: hashtable size (number of hlists) +* @entry_size: size of an entry +* @limit: limit the number of entries to this maximum, when reached the cache +* is dropped and caching begins again with an empty cache +* @cnt: current number of entries +* @bits: hashtable size (@sz = 2^@bits) +*/ +struct itrace_cache { +struct hlist_head *hashtable; +size_t sz; +size_t entry_size; +size_t limit; +size_t cnt; +unsigned int bits; +}; + +struct itrace_cache *itrace_cache__new (unsigned int bits,size_t entry_size, +unsigned int limit_percent) +{ +struct itrace_cache *c; +struct hlist_head *ht; +size_t sz, i; + + c =zalloc (sizeof (struct itrace_cache )); +if (!c) +return NULL ; + + sz =1UL << bits; + + ht =calloc (sz,sizeof (struct hlist_head )); +if (!ht) + goto out_free; + +for (i =0 ; i < sz; i++) +INIT_HLIST_HEAD (&ht[i]); + + c->hashtable = ht; + c->sz = sz; + c->entry_size = entry_size; + c->limit = (c->sz * limit_percent) /100 ; + c->bits = bits; + +return c; + +out_free: +free (c); +return NULL ; +} + +static void itrace_cache__drop (struct itrace_cache *c) +{ +struct itrace_cache_entry *entry; +struct hlist_node *tmp; +size_t i; + +if (!c) +return ; + +for (i =0 ; i < c->sz; i++) { +hlist_for_each_entry_safe (entry, tmp, &c->hashtable[i], hash) { +hlist_del (&entry->hash); +itrace_cache__free_entry (c, entry); + } + } + + c->cnt =0 ; +} + +void itrace_cache__free (struct itrace_cache *c) +{ +if (!c) +return ; + +itrace_cache__drop (c); +free (c->hashtable); +free (c); +} + +void *itrace_cache__alloc_entry (struct itrace_cache *c) +{ +return malloc (c->entry_size); +} + +void itrace_cache__free_entry (struct itrace_cache *c__maybe_unused , +void *entry) +{ +free (entry); +} + +int itrace_cache__add (struct itrace_cache *c,u32 key, +struct itrace_cache_entry *entry) +{ +if (c->limit && ++c->cnt > c->limit) +itrace_cache__drop (c); + + entry->key = key; +hlist_add_head (&entry->hash, &c->hashtable[hash_32 (key, c->bits)]); + +return 0 ; +} + +void *itrace_cache__lookup (struct itrace_cache *c,u32 key) +{ +struct itrace_cache_entry *entry; +struct hlist_head *hlist; + +if (!c) +return NULL ; + + hlist = &c->hashtable[hash_32 (key, c->bits)]; +hlist_for_each_entry (entry, hlist, hash) { +if (entry->key == key) +return entry; + } + +return NULL ; +}
tools/perf/util/itrace.h +14 -0
@@ -316,6 +316,20 @@ int itrace_heap__add(struct itrace_heap *heap, unsigned int queue_nr,void itrace_heap__pop (struct itrace_heap *heap);void itrace_heap__free (struct itrace_heap *heap); +struct itrace_cache_entry { +struct hlist_node hash; +u32 key; +}; + +struct itrace_cache *itrace_cache__new (unsigned int bits,size_t entry_size, +unsigned int limit_percent); +void itrace_cache__free (struct itrace_cache *itrace_cache); +void *itrace_cache__alloc_entry (struct itrace_cache *c); +void itrace_cache__free_entry (struct itrace_cache *c,void *entry); +int itrace_cache__add (struct itrace_cache *c,u32 key, +struct itrace_cache_entry *entry); +void *itrace_cache__lookup (struct itrace_cache *c,u32 key); +struct itrace_record *itrace_record__init (int *err); int itrace_record__options(struct itrace_record *itr,
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 18/25 perf tools: Add member to struct dso for an instruction cache
In reply to Adrian HunterAdd a member to struct dso that can be used by Instruction Trace implementations to hold a cache for decoded instructions.
--- tools/perf/util/dso.c | 2 ++ tools/perf/util/dso.h | 3 +++ 2 files changed, 5 insertions(+)
tools/perf/util/dso.c +2 -0
@@ -4,6 +4,7 @@#include "symbol.h" #include "dso.h" #include "machine.h" +#include "itrace.h" #include "util.h" #include "debug.h"
@@ -914,6 +915,7 @@ void dso__delete(struct dso *dso) }dso__data_close (dso); +itrace_cache__free (dso->itrace_cache);dso_cache__free (&dso->data.cache);dso__free_a2l (dso);zfree (&dso->symsrc_filename);
tools/perf/util/dso.h +3 -0
@@ -101,6 +101,8 @@ struct dsos {struct rb_root root;/* rbtree root sorted by long name */ }; +struct itrace_cache ; +struct dso {struct list_head node;struct rb_node rb_node;/* rbtree node sorted by long name */
@@ -130,6 +132,7 @@ struct dso {u16 long_name_len;u16 short_name_len;void *dwfl;/* DWARF debug info */ +struct itrace_cache *itrace_cache;/* dso data file */ struct {
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 19/25 perf script: Add Instruction Tracing support
In reply to Adrian HunterAdd support for decoding an Instruction Trace.
--- tools/perf/Documentation/perf-script.txt | 28 ++++++++++++++++++++++++++++ tools/perf/builtin-script.c | 11 +++++++++++ 2 files changed, 39 insertions(+)
tools/perf/Documentation/perf-script.txt +28 -0
@@ -215,6 +215,34 @@ OPTIONS --header-only Show only perf.data header. +-Z:: +--itrace:: + Options for decoding Instruction Tracing data. The options are: + + i synthesize instructions events + b synthesize branches events + c synthesize branches events (calls only) + r synthesize branches events (returns only) + e synthesize error events + d create a debug log + g synthesize a call chain for instructions events + + The default is all events i.e. the same as -Zibe + + In addition, the period (default 1000) for instructions events can be + specified in units of: + + i instructions (default) + t ticks + ms milliseconds + us microseconds + ns nanoseconds + + Also the call chain size (default 16, max. 1024) for instructions + events can be specified. + + To disable decoding entirely, use --no-itrace. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1],
tools/perf/builtin-script.c +11 -0
@@ -16,6 +16,7 @@#include "util/evsel.h" #include "util/sort.h" #include "util/data.h" +#include "util/itrace.h" #include <linux/bitmap.h> static char const *script_name;
@@ -1505,6 +1506,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)char *rec_script_path =NULL ;char *rep_script_path =NULL ;struct perf_session *session; +struct itrace_synth_opts itrace_synth_opts = {0 };char *script_path =NULL ;const char **__argv;int i, j, err =0 ;
@@ -1519,6 +1521,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) .attr = process_attr, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, + .id_index = perf_event__process_id_index, + .itrace_info = perf_event__process_itrace_info, + .itrace = perf_event__process_itrace, + .itrace_error = perf_event__process_itrace_error, .ordered_events = true, .ordering_requires_timestamps = true, },
@@ -1570,6 +1576,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "Show the fork/comm/exit events"),OPT_BOOLEAN ('\0' ,"show-mmap-events" , &script.show_mmap_events,"Show the mmap events" ), +OPT_CALLBACK_OPTARG ('Z' ,"itrace" , &itrace_synth_opts,NULL ,"opts" , +"Instruction Tracing options" , + itrace_parse_synth_opts),OPT_END () }; const char * const script_usage[] = {
@@ -1767,6 +1776,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) script.session = session; + session->itrace_synth_opts = &itrace_synth_opts; +if (cpu_list) { err =perf_session__cpu_bitmap (session, cpu_list, cpu_bitmap);if (err <0 )
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 20/25 perf script: Always allow fields 'addr' and 'cpu' for itrace
In reply to Adrian HunterIf a file contains Instruction Tracing data then always allow fields 'addr' and 'cpu' to be selected as options for perf script. This is necessary because Instruction Trace decoding may synthesize events with that information.
--- tools/perf/builtin-script.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-)
tools/perf/builtin-script.c +21 -7
@@ -147,9 +147,10 @@ static const char *output_field2str(enum perf_output_field field)#define PRINT_FIELD (x) (output[attr->type].fields & PERF_OUTPUT_##x) -static int perf_evsel__check_stype (struct perf_evsel *evsel, -u64 sample_type,const char *sample_msg, -enum perf_output_field field) +static int perf_evsel__do_check_stype (struct perf_evsel *evsel, +u64 sample_type,const char *sample_msg, +enum perf_output_field field, +bool allow_user_set) {struct perf_event_attr *attr = &evsel->attr;int type = attr->type;
@@ -159,6 +160,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,return 0 ;if (output[type].user_set) { +if (allow_user_set) +return 0 ; evname =perf_evsel__name (evsel); pr_err("Samples for '%s' event do not have %s attribute set. " "Cannot print '%s' field.\n",
@@ -176,10 +179,21 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,return 0 ; } +static int perf_evsel__check_stype (struct perf_evsel *evsel, +u64 sample_type,const char *sample_msg, +enum perf_output_field field) +{ +return perf_evsel__do_check_stype (evsel, sample_type, sample_msg, field, + false); +} +static int perf_evsel__check_attr (struct perf_evsel *evsel,struct perf_session *session) {struct perf_event_attr *attr = &evsel->attr; +bool allow_user_set; + + allow_user_set =perf_header__has_feat (&session->header,HEADER_ITRACE );if (PRINT_FIELD (TRACE ) && !perf_session__has_traces (session,"record -R" ))
@@ -192,8 +206,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, }if (PRINT_FIELD (ADDR ) && -perf_evsel__check_stype (evsel,PERF_SAMPLE_ADDR ,"ADDR" , -PERF_OUTPUT_ADDR )) +perf_evsel__do_check_stype (evsel,PERF_SAMPLE_ADDR ,"ADDR" , +PERF_OUTPUT_ADDR , allow_user_set))return -EINVAL ;if (PRINT_FIELD (SYM ) && !PRINT_FIELD (IP ) && !PRINT_FIELD (ADDR )) {
@@ -230,8 +244,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,return -EINVAL ;if (PRINT_FIELD (CPU ) && -perf_evsel__check_stype (evsel,PERF_SAMPLE_CPU ,"CPU" , -PERF_OUTPUT_CPU )) +perf_evsel__do_check_stype (evsel,PERF_SAMPLE_CPU ,"CPU" , +PERF_OUTPUT_CPU , allow_user_set))return -EINVAL ; if (PRINT_FIELD(PERIOD) &&
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 21/25 perf report: Add Instruction Tracing support
In reply to Adrian HunterAdd support for decoding an Instruction Trace.
--- tools/perf/Documentation/perf-report.txt | 28 ++++++++++++++++++++++++++++ tools/perf/builtin-report.c | 12 ++++++++++++ 2 files changed, 40 insertions(+)
tools/perf/Documentation/perf-report.txt +28 -0
@@ -308,6 +308,34 @@ OPTIONS --header-only:: Show only perf.data header (forces --stdio). +-Z:: +--itrace:: + Options for decoding Instruction Tracing data. The options are: + + i synthesize instructions events + b synthesize branches events + c synthesize branches events (calls only) + r synthesize branches events (returns only) + e synthesize error events + d create a debug log + g synthesize a call chain for instructions events + + The default is all events i.e. the same as -Zibe + + In addition, the period (default 1000) for instructions events can be + specified in units of: + + i instructions (default) + t ticks + ms milliseconds + us microseconds + ns nanoseconds + + Also the call chain size (default 16, max. 1024) for instructions + events can be specified. + + To disable decoding entirely, use --no-itrace. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-annotate[1]
tools/perf/builtin-report.c +12 -0
@@ -36,6 +36,8 @@#include "util/data.h" #include "arch/common.h" +#include "util/itrace.h" +#include <dlfcn.h> #include <linux/bitmap.h>
@@ -572,6 +574,7 @@ parse_percent_limit(const struct option *opt, const char *str,int cmd_report (int argc,const char **argv,const char *prefix__maybe_unused ) {struct perf_session *session; +struct itrace_synth_opts itrace_synth_opts = {0 };struct stat st;bool has_br_stack = false;int branch_mode =-1 ;
@@ -593,6 +596,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) .attr = perf_event__process_attr, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, + .id_index = perf_event__process_id_index, + .itrace_info = perf_event__process_itrace_info, + .itrace = perf_event__process_itrace, + .itrace_error = perf_event__count_itrace_error, .ordered_events = true, .ordering_requires_timestamps = true, },
@@ -696,6 +703,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "Don't show entries under that percent", parse_percent_limit),OPT_CALLBACK (0 ,"percentage" ,NULL ,"relative|absolute" ,"how to display percentage of filtered entries" , parse_filter_percentage), +OPT_CALLBACK_OPTARG ('Z' ,"itrace" , &itrace_synth_opts,NULL ,"opts" , +"Instruction Tracing options" , + itrace_parse_synth_opts),OPT_END () }; struct perf_data_file file = {
@@ -740,6 +750,8 @@ repeat: report.queue_size); } + session->itrace_synth_opts = &itrace_synth_opts; + report.session = session; has_br_stack = perf_header__has_feat(&session->header,
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 22/25 perf inject: Re-pipe Instruction Tracing events
In reply to Adrian HunterNew Instruction Tracing events must be re-piped by default.
--- tools/perf/builtin-inject.c | 63 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-)
tools/perf/builtin-inject.c +58 -5
@@ -38,14 +38,11 @@ struct event_entry {union perf_event event[0 ]; }; -static int perf_event__repipe_synth (struct perf_tool *tool, -union perf_event *event) +static int output_bytes (struct perf_inject *inject,void *buf,size_t sz) { - struct perf_inject *inject = container_of(tool, struct perf_inject, tool);ssize_t size; - size =perf_data_file__write (&inject->output, event, - event->header.size); + size =perf_data_file__write (&inject->output, buf, sz);if (size <0 )return -errno;
@@ -53,6 +50,34 @@ static int perf_event__repipe_synth(struct perf_tool *tool,return 0 ; } +static int copy_bytes (struct perf_inject *inject,int fd,off_t size) +{ +char buf[4096 ]; +ssize_t ssz; +int ret; + +while (size >0 ) { + ssz =read (fd, buf,MIN (size,sizeof (buf))); +if (ssz <0 ) +return -errno; + ret =output_bytes (inject, buf, ssz); +if (ret) +return ret; + size -= ssz; + } + +return 0 ; +} + +static int perf_event__repipe_synth (struct perf_tool *tool, +union perf_event *event) +{ + struct perf_inject *inject = container_of(tool, struct perf_inject, + tool); + +return output_bytes (inject, event, event->header.size); +} +static int perf_event__repipe_op2_synth (struct perf_tool *tool,union perf_event *event, struct perf_session *session
@@ -79,6 +104,31 @@ static int perf_event__repipe_attr(struct perf_tool *tool,return perf_event__repipe_synth (tool, event); } +static s64 perf_event__repipe_itrace (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session +__maybe_unused ) +{ + struct perf_inject *inject = container_of(tool, struct perf_inject, + tool); +int ret; + +if (perf_data_file__is_pipe (session->file) || !session->one_mmap) { + ret =output_bytes (inject, event, event->header.size); +if (ret <0 ) +return ret; + ret =copy_bytes (inject,perf_data_file__fd (session->file), + event->itrace.size); + }else { + ret =output_bytes (inject, event, + event->header.size + event->itrace.size); + } +if (ret <0 ) +return ret; + +return event->itrace.size; +} + static int perf_event__repipe(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __maybe_unused,
@@ -407,6 +457,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .unthrottle = perf_event__repipe, .attr = perf_event__repipe_attr, .tracing_data = perf_event__repipe_op2_synth, + .itrace_info = perf_event__repipe_op2_synth, + .itrace = perf_event__repipe_itrace, + .itrace_error = perf_event__repipe_op2_synth, .finished_round = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth, .id_index = perf_event__repipe_op2_synth,
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 23/25 perf inject: Add Instruction Tracing support
In reply to Adrian HunterAdd support for decoding an Instruction Trace. The Instruction Tracing events are stripped and replaced by synthesized events.
--- tools/perf/Documentation/perf-inject.txt | 27 ++++++++++++ tools/perf/builtin-inject.c | 71 +++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 2 deletions(-)
tools/perf/Documentation/perf-inject.txt +27 -0
@@ -44,6 +44,33 @@ OPTIONS --kallsyms=<file>:: kallsyms pathname +-Z:: +--itrace:: + Decode Instruction Tracing data, replacing it with synthesized events. + Options are: + + i synthesize instructions events + b synthesize branches events + c synthesize branches events (calls only) + r synthesize branches events (returns only) + e synthesize error events + d create a debug log + g synthesize a call chain for instructions events + + The default is all events i.e. the same as -Zibe + + In addition, the period (default 1000) for instructions events can be + specified in units of: + + i instructions (default) + t ticks + ms milliseconds + us microseconds + ns nanoseconds + + Also the call chain size (default 16, max. 1024) for instructions + events can be specified. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
tools/perf/builtin-inject.c +69 -2
131 lines not on this page · raw message
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 24/25 perf tools: Add Instruction Tracing index
In reply to Adrian HunterAdd an index of Instruction Tracing events within a perf.data file.
perf record uses a special user event PERF_RECORD_FINISHED_ROUND to enable sorting of events in chunks instead of having to sort all events altogether.
Instruction Tracing events contain data that can span back to the very beginning of the recording period. i.e. they do not obey the rules of PERF_RECORD_FINISHED_ROUND.
By adding an index, Instruction Tracing events can be found in advance and the PERF_RECORD_FINISHED_ROUND approach works as usual.
The index is recorded with the itrace feature in the perf.data file. A session reads the index but does not process it. An Instruction Trace decoder can queue all the Instruction Trace data in advance using itrace_queues__process_index() or otherwise process the index in some custom manner.
--- tools/perf/builtin-inject.c | 15 ++++ tools/perf/builtin-record.c | 15 ++++ tools/perf/util/header.c | 30 ++++++- tools/perf/util/itrace.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/itrace.h | 35 ++++++++ tools/perf/util/session.c | 2 + tools/perf/util/session.h | 1 + 7 files changed, 308 insertions(+), 4 deletions(-)
tools/perf/builtin-inject.c +15 -0
@@ -115,6 +115,18 @@ static s64 perf_event__repipe_itrace(struct perf_tool *tool, tool);int ret; +if (!inject->output.is_pipe) { +off_t offset; + + offset =lseek (inject->output.fd,0 ,SEEK_CUR ); +if (offset ==-1 ) +return -errno; + ret =itrace_index__itrace_event (&session->itrace_index, event, + offset); +if (ret <0 ) +return ret; + } +if (perf_data_file__is_pipe (session->file) || !session->one_mmap) { ret =output_bytes (inject, event, event->header.size);if (ret <0 )
@@ -481,6 +493,9 @@ static int __cmd_inject(struct perf_inject *inject) output_data_offset =4096 ; } +if (!inject->itrace_synth_opts.set) +itrace_index__free (&session->itrace_index); +if (!file_out->is_pipe)lseek (file_out->fd, output_data_offset,SEEK_SET );
tools/perf/builtin-record.c +15 -0
@@ -117,9 +117,24 @@ static int record__process_itrace(struct perf_tool *tool, size_t len1, void *data2, size_t len2) { struct record *rec = container_of(tool, struct record, tool); +struct perf_data_file *file = &rec->file;size_t padding;u8 pad[8 ] = {0 }; +if (!perf_data_file__is_pipe (file)) { +off_t file_offset; +int fd =perf_data_file__fd (file); +int err; + + file_offset =lseek (fd,0 ,SEEK_CUR ); +if (file_offset ==-1 ) +return -1 ; + err =itrace_index__itrace_event (&rec->session->itrace_index, + event, file_offset); +if (err) +return err; + } +/* event.itrace.size includes padding, see __itrace_mmap__read() */ padding = (len1 + len2) &7 ;if (padding)
tools/perf/util/header.c +26 -4
@@ -869,11 +869,18 @@ static int write_branch_stack(int fd __maybe_unused,return 0 ; } -static int write_itrace (int fd__maybe_unused , -struct perf_header *h__maybe_unused , +static int write_itrace (int fd,struct perf_header *h,struct perf_evlist *evlist__maybe_unused ) { -return 0 ; +struct perf_session *session; +int err; + + session = container_of(h, struct perf_session, header); + + err =itrace_index__write (fd, &session->itrace_index); +if (err <0 ) +pr_err ("Failed to write itrace index\n" ); +return err; } static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
@@ -1846,6 +1853,21 @@ out_free:return ret; } +static int process_itrace (struct perf_file_section *section, +struct perf_header *ph,int fd, +void *data__maybe_unused ) +{ +struct perf_session *session; +int err; + + session = container_of(ph, struct perf_session, header); + + err =itrace_index__process (fd, section->size, session, ph->needs_swap); +if (err <0 ) +pr_err ("Failed to process itrace index\n" ); +return err; +} +struct feature_ops {int (*write)(int fd,struct perf_header *h,struct perf_evlist *evlist);void (*print)(struct perf_header *h,int fd,FILE *fp);
@@ -1886,7 +1908,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {FEAT_OPA (HEADER_BRANCH_STACK , branch_stack),FEAT_OPP (HEADER_PMU_MAPPINGS , pmu_mappings),FEAT_OPP (HEADER_GROUP_DESC , group_desc), - FEAT_OPA(HEADER_ITRACE, itrace), + FEAT_OPP(HEADER_ITRACE, itrace), }; struct header_print_data {
tools/perf/util/itrace.c +214 -0
226 lines not on this page · raw message
tools/perf/util/itrace.h +35 -0
@@ -82,6 +82,32 @@ struct itrace_synth_opts { };/** +* struct itrace_index_entry - indexes a Instruction Tracing event within a +* perf.data file. +* @file_offset: offset within the perf.data file +* @sz: size of the event +*/ +struct itrace_index_entry { +u64 file_offset; +u64 sz; +}; + +#define PERF_ITRACE_INDEX_ENTRY_COUNT 256 + +/** +* struct itrace_index - index of Instruction Tracing events within a perf.data +* file. +* @list: linking a number of arrays of entries +* @nr: number of entries +* @entries: array of entries +*/ +struct itrace_index { +struct list_head list; +size_t nr; +struct itrace_index_entry entries[PERF_ITRACE_INDEX_ENTRY_COUNT ]; +}; + +/** * struct itrace - session callbacks to allow Instruction Trace data decoding. * @process_event: lets the decoder see all session events * @flush_events: process any remaining data
@@ -304,6 +330,8 @@ int itrace_queues__add_event(struct itrace_queues *queues, union perf_event *event, off_t data_offset, struct itrace_buffer **buffer_ptr);void itrace_queues__free (struct itrace_queues *queues); +int itrace_queues__process_index (struct itrace_queues *queues, +struct perf_session *session);struct itrace_buffer *itrace_buffer__next (struct itrace_queue *queue,struct itrace_buffer *buffer);void *itrace_buffer__get_data (struct itrace_buffer *buffer,int fd);
@@ -343,6 +371,13 @@ int itrace_record__info_fill(struct itrace_record *itr,void itrace_record__free (struct itrace_record *itr);u64 itrace_record__reference (struct itrace_record *itr); +int itrace_index__itrace_event (struct list_head *head,union perf_event *event, +off_t file_offset); +int itrace_index__write (int fd,struct list_head *head); +int itrace_index__process (int fd,u64 size,struct perf_session *session, +bool needs_swap); +void itrace_index__free (struct list_head *head); +void itrace_synth_error (struct itrace_error_event *itrace_error,int type,int code,int cpu,pid_t pid,pid_t tid,u64 ip,const char *msg);
tools/perf/util/session.c +2 -0
@@ -97,6 +97,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, session->repipe = repipe;ordered_events__init (&session->ordered_events); +INIT_LIST_HEAD (&session->itrace_index);machines__init (&session->machines);if (file) {
@@ -168,6 +169,7 @@ static void perf_session_env__delete(struct perf_session_env *env)void perf_session__delete (struct perf_session *session) {itrace__free (session); +itrace_index__free (&session->itrace_index);perf_session__destroy_kernel_maps (session);perf_session__delete_dead_threads (session);perf_session__delete_threads (session);
tools/perf/util/session.h +1 -0
@@ -24,6 +24,7 @@ struct perf_session {struct perf_evlist *evlist;struct itrace *itrace;struct itrace_synth_opts *itrace_synth_opts; +struct list_head itrace_index;struct trace_event tevent;struct events_stats stats;bool repipe;
Signature · 1 line
1.9.1
Adrian Hunter
reviewerPATCH 25/25 perf tools: Hit all build ids when Instruction Tracing
In reply to Adrian HunterWe need to include all buildids when a perf.data file contains Instruction Tracing data because we do not decode the trace for that purpose because it would take too long.
--- tools/perf/builtin-buildid-list.c | 9 +++++++++ tools/perf/builtin-inject.c | 8 +++++++- tools/perf/builtin-record.c | 10 +++++++++- 3 files changed, 25 insertions(+), 2 deletions(-)
tools/perf/builtin-buildid-list.c +9 -0
@@ -69,6 +69,15 @@ static int perf_session__list_build_ids(bool force, bool with_hits) session =perf_session__new (&file, false, &build_id__mark_dso_hit_ops);if (session ==NULL )return -1 ; + +/* +* We take all buildids when the file contains Instruction Tracing data +* because we do not decode the trace because it would take too long. +*/ +if (!perf_data_file__is_pipe (&file) && +perf_header__has_feat (&session->header,HEADER_ITRACE )) + with_hits = false; +/* * in pipe-mode, the only way to get the buildids is to parse * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
tools/perf/builtin-inject.c +7 -1
@@ -27,6 +27,7 @@ struct perf_inject {struct perf_session *session;bool build_ids;bool sched_stat; +bool have_itrace;const char *input_name;struct perf_data_file output;u64 bytes_written;
@@ -115,6 +116,8 @@ static s64 perf_event__repipe_itrace(struct perf_tool *tool, tool);int ret; + inject->have_itrace = true; +if (!inject->output.is_pipe) {off_t offset;
@@ -502,9 +505,12 @@ static int __cmd_inject(struct perf_inject *inject) ret =perf_session__process_events (session, &inject->tool);if (!file_out->is_pipe) { -if (inject->build_ids) +if (inject->build_ids) {perf_header__set_feat (&session->header,HEADER_BUILD_ID ); +if (inject->have_itrace) +dsos__hit_all (session); + }/* * The instruction traces have been removed and replaced with * synthesized hardware events, so clear the feature flag.
tools/perf/builtin-record.c +9 -1
@@ -613,8 +613,16 @@ out_child:if (!err && !file->is_pipe) { rec->session->header.data_size += rec->bytes_written; -if (!rec->no_buildid) +if (!rec->no_buildid) {process_buildids (rec); +/* +* We take all buildids when the file contains +* Instruction Tracing data because we do not decode the +* trace because it would take too long. +*/ +if (rec->opts.full_itrace) +dsos__hit_all (rec->session); + }perf_session__write_header (rec->session, rec->evlist, file->fd, true); }
Signature · 1 line
1.9.1