Commit 54a0f913 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf top: Fix live annotation in the --stdio interface
  perf top tui: Don't recalc column widths considering just the first page
  perf report: Add progress bar when processing time ordered events
  perf hists browser: Warn about lost events
  perf tools: Fix a typo of command name as trace-cmd
  perf hists: Fix recalculation of total_period when sorting entries
  perf header: Fix build on old systems
  perf ui browser: Handle K_RESIZE in dialog windows
  perf ui browser: No need to switch char sets that often
  perf hists browser: Use K_TIMER
  perf ui: Rename ui__warning_paranoid to ui__error_paranoid
  perf ui: Reimplement the popup windows using libslang
  perf ui: Reimplement ui__popup_menu using ui__browser
  perf ui: Reimplement ui_helpline using libslang
  perf ui: Improve handling sigwinch a bit
  perf ui progress: Reimplement using slang
  perf evlist: Fix grouping of multiple events
parents 94956eed f9e3d4b1
......@@ -262,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
static void open_counters(struct perf_evlist *evlist)
{
struct perf_evsel *pos;
struct perf_evsel *pos, *first;
if (evlist->cpus->map[0] < 0)
no_inherit = true;
first = list_entry(evlist->entries.next, struct perf_evsel, node);
list_for_each_entry(pos, &evlist->entries, node) {
struct perf_event_attr *attr = &pos->attr;
struct xyarray *group_fd = NULL;
/*
* Check if parse_single_tracepoint_event has already asked for
* PERF_SAMPLE_TIME.
......@@ -283,15 +286,19 @@ static void open_counters(struct perf_evlist *evlist)
*/
bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
if (group && pos != first)
group_fd = first->fd;
config_attr(pos, evlist);
retry_sample_id:
attr->sample_id_all = sample_id_all_avail ? 1 : 0;
try_again:
if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
group_fd) < 0) {
int err = errno;
if (err == EPERM || err == EACCES) {
ui__warning_paranoid();
ui__error_paranoid();
exit(EXIT_FAILURE);
} else if (err == ENODEV && cpu_list) {
die("No such device - did you specify"
......
......@@ -278,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
struct stats walltime_nsecs_stats;
static int create_perf_stat_counter(struct perf_evsel *evsel)
static int create_perf_stat_counter(struct perf_evsel *evsel,
struct perf_evsel *first)
{
struct perf_event_attr *attr = &evsel->attr;
struct xyarray *group_fd = NULL;
if (group && evsel != first)
group_fd = first->fd;
if (scale)
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
......@@ -289,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
attr->inherit = !no_inherit;
if (system_wide)
return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
group, group_fd);
if (target_pid == -1 && target_tid == -1) {
attr->disabled = 1;
attr->enable_on_exec = 1;
}
return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
return perf_evsel__open_per_thread(evsel, evsel_list->threads,
group, group_fd);
}
/*
......@@ -396,7 +402,7 @@ static int read_counter(struct perf_evsel *counter)
static int run_perf_stat(int argc __used, const char **argv)
{
unsigned long long t0, t1;
struct perf_evsel *counter;
struct perf_evsel *counter, *first;
int status = 0;
int child_ready_pipe[2], go_pipe[2];
const bool forks = (argc > 0);
......@@ -453,8 +459,10 @@ static int run_perf_stat(int argc __used, const char **argv)
close(child_ready_pipe[0]);
}
first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
list_for_each_entry(counter, &evsel_list->entries, node) {
if (create_perf_stat_counter(counter) < 0) {
if (create_perf_stat_counter(counter, first) < 0) {
if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
if (verbose)
ui__warning("%s event is not supported by the kernel.\n",
......
......@@ -291,7 +291,7 @@ static int test__open_syscall_event(void)
goto out_thread_map_delete;
}
if (perf_evsel__open_per_thread(evsel, threads, false) < 0) {
if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
pr_debug("failed to open counter: %s, "
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
strerror(errno));
......@@ -366,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void)
goto out_thread_map_delete;
}
if (perf_evsel__open(evsel, cpus, threads, false) < 0) {
if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
pr_debug("failed to open counter: %s, "
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
strerror(errno));
......@@ -531,7 +531,7 @@ static int test__basic_mmap(void)
perf_evlist__add(evlist, evsels[i]);
if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) {
if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
pr_debug("failed to open counter: %s, "
"tweak /proc/sys/kernel/perf_event_paranoid?\n",
strerror(errno));
......
......@@ -89,6 +89,7 @@ static bool vmlinux_warned;
static bool inherit = false;
static int realtime_prio = 0;
static bool group = false;
static bool sample_id_all_avail = true;
static unsigned int mmap_pages = 128;
static bool dump_symtab = false;
......@@ -199,7 +200,8 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
struct symbol *sym;
if (he == NULL || he->ms.sym == NULL ||
(he != top.sym_filter_entry && use_browser != 1))
((top.sym_filter_entry == NULL ||
top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
return;
sym = he->ms.sym;
......@@ -289,11 +291,13 @@ static void print_sym_table(void)
printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
if (top.total_lost_warned != top.session->hists.stats.total_lost) {
top.total_lost_warned = top.session->hists.stats.total_lost;
color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
top.total_lost_warned);
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];
color_fprintf(stdout, PERF_COLOR_RED,
"WARNING: LOST %d chunks, Check IO/CPU overload",
top.sym_evsel->hists.stats.nr_lost_warned);
++printed;
}
......@@ -561,7 +565,6 @@ static void perf_top__sort_new_samples(void *arg)
hists__decay_entries_threaded(&t->sym_evsel->hists,
top.hide_user_symbols,
top.hide_kernel_symbols);
hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3);
}
static void *display_thread_tui(void *arg __used)
......@@ -671,6 +674,7 @@ static int symbol_filter(struct map *map __used, struct symbol *sym)
}
static void perf_event__process_sample(const union perf_event *event,
struct perf_evsel *evsel,
struct perf_sample *sample,
struct perf_session *session)
{
......@@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event,
}
if (al.sym == NULL || !al.sym->ignore) {
struct perf_evsel *evsel;
struct hist_entry *he;
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
assert(evsel != NULL);
if ((sort__has_parent || symbol_conf.use_callchain) &&
sample->callchain) {
err = perf_session__resolve_callchain(session, al.thread,
......@@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event,
static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
{
struct perf_sample sample;
struct perf_evsel *evsel;
union perf_event *event;
int ret;
......@@ -817,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
continue;
}
evsel = perf_evlist__id2evsel(self->evlist, sample.id);
assert(evsel != NULL);
if (event->header.type == PERF_RECORD_SAMPLE)
perf_event__process_sample(event, &sample, self);
else
perf_event__process_sample(event, evsel, &sample, self);
else if (event->header.type < PERF_RECORD_MAX) {
hists__inc_nr_events(&evsel->hists, event->header.type);
perf_event__process(event, &sample, self);
} else
++self->hists.stats.nr_unknown_events;
}
}
......@@ -834,10 +841,16 @@ static void perf_session__mmap_read(struct perf_session *self)
static void start_counters(struct perf_evlist *evlist)
{
struct perf_evsel *counter;
struct perf_evsel *counter, *first;
first = list_entry(evlist->entries.next, struct perf_evsel, node);
list_for_each_entry(counter, &evlist->entries, node) {
struct perf_event_attr *attr = &counter->attr;
struct xyarray *group_fd = NULL;
if (group && counter != first)
group_fd = first->fd;
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
......@@ -858,14 +871,23 @@ static void start_counters(struct perf_evlist *evlist)
attr->mmap = 1;
attr->comm = 1;
attr->inherit = inherit;
retry_sample_id:
attr->sample_id_all = sample_id_all_avail ? 1 : 0;
try_again:
if (perf_evsel__open(counter, top.evlist->cpus,
top.evlist->threads, group) < 0) {
top.evlist->threads, group,
group_fd) < 0) {
int err = errno;
if (err == EPERM || err == EACCES) {
ui__warning_paranoid();
ui__error_paranoid();
goto out_err;
} else if (err == EINVAL && sample_id_all_avail) {
/*
* Old kernel, no attr->sample_id_type_all field
*/
sample_id_all_avail = false;
goto retry_sample_id;
}
/*
* If it's cycles then fall back to hrtimer
......
......@@ -310,9 +310,12 @@ fallback:
}
err = -ENOENT;
dso->annotate_warned = 1;
pr_err("Can't annotate %s: No vmlinux file%s was found in the "
"path.\nPlease use 'perf buildid-cache -av vmlinux' or "
"--vmlinux vmlinux.\n",
pr_err("Can't annotate %s:\n\n"
"No vmlinux file%s\nwas found in the path.\n\n"
"Please use:\n\n"
" perf buildid-cache -av vmlinux\n\n"
"or:\n\n"
" --vmlinux vmlinux",
sym->name, build_id_msg ?: "");
goto out_free_filename;
}
......
......@@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...)
}
#ifdef NO_NEWT_SUPPORT
void ui__warning(const char *format, ...)
int ui__warning(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
return 0;
}
#endif
void ui__warning_paranoid(void)
int ui__error_paranoid(void)
{
ui__warning("Permission error - are you root?\n"
return ui__error("Permission error - are you root?\n"
"Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
" -1 - Not paranoid at all\n"
" 0 - Disallow raw tracepoint access for unpriv\n"
......
......@@ -19,23 +19,18 @@ static inline int ui_helpline__show_help(const char *format __used, va_list ap _
return 0;
}
static inline struct ui_progress *ui_progress__new(const char *title __used,
u64 total __used)
{
return (struct ui_progress *)1;
}
static inline void ui_progress__update(struct ui_progress *self __used,
u64 curr __used) {}
static inline void ui_progress__update(u64 curr __used, u64 total __used,
const char *title __used) {}
static inline void ui_progress__delete(struct ui_progress *self __used) {}
#define ui__error(format, arg...) ui__warning(format, ##arg)
#else
extern char ui_helpline__last_msg[];
int ui_helpline__show_help(const char *format, va_list ap);
#include "ui/progress.h"
int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
#endif
void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
void ui__warning_paranoid(void);
int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
int ui__error_paranoid(void);
#endif /* __PERF_DEBUG_H */
......@@ -539,3 +539,33 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
{
evlist->selected = evsel;
}
int perf_evlist__open(struct perf_evlist *evlist, bool group)
{
struct perf_evsel *evsel, *first;
int err, ncpus, nthreads;
first = list_entry(evlist->entries.next, struct perf_evsel, node);
list_for_each_entry(evsel, &evlist->entries, node) {
struct xyarray *group_fd = NULL;
if (group && evsel != first)
group_fd = first->fd;
err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
group, group_fd);
if (err < 0)
goto out_err;
}
return 0;
out_err:
ncpus = evlist->cpus ? evlist->cpus->nr : 1;
nthreads = evlist->threads ? evlist->threads->nr : 1;
list_for_each_entry_reverse(evsel, &evlist->entries, node)
perf_evsel__close(evsel, ncpus, nthreads);
return err;
}
......@@ -50,6 +50,8 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
int perf_evlist__open(struct perf_evlist *evlist, bool group);
int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
void perf_evlist__munmap(struct perf_evlist *evlist);
......
......@@ -16,6 +16,7 @@
#include "thread_map.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
int __perf_evsel__sample_size(u64 sample_type)
{
......@@ -204,15 +205,16 @@ int __perf_evsel__read(struct perf_evsel *evsel,
}
static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
struct thread_map *threads, bool group)
struct thread_map *threads, bool group,
struct xyarray *group_fds)
{
int cpu, thread;
unsigned long flags = 0;
int pid = -1;
int pid = -1, err;
if (evsel->fd == NULL &&
perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
return -1;
return -ENOMEM;
if (evsel->cgrp) {
flags = PERF_FLAG_PID_CGROUP;
......@@ -220,7 +222,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
}
for (cpu = 0; cpu < cpus->nr; cpu++) {
int group_fd = -1;
int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
for (thread = 0; thread < threads->nr; thread++) {
......@@ -231,8 +233,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
pid,
cpus->map[cpu],
group_fd, flags);
if (FD(evsel, cpu, thread) < 0)
if (FD(evsel, cpu, thread) < 0) {
err = -errno;
goto out_close;
}
if (group && group_fd == -1)
group_fd = FD(evsel, cpu, thread);
......@@ -249,7 +253,17 @@ out_close:
}
thread = threads->nr;
} while (--cpu >= 0);
return -1;
return err;
}
void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
{
if (evsel->fd == NULL)
return;
perf_evsel__close_fd(evsel, ncpus, nthreads);
perf_evsel__free_fd(evsel);
evsel->fd = NULL;
}
static struct {
......@@ -269,7 +283,8 @@ static struct {
};
int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
struct thread_map *threads, bool group)
struct thread_map *threads, bool group,
struct xyarray *group_fd)
{
if (cpus == NULL) {
/* Work around old compiler warnings about strict aliasing */
......@@ -279,19 +294,23 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
if (threads == NULL)
threads = &empty_thread_map.map;
return __perf_evsel__open(evsel, cpus, threads, group);
return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
}
int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
struct cpu_map *cpus, bool group)
struct cpu_map *cpus, bool group,
struct xyarray *group_fd)
{
return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
group_fd);
}
int perf_evsel__open_per_thread(struct perf_evsel *evsel,
struct thread_map *threads, bool group)
struct thread_map *threads, bool group,
struct xyarray *group_fd)
{
return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
group_fd);
}
static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
......
......@@ -82,11 +82,15 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
struct cpu_map *cpus, bool group);
struct cpu_map *cpus, bool group,
struct xyarray *group_fds);
int perf_evsel__open_per_thread(struct perf_evsel *evsel,
struct thread_map *threads, bool group);
struct thread_map *threads, bool group,
struct xyarray *group_fds);
int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
struct thread_map *threads, bool group);
struct thread_map *threads, bool group,
struct xyarray *group_fds);
void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
#define perf_evsel__match(evsel, t, c) \
(evsel->attr.type == PERF_TYPE_##t && \
......
#define _FILE_OFFSET_BITS 64
#include "util.h"
#include <sys/types.h>
#include <byteswap.h>
#include <unistd.h>
......@@ -11,7 +12,6 @@
#include "evlist.h"
#include "evsel.h"
#include "util.h"
#include "header.h"
#include "../perf.h"
#include "trace-event.h"
......
......@@ -365,7 +365,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
root = hists__get_rotate_entries_in(hists);
next = rb_first(root);
hists->stats.total_period = 0;
while (next) {
n = rb_entry(next, struct hist_entry, rb_node_in);
......@@ -379,7 +378,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
* been set by, say, the hist_browser.
*/
hists__apply_filters(hists, n);
hists__inc_nr_entries(hists, n);
}
}
}
......@@ -442,6 +440,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
hists->entries = RB_ROOT;
hists->nr_entries = 0;
hists->stats.total_period = 0;
hists__reset_col_len(hists);
while (next) {
......
......@@ -28,6 +28,7 @@ struct events_stats {
u64 total_lost;
u64 total_invalid_chains;
u32 nr_events[PERF_RECORD_HEADER_MAX];
u32 nr_lost_warned;
u32 nr_unknown_events;
u32 nr_invalid_chains;
u32 nr_unknown_id;
......
......@@ -623,7 +623,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
evsel->attr.inherit = inherit;
if (perf_evsel__open(evsel, cpus, threads, group) < 0) {
/*
* This will group just the fds for this single evsel, to group
* multiple events, use evlist.open().
*/
if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
......@@ -814,6 +818,25 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
return Py_None;
}
static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
PyObject *args, PyObject *kwargs)
{
struct perf_evlist *evlist = &pevlist->evlist;
int group = 0;
static char *kwlist[] = { "group", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
return NULL;
if (perf_evlist__open(evlist, group) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef pyrf_evlist__methods[] = {
{
.ml_name = "mmap",
......@@ -821,6 +844,12 @@ static PyMethodDef pyrf_evlist__methods[] = {
.ml_flags = METH_VARARGS | METH_KEYWORDS,
.ml_doc = PyDoc_STR("mmap the file descriptor table.")
},
{
.ml_name = "open",
.ml_meth = (PyCFunction)pyrf_evlist__open,
.ml_flags = METH_VARARGS | METH_KEYWORDS,
.ml_doc = PyDoc_STR("open the file descriptors.")
},
{
.ml_name = "poll",
.ml_meth = (PyCFunction)pyrf_evlist__poll,
......
......@@ -502,6 +502,7 @@ static void flush_sample_queue(struct perf_session *s,
struct perf_sample sample;
u64 limit = os->next_flush;
u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
unsigned idx = 0, progress_next = os->nr_samples / 16;
int ret;
if (!ops->ordered_samples || !limit)
......@@ -521,6 +522,11 @@ static void flush_sample_queue(struct perf_session *s,
os->last_flush = iter->timestamp;
list_del(&iter->list);
list_add(&iter->list, &os->sample_cache);
if (++idx >= progress_next) {
progress_next += os->nr_samples / 16;