mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
Infrastructure fixes and changes:
* Fix off-by-one bugs in map->end handling (Stephane Eranian)
* Fix off-by-one bug in maps__find(), also related to map->end handling (Namhyung Kim)
* Make struct symbol->end be the first addr after the symbol range, to make it
match the convention used for struct map->end. (Arnaldo Carvalho de Melo)
* Fix perf_evlist__add_pollfd() error handling in 'perf kvm stat live' (Jiri Olsa)
* Fix python test build by moving callchain_param to an object linked into the
python binding (Jiri Olsa)
* Do not include a struct hists per perf_evsel, untangling the histogram code
from perf_evsel, to pave the way for exporting a minimalistic
tools/lib/api/perf/ library usable by tools/perf and initially by the rasd
daemon being developed by Borislav Petkov, Robert Richter and Jean Pihet.
(Arnaldo Carvalho de Melo)
* Make perf_evlist__open(evlist, NULL, NULL), i.e. without cpu and thread
maps mean syswide monitoring, reducing the boilerplate for tools that
only want system wide mode. (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:
@@ -51,6 +51,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
|
||||
struct addr_location *al,
|
||||
struct perf_annotate *ann)
|
||||
{
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
int ret;
|
||||
|
||||
@@ -66,13 +67,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0,
|
||||
true);
|
||||
he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true);
|
||||
if (he == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
|
||||
hists__inc_nr_samples(&evsel->hists, true);
|
||||
hists__inc_nr_samples(hists, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -214,6 +214,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
|
||||
if (dump_trace) {
|
||||
perf_session__fprintf_nr_events(session, stdout);
|
||||
perf_evlist__fprintf_nr_events(session->evlist, stdout);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -225,7 +226,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
|
||||
total_nr_samples = 0;
|
||||
evlist__for_each(session->evlist, pos) {
|
||||
struct hists *hists = &pos->hists;
|
||||
struct hists *hists = evsel__hists(pos);
|
||||
u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
|
||||
if (nr_samples > 0) {
|
||||
@@ -325,7 +326,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"Show event group information together"),
|
||||
OPT_END()
|
||||
};
|
||||
int ret;
|
||||
int ret = hists__init();
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
argc = parse_options(argc, argv, options, annotate_usage, 0);
|
||||
|
||||
|
||||
@@ -327,6 +327,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
struct machine *machine)
|
||||
{
|
||||
struct addr_location al;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
|
||||
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
|
||||
pr_warning("problem processing %d event, skipping it.\n",
|
||||
@@ -334,7 +335,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hists__add_entry(&evsel->hists, &al, sample->period,
|
||||
if (hists__add_entry(hists, &al, sample->period,
|
||||
sample->weight, sample->transaction)) {
|
||||
pr_warning("problem incrementing symbol period, skipping event\n");
|
||||
return -1;
|
||||
@@ -346,9 +347,9 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
* hists__output_resort() and precompute needs the total
|
||||
* period in order to sort entries by percentage delta.
|
||||
*/
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
hists->stats.total_period += sample->period;
|
||||
if (!al.filtered)
|
||||
evsel->hists.stats.total_non_filtered_period += sample->period;
|
||||
hists->stats.total_non_filtered_period += sample->period;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -382,7 +383,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
|
||||
hists__collapse_resort(hists, NULL);
|
||||
}
|
||||
@@ -631,24 +632,26 @@ static void data_process(void)
|
||||
bool first = true;
|
||||
|
||||
evlist__for_each(evlist_base, evsel_base) {
|
||||
struct hists *hists_base = evsel__hists(evsel_base);
|
||||
struct data__file *d;
|
||||
int i;
|
||||
|
||||
data__for_each_file_new(i, d) {
|
||||
struct perf_evlist *evlist = d->session->evlist;
|
||||
struct perf_evsel *evsel;
|
||||
struct hists *hists;
|
||||
|
||||
evsel = evsel_match(evsel_base, evlist);
|
||||
if (!evsel)
|
||||
continue;
|
||||
|
||||
d->hists = &evsel->hists;
|
||||
hists = evsel__hists(evsel);
|
||||
d->hists = hists;
|
||||
|
||||
hists__match(&evsel_base->hists, &evsel->hists);
|
||||
hists__match(hists_base, hists);
|
||||
|
||||
if (!show_baseline_only)
|
||||
hists__link(&evsel_base->hists,
|
||||
&evsel->hists);
|
||||
hists__link(hists_base, hists);
|
||||
}
|
||||
|
||||
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
|
||||
@@ -659,7 +662,7 @@ static void data_process(void)
|
||||
if (verbose || data__files_cnt > 2)
|
||||
data__fprintf();
|
||||
|
||||
hists__process(&evsel_base->hists);
|
||||
hists__process(hists_base);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -896,8 +896,7 @@ static int perf_kvm__handle_stdin(void)
|
||||
|
||||
static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
struct pollfd *pollfds = NULL;
|
||||
int nr_fds, nr_stdin, ret, err = -EINVAL;
|
||||
int nr_stdin, ret, err = -EINVAL;
|
||||
struct termios save;
|
||||
|
||||
/* live flag must be set first */
|
||||
@@ -919,34 +918,27 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
/* use pollfds -- need to add timerfd and stdin */
|
||||
nr_fds = kvm->evlist->pollfd.nr;
|
||||
|
||||
/* add timer fd */
|
||||
if (perf_kvm__timerfd_create(kvm) < 0) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd))
|
||||
if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0)
|
||||
goto out;
|
||||
|
||||
nr_fds++;
|
||||
|
||||
if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
|
||||
nr_stdin = perf_evlist__add_pollfd(kvm->evlist, fileno(stdin));
|
||||
if (nr_stdin < 0)
|
||||
goto out;
|
||||
|
||||
nr_stdin = nr_fds;
|
||||
nr_fds++;
|
||||
if (fd_set_nonblock(fileno(stdin)) != 0)
|
||||
goto out;
|
||||
|
||||
pollfds = kvm->evlist->pollfd.entries;
|
||||
|
||||
/* everything is good - enable the events and process */
|
||||
perf_evlist__enable(kvm->evlist);
|
||||
|
||||
while (!done) {
|
||||
struct fdarray *fda = &kvm->evlist->pollfd;
|
||||
int rc;
|
||||
|
||||
rc = perf_kvm__mmap_read(kvm);
|
||||
@@ -957,11 +949,11 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (pollfds[nr_stdin].revents & POLLIN)
|
||||
if (fda->entries[nr_stdin].revents & POLLIN)
|
||||
done = perf_kvm__handle_stdin();
|
||||
|
||||
if (!rc && !done)
|
||||
err = poll(pollfds, nr_fds, 100);
|
||||
err = fdarray__poll(fda, 100);
|
||||
}
|
||||
|
||||
perf_evlist__disable(kvm->evlist);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "util/parse-options.h"
|
||||
#include "util/parse-events.h"
|
||||
|
||||
#include "util/callchain.h"
|
||||
#include "util/header.h"
|
||||
#include "util/event.h"
|
||||
#include "util/evlist.h"
|
||||
|
||||
@@ -288,12 +288,14 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
|
||||
evname = buf;
|
||||
|
||||
for_each_group_member(pos, evsel) {
|
||||
const struct hists *pos_hists = evsel__hists(pos);
|
||||
|
||||
if (symbol_conf.filter_relative) {
|
||||
nr_samples += pos->hists.stats.nr_non_filtered_samples;
|
||||
nr_events += pos->hists.stats.total_non_filtered_period;
|
||||
nr_samples += pos_hists->stats.nr_non_filtered_samples;
|
||||
nr_events += pos_hists->stats.total_non_filtered_period;
|
||||
} else {
|
||||
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
nr_events += pos->hists.stats.total_period;
|
||||
nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
nr_events += pos_hists->stats.total_period;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
|
||||
struct perf_evsel *pos;
|
||||
|
||||
evlist__for_each(evlist, pos) {
|
||||
struct hists *hists = &pos->hists;
|
||||
struct hists *hists = evsel__hists(pos);
|
||||
const char *evname = perf_evsel__name(pos);
|
||||
|
||||
if (symbol_conf.event_group &&
|
||||
@@ -427,7 +429,7 @@ static void report__collapse_hists(struct report *rep)
|
||||
ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
|
||||
|
||||
evlist__for_each(rep->session->evlist, pos) {
|
||||
struct hists *hists = &pos->hists;
|
||||
struct hists *hists = evsel__hists(pos);
|
||||
|
||||
if (pos->idx == 0)
|
||||
hists->symbol_filter_str = rep->symbol_filter_str;
|
||||
@@ -437,7 +439,7 @@ static void report__collapse_hists(struct report *rep)
|
||||
/* Non-group events are considered as leader */
|
||||
if (symbol_conf.event_group &&
|
||||
!perf_evsel__is_group_leader(pos)) {
|
||||
struct hists *leader_hists = &pos->leader->hists;
|
||||
struct hists *leader_hists = evsel__hists(pos->leader);
|
||||
|
||||
hists__match(leader_hists, hists);
|
||||
hists__link(leader_hists, hists);
|
||||
@@ -485,6 +487,7 @@ static int __cmd_report(struct report *rep)
|
||||
|
||||
if (dump_trace) {
|
||||
perf_session__fprintf_nr_events(session, stdout);
|
||||
perf_evlist__fprintf_nr_events(session->evlist, stdout);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -500,7 +503,7 @@ static int __cmd_report(struct report *rep)
|
||||
}
|
||||
|
||||
evlist__for_each(session->evlist, pos)
|
||||
hists__output_resort(&pos->hists);
|
||||
hists__output_resort(evsel__hists(pos));
|
||||
|
||||
return report__browse_hists(rep);
|
||||
}
|
||||
@@ -565,7 +568,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
struct stat st;
|
||||
bool has_br_stack = false;
|
||||
int branch_mode = -1;
|
||||
int ret = -1;
|
||||
char callchain_default_opt[] = "fractal,0.5,callee";
|
||||
const char * const report_usage[] = {
|
||||
"perf report [<options>]",
|
||||
@@ -692,6 +694,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
struct perf_data_file file = {
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
int ret = hists__init();
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
perf_config(report__config, &report);
|
||||
|
||||
|
||||
@@ -1431,9 +1431,6 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
hists__inc_nr_samples(&evsel->hists, true);
|
||||
|
||||
if (evsel->handler != NULL) {
|
||||
tracepoint_handler f = evsel->handler;
|
||||
err = f(tool, evsel, sample, machine);
|
||||
|
||||
@@ -572,7 +572,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
|
||||
scripting_ops->process_event(event, sample, evsel, thread, &al);
|
||||
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+34
-26
@@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
|
||||
char bf[160];
|
||||
int printed = 0;
|
||||
const int win_width = top->winsize.ws_col - 1;
|
||||
struct hists *hists = evsel__hists(top->sym_evsel);
|
||||
|
||||
puts(CONSOLE_CLEAR);
|
||||
|
||||
@@ -261,13 +262,13 @@ static void perf_top__print_sym_table(struct perf_top *top)
|
||||
|
||||
printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
|
||||
|
||||
if (top->sym_evsel->hists.stats.nr_lost_warned !=
|
||||
top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
|
||||
top->sym_evsel->hists.stats.nr_lost_warned =
|
||||
top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
|
||||
if (hists->stats.nr_lost_warned !=
|
||||
hists->stats.nr_events[PERF_RECORD_LOST]) {
|
||||
hists->stats.nr_lost_warned =
|
||||
hists->stats.nr_events[PERF_RECORD_LOST];
|
||||
color_fprintf(stdout, PERF_COLOR_RED,
|
||||
"WARNING: LOST %d chunks, Check IO/CPU overload",
|
||||
top->sym_evsel->hists.stats.nr_lost_warned);
|
||||
hists->stats.nr_lost_warned);
|
||||
++printed;
|
||||
}
|
||||
|
||||
@@ -277,21 +278,18 @@ static void perf_top__print_sym_table(struct perf_top *top)
|
||||
}
|
||||
|
||||
if (top->zero) {
|
||||
hists__delete_entries(&top->sym_evsel->hists);
|
||||
hists__delete_entries(hists);
|
||||
} else {
|
||||
hists__decay_entries(&top->sym_evsel->hists,
|
||||
top->hide_user_symbols,
|
||||
hists__decay_entries(hists, top->hide_user_symbols,
|
||||
top->hide_kernel_symbols);
|
||||
}
|
||||
|
||||
hists__collapse_resort(&top->sym_evsel->hists, NULL);
|
||||
hists__output_resort(&top->sym_evsel->hists);
|
||||
hists__collapse_resort(hists, NULL);
|
||||
hists__output_resort(hists);
|
||||
|
||||
hists__output_recalc_col_len(&top->sym_evsel->hists,
|
||||
top->print_entries - printed);
|
||||
hists__output_recalc_col_len(hists, top->print_entries - printed);
|
||||
putchar('\n');
|
||||
hists__fprintf(&top->sym_evsel->hists, false,
|
||||
top->print_entries - printed, win_width,
|
||||
hists__fprintf(hists, false, top->print_entries - printed, win_width,
|
||||
top->min_percent, stdout);
|
||||
}
|
||||
|
||||
@@ -334,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
|
||||
{
|
||||
char *buf = malloc(0), *p;
|
||||
struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
|
||||
struct hists *hists = evsel__hists(top->sym_evsel);
|
||||
struct rb_node *next;
|
||||
size_t dummy = 0;
|
||||
|
||||
@@ -351,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
|
||||
if (p)
|
||||
*p = 0;
|
||||
|
||||
next = rb_first(&top->sym_evsel->hists.entries);
|
||||
next = rb_first(&hists->entries);
|
||||
while (next) {
|
||||
n = rb_entry(next, struct hist_entry, rb_node);
|
||||
if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
|
||||
@@ -538,21 +537,24 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
|
||||
static void perf_top__sort_new_samples(void *arg)
|
||||
{
|
||||
struct perf_top *t = arg;
|
||||
struct hists *hists;
|
||||
|
||||
perf_top__reset_sample_counters(t);
|
||||
|
||||
if (t->evlist->selected != NULL)
|
||||
t->sym_evsel = t->evlist->selected;
|
||||
|
||||
hists = evsel__hists(t->sym_evsel);
|
||||
|
||||
if (t->zero) {
|
||||
hists__delete_entries(&t->sym_evsel->hists);
|
||||
hists__delete_entries(hists);
|
||||
} else {
|
||||
hists__decay_entries(&t->sym_evsel->hists,
|
||||
t->hide_user_symbols,
|
||||
hists__decay_entries(hists, t->hide_user_symbols,
|
||||
t->hide_kernel_symbols);
|
||||
}
|
||||
|
||||
hists__collapse_resort(&t->sym_evsel->hists, NULL);
|
||||
hists__output_resort(&t->sym_evsel->hists);
|
||||
hists__collapse_resort(hists, NULL);
|
||||
hists__output_resort(hists);
|
||||
}
|
||||
|
||||
static void *display_thread_tui(void *arg)
|
||||
@@ -573,8 +575,10 @@ static void *display_thread_tui(void *arg)
|
||||
* Zooming in/out UIDs. For now juse use whatever the user passed
|
||||
* via --uid.
|
||||
*/
|
||||
evlist__for_each(top->evlist, pos)
|
||||
pos->hists.uid_filter_str = top->record_opts.target.uid_str;
|
||||
evlist__for_each(top->evlist, pos) {
|
||||
struct hists *hists = evsel__hists(pos);
|
||||
hists->uid_filter_str = top->record_opts.target.uid_str;
|
||||
}
|
||||
|
||||
perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
|
||||
&top->session->header.env);
|
||||
@@ -768,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
}
|
||||
|
||||
if (al.sym == NULL || !al.sym->ignore) {
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry_iter iter = {
|
||||
.add_entry_cb = hist_iter__top_callback,
|
||||
};
|
||||
@@ -777,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
else
|
||||
iter.ops = &hist_iter_normal;
|
||||
|
||||
pthread_mutex_lock(&evsel->hists.lock);
|
||||
pthread_mutex_lock(&hists->lock);
|
||||
|
||||
err = hist_entry_iter__add(&iter, &al, evsel, sample,
|
||||
top->max_stack, top);
|
||||
if (err < 0)
|
||||
pr_err("Problem incrementing symbol period, skipping event\n");
|
||||
|
||||
pthread_mutex_unlock(&evsel->hists.lock);
|
||||
pthread_mutex_unlock(&hists->lock);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -849,7 +854,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
|
||||
perf_event__process_sample(&top->tool, event, evsel,
|
||||
&sample, machine);
|
||||
} else if (event->header.type < PERF_RECORD_MAX) {
|
||||
hists__inc_nr_events(&evsel->hists, event->header.type);
|
||||
hists__inc_nr_events(evsel__hists(evsel), event->header.type);
|
||||
machine__process_event(machine, event, &sample);
|
||||
} else
|
||||
++session->stats.nr_unknown_events;
|
||||
@@ -1042,7 +1047,6 @@ parse_percent_limit(const struct option *opt, const char *arg,
|
||||
|
||||
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
int status = -1;
|
||||
char errbuf[BUFSIZ];
|
||||
struct perf_top top = {
|
||||
.count_filter = 5,
|
||||
@@ -1160,6 +1164,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"perf top [<options>]",
|
||||
NULL
|
||||
};
|
||||
int status = hists__init();
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
top.evlist = perf_evlist__new();
|
||||
if (top.evlist == NULL)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "builtin.h"
|
||||
#include "hist.h"
|
||||
#include "intlist.h"
|
||||
#include "tests.h"
|
||||
#include "debug.h"
|
||||
@@ -302,6 +303,10 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
OPT_END()
|
||||
};
|
||||
struct intlist *skiplist = NULL;
|
||||
int ret = hists__init();
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
argc = parse_options(argc, argv, test_options, test_usage, 0);
|
||||
if (argc >= 1 && !strcmp(argv[0], "list"))
|
||||
|
||||
@@ -245,7 +245,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
|
||||
static int test1(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
/*
|
||||
* expected output:
|
||||
*
|
||||
@@ -295,7 +295,7 @@ out:
|
||||
static int test2(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
/*
|
||||
* expected output:
|
||||
*
|
||||
@@ -442,7 +442,7 @@ out:
|
||||
static int test3(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
/*
|
||||
* expected output:
|
||||
*
|
||||
@@ -498,7 +498,7 @@ out:
|
||||
static int test4(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
/*
|
||||
* expected output:
|
||||
*
|
||||
|
||||
@@ -66,11 +66,12 @@ static int add_hist_entries(struct perf_evlist *evlist,
|
||||
.ops = &hist_iter_normal,
|
||||
.hide_unresolved = false,
|
||||
};
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
|
||||
/* make sure it has no filter at first */
|
||||
evsel->hists.thread_filter = NULL;
|
||||
evsel->hists.dso_filter = NULL;
|
||||
evsel->hists.symbol_filter_str = NULL;
|
||||
hists->thread_filter = NULL;
|
||||
hists->dso_filter = NULL;
|
||||
hists->symbol_filter_str = NULL;
|
||||
|
||||
sample.pid = fake_samples[i].pid;
|
||||
sample.tid = fake_samples[i].pid;
|
||||
@@ -134,7 +135,7 @@ int test__hists_filter(void)
|
||||
goto out;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
|
||||
hists__collapse_resort(hists, NULL);
|
||||
hists__output_resort(hists);
|
||||
@@ -160,7 +161,7 @@ int test__hists_filter(void)
|
||||
hists->stats.total_non_filtered_period);
|
||||
|
||||
/* now applying thread filter for 'bash' */
|
||||
evsel->hists.thread_filter = fake_samples[9].thread;
|
||||
hists->thread_filter = fake_samples[9].thread;
|
||||
hists__filter_by_thread(hists);
|
||||
|
||||
if (verbose > 2) {
|
||||
@@ -185,11 +186,11 @@ int test__hists_filter(void)
|
||||
hists->stats.total_non_filtered_period == 400);
|
||||
|
||||
/* remove thread filter first */
|
||||
evsel->hists.thread_filter = NULL;
|
||||
hists->thread_filter = NULL;
|
||||
hists__filter_by_thread(hists);
|
||||
|
||||
/* now applying dso filter for 'kernel' */
|
||||
evsel->hists.dso_filter = fake_samples[0].map->dso;
|
||||
hists->dso_filter = fake_samples[0].map->dso;
|
||||
hists__filter_by_dso(hists);
|
||||
|
||||
if (verbose > 2) {
|
||||
@@ -214,7 +215,7 @@ int test__hists_filter(void)
|
||||
hists->stats.total_non_filtered_period == 300);
|
||||
|
||||
/* remove dso filter first */
|
||||
evsel->hists.dso_filter = NULL;
|
||||
hists->dso_filter = NULL;
|
||||
hists__filter_by_dso(hists);
|
||||
|
||||
/*
|
||||
@@ -224,7 +225,7 @@ int test__hists_filter(void)
|
||||
* be counted as a separate entry but the sample count and
|
||||
* total period will be remained.
|
||||
*/
|
||||
evsel->hists.symbol_filter_str = "main";
|
||||
hists->symbol_filter_str = "main";
|
||||
hists__filter_by_symbol(hists);
|
||||
|
||||
if (verbose > 2) {
|
||||
@@ -249,8 +250,8 @@ int test__hists_filter(void)
|
||||
hists->stats.total_non_filtered_period == 300);
|
||||
|
||||
/* now applying all filters at once. */
|
||||
evsel->hists.thread_filter = fake_samples[1].thread;
|
||||
evsel->hists.dso_filter = fake_samples[1].map->dso;
|
||||
hists->thread_filter = fake_samples[1].thread;
|
||||
hists->dso_filter = fake_samples[1].map->dso;
|
||||
hists__filter_by_thread(hists);
|
||||
hists__filter_by_dso(hists);
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
|
||||
* "bash [libc] malloc" so total 9 entries will be in the tree.
|
||||
*/
|
||||
evlist__for_each(evlist, evsel) {
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
|
||||
for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
|
||||
const union perf_event event = {
|
||||
.header = {
|
||||
@@ -87,7 +89,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
|
||||
&sample) < 0)
|
||||
goto out;
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, &al, NULL,
|
||||
he = __hists__add_entry(hists, &al, NULL,
|
||||
NULL, NULL, 1, 1, 0, true);
|
||||
if (he == NULL)
|
||||
goto out;
|
||||
@@ -111,7 +113,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
|
||||
&sample) < 0)
|
||||
goto out;
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, &al, NULL,
|
||||
he = __hists__add_entry(hists, &al, NULL,
|
||||
NULL, NULL, 1, 1, 0, true);
|
||||
if (he == NULL)
|
||||
goto out;
|
||||
@@ -271,6 +273,7 @@ static int validate_link(struct hists *leader, struct hists *other)
|
||||
int test__hists_link(void)
|
||||
{
|
||||
int err = -1;
|
||||
struct hists *hists, *first_hists;
|
||||
struct machines machines;
|
||||
struct machine *machine = NULL;
|
||||
struct perf_evsel *evsel, *first;
|
||||
@@ -306,24 +309,28 @@ int test__hists_link(void)
|
||||
goto out;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
hists__collapse_resort(&evsel->hists, NULL);
|
||||
hists = evsel__hists(evsel);
|
||||
hists__collapse_resort(hists, NULL);
|
||||
|
||||
if (verbose > 2)
|
||||
print_hists_in(&evsel->hists);
|
||||
print_hists_in(hists);
|
||||
}
|
||||
|
||||
first = perf_evlist__first(evlist);
|
||||
evsel = perf_evlist__last(evlist);
|
||||
|
||||
first_hists = evsel__hists(first);
|
||||
hists = evsel__hists(evsel);
|
||||
|
||||
/* match common entries */
|
||||
hists__match(&first->hists, &evsel->hists);
|
||||
err = validate_match(&first->hists, &evsel->hists);
|
||||
hists__match(first_hists, hists);
|
||||
err = validate_match(first_hists, hists);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* link common and/or dummy entries */
|
||||
hists__link(&first->hists, &evsel->hists);
|
||||
err = validate_link(&first->hists, &evsel->hists);
|
||||
hists__link(first_hists, hists);
|
||||
err = validate_link(first_hists, hists);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
|
||||
static int test1(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_node *node;
|
||||
@@ -159,7 +159,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
|
||||
print_hists_out(hists);
|
||||
}
|
||||
|
||||
root = &evsel->hists.entries;
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
@@ -224,7 +224,7 @@ out:
|
||||
static int test2(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_node *node;
|
||||
@@ -259,7 +259,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
|
||||
print_hists_out(hists);
|
||||
}
|
||||
|
||||
root = &evsel->hists.entries;
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
@@ -280,7 +280,7 @@ out:
|
||||
static int test3(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_node *node;
|
||||
@@ -313,7 +313,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
|
||||
print_hists_out(hists);
|
||||
}
|
||||
|
||||
root = &evsel->hists.entries;
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
@@ -354,7 +354,7 @@ out:
|
||||
static int test4(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_node *node;
|
||||
@@ -391,7 +391,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
|
||||
print_hists_out(hists);
|
||||
}
|
||||
|
||||
root = &evsel->hists.entries;
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
@@ -456,7 +456,7 @@ out:
|
||||
static int test5(struct perf_evsel *evsel, struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_node *node;
|
||||
@@ -494,7 +494,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
|
||||
print_hists_out(hists);
|
||||
}
|
||||
|
||||
root = &evsel->hists.entries;
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "util/cache.h"
|
||||
#include "util/debug.h"
|
||||
#include "ui/browser.h"
|
||||
#include "ui/keysyms.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/util.h"
|
||||
#include "ui/libslang.h"
|
||||
|
||||
@@ -1229,12 +1229,14 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size)
|
||||
ev_name = buf;
|
||||
|
||||
for_each_group_member(pos, evsel) {
|
||||
struct hists *pos_hists = evsel__hists(pos);
|
||||
|
||||
if (symbol_conf.filter_relative) {
|
||||
nr_samples += pos->hists.stats.nr_non_filtered_samples;
|
||||
nr_events += pos->hists.stats.total_non_filtered_period;
|
||||
nr_samples += pos_hists->stats.nr_non_filtered_samples;
|
||||
nr_events += pos_hists->stats.total_non_filtered_period;
|
||||
} else {
|
||||
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
nr_events += pos->hists.stats.total_period;
|
||||
nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
nr_events += pos_hists->stats.total_period;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1387,7 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
|
||||
float min_pcnt,
|
||||
struct perf_session_env *env)
|
||||
{
|
||||
struct hists *hists = &evsel->hists;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_browser *browser = hist_browser__new(hists);
|
||||
struct branch_info *bi;
|
||||
struct pstack *fstack;
|
||||
@@ -1802,8 +1804,9 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
|
||||
struct perf_evsel_menu *menu = container_of(browser,
|
||||
struct perf_evsel_menu, b);
|
||||
struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
bool current_entry = ui_browser__is_current_entry(browser, row);
|
||||
unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
const char *ev_name = perf_evsel__name(evsel);
|
||||
char bf[256], unit;
|
||||
const char *warn = " ";
|
||||
@@ -1818,7 +1821,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
|
||||
ev_name = perf_evsel__group_name(evsel);
|
||||
|
||||
for_each_group_member(pos, evsel) {
|
||||
nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
struct hists *pos_hists = evsel__hists(pos);
|
||||
nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1827,7 +1831,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
|
||||
unit, unit == ' ' ? "" : " ", ev_name);
|
||||
slsmg_printf("%s", bf);
|
||||
|
||||
nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
|
||||
nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
|
||||
if (nr_events != 0) {
|
||||
menu->lost_events = true;
|
||||
if (!current_entry)
|
||||
|
||||
@@ -319,7 +319,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
|
||||
gtk_container_add(GTK_CONTAINER(window), vbox);
|
||||
|
||||
evlist__for_each(evlist, pos) {
|
||||
struct hists *hists = &pos->hists;
|
||||
struct hists *hists = evsel__hists(pos);
|
||||
const char *evname = perf_evsel__name(pos);
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *tab_label;
|
||||
|
||||
@@ -478,7 +478,7 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
|
||||
|
||||
pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
|
||||
|
||||
if (addr < sym->start || addr > sym->end)
|
||||
if (addr < sym->start || addr >= sym->end)
|
||||
return -ERANGE;
|
||||
|
||||
offset = addr - sym->start;
|
||||
@@ -836,7 +836,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
|
||||
end = map__rip_2objdump(map, sym->end);
|
||||
|
||||
offset = line_ip - start;
|
||||
if ((u64)line_ip < start || (u64)line_ip > end)
|
||||
if ((u64)line_ip < start || (u64)line_ip >= end)
|
||||
offset = -1;
|
||||
else
|
||||
parsed_line = tmp2 + 1;
|
||||
@@ -966,7 +966,7 @@ fallback:
|
||||
kce.kcore_filename = symfs_filename;
|
||||
kce.addr = map__rip_2objdump(map, sym->start);
|
||||
kce.offs = sym->start;
|
||||
kce.len = sym->end + 1 - sym->start;
|
||||
kce.len = sym->end - sym->start;
|
||||
if (!kcore_extract__create(&kce)) {
|
||||
delete_extract = true;
|
||||
strlcpy(symfs_filename, kce.extract_filename,
|
||||
@@ -987,7 +987,7 @@ fallback:
|
||||
disassembler_style ? "-M " : "",
|
||||
disassembler_style ? disassembler_style : "",
|
||||
map__rip_2objdump(map, sym->start),
|
||||
map__rip_2objdump(map, sym->end+1),
|
||||
map__rip_2objdump(map, sym->end),
|
||||
symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
|
||||
symbol_conf.annotate_src ? "-S" : "",
|
||||
symfs_filename, filename);
|
||||
|
||||
@@ -65,6 +65,8 @@ struct callchain_param {
|
||||
enum chain_key key;
|
||||
};
|
||||
|
||||
extern struct callchain_param callchain_param;
|
||||
|
||||
struct callchain_list {
|
||||
u64 ip;
|
||||
struct map_symbol ms;
|
||||
|
||||
@@ -190,6 +190,32 @@ enum perf_user_event_type { /* above any possible kernel type */
|
||||
PERF_RECORD_HEADER_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* The kernel collects the number of events it couldn't send in a stretch and
|
||||
* when possible sends this number in a PERF_RECORD_LOST event. The number of
|
||||
* such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while
|
||||
* total_lost tells exactly how many events the kernel in fact lost, i.e. it is
|
||||
* the sum of all struct lost_event.lost fields reported.
|
||||
*
|
||||
* The total_period is needed because by default auto-freq is used, so
|
||||
* multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get
|
||||
* the total number of low level events, it is necessary to to sum all struct
|
||||
* sample_event.period and stash the result in total_period.
|
||||
*/
|
||||
struct events_stats {
|
||||
u64 total_period;
|
||||
u64 total_non_filtered_period;
|
||||
u64 total_lost;
|
||||
u64 total_invalid_chains;
|
||||
u32 nr_events[PERF_RECORD_HEADER_MAX];
|
||||
u32 nr_non_filtered_samples;
|
||||
u32 nr_lost_warned;
|
||||
u32 nr_unknown_events;
|
||||
u32 nr_invalid_chains;
|
||||
u32 nr_unknown_id;
|
||||
u32 nr_unprocessable_samples;
|
||||
};
|
||||
|
||||
struct attr_event {
|
||||
struct perf_event_header header;
|
||||
struct perf_event_attr attr;
|
||||
|
||||
@@ -1175,11 +1175,51 @@ void perf_evlist__close(struct perf_evlist *evlist)
|
||||
}
|
||||
}
|
||||
|
||||
static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
||||
/*
|
||||
* Try reading /sys/devices/system/cpu/online to get
|
||||
* an all cpus map.
|
||||
*
|
||||
* FIXME: -ENOMEM is the best we can do here, the cpu_map
|
||||
* code needs an overhaul to properly forward the
|
||||
* error, and we may not want to do that fallback to a
|
||||
* default cpu identity map :-\
|
||||
*/
|
||||
evlist->cpus = cpu_map__new(NULL);
|
||||
if (evlist->cpus == NULL)
|
||||
goto out;
|
||||
|
||||
evlist->threads = thread_map__new_dummy();
|
||||
if (evlist->threads == NULL)
|
||||
goto out_free_cpus;
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
out_free_cpus:
|
||||
cpu_map__delete(evlist->cpus);
|
||||
evlist->cpus = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int perf_evlist__open(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Default: one fd per CPU, all threads, aka systemwide
|
||||
* as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL
|
||||
*/
|
||||
if (evlist->threads == NULL && evlist->cpus == NULL) {
|
||||
err = perf_evlist__create_syswide_maps(evlist);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
perf_evlist__update_id_pos(evlist);
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
@@ -1276,8 +1316,14 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
|
||||
sigaction(SIGUSR1, &act, NULL);
|
||||
}
|
||||
|
||||
if (target__none(target))
|
||||
if (target__none(target)) {
|
||||
if (evlist->threads == NULL) {
|
||||
fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n",
|
||||
__func__, __LINE__);
|
||||
goto out_close_pipes;
|
||||
}
|
||||
evlist->threads->map[0] = evlist->workload.pid;
|
||||
}
|
||||
|
||||
close(child_ready_pipe[1]);
|
||||
close(go_pipe[0]);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user