perf/core improvements and fixes
Arnaldo Carvalho de Melo
maintainerHi Ingo,
Please consider pulling, more to come, will continue tomorrow,
- Arnaldo
The following changes since commit 94ac003b665fc04f13a7ab3b2be896b9b9503451:
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (2015-03-03 07:17:53 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo
for you to fetch changes up to 7afa95d95b7b4c17f3c648f58f8c8abdcb619b85:
perf data: Add tracepoint events fields CTF conversion support (2015-03-12 16:10:41 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
User visible:
. Fix UI bug after zoom into thread/dso/symbol and another, after fold/unfold,
in the TUI hists browser (He Kuang)
. Fixes for 'perf probe' handle aliased symbols, for instance in glibc (Masami Hiramatsu, Namhyung Kim)
- 'perf kmem' improvements and fixes: (Namhyung Kim)
- Fix segfault when invalid sort key is given
- Allow -v option
- Fix alignment of slab result table
- 'perf stat' improvements and fixes: (Andi Kleen)
- Output running time and run/enabled ratio in CSV mode
- Fix IPC and other formulas with -A
- Always correctly indent ratio column
. Add tracepoint events fields CTF conversion support to 'perf data' (Sebastian Andrzej Siewior)
Infrastructure:
. Output feature detection's gcc output to a file, to help in debugging (Arnaldo Carvalho de Melo)
. Fix 'perf probe' compiles due to declarations using perf_probe_point (David Ahern)
. Fix possible double free on error in 'perf probe' (He Kuang)
. Remove superfluous thread->comm_set setting (Jiri Olsa)
. Fix libbabeltrace detection (Jiri Olsa)
. More work on separating ordered_events code out of perf_session (Arnaldo Carvalho de Melo)
----------------------------------------------------------------
Andi Kleen (3):
perf stat: Output running time and run/enabled ratio in CSV mode perf stat: Fix IPC and other formulas with -A
perf stat: Always correctly indent ratio column
Arnaldo Carvalho de Melo (6):
perf ordered_events: Untangle from perf_session perf ordered_events: Shorten function signatures perf ordered_events: Allow tools to specify a deliver method perf tools: tool->finished_round() doesn't need perf_session perf ordered_events: Adopt queue() method
perf tools: Output feature detection's gcc output to a file
David Ahern (1):
perf probe: Fix compiles due to declarations using perf_probe_point
He Kuang (3):
perf probe: Fix possible double free on error
perf hists browser: Fix UI bug after zoom into thread/dso/symbol perf hists browser: Fix UI bug after fold/unfold
Jiri Olsa (2):
perf tools: Remove superfluous thread->comm_set setting perf build: Fix libbabeltrace detection
Masami Hiramatsu (3):
perf probe: Fix to handle aliased symbols in glibc
perf probe: Fix --line to handle aliased symbols in glibc Revert "perf probe: Fix to fall back to find probe point in symbols"
Namhyung Kim (5):
perf symbols: Allow symbol alias when loading map for symbol name perf probe: Allow weak symbols to be probed
perf kmem: Fix segfault when invalid sort key is given perf kmem: Allow -v option
perf kmem: Fix alignment of slab result table
Sebastian Andrzej Siewior (1):
perf data: Add tracepoint events fields CTF conversion support
tools/perf/Documentation/perf-kmem.txt | 4 + tools/perf/Makefile.perf | 1 + tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-buildid-list.c | 2 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-inject.c | 15 +- tools/perf/builtin-kmem.c | 17 +- tools/perf/builtin-kvm.c | 13 +- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-record.c | 4 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-stat.c | 89 ++++---- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/config/Makefile | 2 +- .../config/feature-checks/test-libbabeltrace.c | 1 + tools/perf/ui/browsers/hists.c | 19 ++ tools/perf/util/data-convert-bt.c | 246 ++++++++++++++++++++- tools/perf/util/hist.c | 1 + tools/perf/util/ordered-events.c | 57 +++-- tools/perf/util/ordered-events.h | 27 ++- tools/perf/util/probe-event.c | 194 +++++++++++++--- tools/perf/util/session.c | 140 ++++++------ tools/perf/util/session.h | 16 +- tools/perf/util/symbol-elf.c | 3 +- tools/perf/util/symbol.h | 1 + tools/perf/util/thread.c | 1 - tools/perf/util/tool.h | 8 +- 31 files changed, 672 insertions(+), 207 deletions(-)
Arnaldo Carvalho de Melo
maintainerPATCH 1/24 perf ordered_events: Untangle from perf_session
From: Arnaldo Carvalho de Melo <[email protected]>
For use by tools that are not perf.data based, as maybe 'perf trace' in live mode.
--- tools/perf/util/ordered-events.c | 17 +++++++++-------- tools/perf/util/ordered-events.h | 8 +++++--- tools/perf/util/session.c | 37 ++++++++++++++++++++++++++----------- tools/perf/util/session.h | 3 ++- 4 files changed, 42 insertions(+), 23 deletions(-)
tools/perf/util/ordered-events.c +9 -8
@@ -153,10 +153,11 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *evefree_dup_event (oe, event->event); } -static int __ordered_events__flush (struct perf_session *s, +static int __ordered_events__flush (struct ordered_events *oe, +struct machines *machines, +struct perf_evlist *evlist,struct perf_tool *tool) { -struct ordered_events *oe = &s->ordered_events;struct list_head *head = &oe->events;struct ordered_event *tmp, *iter;struct perf_sample sample;
@@ -179,12 +180,12 @@ static int __ordered_events__flush(struct perf_session *s,if (iter->timestamp > limit)break ; - ret =perf_evlist__parse_sample (s->evlist, iter->event, &sample); + ret =perf_evlist__parse_sample (evlist, iter->event, &sample);if (ret)pr_err ("Can't parse sample, err = %d\n" , ret);else { - ret =perf_session__deliver_event (s, iter->event, &sample, tool, - iter->file_offset); + ret =machines__deliver_event (machines, evlist, iter->event, + &sample, tool, iter->file_offset);if (ret)return ret; }
@@ -204,10 +205,10 @@ static int __ordered_events__flush(struct perf_session *s,return 0 ; } -int ordered_events__flush (struct perf_session *s,struct perf_tool *tool, +int ordered_events__flush (struct ordered_events *oe,struct machines *machines, +struct perf_evlist *evlist,struct perf_tool *tool,enum oe_flush how) { -struct ordered_events *oe = &s->ordered_events;static const char *const str[] = {"NONE" ,"FINAL" ,
@@ -251,7 +252,7 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, str[how], oe->nr_events);pr_oe_time (oe->max_timestamp,"max_timestamp\n" ); - err =__ordered_events__flush (s, tool); + err =__ordered_events__flush (oe, machines, evlist, tool);if (!err) {if (how ==OE_FLUSH__ROUND )
tools/perf/util/ordered-events.h +5 -3
@@ -2,9 +2,10 @@#define __ORDERED_EVENTS_H#include <linux/types.h> -#include "tool.h" -struct perf_session ; +struct perf_tool ; +struct perf_evlist ; +struct machines ;struct ordered_event {u64 timestamp;
@@ -40,7 +41,8 @@ struct ordered_events {struct ordered_event *ordered_events__new (struct ordered_events *oe,u64 timestamp,union perf_event *event);void ordered_events__delete (struct ordered_events *oe,struct ordered_event *event); -int ordered_events__flush (struct perf_session *s,struct perf_tool *tool, +int ordered_events__flush (struct ordered_events *oe,struct machines *machines, +struct perf_evlist *evlist,struct perf_tool *tool,enum oe_flush how);void ordered_events__init (struct ordered_events *oe);void ordered_events__free (struct ordered_events *oe);
tools/perf/util/session.c +26 -11
@@ -512,7 +512,11 @@ static int process_finished_round(struct perf_tool *tool,union perf_event *event__maybe_unused , struct perf_session *session) { - return ordered_events__flush(session, tool, OE_FLUSH__ROUND); + struct ordered_events *oe = &session->ordered_events; +struct perf_evlist *evlist = session->evlist; +struct machines *machines = &session->machines; + +return ordered_events__flush (oe, machines, evlist, tool,OE_FLUSH__ROUND ); } int perf_session_queue_event(struct perf_session *s, union perf_event *event,
@@ -520,6 +524,9 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, u64 file_offset) {struct ordered_events *oe = &s->ordered_events; +struct perf_evlist *evlist = s->evlist; +struct machines *machines = &s->machines; +u64 timestamp = sample->time;struct ordered_event *new;
@@ -536,7 +543,7 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, new =ordered_events__new (oe, timestamp, event);if (!new) { -ordered_events__flush (s, tool,OE_FLUSH__HALF ); +ordered_events__flush (oe, machines, evlist, tool,OE_FLUSH__HALF ); new =ordered_events__new (oe, timestamp, event); }
@@ -886,12 +893,12 @@ static int &sample->read.one, machine); } -int perf_session__deliver_event (struct perf_session *session, +int machines__deliver_event (struct machines *machines, +struct perf_evlist *evlist,union perf_event *event,struct perf_sample *sample,struct perf_tool *tool,u64 file_offset) { -struct perf_evlist *evlist = session->evlist;struct perf_evsel *evsel;struct machine *machine;
@@ -899,7 +906,7 @@ int perf_session__deliver_event(struct perf_session *session, evsel =perf_evlist__id2evsel (evlist, sample->id); - machine =machines__find_for_cpumode (&session->machines, event, sample); + machine =machines__find_for_cpumode (machines, event, sample);switch (event->header.type) {case PERF_RECORD_SAMPLE :
@@ -984,12 +991,14 @@ int perf_session__deliver_synth_event(struct perf_session *session,struct perf_sample *sample, struct perf_tool *tool) { - events_stats__inc(&session->evlist->stats, event->header.type); + struct perf_evlist *evlist = session->evlist; + +events_stats__inc (&evlist->stats, event->header.type);if (event->header.type >=PERF_RECORD_USER_TYPE_START )return perf_session__process_user_event (session, event, tool,0 ); -return perf_session__deliver_event (session, event, sample, tool,0 ); +return machines__deliver_event (&session->machines, evlist, event, sample, tool,0 ); }static void event_swap (union perf_event *event,bool sample_id_all)
@@ -1090,8 +1099,8 @@ static s64 perf_session__process_event(struct perf_session *session,return ret; } -return perf_session__deliver_event (session, event, &sample, tool, - file_offset); +return machines__deliver_event (&session->machines, evlist, event, + &sample, tool, file_offset); }void perf_event_header__bswap (struct perf_event_header *hdr)
@@ -1167,6 +1176,9 @@ volatile int session_done;static int __perf_session__process_pipe_events (struct perf_session *session,struct perf_tool *tool) { +struct ordered_events *oe = &session->ordered_events; +struct perf_evlist *evlist = session->evlist; +struct machines *machines = &session->machines;int fd =perf_data_file__fd (session->file);union perf_event *event;uint32_t size, cur_size =0 ;
@@ -1246,7 +1258,7 @@ more: goto more; done:/* do the final flush for ordered samples */ - err =ordered_events__flush (session, tool,OE_FLUSH__FINAL ); + err =ordered_events__flush (oe, machines, evlist, tool,OE_FLUSH__FINAL ); out_err:free (buf);perf_tool__warn_about_errors (tool, &session->evlist->stats);
@@ -1298,6 +1310,9 @@ static int __perf_session__process_events(struct perf_session *session, u64 data_offset, u64 data_size, u64 file_size, struct perf_tool *tool) { + struct ordered_events *oe = &session->ordered_events; +struct perf_evlist *evlist = session->evlist; +struct machines *machines = &session->machines;int fd =perf_data_file__fd (session->file);u64 head, page_offset, file_offset, file_pos, size;int err, mmap_prot, mmap_flags, map_idx =0 ;
@@ -1391,7 +1406,7 @@ more: out:/* do the final flush for ordered samples */ - err =ordered_events__flush (session, tool,OE_FLUSH__FINAL ); + err =ordered_events__flush (oe, machines, evlist, tool,OE_FLUSH__FINAL ); out_err:ui_progress__finish ();perf_tool__warn_about_errors (tool, &session->evlist->stats);
tools/perf/util/session.h +2 -1
@@ -57,7 +57,8 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,void perf_tool__fill_defaults (struct perf_tool *tool); -int perf_session__deliver_event (struct perf_session *session, +int machines__deliver_event (struct machines *machines, +struct perf_evlist *evlist,union perf_event *event,struct perf_sample *sample,struct perf_tool *tool,u64 file_offset);
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 2/24 perf ordered_events: Shorten function signatures
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
By keeping pointers to machines, evlist and tool in ordered_events.
--- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-buildid-list.c | 2 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-inject.c | 6 ++-- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-kvm.c | 6 ++-- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-record.c | 4 +-- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/util/data-convert-bt.c | 4 +-- tools/perf/util/ordered-events.c | 23 +++++++------- tools/perf/util/ordered-events.h | 10 +++--- tools/perf/util/session.c | 65 ++++++++++++++++----------------------- tools/perf/util/session.h | 11 +++---- 19 files changed, 68 insertions(+), 83 deletions(-)
tools/perf/builtin-annotate.c +1 -1
@@ -208,7 +208,7 @@ static int __cmd_annotate(struct perf_annotate *ann) goto out; } - ret =perf_session__process_events (session, &ann->tool); + ret =perf_session__process_events (session);if (ret) goto out;
tools/perf/builtin-buildid-list.c +1 -1
@@ -74,7 +74,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)* the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID */ if (with_hits ||perf_data_file__is_pipe (&file)) -perf_session__process_events (session, &build_id__mark_dso_hit_ops); +perf_session__process_events (session);perf_session__fprintf_dsos_buildid (session, stdout, dso__skip_buildid, with_hits);perf_session__delete (session);
tools/perf/builtin-diff.c +1 -1
@@ -747,7 +747,7 @@ static int __cmd_diff(void) goto out_delete; } - ret =perf_session__process_events (d->session, &tool); + ret =perf_session__process_events (d->session);if (ret) {pr_err ("Failed to process %s\n" , d->file.path); goto out_delete;
tools/perf/builtin-inject.c +3 -3
@@ -359,8 +359,6 @@ static int __cmd_inject(struct perf_inject *inject) }else if (inject->sched_stat) {struct perf_evsel *evsel; - inject->tool.ordered_events = true; -evlist__for_each (session->evlist, evsel) {const char *name =perf_evsel__name (evsel);
@@ -379,7 +377,7 @@ static int __cmd_inject(struct perf_inject *inject)if (!file_out->is_pipe)lseek (fd, session->header.data_offset,SEEK_SET ); - ret =perf_session__process_events (session, &inject->tool); + ret =perf_session__process_events (session);if (!file_out->is_pipe) {if (inject->build_ids)
@@ -458,6 +456,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)return -1 ; } + inject.tool.ordered_events = inject.sched_stat; + file.path = inject.input_name; inject.session =perf_session__new (&file, true, &inject.tool);if (inject.session ==NULL )
tools/perf/builtin-kmem.c +1 -1
@@ -426,7 +426,7 @@ static int __cmd_kmem(struct perf_session *session) }setup_pager (); - err =perf_session__process_events (session, &perf_kmem); + err =perf_session__process_events (session);if (err !=0 ) goto out;sort_result ();
tools/perf/builtin-kvm.c +3 -3
@@ -730,9 +730,9 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,return -1 ; } - err =perf_session_queue_event (kvm->session, event, &kvm->tool, &sample,0 ); + err =perf_session__queue_event (kvm->session, event, &sample,0 );/* -* FIXME: Here we can't consume the event, as perf_session_queue_event will +* FIXME: Here we can't consume the event, as perf_session__queue_event will * point to it, and it'll get possibly overwritten by the kernel. */ perf_evlist__mmap_consume (kvm->evlist, idx);
@@ -1066,7 +1066,7 @@ static int read_events(struct perf_kvm_stat *kvm)if (ret <0 )return ret; -return perf_session__process_events (kvm->session, &kvm->tool); +return perf_session__process_events (kvm->session); }static int parse_target_str (struct perf_kvm_stat *kvm)
tools/perf/builtin-lock.c +1 -1
@@ -878,7 +878,7 @@ static int __cmd_report(bool display_info)if (select_key ()) goto out_delete; - err =perf_session__process_events (session, &eops); + err =perf_session__process_events (session);if (err) goto out_delete;
tools/perf/builtin-mem.c +1 -1
@@ -141,7 +141,7 @@ static int report_raw_events(struct perf_mem *mem)printf ("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n" ); - err =perf_session__process_events (session, &mem->tool); + err =perf_session__process_events (session);if (err)return err;
tools/perf/builtin-record.c +2 -2
@@ -225,7 +225,7 @@ static int process_buildids(struct record *rec)*/ symbol_conf.ignore_vmlinux_buildid = true; -return perf_session__process_events (session, &rec->tool); +return perf_session__process_events (session); }static void perf_event__synthesize_guest_os (struct machine *machine,void *data)
@@ -343,7 +343,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)signal (SIGINT , sig_handler);signal (SIGTERM , sig_handler); - session =perf_session__new (file, false,NULL ); + session =perf_session__new (file, false, tool);if (session ==NULL ) {pr_err ("Perf session creation failed.\n" );return -1 ;
tools/perf/builtin-report.c +1 -1
@@ -482,7 +482,7 @@ static int __cmd_report(struct report *rep)if (ret)return ret; - ret =perf_session__process_events (session, &rep->tool); + ret =perf_session__process_events (session);if (ret)return ret;
tools/perf/builtin-sched.c +1 -1
@@ -1467,7 +1467,7 @@ static int perf_sched__read_events(struct perf_sched *sched) goto out_delete;if (perf_session__has_traces (session,"record -R" )) { -int err =perf_session__process_events (session, &sched->tool); +int err =perf_session__process_events (session);if (err) {pr_err ("Failed to process events, error %d" , err); goto out_delete;
tools/perf/builtin-script.c +1 -1
@@ -800,7 +800,7 @@ static int __cmd_script(struct perf_script *script) script->tool.mmap2 = process_mmap2_event; } - ret =perf_session__process_events (script->session, &script->tool); + ret =perf_session__process_events (script->session);if (debug_mode)pr_err ("Misordered timestamps: %" PRIu64"\n" , nr_unordered);
tools/perf/builtin-timechart.c +1 -1
@@ -1623,7 +1623,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) goto out_delete; } - ret =perf_session__process_events (session, &tchart->tool); + ret =perf_session__process_events (session);if (ret) goto out_delete;
tools/perf/builtin-trace.c +1 -1
@@ -2408,7 +2408,7 @@ static int trace__replay(struct trace *trace)setup_pager (); - err =perf_session__process_events (session, &trace->tool); + err =perf_session__process_events (session);if (err)pr_err ("Failed to process events, error %d" , err);
tools/perf/util/data-convert-bt.c +2 -2
@@ -579,7 +579,7 @@ int bt_convert__perf2ctf(const char *input, const char *path)return -1 ;/* perf.data session */ - session =perf_session__new (&file,0 ,NULL ); + session =perf_session__new (&file,0 , &c.tool);if (!session) goto free_writer;
@@ -591,7 +591,7 @@ int bt_convert__perf2ctf(const char *input, const char *path)if (setup_events (cw, session)) goto free_session; - err =perf_session__process_events (session, &c.tool); + err =perf_session__process_events (session);if (!err) err =bt_ctf_stream_flush (cw->stream);
tools/perf/util/ordered-events.c +11 -12
@@ -153,10 +153,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *evefree_dup_event (oe, event->event); } -static int __ordered_events__flush (struct ordered_events *oe, -struct machines *machines, -struct perf_evlist *evlist, -struct perf_tool *tool) +static int __ordered_events__flush (struct ordered_events *oe) {struct list_head *head = &oe->events;struct ordered_event *tmp, *iter;
@@ -180,12 +177,12 @@ static int __ordered_events__flush(struct ordered_events *oe,if (iter->timestamp > limit)break ; - ret =perf_evlist__parse_sample (evlist, iter->event, &sample); + ret =perf_evlist__parse_sample (oe->evlist, iter->event, &sample);if (ret)pr_err ("Can't parse sample, err = %d\n" , ret);else { - ret =machines__deliver_event (machines, evlist, iter->event, - &sample, tool, iter->file_offset); + ret =machines__deliver_event (oe->machines, oe->evlist, iter->event, + &sample, oe->tool, iter->file_offset);if (ret)return ret; }
@@ -205,9 +202,7 @@ static int __ordered_events__flush(struct ordered_events *oe,return 0 ; } -int ordered_events__flush (struct ordered_events *oe,struct machines *machines, -struct perf_evlist *evlist,struct perf_tool *tool, -enum oe_flush how) +int ordered_events__flush (struct ordered_events *oe,enum oe_flush how) {static const char *const str[] = {"NONE" ,
@@ -252,7 +247,7 @@ int ordered_events__flush(struct ordered_events *oe, struct machines *machines, str[how], oe->nr_events);pr_oe_time (oe->max_timestamp,"max_timestamp\n" ); - err =__ordered_events__flush (oe, machines, evlist, tool); + err =__ordered_events__flush (oe);if (!err) {if (how ==OE_FLUSH__ROUND )
@@ -268,13 +263,17 @@ int ordered_events__flush(struct ordered_events *oe, struct machines *machines,return err; } -void ordered_events__init (struct ordered_events *oe) +void ordered_events__init (struct ordered_events *oe,struct machines *machines, +struct perf_evlist *evlist,struct perf_tool *tool) {INIT_LIST_HEAD (&oe->events);INIT_LIST_HEAD (&oe->cache);INIT_LIST_HEAD (&oe->to_free); oe->max_alloc_size = (u64) -1 ; oe->cur_alloc_size =0 ; + oe->evlist = evlist; + oe->machines = machines; + oe->tool = tool; }void ordered_events__free (struct ordered_events *oe)
tools/perf/util/ordered-events.h +6 -4
@@ -32,6 +32,9 @@ struct ordered_events {struct list_head to_free;struct ordered_event *buffer;struct ordered_event *last; +struct machines *machines; +struct perf_evlist *evlist; +struct perf_tool *tool;int buffer_idx;unsigned int nr_events;enum oe_flush last_flush_type;
@@ -41,10 +44,9 @@ struct ordered_events {struct ordered_event *ordered_events__new (struct ordered_events *oe,u64 timestamp,union perf_event *event);void ordered_events__delete (struct ordered_events *oe,struct ordered_event *event); -int ordered_events__flush (struct ordered_events *oe,struct machines *machines, -struct perf_evlist *evlist,struct perf_tool *tool, -enum oe_flush how); -void ordered_events__init (struct ordered_events *oe); +int ordered_events__flush (struct ordered_events *oe,enum oe_flush how); +void ordered_events__init (struct ordered_events *oe,struct machines *machines, +struct perf_evlist *evlsit,struct perf_tool *tool);void ordered_events__free (struct ordered_events *oe); static inline
tools/perf/util/session.c +26 -39
191 lines not on this page · raw message
tools/perf/util/session.h +4 -7
@@ -48,12 +48,10 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,union perf_event **event_ptr, struct perf_sample *sample); -int perf_session__process_events (struct perf_session *session, -struct perf_tool *tool); +int perf_session__process_events (struct perf_session *session); -int perf_session_queue_event (struct perf_session *s,union perf_event *event, -struct perf_tool *tool,struct perf_sample *sample, -u64 file_offset); +int perf_session__queue_event (struct perf_session *s,union perf_event *event, +struct perf_sample *sample,u64 file_offset);void perf_tool__fill_defaults (struct perf_tool *tool);
@@ -126,8 +124,7 @@ extern volatile int session_done;int perf_session__deliver_synth_event (struct perf_session *session,union perf_event *event, -struct perf_sample *sample, -struct perf_tool *tool); +struct perf_sample *sample); int perf_event__process_id_index(struct perf_tool *tool, union perf_event *event,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 3/24 perf ordered_events: Allow tools to specify a deliver method
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
So that we can simplify the deliver method to pass just:
(ordered_events, ordered_event, sample);
--- tools/perf/util/ordered-events.c | 7 ++++--- tools/perf/util/ordered-events.h | 11 ++++++++++- tools/perf/util/session.c | 30 +++++++++++++++++++++++------- tools/perf/util/session.h | 6 ------ 4 files changed, 37 insertions(+), 17 deletions(-)
tools/perf/util/ordered-events.c +4 -3
@@ -181,8 +181,7 @@ static int __ordered_events__flush(struct ordered_events *oe)if (ret)pr_err ("Can't parse sample, err = %d\n" , ret);else { - ret =machines__deliver_event (oe->machines, oe->evlist, iter->event, - &sample, oe->tool, iter->file_offset); + ret = oe->deliver (oe, iter, &sample);if (ret)return ret; }
@@ -264,7 +263,8 @@ int ordered_events__flush(struct ordered_events *oe, enum oe_flush how) }void ordered_events__init (struct ordered_events *oe,struct machines *machines, -struct perf_evlist *evlist,struct perf_tool *tool) +struct perf_evlist *evlist,struct perf_tool *tool, +ordered_events__deliver_t deliver) {INIT_LIST_HEAD (&oe->events);INIT_LIST_HEAD (&oe->cache);
@@ -274,6 +274,7 @@ void ordered_events__init(struct ordered_events *oe, struct machines *machines, oe->evlist = evlist; oe->machines = machines; oe->tool = tool; + oe->deliver = deliver; }void ordered_events__free (struct ordered_events *oe)
tools/perf/util/ordered-events.h +10 -1
@@ -5,6 +5,7 @@struct perf_tool ;struct perf_evlist ; +struct perf_sample ;struct machines ;struct ordered_event {
@@ -21,6 +22,12 @@ enum oe_flush { OE_FLUSH__HALF, }; +struct ordered_events ; + +typedef int (*ordered_events__deliver_t )(struct ordered_events *oe, +struct ordered_event *event, +struct perf_sample *sample); +struct ordered_events {u64 last_flush;u64 next_flush;
@@ -35,6 +42,7 @@ struct ordered_events {struct machines *machines;struct perf_evlist *evlist;struct perf_tool *tool; +ordered_events__deliver_t deliver;int buffer_idx;unsigned int nr_events;enum oe_flush last_flush_type;
@@ -46,7 +54,8 @@ struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestavoid ordered_events__delete (struct ordered_events *oe,struct ordered_event *event);int ordered_events__flush (struct ordered_events *oe,enum oe_flush how);void ordered_events__init (struct ordered_events *oe,struct machines *machines, -struct perf_evlist *evlsit,struct perf_tool *tool); +struct perf_evlist *evlsit,struct perf_tool *tool, +ordered_events__deliver_t deliver);void ordered_events__free (struct ordered_events *oe); static inline
tools/perf/util/session.c +23 -7
@@ -16,6 +16,12 @@#include "perf_regs.h" #include "asm/bug.h" +static int machines__deliver_event (struct machines *machines, +struct perf_evlist *evlist, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool,u64 file_offset); +static int perf_session__open (struct perf_session *session) {struct perf_data_file *file = session->file;
@@ -86,6 +92,14 @@ static void perf_session__set_comm_exec(struct perf_session *session)machines__set_comm_exec (&session->machines, comm_exec); } +static int ordered_events__deliver_event (struct ordered_events *oe, +struct ordered_event *event, +struct perf_sample *sample) +{ +return machines__deliver_event (oe->machines, oe->evlist, event->event, + sample, oe->tool, event->file_offset); +} +struct perf_session *perf_session__new (struct perf_data_file *file,bool repipe,struct perf_tool *tool) {
@@ -125,8 +139,10 @@ struct perf_session *perf_session__new(struct perf_data_file *file, tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_events = false; - } else - ordered_events__init(&session->ordered_events, &session->machines, session->evlist, tool); + } else { +ordered_events__init (&session->ordered_events, &session->machines, + session->evlist, tool, ordered_events__deliver_event); + }return session;
@@ -888,11 +904,11 @@ static int &sample->read.one, machine); } -int machines__deliver_event (struct machines *machines, -struct perf_evlist *evlist, -union perf_event *event, -struct perf_sample *sample, -struct perf_tool *tool,u64 file_offset) +static int machines__deliver_event (struct machines *machines, +struct perf_evlist *evlist, +union perf_event *event, +struct perf_sample *sample, +struct perf_tool *tool,u64 file_offset) {struct perf_evsel *evsel;struct machine *machine;
tools/perf/util/session.h +0 -6
@@ -55,12 +55,6 @@ int perf_session__queue_event(struct perf_session *s, union perf_event *event,void perf_tool__fill_defaults (struct perf_tool *tool); -int machines__deliver_event (struct machines *machines, -struct perf_evlist *evlist, -union perf_event *event, -struct perf_sample *sample, -struct perf_tool *tool,u64 file_offset); - int perf_session__resolve_callchain(struct perf_session *session, struct perf_evsel *evsel, struct thread *thread,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 4/24 perf tools: tool->finished_round() doesn't need perf_session
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
It is all about flushing the ordered queue or piping it thru, no need for a perf_session pointer.
--- tools/perf/builtin-inject.c | 9 ++++++++- tools/perf/builtin-kvm.c | 7 +++++-- tools/perf/util/session.c | 24 +++++++++++++++--------- tools/perf/util/tool.h | 8 ++++++-- 4 files changed, 34 insertions(+), 14 deletions(-)
tools/perf/builtin-inject.c +8 -1
@@ -53,6 +53,13 @@ static int perf_event__repipe_synth(struct perf_tool *tool,return 0 ; } +static int perf_event__repipe_oe_synth (struct perf_tool *tool, +union perf_event *event, +struct ordered_events *oe__maybe_unused ) +{ +return perf_event__repipe_synth (tool, event); +} +static int perf_event__repipe_op2_synth (struct perf_tool *tool,union perf_event *event, struct perf_session *session
@@ -406,7 +413,7 @@ 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, - .finished_round = perf_event__repipe_op2_synth, + .finished_round = perf_event__repipe_oe_synth, .build_id = perf_event__repipe_op2_synth, .id_index = perf_event__repipe_op2_synth, },
tools/perf/builtin-kvm.c +5 -2
@@ -18,6 +18,7 @@#include "util/stat.h" #include "util/top.h" #include "util/data.h" +#include "util/ordered-events.h" #include <sys/prctl.h> #ifdef HAVE_TIMERFD_SUPPORT
@@ -783,8 +784,10 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)/* flush queue after each round in which we processed events */ if (ntotal) { - kvm->session->ordered_events.next_flush = flush_time; - err = kvm->tool.finished_round (&kvm->tool,NULL , kvm->session); +struct ordered_events *oe = &kvm->session->ordered_events; + + oe->next_flush = flush_time; + err =ordered_events__flush (oe,OE_FLUSH__ROUND );if (err) {if (kvm->lost_events) pr_info("\nLost events: %" PRIu64 "\n\n",
tools/perf/util/session.c +15 -9
@@ -225,10 +225,17 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,return 0 ; } +static int process_build_id_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 ; +} +static int process_finished_round_stub (struct perf_tool *tool__maybe_unused ,union perf_event *event__maybe_unused , -struct perf_session *perf_session -__maybe_unused ) +struct ordered_events *oe__maybe_unused ) {dump_printf (": unhandled!\n" );return 0 ;
@@ -236,7 +243,7 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,static int process_finished_round (struct perf_tool *tool,union perf_event *event, -struct perf_session *session); +struct ordered_events *oe); static int process_id_index_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused,
@@ -274,7 +281,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)if (tool->tracing_data ==NULL ) tool->tracing_data = process_event_synth_tracing_data_stub;if (tool->build_id ==NULL ) - tool->build_id = process_finished_round_stub; + tool->build_id = process_build_id_stub;if (tool->finished_round ==NULL ) {if (tool->ordered_events) tool->finished_round = process_finished_round;
@@ -526,10 +533,8 @@ static perf_event__swap_op perf_event__swap_ops[] = {*/ static int process_finished_round (struct perf_tool *tool__maybe_unused ,union perf_event *event__maybe_unused , -struct perf_session *session) +struct ordered_events *oe) { -struct ordered_events *oe = &session->ordered_events; -return ordered_events__flush (oe,OE_FLUSH__ROUND ); }
@@ -961,7 +966,8 @@ static s64 perf_session__process_user_event(struct perf_session *session, union perf_event *event, u64 file_offset) { -struct perf_tool *tool = session->ordered_events.tool; +struct ordered_events *oe = &session->ordered_events; +struct perf_tool *tool = oe->tool;int fd =perf_data_file__fd (session->file);int err;
@@ -989,7 +995,7 @@ static s64 perf_session__process_user_event(struct perf_session *session,case PERF_RECORD_HEADER_BUILD_ID :return tool->build_id (tool, event, session);case PERF_RECORD_FINISHED_ROUND : -return tool->finished_round (tool, event, session); +return tool->finished_round (tool, event, oe);case PERF_RECORD_ID_INDEX :return tool->id_index (tool, event, session);default :
tools/perf/util/tool.h +6 -2
@@ -10,6 +10,7 @@ struct perf_evsel;struct perf_sample ;struct perf_tool ;struct machine ; +struct ordered_events ; typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample,
@@ -25,6 +26,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 int (*event_oe )(struct perf_tool *tool,union perf_event *event, +struct ordered_events *oe); +struct perf_tool {event_sample sample, read;
@@ -38,8 +42,8 @@ struct perf_tool { unthrottle;event_attr_op attr;event_op2 tracing_data; -event_op2 finished_round, - build_id, +event_oe finished_round; +event_op2 build_id, id_index;bool ordered_events;bool ordering_requires_timestamps;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 5/24 perf tools: Remove superfluous thread->comm_set setting
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
It is set by calling thread__set_comm right before the removed line.
--- tools/perf/util/thread.c | 1 - 1 file changed, 1 deletion(-)
tools/perf/util/thread.c +0 -1
@@ -206,7 +206,6 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) err =thread__set_comm (thread, comm, timestamp);if (err)return err; - thread->comm_set = true; } thread->ppid = parent->tid;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 6/24 perf ordered_events: Adopt queue() method
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Quoted 1 line
From
perf_session, will be used in 'trace'.
--- tools/perf/util/ordered-events.c | 34 ++++++++++++++++++++++++++++++++-- tools/perf/util/ordered-events.h | 4 ++-- tools/perf/util/session.c | 28 +--------------------------- 3 files changed, 35 insertions(+), 31 deletions(-)
tools/perf/util/ordered-events.c +32 -2
@@ -131,8 +131,8 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,return new; } -struct ordered_event * -ordered_events__new (struct ordered_events *oe,u64 timestamp, +static struct ordered_event * +ordered_events__new_event (struct ordered_events *oe,u64 timestamp,union perf_event *event) {struct ordered_event *new;
@@ -153,6 +153,36 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *evefree_dup_event (oe, event->event); } +int ordered_events__queue (struct ordered_events *oe,union perf_event *event, +struct perf_sample *sample,u64 file_offset) +{ +u64 timestamp = sample->time; +struct ordered_event *oevent; + +if (!timestamp || timestamp == ~0ULL ) +return -ETIME ; + +if (timestamp < oe->last_flush) { +pr_oe_time (timestamp,"out of order event\n" ); +pr_oe_time (oe->last_flush,"last flush, last_flush_type %d\n" , + oe->last_flush_type); + + oe->evlist->stats.nr_unordered_events++; + } + + oevent =ordered_events__new_event (oe, timestamp, event); +if (!oevent) { +ordered_events__flush (oe,OE_FLUSH__HALF ); + oevent =ordered_events__new_event (oe, timestamp, event); + } + +if (!oevent) +return -ENOMEM ; + + oevent->file_offset = file_offset; +return 0 ; +} +static int __ordered_events__flush (struct ordered_events *oe) {struct list_head *head = &oe->events;
tools/perf/util/ordered-events.h +2 -2
@@ -49,8 +49,8 @@ struct ordered_events {bool copy_on_queue; }; -struct ordered_event *ordered_events__new (struct ordered_events *oe,u64 timestamp, -union perf_event *event); +int ordered_events__queue (struct ordered_events *oe,union perf_event *event, +struct perf_sample *sample,u64 file_offset);void ordered_events__delete (struct ordered_events *oe,struct ordered_event *event);int ordered_events__flush (struct ordered_events *oe,enum oe_flush how); void ordered_events__init(struct ordered_events *oe, struct machines *machines,
tools/perf/util/session.c +1 -27
@@ -541,33 +541,7 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused,int perf_session__queue_event (struct perf_session *s,union perf_event *event,struct perf_sample *sample,u64 file_offset) { -struct ordered_events *oe = &s->ordered_events; - -u64 timestamp = sample->time; -struct ordered_event *new; - -if (!timestamp || timestamp == ~0ULL ) -return -ETIME ; - -if (timestamp < oe->last_flush) { -pr_oe_time (timestamp,"out of order event\n" ); -pr_oe_time (oe->last_flush,"last flush, last_flush_type %d\n" , - oe->last_flush_type); - - s->evlist->stats.nr_unordered_events++; - } - - new =ordered_events__new (oe, timestamp, event); -if (!new) { -ordered_events__flush (oe,OE_FLUSH__HALF ); - new =ordered_events__new (oe, timestamp, event); - } - -if (!new) -return -ENOMEM ; - - new->file_offset = file_offset; -return 0 ; +return ordered_events__queue (&s->ordered_events, event, sample, file_offset); }static void callchain__lbr_callstack_printf (struct perf_sample *sample)
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 7/24 perf probe: Fix to handle aliased symbols in glibc
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix perf probe to handle aliased symbols correctly in glibc. In the glibc, several symbols are defined as an alias of __libc_XXX, e.g. malloc is an alias of __libc_malloc.
In such cases, dwarf has no subroutine instances of the alias functions (e.g. no "malloc" instance), but the map has that symbol and its address.
Thus, if we search the alieased symbol in debuginfo, we always fail to find it, but it is in the map.
To solve this problem, this fails back to address-based alternative search, which searches the symbol in the map, translates its address to alternative (correct) function name by using debuginfo, and retry to find the alternative function point from debuginfo.
This adds fail-back process to --vars, --lines and --add options. So, now you can use those on malloc@libc :)
Without this patch;
-----
# ./perf probe -x /usr/lib64/libc-2.17.so -V malloc
Failed to find the address of malloc
Error: Failed to show vars.
# ./perf probe -x /usr/lib64/libc-2.17.so -a "malloc bytes"
Probe point 'malloc' not found in debuginfo.
Error: Failed to add events.
-----With this patch;
-----
# ./perf probe -x /usr/lib64/libc-2.17.so -V malloc
Available variables at malloc
@<__libc_malloc+0>
size_t bytes
# ./perf probe -x /usr/lib64/libc-2.17.so -a "malloc bytes"
Added new event:
probe_libc:malloc (on malloc in /usr/lib64/libc-2.17.so with bytes)You can now use it in all perf tools, such as:
perf record -e probe_libc:malloc -aR sleep 1
-----
--- tools/perf/util/probe-event.c | 140 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 16 deletions(-)
tools/perf/util/probe-event.c +124 -16
@@ -178,6 +178,25 @@ static struct map *kernel_get_module_map(const char *module)return NULL ; } +static struct map *get_target_map (const char *target,bool user) +{ +/* Init maps of given executable or kernel */ +if (user) +return dso__new_map (target); +else +return kernel_get_module_map (target); +} + +static void put_target_map (struct map *map,bool user) +{ +if (map && user) { +/* Only the user map needs to be released */ +dso__delete (map->dso); +map__delete (map); + } +} + +static struct dso *kernel_get_module_dso (const char *module) {struct dso *dso;
@@ -249,6 +268,13 @@ out:return ret; } +static void clear_perf_probe_point (struct perf_probe_point *pp) +{ +free (pp->file); +free (pp->function); +free (pp->lazy_line); +} +static void clear_probe_trace_events (struct probe_trace_event *tevs,int ntevs) {int i;
@@ -258,6 +284,74 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) }#ifdef HAVE_DWARF_SUPPORT +/* +* Some binaries like glibc have special symbols which are on the symbol +* table, but not in the debuginfo. If we can find the address of the +* symbol from map, we can translate the address back to the probe point. +*/ +static int find_alternative_probe_point (struct debuginfo *dinfo, +struct perf_probe_point *pp, +struct perf_probe_point *result, +const char *target,bool uprobes) +{ +struct map *map =NULL ; +struct symbol *sym; +u64 address =0 ; +int ret = -ENOENT ; + +/* This can work only for function-name based one */ +if (!pp->function || pp->file) +return -ENOTSUP ; + + map =get_target_map (target, uprobes); +if (!map) +return -EINVAL ; + +/* Find the address of given function */ +map__for_each_symbol_by_name (map, pp->function, sym) { +if (sym->binding ==STB_GLOBAL || sym->binding ==STB_LOCAL ) { + address = sym->start; +break ; + } + } +if (!address) { + ret = -ENOENT ; + goto out; + } +pr_debug ("Symbol %s address found : %lx\n" , pp->function, address); + + ret =debuginfo__find_probe_point (dinfo, (unsigned long )address, + result); +if (ret <=0 ) + ret = (!ret) ? -ENOENT : ret; +else { + result->offset += pp->offset; + result->line += pp->line; + ret =0 ; + } + +out: +put_target_map (map, uprobes); +return ret; + +} + +static int get_alternative_probe_event (struct debuginfo *dinfo, +struct perf_probe_event *pev, +struct perf_probe_point *tmp, +const char *target) +{ +int ret; + +memcpy (tmp, &pev->point,sizeof (*tmp)); +memset (&pev->point,0 ,sizeof (pev->point)); + ret =find_alternative_probe_point (dinfo, tmp, &pev->point, + target, pev->uprobes); +if (ret <0 ) +memcpy (&pev->point, tmp,sizeof (*tmp)); + +return ret; +}/* Open new debuginfo of given module */ static struct debuginfo *open_debuginfo (const char *module,bool silent)
@@ -466,6 +560,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, int max_tevs, const char *target) { bool need_dwarf = perf_probe_event_need_dwarf(pev); +struct perf_probe_point tmp;struct debuginfo *dinfo;int ntevs, ret =0 ;
@@ -482,6 +577,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,/* Searching trace events corresponding to a probe event */ ntevs =debuginfo__find_trace_events (dinfo, pev, tevs, max_tevs); +if (ntevs ==0 ) {/* Not found, retry with an alternative */ + ret =get_alternative_probe_event (dinfo, pev, &tmp, target); +if (!ret) { + ntevs =debuginfo__find_trace_events (dinfo, pev, + tevs, max_tevs); +/* +* Write back to the original probe_event for +* setting appropriate (user given) event name +*/ +clear_perf_probe_point (&pev->point); +memcpy (&pev->point, &tmp,sizeof (tmp)); + } + } +debuginfo__delete (dinfo);if (ntevs >0 ) {/* Succeeded to find trace events */
@@ -719,12 +828,13 @@ int show_line_range(struct line_range *lr, const char *module, bool user)static int show_available_vars_at (struct debuginfo *dinfo,struct perf_probe_event *pev,int max_vls,struct strfilter *_filter, -bool externs) +bool externs,const char *target) {char *buf;int ret, i, nvars;struct str_node *node;struct variable_list *vls =NULL , *vl; +struct perf_probe_point tmp;const char *var; buf =synthesize_perf_probe_point (&pev->point);
@@ -734,6 +844,15 @@ static int show_available_vars_at(struct debuginfo *dinfo, ret =debuginfo__find_available_vars_at (dinfo, pev, &vls, max_vls, externs); +if (!ret) {/* Not found, retry with an alternative */ + ret =get_alternative_probe_event (dinfo, pev, &tmp, target); +if (!ret) { + ret =debuginfo__find_available_vars_at (dinfo, pev, + &vls, max_vls, externs); +/* Release the old probe_point */ +clear_perf_probe_point (&tmp); + } + }if (ret <=0 ) {if (ret ==0 || ret == -ENOENT ) {pr_err ("Failed to find the address of %s\n" , buf);
@@ -796,7 +915,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,for (i =0 ; i < npevs && ret >=0 ; i++) ret =show_available_vars_at (dinfo, &pevs[i], max_vls, _filter, - externs); + externs, module);debuginfo__delete (dinfo); out:
@@ -1742,15 +1861,12 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,void clear_perf_probe_event (struct perf_probe_event *pev) { -struct perf_probe_point *pp = &pev->point;struct perf_probe_arg_field *field, *next;int i;free (pev->event);free (pev->group); -free (pp->file); -free (pp->function); -free (pp->lazy_line); +clear_perf_probe_point (&pev->point);for (i =0 ; i < pev->nargs; i++) {free (pev->args[i].name);
@@ -2367,11 +2483,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,int num_matched_functions;int ret, i; -/* Init maps of given executable or kernel */ -if (pev->uprobes) - map =dso__new_map (target); -else - map =kernel_get_module_map (target); + map =get_target_map (target, pev->uprobes);if (!map) { ret = -EINVAL ; goto out;
@@ -2464,11 +2576,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, } out: -if (map && pev->uprobes) { -/* Only when using uprobe(exec) map needs to be released */ -dso__delete (map->dso); -map__delete (map); - } +put_target_map (map, pev->uprobes);return ret; nomem_out:
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 8/24 perf probe: Fix --line to handle aliased symbols in glibc
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix perf probe --line to handle aliased symbols correctly in glibc.
This makes line_range search failing back to address-based alternative search as same as --add and --vars.
Without this patch;
-----
# ./perf probe -x /usr/lib64/libc-2.17.so -L malloc
Specified source line is not found.
Error: Failed to show lines.
-----With this patch;
-----
# ./perf probe -x /usr/lib64/libc-2.17.so -L malloc
<__libc_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:0>
0 __libc_malloc(size_t bytes)
1 {
mstate ar_ptr;
void *victim; __malloc_ptr_t (*hook) (size_t, const __malloc_ptr_t)
6 = force_reg (__malloc_hook);
7 if (__builtin_expect (hook != NULL, 0))
8 return (*hook)(bytes, RETURN_ADDRESS (0));
10 arena_lookup(ar_ptr);
12 arena_lock(ar_ptr, bytes);-----
Note that this actually shows __libc_malloc, since it is the real instance of malloc. User can use both __libc_malloc and malloc for --line.
--- tools/perf/util/probe-event.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
tools/perf/util/probe-event.c +33 -2
@@ -353,6 +353,31 @@ static int get_alternative_probe_event(struct debuginfo *dinfo,return ret; } +static int get_alternative_line_range (struct debuginfo *dinfo, +struct line_range *lr, +const char *target,bool user) +{ +struct perf_probe_point pp = {0 }, result = {0 }; +int ret, len =0 ; + + pp.function = lr->function; + pp.file = lr->file; + pp.line = lr->start; +if (lr->end !=INT_MAX ) + len = lr->end - lr->start; + ret =find_alternative_probe_point (dinfo, &pp, &result, + target, user); +if (!ret) { + lr->function = result.function; + lr->file = result.file; + lr->start = result.line; +if (lr->end !=INT_MAX ) + lr->end = lr->start + len; +clear_perf_probe_point (&pp); + } +return ret; +} +/* Open new debuginfo of given module */ static struct debuginfo *open_debuginfo (const char *module,bool silent) {
@@ -734,7 +759,8 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)* Show line-range always requires debuginfo to find source file and * line number. */ -static int __show_line_range (struct line_range *lr,const char *module) +static int __show_line_range (struct line_range *lr,const char *module, +bool user) {int l =1 ;struct int_node *ln;
@@ -750,6 +776,11 @@ static int __show_line_range(struct line_range *lr, const char *module)return -ENOENT ; ret =debuginfo__find_line_range (dinfo, lr); +if (!ret) {/* Not found, retry with an alternative */ + ret =get_alternative_line_range (dinfo, lr, module, user); +if (!ret) + ret =debuginfo__find_line_range (dinfo, lr); + }debuginfo__delete (dinfo);if (ret ==0 || ret == -ENOENT ) {pr_warning ("Specified source line is not found.\n" );
@@ -819,7 +850,7 @@ int show_line_range(struct line_range *lr, const char *module, bool user) ret =init_symbol_maps (user);if (ret <0 )return ret; - ret =__show_line_range (lr, module); + ret =__show_line_range (lr, module, user);exit_symbol_maps ();return ret;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 9/24 Revert "perf probe: Fix to fall back to find probe point in symbols"
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
This reverts commit 906451b98b67 ("perf probe: Fix to fall back to find probe point in symbols").
Since 'perf probe' now retries with the address of given symbol searched from map before this path, this fall back routine isn't needed anymore.
--- tools/perf/util/probe-event.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
tools/perf/util/probe-event.c +2 -4
@@ -630,11 +630,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, }if (ntevs ==0 ) {/* No error but failed to find probe point. */ -pr_warning ("Probe point '%s' not found in debuginfo.\n" , +pr_warning ("Probe point '%s' not found.\n" ,synthesize_perf_probe_point (&pev->point)); -if (need_dwarf) -return -ENOENT ; -return 0 ; +return -ENOENT ; }/* Error path : ntevs < 0 */ pr_debug ("An error occurred in debuginfo analysis (%d).\n" , ntevs);
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 10/24 perf symbols: Allow symbol alias when loading map for symbol name
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
When perf probe tries to add a probe in a binary using symbol name, it sometimes failed since some symbols were discard during loading dso.
When it resolves an address to symbol, it'd be better to have just one symbol at given address. But for finding address from symbol, it'd be better to keep all names (including aliases).
So allow tools to state that they want to allow aliases via symbol_conf.allow_aliases.
--- tools/perf/util/probe-event.c | 1 + tools/perf/util/symbol-elf.c | 3 ++- tools/perf/util/symbol.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-)
tools/perf/util/probe-event.c +1 -0
@@ -80,6 +80,7 @@ static int init_symbol_maps(bool user_only)int ret; symbol_conf.sort_by_name = true; + symbol_conf.allow_aliases = true; ret =symbol__init (NULL );if (ret <0 ) {pr_debug ("Failed to init symbol map.\n" );
tools/perf/util/symbol-elf.c +2 -1
@@ -1048,7 +1048,8 @@ new_symbol:* For misannotated, zeroed, ASM function sizes. */ if (nr >0 ) { -symbols__fixup_duplicate (&dso->symbols[map->type]); +if (!symbol_conf.allow_aliases) +symbols__fixup_duplicate (&dso->symbols[map->type]);symbols__fixup_end (&dso->symbols[map->type]);if (kmap) {/*
tools/perf/util/symbol.h +1 -0
@@ -87,6 +87,7 @@ struct symbol_conf { ignore_vmlinux_buildid, show_kernel_path, use_modules, + allow_aliases, sort_by_name, show_nr_samples, show_total_period,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 11/24 perf probe: Allow weak symbols to be probed
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
It currently prevents adding probes in weak symbols. But there're cases that given name is an only weak symbol so that we cannot add probe.
$ perf probe -x /usr/lib/libc.so.6 -a calloc
Failed to find symbol calloc in /usr/lib/libc-2.21.so
Error: Failed to add events.$ nm /usr/lib/libc.so.6 | grep calloc 000000000007b1f0 t __calloc 000000000007b1f0 T __libc_calloc 000000000007b1f0 W calloc
This change will result in duplicate probes when strong and weak symbols co-exist in a binary. But I think it's not a big problem since probes at the weak symbol will never be hit anyway.
--- tools/perf/util/probe-event.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
tools/perf/util/probe-event.c +4 -8
@@ -310,10 +310,8 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,/* Find the address of given function */ map__for_each_symbol_by_name (map, pp->function, sym) { -if (sym->binding ==STB_GLOBAL || sym->binding ==STB_LOCAL ) { - address = sym->start; -break ; - } + address = sym->start; +break ; }if (!address) { ret = -ENOENT ;
@@ -2485,8 +2483,7 @@ static int find_probe_functions(struct map *map, char *name)struct symbol *sym;map__for_each_symbol_by_name (map, name, sym) { -if (sym->binding ==STB_GLOBAL || sym->binding ==STB_LOCAL ) - found++; + found++; }return found;
@@ -2846,8 +2843,7 @@ static struct strfilter *available_func_filter;static int filter_available_functions (struct map *map__maybe_unused ,struct symbol *sym) { -if ((sym->binding ==STB_GLOBAL || sym->binding ==STB_LOCAL ) && -strfilter__compare (available_func_filter, sym->name)) +if (strfilter__compare (available_func_filter, sym->name))return 0 ;return 1 ; }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 12/24 perf build: Fix libbabeltrace detection
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Following patch added -Werror for feature builds:
b49f1a4be701 perf tools: Improve feature test debuggability
and exposed a problem in the libbabeltrace feature build, because it was including wrong header and gcc couldn't find the used symbol definition.
Adding proper header and keeping the old one as it is needed also (libbabeltrace quirk).
--- tools/perf/config/feature-checks/test-libbabeltrace.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/config/feature-checks/test-libbabeltrace.c +1 -0
@@ -1,5 +1,6 @@#include <babeltrace/ctf-writer/writer.h> +#include <babeltrace/ctf-ir/stream-class.h> int main (void ) {
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 13/24 perf tools: Output feature detection's gcc output to a file
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
So that we can debug feature detection problems.
It will appear on $(OUTPUT)feature-checks/.make-libbabeltrace.output, using the libbabeltrace feature test.
Whole process:
[acme@ssdandy linux]$ make -C tools/perf install-bin
make: Entering directory `/home/acme/git/linux/tools/perf'
BUILD: Doing 'make -j8' parallel build
config/Makefile:425: No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR config/Makefile:709: No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev
Auto-detecting system features:
... dwarf: [ on ]
... glibc: [ on ]
... gtk2: [ on ]
... libaudit: [ on ]
... libbfd: [ on ]
... libelf: [ on ]
... libnuma: [ on ]
... libperl: [ on ]
... libpython: [ on ]
... libslang: [ on ]
... libunwind: [ OFF ]
... libdw-dwarf-unwind: [ on ]
... libbabeltrace: [ OFF ]
<SNIP>
[acme@ssdandy linux]$ find tools/perf -name ".make-*.output" | grep lib | tail -5
tools/perf/config/feature-checks/.make-libdw-dwarf-unwind.output
tools/perf/config/feature-checks/.make-libbabeltrace.output
tools/perf/config/feature-checks/.make-zlib.output
tools/perf/config/feature-checks/.make-liberty.output
tools/perf/config/feature-checks/.make-liberty-z.output
[acme@ssdandy linux]$
[acme@ssdandy linux]$ cat tools/perf/config/feature-checks/.make-libbabeltrace.output
make[1]: Entering directory `/home/acme/git/linux/tools/perf/config/feature-checks'
gcc -MD -Wall -Werror -o test-libbabeltrace.bin test-libbabeltrace.c -Wl,-z,noexecstack -lbabeltrace-ctf # -lbabeltrace provided by
test-libbabeltrace.c:2:42: fatal error: babeltrace/ctf-writer/writer.h: No such file or directory
#include <babeltrace/ctf-writer/writer.h>
^ compilation terminated.
make[1]: *** [test-libbabeltrace.bin] Error 1
make[1]: Leaving directory `/home/acme/git/linux/tools/perf/config/feature-checks' [acme@ssdandy linux]$
So the libbabeltrace feature will not be builtin, but if we do what is required for it to be built, namely point where we have it installed:
[acme@ssdandy linux]$ time make -C tools/perf LIBBABELTRACE_DIR=/opt/libbabeltrace install-bin
make: Entering directory `/home/acme/git/linux/tools/perf'
BUILD: Doing 'make -j8' parallel build
config/Makefile:425: No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR
Auto-detecting system features:
... dwarf: [ on ] ... glibc: [ on ] ... gtk2: [ on ] ... libaudit: [ on ] ... libbfd: [ on ] ... libelf: [ on ] ... libnuma: [ on ] ... libperl: [ on ] ... libpython: [ on ] ... libslang: [ on ] ... libunwind: [ OFF ] ... libdw-dwarf-unwind: [ on ] ... libbabeltrace: [ on ] ... zlib: [ on ]
... DWARF post unwind library: libdw
<SNIP>
[acme@ssdandy linux]$ find tools/perf -name ".make-libbabel*.output" | grep lib | tail -5
tools/perf/config/feature-checks/.make-libbabeltrace.output
[acme@ssdandy linux]$ cat tools/perf/config/feature-checks/.make-libbabeltrace.output
make[1]: Entering directory `/home/acme/git/linux/tools/perf/config/feature-checks'
gcc -MD -I/opt/libbabeltrace/include -Wall -Werror -o test-libbabeltrace.bin test-libbabeltrace.c -Wl,-z,noexecstack -L/opt/libbabeltrace/lib -lbabeltrace-ctf # -lbabeltrace provided by make[1]: Leaving directory `/home/acme/git/linux/tools/perf/config/feature-checks'
[acme@ssdandy linux]$
--- tools/perf/Makefile.perf | 1 + tools/perf/config/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
tools/perf/Makefile.perf +1 -0
@@ -529,6 +529,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean $(Q)$(RM) .config-detected $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* + $(call QUIET_CLEAN, feature-detect) $(RM) $(OUTPUT)config/feature-checks/.make-*.output $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean $(python-clean)
tools/perf/config/Makefile +1 -1
@@ -184,7 +184,7 @@ endif feature_check = $(eval $(feature_check_code)) define feature_check_code - feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) + feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin > $(OUTPUT)config/feature-checks/.make-$(1).output 2>&1 && echo 1 || echo 0) endef feature_set = $(eval $(feature_set_code))
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 14/24 perf probe: Fix possible double free on error
In reply to Arnaldo Carvalho de MeloFrom: He Kuang <[email protected]>
A double free occurred when get source file path failed. If lr->path failed to assign a new value, it will be freed as the old path and then be freed again during line_range__clear(), and causes this:
$ perf probe -L do_execve -k vmlinux
*** Error in `/usr/bin/perf': double free or corruption (fasttop):
0x0000000000a9ac50 ***
======= Backtrace: =========
../lib64/libc.so.6(+0x6eeef)[0x7ffff5e44eef]
../lib64/libc.so.6(+0x78cae)[0x7ffff5e4ecae]
../lib64/libc.so.6(+0x79987)[0x7ffff5e4f987]
../bin/perf[0x4ab41f]
...This patch fix this problem.
--- tools/perf/util/probe-event.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/probe-event.c +5 -1
@@ -790,7 +790,11 @@ static int __show_line_range(struct line_range *lr, const char *module,/* Convert source file path */ tmp = lr->path; ret =get_real_path (tmp, lr->comp_dir, &lr->path); -free (tmp);/* Free old path */ + +/* Free old path when new path is assigned */ +if (tmp != lr->path) +free (tmp); +if (ret <0 ) {pr_warning ("Failed to find source file path.\n" );return ret;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 15/24 perf hists browser: Fix UI bug after zoom into thread/dso/symbol
In reply to Arnaldo Carvalho de MeloFrom: He Kuang <[email protected]>
When zoom into thread/dso/symbol, the fold/unfold stat is cleared in hists__filter_by_thread/dso/symbol(), but h->nr_rows is not cleared. So if we toggle fold stat on the unfold entires, nr_entries got a wrong value.
This bug can be reproduced as follows:
$ perf record -g -e syscalls:sys_enter_open ls $ perf report
Children Self Command Shared Object Symbol
================================================================
+ 50.00% 0.00% ls ld64.so [.] _dl_get_ready_to_run - 50.00% 0.00% ls ld64.so [.] _dl_load_shared_library
_dl_load_shared_library <= [Zoom into thread/dso] _dl_get_ready_to_run
_start
...
In the new thread hists, all entries reset to fold, if we unfold the same entry as we previously unfolded, nr_entries got wrong value, and we can't move down cursor to bottom row.
Thread: ls
Children Self Command Shared Object Symbol
================================================================
+ 50.00% 0.00% ls ld64.so [.] _dl_get_ready_to_run - 50.00% 0.00% ls ld64.so [.] _dl_load_shared_library
_dl_load_shared_library
_dl_get_ready_to_run <= [cursor may stop here, can't move down] _start
...
This patch clear h->nr_rows to fix this bug.
--- tools/perf/util/hist.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/hist.c +1 -0
@@ -1171,6 +1171,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h/* force fold unfiltered entry for simplicity */ h->ms.unfolded = false; h->row_offset =0 ; + h->nr_rows =0 ; hists->stats.nr_non_filtered_samples += h->stat.nr_events;
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 16/24 perf probe: Fix compiles due to declarations using perf_probe_point
In reply to Arnaldo Carvalho de MeloFrom: David Ahern <[email protected]>
perf fails to build with gcc "(GCC) 4.4.7 20120313 (Red Hat 4.4.7-4.0.9)" (a.k.a., RHEL6 / CentOS 6 / OL 6):
cc1: warnings being treated as errors
util/probe-event.c: In function ‘get_alternative_line_range’:
util/probe-event.c:359: error: missing initializer util/probe-event.c:359: error: (near initialization for ‘pp.file’) util/probe-event.c:359: error: missing initializer util/probe-event.c:359: error: (near initialization for ‘result.function’)
Fix by bringing in initializers to declaration.
--- tools/perf/util/probe-event.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
tools/perf/util/probe-event.c +6 -4
@@ -356,12 +356,14 @@ static int get_alternative_line_range(struct debuginfo *dinfo,struct line_range *lr, const char *target, bool user) { - struct perf_probe_point pp = { 0 }, result = { 0 }; + struct perf_probe_point pp = { .function = lr->function, + .file = lr->file, + .line = lr->start }; +struct perf_probe_point result;int ret, len =0 ; - pp.function = lr->function; - pp.file = lr->file; - pp.line = lr->start; +memset (&result,0 ,sizeof (result)); +if (lr->end !=INT_MAX ) len = lr->end - lr->start; ret = find_alternative_probe_point(dinfo, &pp, &result,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 17/24 perf hists browser: Fix UI bug after fold/unfold
In reply to Arnaldo Carvalho de MeloFrom: He Kuang <[email protected]>
In perf hists browser, the fold/unfold stat of each hist entry is recorded but hb->nr_callchain_rows loses its value after zoom out and zoom in back. This causes a wrong row cursor range that restrict user to move down anymore.
This bug can be reproduced as follows:
$ perf record -g -e syscalls:* ls $ perf report
Available samples
================================================================
2 syscalls:sys_enter_mprotect <= [enter one of the entries] 2 syscalls:sys_exit_mprotect
13 syscalls:sys_enter_brk
...
In the hists brower, unfold some of the items, now the cursor can reach to any rows:
Children Self Command Shared Object Symbol
================================================================
- 100.00% 100.00% ls libuClibc-0.9.33.2.so [.] lstat64
- lstat64
16.67% 0x6469702e64
8.33% 0x646970
8.33% 0x617461
8.33% 0x65
- 16.67% 0.00% ls [unknown] [.]0x6469702e64
0x6469702e64 <= [cursor can reach to bottom line, everything is ok]Now, zoom back to "Available samples" and enter again:
Children Self Command Shared Object Symbol
================================================================
- 100.00% 100.00% ls libuClibc-0.9.33.2.so [.] lstat64
- lstat64
16.67% 0x6469702e64
8.33% 0x646970
8.33% 0x617461 <= [cursor may stop here, can't move down anymore]
8.33% 0x65
- 16.67% 0.00% ls [unknown] [.]0x6469702e64
0x6469702e64This patch recalculates hb->nr_callchain_rows to fix the bug.
--- tools/perf/ui/browsers/hists.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
tools/perf/ui/browsers/hists.c +19 -0
@@ -48,6 +48,24 @@ static bool hist_browser__has_filter(struct hist_browser *hb)return hists__has_filter (hb->hists) || hb->min_pcnt; } +static int hist_browser__get_folding (struct hist_browser *browser) +{ +struct rb_node *nd; +struct hists *hists = browser->hists; +int unfolded_rows =0 ; + +for (nd =rb_first (&hists->entries); + (nd =hists__filter_entries (nd, browser->min_pcnt)) !=NULL ; + nd =rb_next (nd)) { +struct hist_entry *he = + rb_entry(nd, struct hist_entry, rb_node); + +if (he->ms.unfolded) + unfolded_rows += he->nr_rows; + } +return unfolded_rows; +} +static u32 hist_browser__nr_entries (struct hist_browser *hb) {u32 nr_entries;
@@ -57,6 +75,7 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)else nr_entries = hb->hists->nr_entries; + hb->nr_callchain_rows =hist_browser__get_folding (hb);return nr_entries + hb->nr_callchain_rows; }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 18/24 perf stat: Output running time and run/enabled ratio in CSV mode
In reply to Arnaldo Carvalho de MeloFrom: Andi Kleen <[email protected]>
The information how much a counter ran in 'perf stat' can be quite interesting for other tools to judge how trustworthy a measurement is.
Currently it is only output in non CSV mode.
This patches make perf stat always output the running time and the enabled/running ratio in CSV mode.
This adds two new fields at the end for each line. I assume that existing tools ignore new fields at the end, so it's on by default.
Only CSV mode is affected, no difference otherwise.
v2: Add extra print_running function
v3: Avoid printing nan
v4: Remove some elses and add brackets.
v5: Move non CSV case into print_running
--- tools/perf/builtin-stat.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-)
tools/perf/builtin-stat.c +24 -23
@@ -769,6 +769,18 @@ static int run_perf_stat(int argc, const char **argv)return ret; } +static void print_running (u64 run,u64 ena) +{ +if (csv_output) { +fprintf (output,"%s%" PRIu64"%s%.2f" , + csv_sep, + run, + csv_sep, + ena ?100.0 * run / ena :100.0 ); + }else if (run != ena) +fprintf (output," (%.2f%%)" ,100.0 * run / ena); +} +static void print_noise_pct (double total,double avg) {double pct =rel_stddev_stats (total, avg);
@@ -1252,6 +1264,7 @@ static void print_aggr(char *prefix)fprintf (output,"%s%s" , csv_sep, counter->cgrp->name); +print_running (run, ena);fputc ('\n' , output);continue ; }
@@ -1262,13 +1275,10 @@ static void print_aggr(char *prefix)else abs_printout (id, nr, counter, uval); -if (!csv_output) { +if (!csv_output)print_noise (counter,1.0 ); -if (run != ena) -fprintf (output," (%.2f%%)" , -100.0 * run / ena); - } +print_running (run, ena);fputc ('\n' , output); } }
@@ -1284,6 +1294,10 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)double avg =avg_stats (&ps->res_stats[0 ]);int scaled = counter->counts->scaled;double uval; +double avg_enabled, avg_running; + + avg_enabled =avg_stats (&ps->res_stats[1 ]); + avg_running =avg_stats (&ps->res_stats[2 ]);if (prefix)fprintf (output,"%s" , prefix);
@@ -1303,6 +1317,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)if (counter->cgrp)fprintf (output,"%s%s" , csv_sep, counter->cgrp->name); +print_running (avg_running, avg_enabled);fputc ('\n' , output);return ; }
@@ -1316,19 +1331,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)print_noise (counter, avg); -if (csv_output) { -fputc ('\n' , output); -return ; - } - -if (scaled) { -double avg_enabled, avg_running; - - avg_enabled =avg_stats (&ps->res_stats[1 ]); - avg_running =avg_stats (&ps->res_stats[2 ]); - -fprintf (output," [%5.2f%%]" ,100 * avg_running / avg_enabled); - } +print_running (avg_running, avg_enabled);fprintf (output,"\n" ); }
@@ -1370,6 +1373,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix)fprintf (output,"%s%s" , csv_sep, counter->cgrp->name); +print_running (run, ena);fputc ('\n' , output);continue ; }
@@ -1381,13 +1385,10 @@ static void print_counter(struct perf_evsel *counter, char *prefix)else abs_printout (cpu,0 , counter, uval); -if (!csv_output) { +if (!csv_output)print_noise (counter,1.0 ); +print_running (run, ena); -if (run != ena) -fprintf (output," (%.2f%%)" , -100.0 * run / ena); - }fputc ('\n' , output); } }
Signature · 1 line
1.9.3
Re: [PATCH 18/24] perf stat: Output running time and run/enabled ratio in CSV mode
Quoted 38 lines · Arnaldo Carvalho de Melo
From: Andi Kleen <[email protected]>
The information how much a counter ran in 'perf stat' can be quite interesting for other tools to judge how trustworthy a measurement is.
Currently it is only output in non CSV mode.
This patches make perf stat always output the running time and the enabled/running ratio in CSV mode.
This adds two new fields at the end for each line. I assume that existing tools ignore new fields at the end, so it's on by default.
Only CSV mode is affected, no difference otherwise.
v2: Add extra
print_runningfunction
v3: Avoid printing nan
v4: Remove some elses and add brackets.
v5: Move non CSV case intoprint_runningSigned-off-by Andi Kleen <[email protected]>Reviewed-by Jiri Olsa <[email protected]>Acked-by Namhyung Kim <[email protected]>Cc Jiri Olsa <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>--- tools/perf/builtin-stat.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-)tools/perf/builtin-stat.c +0
-0@@ -769,6 +769,18 @@ static int run_perf_stat(int argc, const char **argv)return ret; }
tools/perf/builtin-stat.c static int run_perf_stat(int argc, const char **argv) · line 781
Quoted 10 lines
tools/perf/builtin-stat.c +10
-0+static void print_running (u64 run,u64 ena) +{ +if (csv_output) { +fprintf (output,"%s%" PRIu64"%s%.2f" , + csv_sep, + run, + csv_sep, + ena ?100.0 * run / ena :100.0 ); + }else if (run != ena) +fprintf (output," (%.2f%%)" ,100.0 * run / ena);
That's not the standard pattern for 'else if' branches, but:
} else {
if ()
...
}to make it stand apart more from a simple 'else' branch.
Thanks,
Ingo
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 18/24] perf stat: Output running time and run/enabled ratio in CSV mode
Em Fri, Mar 13, 2015 at 08:34:41AM +0100, Ingo Molnar escreveu:
Quoted 15 lines · Arnaldo Carvalho de Melo
tools/perf/builtin-stat.c static int run_perf_stat(int argc, const char **argv) · line 781
Quoted 11 lines
From: Andi Kleen <[email protected]>
tools/perf/builtin-stat.c +10
-0+static void print_running (u64 run,u64 ena) +{ +if (csv_output) { +fprintf (output,"%s%" PRIu64"%s%.2f" , + csv_sep, + run, + csv_sep, + ena ?100.0 * run / ena :100.0 ); + }else if (run != ena) +fprintf (output," (%.2f%%)" ,100.0 * run / ena);That's not the standard pattern for 'else if' branches, but:
Quoted 6 lines
} else { if () ... }to make it stand apart more from a simple 'else' branch.
I think it is preferred to make it match the if branch if it uses curly braces, i.e. make it look:
} else if () {
}i.e switch like series of else if, to avoid too much indentation for such constructs.
Fixed it and the other file, redid the perf-core-for-mingo tag, pushed.
- Arnaldo
Re: [PATCH 18/24] perf stat: Output running time and run/enabled ratio in CSV mode
Quoted 26 lines · Arnaldo Carvalho de Melo
Em Fri, Mar 13, 2015 at 08:34:41AM +0100, Ingo Molnar escreveu:
Quoted 15 lines · Arnaldo Carvalho de Melo
tools/perf/builtin-stat.c static int run_perf_stat(int argc, const char **argv) · line 781
Quoted 11 lines
From: Andi Kleen <[email protected]>
tools/perf/builtin-stat.c +10
-0+static void print_running (u64 run,u64 ena) +{ +if (csv_output) { +fprintf (output,"%s%" PRIu64"%s%.2f" , + csv_sep, + run, + csv_sep, + ena ?100.0 * run / ena :100.0 ); + }else if (run != ena) +fprintf (output," (%.2f%%)" ,100.0 * run / ena);That's not the standard pattern for 'else if' branches, but:
Quoted 6 lines
} else { if () ... }to make it stand apart more from a simple 'else' branch.
I think it is preferred to make it match the if branch if it uses curly braces, i.e. make it look:
Quoted 8 lines
} else if () { }i.e switch like series of else if, to avoid too much indentation for such constructs.
Fixed it and the other file, redid the perf-core-for-mingo tag, pushed.
Pulled into tip:perf/core, thanks a lot Arnaldo!
Ingo
Arnaldo Carvalho de Melo
maintainerPATCH 19/24 perf stat: Fix IPC and other formulas with -A
In reply to Arnaldo Carvalho de MeloFrom: Andi Kleen <[email protected]>
perf stat didn't compute the IPC and other formulas for individual CPUs with -A. Fix this for the easy -A case. As before, --per-core and --per-socket do not handle it, they simply print nothing.
--- tools/perf/builtin-stat.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-)
tools/perf/builtin-stat.c +19 -17
@@ -353,39 +353,40 @@ static struct perf_evsel *nth_evsel(int n)* more semantic information such as miss/hit ratios, * instruction rates, etc: */ -static void update_shadow_stats (struct perf_evsel *counter,u64 *count) +static void update_shadow_stats (struct perf_evsel *counter,u64 *count, +int cpu) {if (perf_evsel__match (counter,SOFTWARE ,SW_TASK_CLOCK )) -update_stats (&runtime_nsecs_stats[0 ], count[0 ]); +update_stats (&runtime_nsecs_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HARDWARE ,HW_CPU_CYCLES )) -update_stats (&runtime_cycles_stats[0 ], count[0 ]); +update_stats (&runtime_cycles_stats[cpu], count[0 ]);else if (transaction_run &&perf_evsel__cmp (counter,nth_evsel (T_CYCLES_IN_TX ))) -update_stats (&runtime_cycles_in_tx_stats[0 ], count[0 ]); +update_stats (&runtime_cycles_in_tx_stats[cpu], count[0 ]);else if (transaction_run &&perf_evsel__cmp (counter,nth_evsel (T_TRANSACTION_START ))) -update_stats (&runtime_transaction_stats[0 ], count[0 ]); +update_stats (&runtime_transaction_stats[cpu], count[0 ]);else if (transaction_run &&perf_evsel__cmp (counter,nth_evsel (T_ELISION_START ))) -update_stats (&runtime_elision_stats[0 ], count[0 ]); +update_stats (&runtime_elision_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HARDWARE ,HW_STALLED_CYCLES_FRONTEND )) -update_stats (&runtime_stalled_cycles_front_stats[0 ], count[0 ]); +update_stats (&runtime_stalled_cycles_front_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HARDWARE ,HW_STALLED_CYCLES_BACKEND )) -update_stats (&runtime_stalled_cycles_back_stats[0 ], count[0 ]); +update_stats (&runtime_stalled_cycles_back_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HARDWARE ,HW_BRANCH_INSTRUCTIONS )) -update_stats (&runtime_branches_stats[0 ], count[0 ]); +update_stats (&runtime_branches_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HARDWARE ,HW_CACHE_REFERENCES )) -update_stats (&runtime_cacherefs_stats[0 ], count[0 ]); +update_stats (&runtime_cacherefs_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HW_CACHE ,HW_CACHE_L1D )) -update_stats (&runtime_l1_dcache_stats[0 ], count[0 ]); +update_stats (&runtime_l1_dcache_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HW_CACHE ,HW_CACHE_L1I )) -update_stats (&runtime_l1_icache_stats[0 ], count[0 ]); +update_stats (&runtime_l1_icache_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HW_CACHE ,HW_CACHE_LL )) -update_stats (&runtime_ll_cache_stats[0 ], count[0 ]); +update_stats (&runtime_ll_cache_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HW_CACHE ,HW_CACHE_DTLB )) -update_stats (&runtime_dtlb_cache_stats[0 ], count[0 ]); +update_stats (&runtime_dtlb_cache_stats[cpu], count[0 ]);else if (perf_evsel__match (counter,HW_CACHE ,HW_CACHE_ITLB )) -update_stats (&runtime_itlb_cache_stats[0 ], count[0 ]); +update_stats (&runtime_itlb_cache_stats[cpu], count[0 ]); }static void zero_per_pkg (struct perf_evsel *counter)
@@ -447,7 +448,8 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,perf_evsel__compute_deltas (evsel, cpu, count);perf_counts_values__scale (count, scale,NULL ); evsel->counts->cpu[cpu] = *count; -update_shadow_stats (evsel, count->values); +if (aggr_mode ==AGGR_NONE ) +update_shadow_stats (evsel, count->values, cpu);break ;case AGGR_GLOBAL : aggr->val += count->val;
@@ -495,7 +497,7 @@ static int read_counter_aggr(struct perf_evsel *counter)/* * Save the full runtime - to allow normalization during printout: */ -update_shadow_stats (counter, count); +update_shadow_stats (counter, count,0 );return 0 ; }
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 20/24 perf stat: Always correctly indent ratio column
In reply to Arnaldo Carvalho de MeloFrom: Andi Kleen <[email protected]>
When cycles or instructions do not print anything, as in being, --per-socket or --per-core modi, the ratio column was not correctly indented for them. This lead to some ratios not lining up with the others. Always indent correctly when nothing is printed.
--- tools/perf/builtin-stat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/builtin-stat.c +4 -2
@@ -1093,7 +1093,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)if (total) { ratio = avg / total;fprintf (output," # %5.2f insns per cycle " , ratio); - } + }else +fprintf (output," " ); total =avg_stats (&runtime_stalled_cycles_front_stats[cpu]); total =max (total,avg_stats (&runtime_stalled_cycles_back_stats[cpu]));
@@ -1162,7 +1163,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)if (total) { ratio = avg / total;fprintf (output," # %8.3f GHz " , ratio); - } + }else +fprintf (output," " ); }else if (transaction_run &&perf_evsel__cmp (evsel,nth_evsel (T_CYCLES_IN_TX ))) { total =avg_stats (&runtime_cycles_stats[cpu]);
Signature · 1 line
1.9.3
Re: [PATCH 20/24] perf stat: Always correctly indent ratio column
Quoted 19 lines · Arnaldo Carvalho de Melo
From: Andi Kleen <[email protected]>
When cycles or instructions do not print anything, as in being, --per-socket or --per-core modi, the ratio column was not correctly indented for them. This lead to some ratios not lining up with the others. Always indent correctly when nothing is printed.
Signed-off-by Andi Kleen <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>--- tools/perf/builtin-stat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)tools/perf/builtin-stat.c +0
-0
tools/perf/builtin-stat.c static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) · line 1097
Quoted 6 lines
tools/perf/builtin-stat.c +2
-1@@ -1093,7 +1093,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)if (total) { ratio = avg / total;fprintf (output," # %5.2f insns per cycle " , ratio); - } + }else +fprintf (output," " );
The standard pattern is symmetric curly braces.
tools/perf/builtin-stat.c static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) · line 1167
Quoted 7 lines
tools/perf/builtin-stat.c +2
-1@@ -1162,7 +1163,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)if (total) { ratio = avg / total;fprintf (output," # %8.3f GHz " , ratio); - } + }else +fprintf (output," " );
Ditto...
Thanks,
Ingo
Arnaldo Carvalho de Melo
maintainerPATCH 21/24 perf kmem: Fix segfault when invalid sort key is given
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
When it tries to free 'str', it was already updated by strsep() - so it needs to save the original pointer.
# perf kmem stat -s xxx,hit
Error: Unknown --sort key: 'xxx'
*** Error in `perf': free(): invalid pointer: 0x0000000000e9e7b6 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x7198e)[0x7fc7e6e0d98e]
/usr/lib/libc.so.6(+0x76dee)[0x7fc7e6e12dee]
/usr/lib/libc.so.6(+0x775cb)[0x7fc7e6e135cb]
./perf[0x44a1b5]
./perf[0x490b20]
./perf(parse_options_step+0x173)[0x491773]
./perf(parse_options_subcommand+0xa7)[0x491fb7]
./perf(cmd_kmem+0x2bc)[0x44ae4c]
./perf[0x47aa13]
./perf(main+0x60a)[0x427a9a]
/usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7fc7e6dbc800]
./perf(_start+0x29)[0x427bb9]--- tools/perf/builtin-kmem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-kmem.c +2 -1
@@ -559,6 +559,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg) {char *tok;char *str =strdup (arg); +char *pos = str;if (!str) {pr_err ("%s: strdup failed\n" , __func__);
@@ -566,7 +567,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg) }while (true) { - tok =strsep (&str,"," ); + tok =strsep (&pos,"," );if (!tok)break ;if (sort_dimension__add (tok, sort_list) <0 ) {
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 22/24 perf kmem: Allow -v option
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Current perf kmem fails when -v option is used. As it's very useful for debugging, let's allow it.
--- tools/perf/Documentation/perf-kmem.txt | 4 ++++ tools/perf/builtin-kmem.c | 2 ++ 2 files changed, 6 insertions(+)
tools/perf/Documentation/perf-kmem.txt +4 -0
@@ -25,6 +25,10 @@ OPTIONS --input=<file>:: Select the input file (default: perf.data unless stdin is a fifo) +-v:: +--verbose:: + Be more verbose. (show symbol address, etc) + --caller:: Show per-callsite statistics
tools/perf/builtin-kmem.c +2 -0
@@ -663,6 +663,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)const char *const default_sort_order ="frag,hit,bytes" ;const struct option kmem_options[] = {OPT_STRING ('i' ,"input" , &input_name,"file" ,"input file name" ), +OPT_INCR ('v' ,"verbose" , &verbose, +"be more verbose (show symbol address, etc)" ),OPT_CALLBACK_NOOPT (0 ,"caller" ,NULL ,NULL ,"show per-callsite statistics" , parse_caller_opt), OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 23/24 perf kmem: Fix alignment of slab result table
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Its table was a bit misaligned. Fix it.
Before:
# perf kmem stat --caller -l 10 ------------------------------------------------------------------------------------------------------ Callsite | Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag ------------------------------------------------------------------------------------------------------ radeon_cs_parser_init.part.1+11a | 2080/260 | 1504/188 | 8 | 0 | 27.692% radeon_cs_parser_init.part.1+e1 | 384/96 | 288/72 | 4 | 0 | 25.000% radeon_cs_parser_init.part.1+93 | 128/32 | 96/24 | 4 | 0 | 25.000% load_elf_binary+a39 | 512/512 | 392/392 | 1 | 0 | 23.438% __alloc_skb+89 | 6144/877 | 4800/685 | 7 | 6 | 21.875% radeon_fence_emit+5c | 1152/192 | 912/152 | 6 | 0 | 20.833% radeon_cs_parser_relocs+ad | 8192/2048 | 6624/1656 | 4 | 0 | 19.141% radeon_sa_bo_new+78 | 1280/64 | 1120/56 | 20 | 0 | 12.500% load_elf_binary+2c4 | 32/32 | 28/28 | 1 | 0 | 12.500% anon_vma_prepare+101 | 576/72 | 512/64 | 8 | 0 | 11.111% ... | ... | ... | ... | ... | ... ------------------------------------------------------------------------------------------------------
After:
---------------------------------------------------------------------------------------------------------
Callsite | Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag
---------------------------------------------------------------------------------------------------------
radeon_cs_parser_init.part.1+11a | 2080/260 | 1504/188 | 8 | 0 | 27.692% radeon_cs_parser_init.part.1+e1 | 384/96 | 288/72 | 4 | 0 | 25.000% radeon_cs_parser_init.part.1+93 | 128/32 | 96/24 | 4 | 0 | 25.000% load_elf_binary+a39 | 512/512 | 392/392 | 1 | 0 | 23.438% __alloc_skb+89 | 6144/877 | 4800/685 | 7 | 6 | 21.875% radeon_fence_emit+5c | 1152/192 | 912/152 | 6 | 0 | 20.833% radeon_cs_parser_relocs+ad | 8192/2048 | 6624/1656 | 4 | 0 | 19.141% radeon_sa_bo_new+78 | 1280/64 | 1120/56 | 20 | 0 | 12.500% load_elf_binary+2c4 | 32/32 | 28/28 | 1 | 0 | 12.500% anon_vma_prepare+101 | 576/72 | 512/64 | 8 | 0 | 11.111% ... | ... | ... | ... | ... | ...
---------------------------------------------------------------------------------------------------------
--- tools/perf/builtin-kmem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
tools/perf/builtin-kmem.c +5 -5
@@ -275,10 +275,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session,struct rb_node *next;struct machine *machine = &session->machines.host; -printf ("%.102s\n" , graph_dotted_line); +printf ("%.105s\n" , graph_dotted_line);printf (" %-34s |" , is_caller ?"Callsite" :"Alloc Ptr" );printf (" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n" ); -printf ("%.102s\n" , graph_dotted_line); +printf ("%.105s\n" , graph_dotted_line); next =rb_first (root);
@@ -304,7 +304,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,snprintf (buf,sizeof (buf),"%#" PRIx64"" , addr);printf (" %-34s |" , buf); - printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n", + printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %9lu | %6.3f%%\n", (unsigned long long)data->bytes_alloc, (unsigned long)data->bytes_alloc / data->hit, (unsigned long long)data->bytes_req,
@@ -317,9 +317,9 @@ static void __print_result(struct rb_root *root, struct perf_session *session, }if (n_lines ==-1 ) -printf (" ... | ... | ... | ... | ... | ... \n" ); +printf (" ... | ... | ... | ... | ... | ... \n" ); -printf ("%.102s\n" , graph_dotted_line); +printf ("%.105s\n" , graph_dotted_line); }static void print_summary (void )
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerPATCH 24/24 perf data: Add tracepoint events fields CTF conversion support
In reply to Arnaldo Carvalho de MeloFrom: Sebastian Andrzej Siewior <[email protected]>
Adding support to convert tracepoint event fields into CTF event fields.
We parse each tracepoint event for CTF conversion and add tracepoint fields as regular CTF event fields, so they appear in babeltrace output like:
$ babeltrace ./ctf-data/
...
[09:02:00.950703057] (+?.?????????) sched:sched_stat_runtime: { }, { perf_ip = ... SNIP ... common_type = 298, common_flags = 1, \
common_preempt_count = 0, common_pid = 31813, comm = "perf", pid = 31813, runtime = 458800, vruntime = 52059858071 }
...--- tools/perf/util/data-convert-bt.c | 242 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+)
tools/perf/util/data-convert-bt.c +242 -0
@@ -126,6 +126,177 @@ FUNC_VALUE_SET(s64)FUNC_VALUE_SET (u64)__FUNC_VALUE_SET (u64_hex, u64) +static struct bt_ctf_field_type* +get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) +{ +unsigned long flags = field->flags; + + if (flags & FIELD_IS_STRING) + return cw->data.string; + + if (!(flags & FIELD_IS_SIGNED)) { +/* unsigned long are mostly pointers */ +if (flags &FIELD_IS_LONG || flags &FIELD_IS_POINTER ) +return cw->data.u64_hex; + } + +if (flags &FIELD_IS_SIGNED ) { +if (field->size ==8 ) +return cw->data.s64; +else +return cw->data.s32; + } + +if (field->size ==8 ) +return cw->data.u64; +else +return cw->data.u32; +} + +static int add_tracepoint_field_value (struct ctf_writer *cw, +struct bt_ctf_event_class *event_class, +struct bt_ctf_event *event, +struct perf_sample *sample, +struct format_field *fmtf) +{ +struct bt_ctf_field_type *type; +struct bt_ctf_field *array_field; +struct bt_ctf_field *field; +const char *name = fmtf->name; +void *data = sample->raw_data; +unsigned long long value_int; +unsigned long flags = fmtf->flags; +unsigned int n_items; +unsigned int i; +unsigned int offset; +unsigned int len; +int ret; + + offset = fmtf->offset; + len = fmtf->size; +if (flags &FIELD_IS_STRING ) + flags &= ~FIELD_IS_ARRAY ; + +if (flags &FIELD_IS_DYNAMIC ) { +unsigned long long tmp_val; + + tmp_val =pevent_read_number (fmtf->event->pevent, + data + offset, len); + offset = tmp_val; + len = offset >>16 ; + offset &=0xffff ; + } + +if (flags &FIELD_IS_ARRAY ) { + + type =bt_ctf_event_class_get_field_by_name ( + event_class, name); + array_field =bt_ctf_field_create (type); +bt_ctf_field_type_put (type); +if (!array_field) { +pr_err ("Failed to create array type %s\n" , name); +return -1 ; + } + + len = fmtf->size / fmtf->arraylen; + n_items = fmtf->arraylen; + }else { + n_items =1 ; + array_field =NULL ; + } + + type =get_tracepoint_field_type (cw, fmtf); + +for (i =0 ; i < n_items; i++) { +if (!(flags &FIELD_IS_STRING )) + value_int =pevent_read_number ( + fmtf->event->pevent, + data + offset + i * len, len); + +if (flags &FIELD_IS_ARRAY ) + field =bt_ctf_field_array_get_field (array_field, i); +else + field =bt_ctf_field_create (type); + +if (!field) { +pr_err ("failed to create a field %s\n" , name); +return -1 ; + } + +if (flags &FIELD_IS_STRING ) + ret =bt_ctf_field_string_set_value (field, + data + offset + i * len); +else if (!(flags &FIELD_IS_SIGNED )) + ret =bt_ctf_field_unsigned_integer_set_value ( + field, value_int); +else + ret =bt_ctf_field_signed_integer_set_value ( + field, value_int); +if (ret) { +pr_err ("failed to set file value %s\n" , name); + goto err_put_field; + } +if (!(flags &FIELD_IS_ARRAY )) { + ret =bt_ctf_event_set_payload (event, name, field); +if (ret) { +pr_err ("failed to set payload %s\n" , name); + goto err_put_field; + } + } +bt_ctf_field_put (field); + } +if (flags &FIELD_IS_ARRAY ) { + ret =bt_ctf_event_set_payload (event, name, array_field); +if (ret) { +pr_err ("Failed add payload array %s\n" , name); +return -1 ; + } +bt_ctf_field_put (array_field); + } +return 0 ; + +err_put_field: +bt_ctf_field_put (field); +return -1 ; +} + +static int add_tracepoint_fields_values (struct ctf_writer *cw, +struct bt_ctf_event_class *event_class, +struct bt_ctf_event *event, +struct format_field *fields, +struct perf_sample *sample) +{ +struct format_field *field; +int ret; + +for (field = fields; field; field = field->next) { + ret =add_tracepoint_field_value (cw, event_class, event, sample, + field); +if (ret) +return -1 ; + } +return 0 ; +} + +static int add_tracepoint_values (struct ctf_writer *cw, +struct bt_ctf_event_class *event_class, +struct bt_ctf_event *event, +struct perf_evsel *evsel, +struct perf_sample *sample) +{ +struct format_field *common_fields = evsel->tp_format->format.common_fields; +struct format_field *fields = evsel->tp_format->format.fields; +int ret; + + ret =add_tracepoint_fields_values (cw, event_class, event, + common_fields, sample); +if (!ret) + ret =add_tracepoint_fields_values (cw, event_class, event, + fields, sample); + +return ret; +} + static int add_generic_values(struct ctf_writer *cw, struct bt_ctf_event *event, struct perf_evsel *evsel,
@@ -246,11 +417,76 @@ static int process_sample_event(struct perf_tool *tool,if (ret)return -1 ; +if (evsel->attr.type ==PERF_TYPE_TRACEPOINT ) { + ret =add_tracepoint_values (cw, event_class, event, + evsel, sample); +if (ret) +return -1 ; + } +bt_ctf_stream_append_event (cw->stream, event);bt_ctf_event_put (event);return 0 ; } +static int add_tracepoint_fields_types (struct ctf_writer *cw, +struct format_field *fields, +struct bt_ctf_event_class *event_class) +{ +struct format_field *field; +int ret; + +for (field = fields; field; field = field->next) { +struct bt_ctf_field_type *type; +unsigned long flags = field->flags; + +pr2 (" field '%s'\n" , field->name); + + type =get_tracepoint_field_type (cw, field); +if (!type) +return -1 ; + +/* +* A string is an array of chars. For this we use the string +* type and don't care that it is an array. What we don't +* support is an array of strings. +*/ +if (flags &FIELD_IS_STRING ) + flags &= ~FIELD_IS_ARRAY ; + +if (flags &FIELD_IS_ARRAY ) + type =bt_ctf_field_type_array_create (type, field->arraylen); + + ret =bt_ctf_event_class_add_field (event_class, type, + field->name); + +if (flags &FIELD_IS_ARRAY ) +bt_ctf_field_type_put (type); + +if (ret) { +pr_err ("Failed to add field '%s\n" , field->name); +return -1 ; + } + } + +return 0 ; +} + +static int add_tracepoint_types (struct ctf_writer *cw, +struct perf_evsel *evsel, +struct bt_ctf_event_class *class) +{ +struct format_field *common_fields = evsel->tp_format->format.common_fields; +struct format_field *fields = evsel->tp_format->format.fields; +int ret; + + ret =add_tracepoint_fields_types (cw, common_fields, class); +if (!ret) + ret =add_tracepoint_fields_types (cw, fields, class); + +return ret; +} +static int add_generic_types (struct ctf_writer *cw,struct perf_evsel *evsel,struct bt_ctf_event_class *event_class) {
@@ -328,6 +564,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)if (ret) goto err; +if (evsel->attr.type ==PERF_TYPE_TRACEPOINT ) { + ret =add_tracepoint_types (cw, evsel, event_class); +if (ret) + goto err; + } + ret =bt_ctf_stream_class_add_event_class (cw->stream_class, event_class);if (ret) {pr ("Failed to add event class into stream.\n" );
Signature · 1 line
1.9.3
Quoted 3 lines · Arnaldo Carvalho de Melo
Infrastructure:
. Fix libbabeltrace detection (Jiri Olsa)
So this still doesn't seem to work for me:
... libbabeltrace: [ OFF ]
it should really not be included in the default build until the required library features are more widely available in distros.
I think we should only use library features by default that are available in the latest Fedora, SuSE and Ubuntu distros. We want them to build and package perf and there's little point in adding features that won't work on packaged up perf.
Thanks,
Ingo
Quoted 5 lines · Ingo Molnar
Quoted 1 line · Arnaldo Carvalho de Melo
Infrastructure:
Quoted 8 lines
Quoted 1 line
. Fix libbabeltrace detection (Jiri Olsa)
So this still doesn't seem to work for me:
... libbabeltrace: [ OFF ]
it should really not be included in the default build until the required library features are more widely available in distros.
the patch that moves babeltrace out of default
check wasn't pulled in yet:
http://marc.info/?l=linux-kernel&m=142606453815125&w=2
also note there's another bug in test-all that prevents the test-all speed up, fixed by this patch:
http://marc.info/?l=linux-kernel&m=142606452415123&w=2
Quoted 5 lines
I think we should only use library features by default that are available in the latest Fedora, SuSE and Ubuntu distros. We want them to build and package perf and there's little point in adding features that won't work on packaged up perf.
I think we should have the possibility to work and commit new features even if the support is not yet in the main distros
for such features we could:
- leave those features out of the default features check like we'll do for babeltrace
- maybe use some sort of EXPERIMENTAL config option dependency once we have the .config file support ;-)
jirka