Commit 0c9f790f authored by Ingo Molnar's avatar Ingo Molnar

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

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

Pull perf/core improvements from Arnaldo Carvalho de Melo:

User visible changes:

- Add "srcline_from" and "srcline_to" branch sort keys to 'perf top' and
  'perf report' (Andi Kleen)

Infrastructure changes:

- Make 'perf trace' auto-attach fd->name and ptr->name beautifiers based
  on the name of syscall arguments, this way new syscalls that have
  'const char * (path,pathname,filename)' will use the fd->name beautifier
  (vfs_getname perf probe, if in place) and the 'fd->name' (vfs_getname
  or via /proc/PID/fd/) (Arnaldo Carvalho de Melo)

- Infrastructure to read from a ring buffer in backward write mode (Wang Nan)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 408cf677 3a62a7b8
...@@ -103,12 +103,13 @@ OPTIONS ...@@ -103,12 +103,13 @@ OPTIONS
If --branch-stack option is used, following sort keys are also If --branch-stack option is used, following sort keys are also
available: available:
dso_from, dso_to, symbol_from, symbol_to, mispredict.
- dso_from: name of library or module branched from - dso_from: name of library or module branched from
- dso_to: name of library or module branched to - dso_to: name of library or module branched to
- symbol_from: name of function branched from - symbol_from: name of function branched from
- symbol_to: name of function branched to - symbol_to: name of function branched to
- srcline_from: source file and line branched from
- srcline_to: source file and line branched to
- mispredict: "N" for predicted branch, "Y" for mispredicted branch - mispredict: "N" for predicted branch, "Y" for mispredicted branch
- in_tx: branch in TSX transaction - in_tx: branch in TSX transaction
- abort: TSX transaction abort. - abort: TSX transaction abort.
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <unistd.h> #include <unistd.h>
#include <sched.h> #include <sched.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <asm/bug.h>
struct record { struct record {
...@@ -82,27 +83,87 @@ static int process_synthesized_event(struct perf_tool *tool, ...@@ -82,27 +83,87 @@ static int process_synthesized_event(struct perf_tool *tool,
return record__write(rec, event, event->header.size); return record__write(rec, event, event->header.size);
} }
static int
backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end)
{
struct perf_event_header *pheader;
u64 evt_head = head;
int size = mask + 1;
pr_debug2("backward_rb_find_range: buf=%p, head=%"PRIx64"\n", buf, head);
pheader = (struct perf_event_header *)(buf + (head & mask));
*start = head;
while (true) {
if (evt_head - head >= (unsigned int)size) {
pr_debug("Finshed reading backward ring buffer: rewind\n");
if (evt_head - head > (unsigned int)size)
evt_head -= pheader->size;
*end = evt_head;
return 0;
}
pheader = (struct perf_event_header *)(buf + (evt_head & mask));
if (pheader->size == 0) {
pr_debug("Finshed reading backward ring buffer: get start\n");
*end = evt_head;
return 0;
}
evt_head += pheader->size;
pr_debug3("move evt_head: %"PRIx64"\n", evt_head);
}
WARN_ONCE(1, "Shouldn't get here\n");
return -1;
}
static int
rb_find_range(struct perf_evlist *evlist,
void *data, int mask, u64 head, u64 old,
u64 *start, u64 *end)
{
if (!evlist->backward) {
*start = old;
*end = head;
return 0;
}
return backward_rb_find_range(data, mask, head, start, end);
}
static int record__mmap_read(struct record *rec, int idx) static int record__mmap_read(struct record *rec, int idx)
{ {
struct perf_mmap *md = &rec->evlist->mmap[idx]; struct perf_mmap *md = &rec->evlist->mmap[idx];
u64 head = perf_mmap__read_head(md); u64 head = perf_mmap__read_head(md);
u64 old = md->prev; u64 old = md->prev;
u64 end = head, start = old;
unsigned char *data = md->base + page_size; unsigned char *data = md->base + page_size;
unsigned long size; unsigned long size;
void *buf; void *buf;
int rc = 0; int rc = 0;
if (old == head) if (rb_find_range(rec->evlist, data, md->mask, head,
old, &start, &end))
return -1;
if (start == end)
return 0; return 0;
rec->samples++; rec->samples++;
size = head - old; size = end - start;
if (size > (unsigned long)(md->mask) + 1) {
WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
md->prev = head;
perf_evlist__mmap_consume(rec->evlist, idx);
return 0;
}
if ((old & md->mask) + size != (head & md->mask)) { if ((start & md->mask) + size != (end & md->mask)) {
buf = &data[old & md->mask]; buf = &data[start & md->mask];
size = md->mask + 1 - (old & md->mask); size = md->mask + 1 - (start & md->mask);
old += size; start += size;
if (record__write(rec, buf, size) < 0) { if (record__write(rec, buf, size) < 0) {
rc = -1; rc = -1;
...@@ -110,16 +171,16 @@ static int record__mmap_read(struct record *rec, int idx) ...@@ -110,16 +171,16 @@ static int record__mmap_read(struct record *rec, int idx)
} }
} }
buf = &data[old & md->mask]; buf = &data[start & md->mask];
size = head - old; size = end - start;
old += size; start += size;
if (record__write(rec, buf, size) < 0) { if (record__write(rec, buf, size) < 0) {
rc = -1; rc = -1;
goto out; goto out;
} }
md->prev = old; md->prev = head;
perf_evlist__mmap_consume(rec->evlist, idx); perf_evlist__mmap_consume(rec->evlist, idx);
out: out:
return rc; return rc;
......
This diff is collapsed.
...@@ -44,6 +44,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, ...@@ -44,6 +44,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
perf_evlist__set_maps(evlist, cpus, threads); perf_evlist__set_maps(evlist, cpus, threads);
fdarray__init(&evlist->pollfd, 64); fdarray__init(&evlist->pollfd, 64);
evlist->workload.pid = -1; evlist->workload.pid = -1;
evlist->backward = false;
} }
struct perf_evlist *perf_evlist__new(void) struct perf_evlist *perf_evlist__new(void)
...@@ -679,6 +680,33 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, ...@@ -679,6 +680,33 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
return NULL; return NULL;
} }
static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value)
{
int i;
for (i = 0; i < evlist->nr_mmaps; i++) {
int fd = evlist->mmap[i].fd;
int err;
if (fd < 0)
continue;
err = ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, value ? 1 : 0);
if (err)
return err;
}
return 0;
}
int perf_evlist__pause(struct perf_evlist *evlist)
{
return perf_evlist__set_paused(evlist, true);
}
int perf_evlist__resume(struct perf_evlist *evlist)
{
return perf_evlist__set_paused(evlist, false);
}
/* When check_messup is true, 'end' must points to a good entry */ /* When check_messup is true, 'end' must points to a good entry */
static union perf_event * static union perf_event *
perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start, perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start,
...@@ -881,6 +909,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) ...@@ -881,6 +909,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
if (evlist->mmap[idx].base != NULL) { if (evlist->mmap[idx].base != NULL) {
munmap(evlist->mmap[idx].base, evlist->mmap_len); munmap(evlist->mmap[idx].base, evlist->mmap_len);
evlist->mmap[idx].base = NULL; evlist->mmap[idx].base = NULL;
evlist->mmap[idx].fd = -1;
atomic_set(&evlist->mmap[idx].refcnt, 0); atomic_set(&evlist->mmap[idx].refcnt, 0);
} }
auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap); auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap);
...@@ -901,10 +930,14 @@ void perf_evlist__munmap(struct perf_evlist *evlist) ...@@ -901,10 +930,14 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
{ {
int i;
evlist->nr_mmaps = cpu_map__nr(evlist->cpus); evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
if (cpu_map__empty(evlist->cpus)) if (cpu_map__empty(evlist->cpus))
evlist->nr_mmaps = thread_map__nr(evlist->threads); evlist->nr_mmaps = thread_map__nr(evlist->threads);
evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
for (i = 0; i < evlist->nr_mmaps; i++)
evlist->mmap[i].fd = -1;
return evlist->mmap != NULL ? 0 : -ENOMEM; return evlist->mmap != NULL ? 0 : -ENOMEM;
} }
...@@ -941,6 +974,7 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, ...@@ -941,6 +974,7 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
evlist->mmap[idx].base = NULL; evlist->mmap[idx].base = NULL;
return -1; return -1;
} }
evlist->mmap[idx].fd = fd;
if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap, if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap,
&mp->auxtrace_mp, evlist->mmap[idx].base, fd)) &mp->auxtrace_mp, evlist->mmap[idx].base, fd))
......
...@@ -28,6 +28,7 @@ struct record_opts; ...@@ -28,6 +28,7 @@ struct record_opts;
struct perf_mmap { struct perf_mmap {
void *base; void *base;
int mask; int mask;
int fd;
atomic_t refcnt; atomic_t refcnt;
u64 prev; u64 prev;
struct auxtrace_mmap auxtrace_mmap; struct auxtrace_mmap auxtrace_mmap;
...@@ -43,6 +44,7 @@ struct perf_evlist { ...@@ -43,6 +44,7 @@ struct perf_evlist {
bool overwrite; bool overwrite;
bool enabled; bool enabled;
bool has_user_cpus; bool has_user_cpus;
bool backward;
size_t mmap_len; size_t mmap_len;
int id_pos; int id_pos;
int is_pos; int is_pos;
...@@ -135,6 +137,8 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); ...@@ -135,6 +137,8 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
int perf_evlist__pause(struct perf_evlist *evlist);
int perf_evlist__resume(struct perf_evlist *evlist);
int perf_evlist__open(struct perf_evlist *evlist); int perf_evlist__open(struct perf_evlist *evlist);
void perf_evlist__close(struct perf_evlist *evlist); void perf_evlist__close(struct perf_evlist *evlist);
......
...@@ -37,6 +37,7 @@ static struct { ...@@ -37,6 +37,7 @@ static struct {
bool clockid; bool clockid;
bool clockid_wrong; bool clockid_wrong;
bool lbr_flags; bool lbr_flags;
bool write_backward;
} perf_missing_features; } perf_missing_features;
static clockid_t clockid; static clockid_t clockid;
...@@ -1376,6 +1377,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1376,6 +1377,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
if (perf_missing_features.lbr_flags) if (perf_missing_features.lbr_flags)
evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
PERF_SAMPLE_BRANCH_NO_CYCLES); PERF_SAMPLE_BRANCH_NO_CYCLES);
if (perf_missing_features.write_backward)
evsel->attr.write_backward = false;
retry_sample_id: retry_sample_id:
if (perf_missing_features.sample_id_all) if (perf_missing_features.sample_id_all)
evsel->attr.sample_id_all = 0; evsel->attr.sample_id_all = 0;
...@@ -1438,6 +1441,12 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1438,6 +1441,12 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
err = -EINVAL; err = -EINVAL;
goto out_close; goto out_close;
} }
if (evsel->overwrite &&
perf_missing_features.write_backward) {
err = -EINVAL;
goto out_close;
}
} }
} }
...@@ -1500,6 +1509,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1500,6 +1509,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
PERF_SAMPLE_BRANCH_NO_FLAGS))) { PERF_SAMPLE_BRANCH_NO_FLAGS))) {
perf_missing_features.lbr_flags = true; perf_missing_features.lbr_flags = true;
goto fallback_missing_features; goto fallback_missing_features;
} else if (!perf_missing_features.write_backward &&
evsel->attr.write_backward) {
perf_missing_features.write_backward = true;
goto fallback_missing_features;
} }
out_close: out_close:
......
...@@ -112,6 +112,7 @@ struct perf_evsel { ...@@ -112,6 +112,7 @@ struct perf_evsel {
bool tracking; bool tracking;
bool per_pkg; bool per_pkg;
bool precise_max; bool precise_max;
bool overwrite;
/* parse modifier helper */ /* parse modifier helper */
int exclude_GH; int exclude_GH;
int nr_members; int nr_members;
......
...@@ -117,6 +117,13 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) ...@@ -117,6 +117,13 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
} }
if (h->branch_info->srcline_from)
hists__new_col_len(hists, HISTC_SRCLINE_FROM,
strlen(h->branch_info->srcline_from));
if (h->branch_info->srcline_to)
hists__new_col_len(hists, HISTC_SRCLINE_TO,
strlen(h->branch_info->srcline_to));
} }
if (h->mem_info) { if (h->mem_info) {
...@@ -1042,6 +1049,8 @@ void hist_entry__delete(struct hist_entry *he) ...@@ -1042,6 +1049,8 @@ void hist_entry__delete(struct hist_entry *he)
if (he->branch_info) { if (he->branch_info) {
map__zput(he->branch_info->from.map); map__zput(he->branch_info->from.map);
map__zput(he->branch_info->to.map); map__zput(he->branch_info->to.map);
free_srcline(he->branch_info->srcline_from);
free_srcline(he->branch_info->srcline_to);
zfree(&he->branch_info); zfree(&he->branch_info);
} }
......
...@@ -52,6 +52,8 @@ enum hist_column { ...@@ -52,6 +52,8 @@ enum hist_column {
HISTC_MEM_IADDR_SYMBOL, HISTC_MEM_IADDR_SYMBOL,
HISTC_TRANSACTION, HISTC_TRANSACTION,
HISTC_CYCLES, HISTC_CYCLES,
HISTC_SRCLINE_FROM,
HISTC_SRCLINE_TO,
HISTC_TRACE, HISTC_TRACE,
HISTC_NR_COLS, /* Last entry */ HISTC_NR_COLS, /* Last entry */
}; };
......
...@@ -353,6 +353,88 @@ struct sort_entry sort_srcline = { ...@@ -353,6 +353,88 @@ struct sort_entry sort_srcline = {
.se_width_idx = HISTC_SRCLINE, .se_width_idx = HISTC_SRCLINE,
}; };
/* --sort srcline_from */
static int64_t
sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
{
if (!left->branch_info->srcline_from) {
struct map *map = left->branch_info->from.map;
if (!map)
left->branch_info->srcline_from = SRCLINE_UNKNOWN;
else
left->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->from.al_addr),
left->branch_info->from.sym, true);
}
if (!right->branch_info->srcline_from) {
struct map *map = right->branch_info->from.map;
if (!map)
right->branch_info->srcline_from = SRCLINE_UNKNOWN;
else
right->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->from.al_addr),
right->branch_info->from.sym, true);
}
return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
}
static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from);
}
struct sort_entry sort_srcline_from = {
.se_header = "From Source:Line",
.se_cmp = sort__srcline_from_cmp,
.se_snprintf = hist_entry__srcline_from_snprintf,
.se_width_idx = HISTC_SRCLINE_FROM,
};
/* --sort srcline_to */
static int64_t
sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
{
if (!left->branch_info->srcline_to) {
struct map *map = left->branch_info->to.map;
if (!map)
left->branch_info->srcline_to = SRCLINE_UNKNOWN;
else
left->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->to.al_addr),
left->branch_info->from.sym, true);
}
if (!right->branch_info->srcline_to) {
struct map *map = right->branch_info->to.map;
if (!map)
right->branch_info->srcline_to = SRCLINE_UNKNOWN;
else
right->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->to.al_addr),
right->branch_info->to.sym, true);
}
return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
}
static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to);
}
struct sort_entry sort_srcline_to = {
.se_header = "To Source:Line",
.se_cmp = sort__srcline_to_cmp,
.se_snprintf = hist_entry__srcline_to_snprintf,
.se_width_idx = HISTC_SRCLINE_TO,
};
/* --sort srcfile */ /* --sort srcfile */
static char no_srcfile[1]; static char no_srcfile[1];
...@@ -1347,6 +1429,8 @@ static struct sort_dimension bstack_sort_dimensions[] = { ...@@ -1347,6 +1429,8 @@ static struct sort_dimension bstack_sort_dimensions[] = {
DIM(SORT_IN_TX, "in_tx", sort_in_tx), DIM(SORT_IN_TX, "in_tx", sort_in_tx),
DIM(SORT_ABORT, "abort", sort_abort), DIM(SORT_ABORT, "abort", sort_abort),
DIM(SORT_CYCLES, "cycles", sort_cycles), DIM(SORT_CYCLES, "cycles", sort_cycles),
DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
}; };
#undef DIM #undef DIM
......
...@@ -215,6 +215,8 @@ enum sort_type { ...@@ -215,6 +215,8 @@ enum sort_type {
SORT_ABORT, SORT_ABORT,
SORT_IN_TX, SORT_IN_TX,
SORT_CYCLES, SORT_CYCLES,
SORT_SRCLINE_FROM,
SORT_SRCLINE_TO,
/* memory mode specific sort keys */ /* memory mode specific sort keys */
__SORT_MEMORY_MODE, __SORT_MEMORY_MODE,
......
...@@ -186,6 +186,8 @@ struct branch_info { ...@@ -186,6 +186,8 @@ struct branch_info {
struct addr_map_symbol from; struct addr_map_symbol from;
struct addr_map_symbol to; struct addr_map_symbol to;
struct branch_flags flags; struct branch_flags flags;
char *srcline_from;
char *srcline_to;
}; };
struct mem_info { struct mem_info {
......
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