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) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJVAsEoAAoJEBpxZoYYoA714cUH/2ve3x3sGqvyJVusPkwcNDfc 65po6FiAA4QhJTXEV3OztjPvlOwsGrMLWAo2CjflcegYhGmQKfQsFuJym0eIGveZ cvqXSpXVfGkNSnGSufVnQ71yvwB/NvicTCS1quBxw2jgrbzugOAXyrO7MycTReFg jD6Hdez2qcQjZe3fViPD02g1304j27nu5GFcVte+OqJ4v8xyGXuNhy1mxkqU299t OkEYbXv94jHUlwfM6jcKgtwvIfvTNbqfC5oG+2haLVsQiEy0oC5D/QiP1GfmsFnm VJJi9ffpZf8QIFeOXO4pJAyMboATHa0fZBaHXkO03RdCIfQuCrb4X6zN/J5MFGQ= =Ffcz -----END PGP SIGNATURE----- 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: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
107eb964d8
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
@ -359,8 +366,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 +384,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)
|
||||
|
@ -408,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,
|
||||
},
|
||||
|
@ -458,6 +463,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)
|
||||
|
|
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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 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,
|
||||
|
|
|
@ -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
|
||||
|
@ -730,9 +731,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);
|
||||
|
@ -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",
|
||||
|
@ -1066,7 +1069,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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -769,6 +771,19 @@ 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);
|
||||
|
@ -1079,6 +1094,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]));
|
||||
|
@ -1148,6 +1165,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))) {
|
||||
|
@ -1252,6 +1271,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 +1282,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 +1301,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 +1324,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 +1338,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 +1380,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 +1392,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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include <babeltrace/ctf-writer/writer.h>
|
||||
#include <babeltrace/ctf-ir/stream-class.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
@ -579,7 +821,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 +833,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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,10 +153,38 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
|
|||
free_dup_event(oe, event->event);
|
||||
}
|
||||
|
||||
static int __ordered_events__flush(struct perf_session *s,
|
||||
struct perf_tool *tool)
|
||||
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 ordered_events *oe = &s->ordered_events;
|
||||
struct list_head *head = &oe->events;
|
||||
struct ordered_event *tmp, *iter;
|
||||
struct perf_sample sample;
|
||||
|
@ -179,12 +207,11 @@ 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(oe->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 = oe->deliver(oe, iter, &sample);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -204,10 +231,8 @@ static int __ordered_events__flush(struct perf_session *s,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
|
||||
enum oe_flush how)
|
||||
int ordered_events__flush(struct ordered_events *oe, enum oe_flush how)
|
||||
{
|
||||
struct ordered_events *oe = &s->ordered_events;
|
||||
static const char * const str[] = {
|
||||
"NONE",
|
||||
"FINAL",
|
||||
|
@ -251,7 +276,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);
|
||||
|
||||
if (!err) {
|
||||
if (how == OE_FLUSH__ROUND)
|
||||
|
@ -267,13 +292,19 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
|
|||
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->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;
|
||||
oe->deliver = deliver;
|
||||
}
|
||||
|
||||
void ordered_events__free(struct ordered_events *oe)
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
#define __ORDERED_EVENTS_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 {
|
||||
u64 timestamp;
|
||||
|
@ -20,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;
|
||||
|
@ -31,18 +39,23 @@ 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;
|
||||
ordered_events__deliver_t deliver;
|
||||
int buffer_idx;
|
||||
unsigned int nr_events;
|
||||
enum oe_flush last_flush_type;
|
||||
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 perf_session *s, 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,
|
||||
ordered_events__deliver_t deliver);
|
||||
void ordered_events__free(struct ordered_events *oe);
|
||||
|
||||
static inline
|
||||
|
|
|
@ -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");
|
||||
|
@ -178,6 +179,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 +269,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 +285,99 @@ 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) {
|
||||
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 */
|
||||
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,
|
|||
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 +603,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 */
|
||||
|
@ -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. */
|
||||
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);
|
||||
|
@ -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
|
||||
* 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;
|
||||
|
@ -641,6 +775,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");
|
||||
|
@ -653,7 +792,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;
|
||||
|
@ -710,7 +853,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;
|
||||
|
@ -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,
|
||||
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 +878,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 +949,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 +1895,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);
|
||||
|
@ -2339,8 +2489,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;
|
||||
|
@ -2367,11 +2516,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 +2609,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:
|
||||
|
@ -2708,8 +2849,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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -95,7 +109,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
|
|||
goto out;
|
||||
|
||||
session->repipe = repipe;
|
||||
ordered_events__init(&session->ordered_events);
|
||||
machines__init(&session->machines);
|
||||
|
||||
if (file) {
|
||||
|
@ -126,6 +139,9 @@ 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, ordered_events__deliver_event);
|
||||
}
|
||||
|
||||
return session;
|
||||
|
@ -209,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;
|
||||
|
@ -220,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,
|
||||
|
@ -258,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;
|
||||
|
@ -508,43 +531,17 @@ static perf_event__swap_op perf_event__swap_ops[] = {
|
|||
* Flush every events below timestamp 7
|
||||
* etc...
|
||||
*/
|
||||
static int process_finished_round(struct perf_tool *tool,
|
||||
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)
|
||||
{
|
||||
return ordered_events__flush(session, tool, OE_FLUSH__ROUND);
|
||||
return ordered_events__flush(oe, OE_FLUSH__ROUND);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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(s, tool, 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)
|
||||
|
@ -886,12 +883,12 @@ static int
|
|||
&sample->read.one, machine);
|
||||
}
|
||||
|
||||
int perf_session__deliver_event(struct perf_session *session,
|
||||
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_evlist *evlist = session->evlist;
|
||||
struct perf_evsel *evsel;
|
||||
struct machine *machine;
|
||||
|
||||
|
@ -899,7 +896,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:
|
||||
|
@ -941,9 +938,10 @@ int perf_session__deliver_event(struct perf_session *session,
|
|||
|
||||
static s64 perf_session__process_user_event(struct perf_session *session,
|
||||
union perf_event *event,
|
||||
struct perf_tool *tool,
|
||||
u64 file_offset)
|
||||
{
|
||||
struct ordered_events *oe = &session->ordered_events;
|
||||
struct perf_tool *tool = oe->tool;
|
||||
int fd = perf_data_file__fd(session->file);
|
||||
int err;
|
||||
|
||||
|
@ -971,7 +969,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:
|
||||
|
@ -981,15 +979,17 @@ static s64 perf_session__process_user_event(struct perf_session *session,
|
|||
|
||||
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)
|
||||
{
|
||||
events_stats__inc(&session->evlist->stats, event->header.type);
|
||||
struct perf_evlist *evlist = session->evlist;
|
||||
struct perf_tool *tool = session->ordered_events.tool;
|
||||
|
||||
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__process_user_event(session, event, 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)
|
||||
|
@ -1057,11 +1057,10 @@ out_parse_sample:
|
|||
}
|
||||
|
||||
static s64 perf_session__process_event(struct perf_session *session,
|
||||
union perf_event *event,
|
||||
struct perf_tool *tool,
|
||||
u64 file_offset)
|
||||
union perf_event *event, u64 file_offset)
|
||||
{
|
||||
struct perf_evlist *evlist = session->evlist;
|
||||
struct perf_tool *tool = session->ordered_events.tool;
|
||||
struct perf_sample sample;
|
||||
int ret;
|
||||
|
||||
|
@ -1074,7 +1073,7 @@ static s64 perf_session__process_event(struct perf_session *session,
|
|||
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, file_offset);
|
||||
return perf_session__process_user_event(session, event, file_offset);
|
||||
|
||||
/*
|
||||
* For all kernel events we get the sample data
|
||||
|
@ -1084,14 +1083,13 @@ static s64 perf_session__process_event(struct perf_session *session,
|
|||
return ret;
|
||||
|
||||
if (tool->ordered_events) {
|
||||
ret = perf_session_queue_event(session, event, tool, &sample,
|
||||
file_offset);
|
||||
ret = perf_session__queue_event(session, event, &sample, file_offset);
|
||||
if (ret != -ETIME)
|
||||
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)
|
||||
|
@ -1164,9 +1162,10 @@ static void perf_tool__warn_about_errors(const struct perf_tool *tool,
|
|||
|
||||
volatile int session_done;
|
||||
|
||||
static int __perf_session__process_pipe_events(struct perf_session *session,
|
||||
struct perf_tool *tool)
|
||||
static int __perf_session__process_pipe_events(struct perf_session *session)
|
||||
{
|
||||
struct ordered_events *oe = &session->ordered_events;
|
||||
struct perf_tool *tool = oe->tool;
|
||||
int fd = perf_data_file__fd(session->file);
|
||||
union perf_event *event;
|
||||
uint32_t size, cur_size = 0;
|
||||
|
@ -1230,7 +1229,7 @@ more:
|
|||
}
|
||||
}
|
||||
|
||||
if ((skip = perf_session__process_event(session, event, tool, head)) < 0) {
|
||||
if ((skip = perf_session__process_event(session, event, head)) < 0) {
|
||||
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
|
||||
head, event->header.size, event->header.type);
|
||||
err = -EINVAL;
|
||||
|
@ -1246,7 +1245,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, OE_FLUSH__FINAL);
|
||||
out_err:
|
||||
free(buf);
|
||||
perf_tool__warn_about_errors(tool, &session->evlist->stats);
|
||||
|
@ -1296,8 +1295,10 @@ fetch_mmaped_event(struct perf_session *session,
|
|||
|
||||
static int __perf_session__process_events(struct perf_session *session,
|
||||
u64 data_offset, u64 data_size,
|
||||
u64 file_size, struct perf_tool *tool)
|
||||
u64 file_size)
|
||||
{
|
||||
struct ordered_events *oe = &session->ordered_events;
|
||||
struct perf_tool *tool = oe->tool;
|
||||
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;
|
||||
|
@ -1366,8 +1367,7 @@ more:
|
|||
size = event->header.size;
|
||||
|
||||
if (size < sizeof(struct perf_event_header) ||
|
||||
(skip = perf_session__process_event(session, event, tool, file_pos))
|
||||
< 0) {
|
||||
(skip = perf_session__process_event(session, event, file_pos)) < 0) {
|
||||
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
|
||||
file_offset + head, event->header.size,
|
||||
event->header.type);
|
||||
|
@ -1391,7 +1391,7 @@ more:
|
|||
|
||||
out:
|
||||
/* do the final flush for ordered samples */
|
||||
err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
|
||||
err = ordered_events__flush(oe, OE_FLUSH__FINAL);
|
||||
out_err:
|
||||
ui_progress__finish();
|
||||
perf_tool__warn_about_errors(tool, &session->evlist->stats);
|
||||
|
@ -1400,8 +1400,7 @@ out_err:
|
|||
return err;
|
||||
}
|
||||
|
||||
int perf_session__process_events(struct perf_session *session,
|
||||
struct perf_tool *tool)
|
||||
int perf_session__process_events(struct perf_session *session)
|
||||
{
|
||||
u64 size = perf_data_file__size(session->file);
|
||||
int err;
|
||||
|
@ -1412,10 +1411,9 @@ int perf_session__process_events(struct perf_session *session,
|
|||
if (!perf_data_file__is_pipe(session->file))
|
||||
err = __perf_session__process_events(session,
|
||||
session->header.data_offset,
|
||||
session->header.data_size,
|
||||
size, tool);
|
||||
session->header.data_size, size);
|
||||
else
|
||||
err = __perf_session__process_pipe_events(session, tool);
|
||||
err = __perf_session__process_pipe_events(session);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -48,20 +48,13 @@ 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);
|
||||
|
||||
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,
|
||||
struct perf_evsel *evsel,
|
||||
struct thread *thread,
|
||||
|
@ -125,8 +118,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,
|
||||
|
|
|
@ -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) {
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue