Commit 107eb964 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

  - 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' to better 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 changes:

  - 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)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 94ac003b 69364727
...@@ -25,6 +25,10 @@ OPTIONS ...@@ -25,6 +25,10 @@ OPTIONS
--input=<file>:: --input=<file>::
Select the input file (default: perf.data unless stdin is a fifo) Select the input file (default: perf.data unless stdin is a fifo)
-v::
--verbose::
Be more verbose. (show symbol address, etc)
--caller:: --caller::
Show per-callsite statistics Show per-callsite statistics
......
...@@ -529,6 +529,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean ...@@ -529,6 +529,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
$(Q)$(RM) .config-detected $(Q)$(RM) .config-detected
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(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, 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 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
$(python-clean) $(python-clean)
......
...@@ -208,7 +208,7 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -208,7 +208,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
goto out; goto out;
} }
ret = perf_session__process_events(session, &ann->tool); ret = perf_session__process_events(session);
if (ret) if (ret)
goto out; goto out;
......
...@@ -74,7 +74,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits) ...@@ -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 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
*/ */
if (with_hits || perf_data_file__is_pipe(&file)) 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__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
perf_session__delete(session); perf_session__delete(session);
......
...@@ -747,7 +747,7 @@ static int __cmd_diff(void) ...@@ -747,7 +747,7 @@ static int __cmd_diff(void)
goto out_delete; goto out_delete;
} }
ret = perf_session__process_events(d->session, &tool); ret = perf_session__process_events(d->session);
if (ret) { if (ret) {
pr_err("Failed to process %s\n", d->file.path); pr_err("Failed to process %s\n", d->file.path);
goto out_delete; goto out_delete;
......
...@@ -53,6 +53,13 @@ static int perf_event__repipe_synth(struct perf_tool *tool, ...@@ -53,6 +53,13 @@ static int perf_event__repipe_synth(struct perf_tool *tool,
return 0; 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, static int perf_event__repipe_op2_synth(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_session *session struct perf_session *session
...@@ -359,8 +366,6 @@ static int __cmd_inject(struct perf_inject *inject) ...@@ -359,8 +366,6 @@ static int __cmd_inject(struct perf_inject *inject)
} else if (inject->sched_stat) { } else if (inject->sched_stat) {
struct perf_evsel *evsel; struct perf_evsel *evsel;
inject->tool.ordered_events = true;
evlist__for_each(session->evlist, evsel) { evlist__for_each(session->evlist, evsel) {
const char *name = perf_evsel__name(evsel); const char *name = perf_evsel__name(evsel);
...@@ -379,7 +384,7 @@ static int __cmd_inject(struct perf_inject *inject) ...@@ -379,7 +384,7 @@ static int __cmd_inject(struct perf_inject *inject)
if (!file_out->is_pipe) if (!file_out->is_pipe)
lseek(fd, session->header.data_offset, SEEK_SET); 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 (!file_out->is_pipe) {
if (inject->build_ids) if (inject->build_ids)
...@@ -408,7 +413,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -408,7 +413,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.unthrottle = perf_event__repipe, .unthrottle = perf_event__repipe,
.attr = perf_event__repipe_attr, .attr = perf_event__repipe_attr,
.tracing_data = perf_event__repipe_op2_synth, .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, .build_id = perf_event__repipe_op2_synth,
.id_index = perf_event__repipe_op2_synth, .id_index = perf_event__repipe_op2_synth,
}, },
...@@ -458,6 +463,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -458,6 +463,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
return -1; return -1;
} }
inject.tool.ordered_events = inject.sched_stat;
file.path = inject.input_name; file.path = inject.input_name;
inject.session = perf_session__new(&file, true, &inject.tool); inject.session = perf_session__new(&file, true, &inject.tool);
if (inject.session == NULL) if (inject.session == NULL)
......
...@@ -275,10 +275,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session, ...@@ -275,10 +275,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
struct rb_node *next; struct rb_node *next;
struct machine *machine = &session->machines.host; 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(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); 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); next = rb_first(root);
...@@ -304,7 +304,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, ...@@ -304,7 +304,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr); snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
printf(" %-34s |", buf); 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 long)data->bytes_alloc,
(unsigned long)data->bytes_alloc / data->hit, (unsigned long)data->bytes_alloc / data->hit,
(unsigned long long)data->bytes_req, (unsigned long long)data->bytes_req,
...@@ -317,9 +317,9 @@ static void __print_result(struct rb_root *root, struct perf_session *session, ...@@ -317,9 +317,9 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
} }
if (n_lines == -1) 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) static void print_summary(void)
...@@ -426,7 +426,7 @@ static int __cmd_kmem(struct perf_session *session) ...@@ -426,7 +426,7 @@ static int __cmd_kmem(struct perf_session *session)
} }
setup_pager(); setup_pager();
err = perf_session__process_events(session, &perf_kmem); err = perf_session__process_events(session);
if (err != 0) if (err != 0)
goto out; goto out;
sort_result(); sort_result();
...@@ -559,6 +559,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg) ...@@ -559,6 +559,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
{ {
char *tok; char *tok;
char *str = strdup(arg); char *str = strdup(arg);
char *pos = str;
if (!str) { if (!str) {
pr_err("%s: strdup failed\n", __func__); pr_err("%s: strdup failed\n", __func__);
...@@ -566,7 +567,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg) ...@@ -566,7 +567,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
} }
while (true) { while (true) {
tok = strsep(&str, ","); tok = strsep(&pos, ",");
if (!tok) if (!tok)
break; break;
if (sort_dimension__add(tok, sort_list) < 0) { if (sort_dimension__add(tok, sort_list) < 0) {
...@@ -662,6 +663,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -662,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 char * const default_sort_order = "frag,hit,bytes";
const struct option kmem_options[] = { const struct option kmem_options[] = {
OPT_STRING('i', "input", &input_name, "file", "input file name"), 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, OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
"show per-callsite statistics", parse_caller_opt), "show per-callsite statistics", parse_caller_opt),
OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "util/stat.h" #include "util/stat.h"
#include "util/top.h" #include "util/top.h"
#include "util/data.h" #include "util/data.h"
#include "util/ordered-events.h"
#include <sys/prctl.h> #include <sys/prctl.h>
#ifdef HAVE_TIMERFD_SUPPORT #ifdef HAVE_TIMERFD_SUPPORT
...@@ -730,9 +731,9 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, ...@@ -730,9 +731,9 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
return -1; 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. * point to it, and it'll get possibly overwritten by the kernel.
*/ */
perf_evlist__mmap_consume(kvm->evlist, idx); perf_evlist__mmap_consume(kvm->evlist, idx);
...@@ -783,8 +784,10 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm) ...@@ -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 */ /* flush queue after each round in which we processed events */
if (ntotal) { if (ntotal) {
kvm->session->ordered_events.next_flush = flush_time; struct ordered_events *oe = &kvm->session->ordered_events;
err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
oe->next_flush = flush_time;
err = ordered_events__flush(oe, OE_FLUSH__ROUND);
if (err) { if (err) {
if (kvm->lost_events) if (kvm->lost_events)
pr_info("\nLost events: %" PRIu64 "\n\n", pr_info("\nLost events: %" PRIu64 "\n\n",
...@@ -1066,7 +1069,7 @@ static int read_events(struct perf_kvm_stat *kvm) ...@@ -1066,7 +1069,7 @@ static int read_events(struct perf_kvm_stat *kvm)
if (ret < 0) if (ret < 0)
return ret; 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) static int parse_target_str(struct perf_kvm_stat *kvm)
......
...@@ -878,7 +878,7 @@ static int __cmd_report(bool display_info) ...@@ -878,7 +878,7 @@ static int __cmd_report(bool display_info)
if (select_key()) if (select_key())
goto out_delete; goto out_delete;
err = perf_session__process_events(session, &eops); err = perf_session__process_events(session);
if (err) if (err)
goto out_delete; goto out_delete;
......
...@@ -141,7 +141,7 @@ static int report_raw_events(struct perf_mem *mem) ...@@ -141,7 +141,7 @@ static int report_raw_events(struct perf_mem *mem)
printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); 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) if (err)
return err; return err;
......
...@@ -225,7 +225,7 @@ static int process_buildids(struct record *rec) ...@@ -225,7 +225,7 @@ static int process_buildids(struct record *rec)
*/ */
symbol_conf.ignore_vmlinux_buildid = true; 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) 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) ...@@ -343,7 +343,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
session = perf_session__new(file, false, NULL); session = perf_session__new(file, false, tool);
if (session == NULL) { if (session == NULL) {
pr_err("Perf session creation failed.\n"); pr_err("Perf session creation failed.\n");
return -1; return -1;
......
...@@ -482,7 +482,7 @@ static int __cmd_report(struct report *rep) ...@@ -482,7 +482,7 @@ static int __cmd_report(struct report *rep)
if (ret) if (ret)
return ret; return ret;
ret = perf_session__process_events(session, &rep->tool); ret = perf_session__process_events(session);
if (ret) if (ret)
return ret; return ret;
......
...@@ -1467,7 +1467,7 @@ static int perf_sched__read_events(struct perf_sched *sched) ...@@ -1467,7 +1467,7 @@ static int perf_sched__read_events(struct perf_sched *sched)
goto out_delete; goto out_delete;
if (perf_session__has_traces(session, "record -R")) { 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) { if (err) {
pr_err("Failed to process events, error %d", err); pr_err("Failed to process events, error %d", err);
goto out_delete; goto out_delete;
......
...@@ -800,7 +800,7 @@ static int __cmd_script(struct perf_script *script) ...@@ -800,7 +800,7 @@ static int __cmd_script(struct perf_script *script)
script->tool.mmap2 = process_mmap2_event; 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) if (debug_mode)
pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
......
...@@ -353,39 +353,40 @@ static struct perf_evsel *nth_evsel(int n) ...@@ -353,39 +353,40 @@ static struct perf_evsel *nth_evsel(int n)
* more semantic information such as miss/hit ratios, * more semantic information such as miss/hit ratios,
* instruction rates, etc: * 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)) 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)) 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 && else if (transaction_run &&
perf_evsel__cmp(counter, nth_evsel(T_CYCLES_IN_TX))) 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 && else if (transaction_run &&
perf_evsel__cmp(counter, nth_evsel(T_TRANSACTION_START))) 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 && else if (transaction_run &&
perf_evsel__cmp(counter, nth_evsel(T_ELISION_START))) 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)) 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)) 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)) 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)) 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)) 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)) 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)) 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)) 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)) 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) 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, ...@@ -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_evsel__compute_deltas(evsel, cpu, count);
perf_counts_values__scale(count, scale, NULL); perf_counts_values__scale(count, scale, NULL);
evsel->counts->cpu[cpu] = *count; evsel->counts->cpu[cpu] = *count;
update_shadow_stats(evsel, count->values); if (aggr_mode == AGGR_NONE)
update_shadow_stats(evsel, count->values, cpu);
break; break;
case AGGR_GLOBAL: case AGGR_GLOBAL:
aggr->val += count->val; aggr->val += count->val;
...@@ -495,7 +497,7 @@ static int read_counter_aggr(struct perf_evsel *counter) ...@@ -495,7 +497,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
/* /*
* Save the full runtime - to allow normalization during printout: * Save the full runtime - to allow normalization during printout:
*/ */
update_shadow_stats(counter, count); update_shadow_stats(counter, count, 0);
return 0; return 0;
} }
...@@ -769,6 +771,19 @@ static int run_perf_stat(int argc, const char **argv) ...@@ -769,6 +771,19 @@ static int run_perf_stat(int argc, const char **argv)
return ret; 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) static void print_noise_pct(double total, double avg)
{ {
double pct = rel_stddev_stats(total, avg); double pct = rel_stddev_stats(total, avg);
...@@ -1079,6 +1094,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) ...@@ -1079,6 +1094,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (total) { if (total) {
ratio = avg / total; ratio = avg / total;
fprintf(output, " # %5.2f insns per cycle ", ratio); fprintf(output, " # %5.2f insns per cycle ", ratio);
} else {
fprintf(output, " ");
} }
total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
...@@ -1148,6 +1165,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) ...@@ -1148,6 +1165,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (total) { if (total) {
ratio = avg / total; ratio = avg / total;
fprintf(output, " # %8.3f GHz ", ratio); fprintf(output, " # %8.3f GHz ", ratio);
} else {
fprintf(output, " ");
} }
} else if (transaction_run && } else if (transaction_run &&
perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) { perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) {
...@@ -1252,6 +1271,7 @@ static void print_aggr(char *prefix) ...@@ -1252,6 +1271,7 @@ static void print_aggr(char *prefix)
fprintf(output, "%s%s", fprintf(output, "%s%s",
csv_sep, counter->cgrp->name); csv_sep, counter->cgrp->name);
print_running(run, ena);
fputc('\n', output); fputc('\n', output);
continue; continue;
} }
...@@ -1262,13 +1282,10 @@ static void print_aggr(char *prefix) ...@@ -1262,13 +1282,10 @@ static void print_aggr(char *prefix)
else else
abs_printout(id, nr, counter, uval); abs_printout(id, nr, counter, uval);
if (!csv_output) { if (!csv_output)
print_noise(counter, 1.0); print_noise(counter, 1.0);
if (run != ena) print_running(run, ena);
fprintf(output, " (%.2f%%)",
100.0 * run / ena);
}
fputc('\n', output); fputc('\n', output);
} }
} }
...@@ -1284,6 +1301,10 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) ...@@ -1284,6 +1301,10 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
double avg = avg_stats(&ps->res_stats[0]); double avg = avg_stats(&ps->res_stats[0]);
int scaled = counter->counts->scaled; int scaled = counter->counts->scaled;
double uval; 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) if (prefix)
fprintf(output, "%s", prefix); fprintf(output, "%s", prefix);
...@@ -1303,6 +1324,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) ...@@ -1303,6 +1324,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
if (counter->cgrp) if (counter->cgrp)
fprintf(output, "%s%s", csv_sep, counter->cgrp->name); fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
print_running(avg_running, avg_enabled);
fputc('\n', output); fputc('\n', output);
return; return;
} }
...@@ -1316,19 +1338,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) ...@@ -1316,19 +1338,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
print_noise(counter, avg); print_noise(counter, avg);
if (csv_output) { print_running(avg_running, avg_enabled);
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);
}
fprintf(output, "\n"); fprintf(output, "\n");
} }
...@@ -1370,6 +1380,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix) ...@@ -1370,6 +1380,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
fprintf(output, "%s%s", fprintf(output, "%s%s",
csv_sep, counter->cgrp->name); csv_sep, counter->cgrp->name);
print_running(run, ena);
fputc('\n', output); fputc('\n', output);
continue; continue;
} }
...@@ -1381,13 +1392,10 @@ static void print_counter(struct perf_evsel *counter, char *prefix) ...@@ -1381,13 +1392,10 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
else else
abs_printout(cpu, 0, counter, uval); abs_printout(cpu, 0, counter, uval);
if (!csv_output) { if (!csv_output)
print_noise(counter, 1.0); print_noise(counter, 1.0);
print_running(run, ena);
if (run != ena)
fprintf(output, " (%.2f%%)",
100.0 * run / ena);
}
fputc('\n', output); fputc('\n', output);
} }
} }
......
...@@ -1623,7 +1623,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) ...@@ -1623,7 +1623,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
goto out_delete; goto out_delete;
} }
ret = perf_session__process_events(session, &tchart->tool); ret = perf_session__process_events(session);
if (ret) if (ret)
goto out_delete; goto out_delete;
......
...@@ -2408,7 +2408,7 @@ static int trace__replay(struct trace *trace) ...@@ -2408,7 +2408,7 @@ static int trace__replay(struct trace *trace)
setup_pager(); setup_pager();
err = perf_session__process_events(session, &trace->tool); err = perf_session__process_events(session);
if (err) if (err)
pr_err("Failed to process events, error %d", err); pr_err("Failed to process events, error %d", err);
......
...@@ -184,7 +184,7 @@ endif ...@@ -184,7 +184,7 @@ endif
feature_check = $(eval $(feature_check_code)) feature_check = $(eval $(feature_check_code))
define 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 endef
feature_set = $(eval $(feature_set_code)) feature_set = $(eval $(feature_set_code))
......
#include <babeltrace/ctf-writer/writer.h> #include <babeltrace/ctf-writer/writer.h>
#include <babeltrace/ctf-ir/stream-class.h>
int main(void) int main(void)
{ {
......
...@@ -48,6 +48,24 @@ static bool hist_browser__has_filter(struct hist_browser *hb) ...@@ -48,6 +48,24 @@ static bool hist_browser__has_filter(struct hist_browser *hb)
return hists__has_filter(hb->hists) || hb->min_pcnt; 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) static u32 hist_browser__nr_entries(struct hist_browser *hb)
{ {
u32 nr_entries; u32 nr_entries;
...@@ -57,6 +75,7 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb) ...@@ -57,6 +75,7 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
else else
nr_entries = hb->hists->nr_entries; nr_entries = hb->hists->nr_entries;
hb->nr_callchain_rows = hist_browser__get_folding(hb);
return nr_entries + hb->nr_callchain_rows; return nr_entries + hb->nr_callchain_rows;
} }
......
...@@ -126,6 +126,177 @@ FUNC_VALUE_SET(s64) ...@@ -126,6 +126,177 @@ FUNC_VALUE_SET(s64)
FUNC_VALUE_SET(u64) FUNC_VALUE_SET(u64)
__FUNC_VALUE_SET(u64_hex, 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, static int add_generic_values(struct ctf_writer *cw,
struct bt_ctf_event *event, struct bt_ctf_event *event,
struct perf_evsel *evsel, struct perf_evsel *evsel,
...@@ -246,11 +417,76 @@ static int process_sample_event(struct perf_tool *tool, ...@@ -246,11 +417,76 @@ static int process_sample_event(struct perf_tool *tool,
if (ret) if (ret)
return -1; 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_stream_append_event(cw->stream, event);
bt_ctf_event_put(event); bt_ctf_event_put(event);
return 0; 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, static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
struct bt_ctf_event_class *event_class) struct bt_ctf_event_class *event_class)
{ {
...@@ -328,6 +564,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) ...@@ -328,6 +564,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
if (ret) if (ret)
goto err; 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); ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
if (ret) { if (ret) {
pr("Failed to add event class into stream.\n"); pr("Failed to add event class into stream.\n");
...@@ -579,7 +821,7 @@ int bt_convert__perf2ctf(const char *input, const char *path) ...@@ -579,7 +821,7 @@ int bt_convert__perf2ctf(const char *input, const char *path)
return -1; return -1;
/* perf.data session */ /* perf.data session */
session = perf_session__new(&file, 0, NULL); session = perf_session__new(&file, 0, &c.tool);
if (!session) if (!session)
goto free_writer; goto free_writer;
...@@ -591,7 +833,7 @@ int bt_convert__perf2ctf(const char *input, const char *path) ...@@ -591,7 +833,7 @@ int bt_convert__perf2ctf(const char *input, const char *path)
if (setup_events(cw, session)) if (setup_events(cw, session))
goto free_session; goto free_session;
err = perf_session__process_events(session, &c.tool); err = perf_session__process_events(session);
if (!err) if (!err)
err = bt_ctf_stream_flush(cw->stream); err = bt_ctf_stream_flush(cw->stream);
......
...@@ -1171,6 +1171,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h ...@@ -1171,6 +1171,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
/* force fold unfiltered entry for simplicity */ /* force fold unfiltered entry for simplicity */
h->ms.unfolded = false; h->ms.unfolded = false;
h->row_offset = 0; h->row_offset = 0;
h->nr_rows = 0;
hists->stats.nr_non_filtered_samples += h->stat.nr_events; hists->stats.nr_non_filtered_samples += h->stat.nr_events;
......
...@@ -131,8 +131,8 @@ static struct ordered_event *alloc_event(struct ordered_events *oe, ...@@ -131,8 +131,8 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
return new; return new;
} }
struct ordered_event * static struct ordered_event *
ordered_events__new(struct ordered_events *oe, u64 timestamp, ordered_events__new_event(struct ordered_events *oe, u64 timestamp,
union perf_event *event) union perf_event *event)
{ {
struct ordered_event *new; struct ordered_event *new;
...@@ -153,10 +153,38 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve ...@@ -153,10 +153,38 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
free_dup_event(oe, event->event); free_dup_event(oe, event->event);
} }
static int __ordered_events__flush(struct perf_session *s, int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
struct perf_tool *tool) 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 ordered_events *oe = &s->ordered_events;
struct list_head *head = &oe->events; struct list_head *head = &oe->events;
struct ordered_event *tmp, *iter; struct ordered_event *tmp, *iter;
struct perf_sample sample; struct perf_sample sample;
...@@ -179,12 +207,11 @@ static int __ordered_events__flush(struct perf_session *s, ...@@ -179,12 +207,11 @@ static int __ordered_events__flush(struct perf_session *s,
if (iter->timestamp > limit) if (iter->timestamp > limit)
break; break;
ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); ret = perf_evlist__parse_sample(oe->evlist, iter->event, &sample);
if (ret) if (ret)
pr_err("Can't parse sample, err = %d\n", ret); pr_err("Can't parse sample, err = %d\n", ret);
else { else {
ret = perf_session__deliver_event(s, iter->event, &sample, tool, ret = oe->deliver(oe, iter, &sample);
iter->file_offset);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -204,10 +231,8 @@ static int __ordered_events__flush(struct perf_session *s, ...@@ -204,10 +231,8 @@ static int __ordered_events__flush(struct perf_session *s,
return 0; return 0;
} }
int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, int ordered_events__flush(struct ordered_events *oe, enum oe_flush how)
enum oe_flush how)
{ {
struct ordered_events *oe = &s->ordered_events;
static const char * const str[] = { static const char * const str[] = {
"NONE", "NONE",
"FINAL", "FINAL",
...@@ -251,7 +276,7 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, ...@@ -251,7 +276,7 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
str[how], oe->nr_events); str[how], oe->nr_events);
pr_oe_time(oe->max_timestamp, "max_timestamp\n"); pr_oe_time(oe->max_timestamp, "max_timestamp\n");
err = __ordered_events__flush(s, tool); err = __ordered_events__flush(oe);
if (!err) { if (!err) {
if (how == OE_FLUSH__ROUND) if (how == OE_FLUSH__ROUND)
...@@ -267,13 +292,19 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, ...@@ -267,13 +292,19 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
return err; 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,
ordered_events__deliver_t deliver)
{ {
INIT_LIST_HEAD(&oe->events); INIT_LIST_HEAD(&oe->events);
INIT_LIST_HEAD(&oe->cache); INIT_LIST_HEAD(&oe->cache);
INIT_LIST_HEAD(&oe->to_free); INIT_LIST_HEAD(&oe->to_free);
oe->max_alloc_size = (u64) -1; oe->max_alloc_size = (u64) -1;
oe->cur_alloc_size = 0; oe->cur_alloc_size = 0;
oe->evlist = evlist;
oe->machines = machines;
oe->tool = tool;
oe->deliver = deliver;
} }
void ordered_events__free(struct ordered_events *oe) void ordered_events__free(struct ordered_events *oe)
......
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
#define __ORDERED_EVENTS_H #define __ORDERED_EVENTS_H
#include <linux/types.h> #include <linux/types.h>
#include "tool.h"
struct perf_session; struct perf_tool;
struct perf_evlist;
struct perf_sample;
struct machines;
struct ordered_event { struct ordered_event {
u64 timestamp; u64 timestamp;
...@@ -20,6 +22,12 @@ enum oe_flush { ...@@ -20,6 +22,12 @@ enum oe_flush {
OE_FLUSH__HALF, 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 { struct ordered_events {
u64 last_flush; u64 last_flush;
u64 next_flush; u64 next_flush;
...@@ -31,18 +39,23 @@ struct ordered_events { ...@@ -31,18 +39,23 @@ struct ordered_events {
struct list_head to_free; struct list_head to_free;
struct ordered_event *buffer; struct ordered_event *buffer;
struct ordered_event *last; struct ordered_event *last;
struct machines *machines;
struct perf_evlist *evlist;
struct perf_tool *tool;
ordered_events__deliver_t deliver;
int buffer_idx; int buffer_idx;
unsigned int nr_events; unsigned int nr_events;
enum oe_flush last_flush_type; enum oe_flush last_flush_type;
bool copy_on_queue; bool copy_on_queue;
}; };
struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp, int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
union perf_event *event); struct perf_sample *sample, u64 file_offset);
void ordered_events__delete(struct ordered_events *oe, struct ordered_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, enum oe_flush how);
enum oe_flush how); void ordered_events__init(struct ordered_events *oe, struct machines *machines,
void ordered_events__init(struct ordered_events *oe); struct perf_evlist *evlsit, struct perf_tool *tool,
ordered_events__deliver_t deliver);
void ordered_events__free(struct ordered_events *oe); void ordered_events__free(struct ordered_events *oe);
static inline static inline
......
...@@ -80,6 +80,7 @@ static int init_symbol_maps(bool user_only) ...@@ -80,6 +80,7 @@ static int init_symbol_maps(bool user_only)
int ret; int ret;
symbol_conf.sort_by_name = true; symbol_conf.sort_by_name = true;
symbol_conf.allow_aliases = true;
ret = symbol__init(NULL); ret = symbol__init(NULL);
if (ret < 0) { if (ret < 0) {
pr_debug("Failed to init symbol map.\n"); pr_debug("Failed to init symbol map.\n");
...@@ -178,6 +179,25 @@ static struct map *kernel_get_module_map(const char *module) ...@@ -178,6 +179,25 @@ static struct map *kernel_get_module_map(const char *module)
return NULL; 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) static struct dso *kernel_get_module_dso(const char *module)
{ {
struct dso *dso; struct dso *dso;
...@@ -249,6 +269,13 @@ static int convert_exec_to_group(const char *exec, char **result) ...@@ -249,6 +269,13 @@ static int convert_exec_to_group(const char *exec, char **result)
return ret; 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) static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
{ {
int i; int i;
...@@ -258,6 +285,99 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) ...@@ -258,6 +285,99 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
} }
#ifdef HAVE_DWARF_SUPPORT #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) {
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;
}
static int get_alternative_line_range(struct debuginfo *dinfo,
struct line_range *lr,
const char *target, bool user)
{
struct perf_probe_point pp = { .function = lr->function,
.file = lr->file,
.line = lr->start };
struct perf_probe_point result;
int ret, len = 0;
memset(&result, 0, sizeof(result));
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 */ /* Open new debuginfo of given module */
static struct debuginfo *open_debuginfo(const char *module, bool silent) static struct debuginfo *open_debuginfo(const char *module, bool silent)
...@@ -466,6 +586,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, ...@@ -466,6 +586,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
int max_tevs, const char *target) int max_tevs, const char *target)
{ {
bool need_dwarf = perf_probe_event_need_dwarf(pev); bool need_dwarf = perf_probe_event_need_dwarf(pev);
struct perf_probe_point tmp;
struct debuginfo *dinfo; struct debuginfo *dinfo;
int ntevs, ret = 0; int ntevs, ret = 0;
...@@ -482,6 +603,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, ...@@ -482,6 +603,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
/* Searching trace events corresponding to a probe event */ /* Searching trace events corresponding to a probe event */
ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 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); debuginfo__delete(dinfo);
if (ntevs > 0) { /* Succeeded to find trace events */ if (ntevs > 0) { /* Succeeded to find trace events */
...@@ -496,11 +631,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, ...@@ -496,11 +631,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. */ 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)); synthesize_perf_probe_point(&pev->point));
if (need_dwarf) return -ENOENT;
return -ENOENT;
return 0;
} }
/* Error path : ntevs < 0 */ /* Error path : ntevs < 0 */
pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
...@@ -625,7 +758,8 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) ...@@ -625,7 +758,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 * Show line-range always requires debuginfo to find source file and
* line number. * 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; int l = 1;
struct int_node *ln; struct int_node *ln;
...@@ -641,6 +775,11 @@ static int __show_line_range(struct line_range *lr, const char *module) ...@@ -641,6 +775,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
return -ENOENT; return -ENOENT;
ret = debuginfo__find_line_range(dinfo, lr); 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); debuginfo__delete(dinfo);
if (ret == 0 || ret == -ENOENT) { if (ret == 0 || ret == -ENOENT) {
pr_warning("Specified source line is not found.\n"); pr_warning("Specified source line is not found.\n");
...@@ -653,7 +792,11 @@ static int __show_line_range(struct line_range *lr, const char *module) ...@@ -653,7 +792,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
/* Convert source file path */ /* Convert source file path */
tmp = lr->path; tmp = lr->path;
ret = get_real_path(tmp, lr->comp_dir, &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) { if (ret < 0) {
pr_warning("Failed to find source file path.\n"); pr_warning("Failed to find source file path.\n");
return ret; return ret;
...@@ -710,7 +853,7 @@ int show_line_range(struct line_range *lr, const char *module, bool user) ...@@ -710,7 +853,7 @@ int show_line_range(struct line_range *lr, const char *module, bool user)
ret = init_symbol_maps(user); ret = init_symbol_maps(user);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = __show_line_range(lr, module); ret = __show_line_range(lr, module, user);
exit_symbol_maps(); exit_symbol_maps();
return ret; return ret;
...@@ -719,12 +862,13 @@ int show_line_range(struct line_range *lr, const char *module, bool user) ...@@ -719,12 +862,13 @@ int show_line_range(struct line_range *lr, const char *module, bool user)
static int show_available_vars_at(struct debuginfo *dinfo, static int show_available_vars_at(struct debuginfo *dinfo,
struct perf_probe_event *pev, struct perf_probe_event *pev,
int max_vls, struct strfilter *_filter, int max_vls, struct strfilter *_filter,
bool externs) bool externs, const char *target)
{ {
char *buf; char *buf;
int ret, i, nvars; int ret, i, nvars;
struct str_node *node; struct str_node *node;
struct variable_list *vls = NULL, *vl; struct variable_list *vls = NULL, *vl;
struct perf_probe_point tmp;
const char *var; const char *var;
buf = synthesize_perf_probe_point(&pev->point); buf = synthesize_perf_probe_point(&pev->point);
...@@ -734,6 +878,15 @@ static int show_available_vars_at(struct debuginfo *dinfo, ...@@ -734,6 +878,15 @@ static int show_available_vars_at(struct debuginfo *dinfo,
ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
max_vls, externs); 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) {
if (ret == 0 || ret == -ENOENT) { if (ret == 0 || ret == -ENOENT) {
pr_err("Failed to find the address of %s\n", buf); pr_err("Failed to find the address of %s\n", buf);
...@@ -796,7 +949,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, ...@@ -796,7 +949,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
for (i = 0; i < npevs && ret >= 0; i++) for (i = 0; i < npevs && ret >= 0; i++)
ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter,
externs); externs, module);
debuginfo__delete(dinfo); debuginfo__delete(dinfo);
out: out:
...@@ -1742,15 +1895,12 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, ...@@ -1742,15 +1895,12 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
void clear_perf_probe_event(struct perf_probe_event *pev) void clear_perf_probe_event(struct perf_probe_event *pev)
{ {
struct perf_probe_point *pp = &pev->point;
struct perf_probe_arg_field *field, *next; struct perf_probe_arg_field *field, *next;
int i; int i;
free(pev->event); free(pev->event);
free(pev->group); free(pev->group);
free(pp->file); clear_perf_probe_point(&pev->point);
free(pp->function);
free(pp->lazy_line);
for (i = 0; i < pev->nargs; i++) { for (i = 0; i < pev->nargs; i++) {
free(pev->args[i].name); free(pev->args[i].name);
...@@ -2339,8 +2489,7 @@ static int find_probe_functions(struct map *map, char *name) ...@@ -2339,8 +2489,7 @@ static int find_probe_functions(struct map *map, char *name)
struct symbol *sym; struct symbol *sym;
map__for_each_symbol_by_name(map, name, sym) { map__for_each_symbol_by_name(map, name, sym) {
if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) found++;
found++;
} }
return found; return found;
...@@ -2367,11 +2516,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, ...@@ -2367,11 +2516,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
int num_matched_functions; int num_matched_functions;
int ret, i; int ret, i;
/* Init maps of given executable or kernel */ map = get_target_map(target, pev->uprobes);
if (pev->uprobes)
map = dso__new_map(target);
else
map = kernel_get_module_map(target);
if (!map) { if (!map) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
...@@ -2464,11 +2609,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, ...@@ -2464,11 +2609,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
} }
out: out:
if (map && pev->uprobes) { put_target_map(map, pev->uprobes);
/* Only when using uprobe(exec) map needs to be released */
dso__delete(map->dso);
map__delete(map);
}
return ret; return ret;
nomem_out: nomem_out:
...@@ -2708,8 +2849,7 @@ static struct strfilter *available_func_filter; ...@@ -2708,8 +2849,7 @@ static struct strfilter *available_func_filter;
static int filter_available_functions(struct map *map __maybe_unused, static int filter_available_functions(struct map *map __maybe_unused,
struct symbol *sym) struct symbol *sym)
{ {
if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && if (strfilter__compare(available_func_filter, sym->name))
strfilter__compare(available_func_filter, sym->name))
return 0; return 0;
return 1; return 1;
} }
......
This diff is collapsed.
...@@ -48,20 +48,13 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset, ...@@ -48,20 +48,13 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
union perf_event **event_ptr, union perf_event **event_ptr,
struct perf_sample *sample); struct perf_sample *sample);
int perf_session__process_events(struct perf_session *session, int perf_session__process_events(struct perf_session *session);
struct perf_tool *tool);
int perf_session_queue_event(struct perf_session *s, union perf_event *event, int perf_session__queue_event(struct perf_session *s, union perf_event *event,
struct perf_tool *tool, struct perf_sample *sample, struct perf_sample *sample, u64 file_offset);
u64 file_offset);
void perf_tool__fill_defaults(struct perf_tool *tool); void perf_tool__fill_defaults(struct perf_tool *tool);
int perf_session__deliver_event(struct perf_session *session,
union perf_event *event,
struct perf_sample *sample,
struct perf_tool *tool, u64 file_offset);
int perf_session__resolve_callchain(struct perf_session *session, int perf_session__resolve_callchain(struct perf_session *session,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct thread *thread, struct thread *thread,
...@@ -125,8 +118,7 @@ extern volatile int session_done; ...@@ -125,8 +118,7 @@ extern volatile int session_done;
int perf_session__deliver_synth_event(struct perf_session *session, int perf_session__deliver_synth_event(struct perf_session *session,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample);
struct perf_tool *tool);
int perf_event__process_id_index(struct perf_tool *tool, int perf_event__process_id_index(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
......
...@@ -1048,7 +1048,8 @@ int dso__load_sym(struct dso *dso, struct map *map, ...@@ -1048,7 +1048,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
* For misannotated, zeroed, ASM function sizes. * For misannotated, zeroed, ASM function sizes.
*/ */
if (nr > 0) { 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]); symbols__fixup_end(&dso->symbols[map->type]);
if (kmap) { if (kmap) {
/* /*
......
...@@ -87,6 +87,7 @@ struct symbol_conf { ...@@ -87,6 +87,7 @@ struct symbol_conf {
ignore_vmlinux_buildid, ignore_vmlinux_buildid,
show_kernel_path, show_kernel_path,
use_modules, use_modules,
allow_aliases,
sort_by_name, sort_by_name,
show_nr_samples, show_nr_samples,
show_total_period, show_total_period,
......
...@@ -206,7 +206,6 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) ...@@ -206,7 +206,6 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
err = thread__set_comm(thread, comm, timestamp); err = thread__set_comm(thread, comm, timestamp);
if (err) if (err)
return err; return err;
thread->comm_set = true;
} }
thread->ppid = parent->tid; thread->ppid = parent->tid;
......
...@@ -10,6 +10,7 @@ struct perf_evsel; ...@@ -10,6 +10,7 @@ struct perf_evsel;
struct perf_sample; struct perf_sample;
struct perf_tool; struct perf_tool;
struct machine; struct machine;
struct ordered_events;
typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -25,6 +26,9 @@ typedef int (*event_attr_op)(struct perf_tool *tool, ...@@ -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, typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
struct perf_session *session); struct perf_session *session);
typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,
struct ordered_events *oe);
struct perf_tool { struct perf_tool {
event_sample sample, event_sample sample,
read; read;
...@@ -38,8 +42,8 @@ struct perf_tool { ...@@ -38,8 +42,8 @@ struct perf_tool {
unthrottle; unthrottle;
event_attr_op attr; event_attr_op attr;
event_op2 tracing_data; event_op2 tracing_data;
event_op2 finished_round, event_oe finished_round;
build_id, event_op2 build_id,
id_index; id_index;
bool ordered_events; bool ordered_events;
bool ordering_requires_timestamps; bool ordering_requires_timestamps;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment