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
--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,
......@@ -319,7 +319,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
if (n_lines == -1)
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))
......
#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 @@ static int convert_exec_to_group(const char *exec, char **result)
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;
}
/* 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,7 +2489,6 @@ 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++;
}
......@@ -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;
}
......
This diff is collapsed.
......@@ -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,6 +1048,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
* For misannotated, zeroed, ASM function sizes.
*/
if (nr > 0) {
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;
......
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