perf/core improvements and fixes:

New user visible features:
 
 - Support multiple probes on different binaries on the same command line (Masami Hiramatsu)
 
 User visible fixes:
 
 - Fix synthesizing fork_event.ppid for non-main thread (David Ahern)
 
 - Fix cross-endian analysis (David Ahern)
 
 - Fix segfault in 'perf buildid-list' when show DSOs with hits (He Kuang)
 
 Infrastructure:
 
 - Fix type for references to data_head/tail (David Ahern)
 
 - Fix error path to do closedir() when synthesizing threads (Arnaldo Carvalho de Melo)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJVKEK2AAoJEBpxZoYYoA71KLYIANWmju2EX7H0ShukvAycQVEw
 O+V9PpUsH+5VsN2KlILKg4daYMNlyp8+zDjIeVaaoFq1nVP1I+iqGFiTXue4GtWh
 yDeGWmikFcLw/YMZUxBfXX/siXxi+PdCtQXpAkogn7JrXeJUSZMJxGg41UZjJZZk
 0xKbq5gHrrJ9DfBoww8bZBtEha7als5xHo7oyxGjtngHRPQwVB+euTlLIxps0Hio
 lF/R+231hABsdiDwesD0GsY5pIXnPh2hy/hm7eZNZllmhJxUc03BkvCQX5SzQqlJ
 KfOgKVo6KlU9T5f9CTj2CAtXsvJZcxuyTkTK58R06Me8reYCfbvjJeRQbWjJYn8=
 =5sLi
 -----END PGP SIGNATURE-----

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

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

New user visible features:

  - Support multiple probes on different binaries on the same command line (Masami Hiramatsu)

User visible changes:

  - Fix synthesizing fork_event.ppid for non-main thread (David Ahern)

  - Fix cross-endian analysis (David Ahern)

  - Fix segfault in 'perf buildid-list' when show DSOs with hits (He Kuang)

Infrastructure changes:

  - Fix type for references to data_head/tail (David Ahern)

  - Fix error path to do closedir() when synthesizing threads (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:
Ingo Molnar 2015-04-11 08:31:19 +02:00
commit 5dafd7cb96
11 changed files with 61 additions and 37 deletions

View File

@ -56,6 +56,7 @@ static struct {
bool mod_events;
bool uprobes;
bool quiet;
bool target_used;
int nevents;
struct perf_probe_event events[MAX_PROBES];
struct strlist *dellist;
@ -78,6 +79,12 @@ static int parse_probe_event(const char *str)
}
pev->uprobes = params.uprobes;
if (params.target) {
pev->target = strdup(params.target);
if (!pev->target)
return -ENOMEM;
params.target_used = true;
}
/* Parse a perf-probe command into event */
ret = parse_perf_probe_command(str, pev);
@ -102,6 +109,7 @@ static int set_target(const char *ptr)
params.target = strdup(ptr);
if (!params.target)
return -ENOMEM;
params.target_used = false;
found = 1;
buf = ptr + (strlen(ptr) - 3);
@ -178,7 +186,7 @@ static int opt_set_target(const struct option *opt, const char *str,
int ret = -ENOENT;
char *tmp;
if (str && !params.target) {
if (str) {
if (!strcmp(opt->long_name, "exec"))
params.uprobes = true;
#ifdef HAVE_DWARF_SUPPORT
@ -200,7 +208,9 @@ static int opt_set_target(const struct option *opt, const char *str,
if (!tmp)
return -ENOMEM;
}
free(params.target);
params.target = tmp;
params.target_used = false;
ret = 0;
}
@ -485,9 +495,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
}
if (params.nevents) {
/* Ensure the last given target is used */
if (params.target && !params.target_used) {
pr_warning(" Error: -x/-m must follow the probe definitions.\n");
usage_with_options(probe_usage, options);
}
ret = add_perf_probe_events(params.events, params.nevents,
params.max_probe_points,
params.target,
params.force_add);
if (ret < 0) {
pr_err_with_code(" Error: Failed to add events.", ret);

View File

@ -70,8 +70,8 @@ static int process_synthesized_event(struct perf_tool *tool,
static int record__mmap_read(struct record *rec, int idx)
{
struct perf_mmap *md = &rec->evlist->mmap[idx];
unsigned int head = perf_mmap__read_head(md);
unsigned int old = md->prev;
u64 head = perf_mmap__read_head(md);
u64 old = md->prev;
unsigned char *data = md->base + page_size;
unsigned long size;
void *buf;

View File

@ -59,12 +59,8 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
event->fork.ppid, event->fork.ptid);
if (thread) {
rb_erase(&thread->rb_node, &machine->threads);
if (machine->last_match == thread)
thread__zput(machine->last_match);
thread__put(thread);
}
if (thread)
machine__remove_thread(machine, thread);
return 0;
}

View File

@ -183,8 +183,18 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
{
memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
event->fork.ppid = ppid;
event->fork.ptid = ppid;
/*
* for main thread set parent to ppid from status file. For other
* threads set parent pid to main thread. ie., assume main thread
* spawns all threads in a process
*/
if (tgid == pid) {
event->fork.ppid = ppid;
event->fork.ptid = ppid;
} else {
event->fork.ppid = tgid;
event->fork.ptid = tgid;
}
event->fork.pid = tgid;
event->fork.tid = pid;
event->fork.header.type = PERF_RECORD_FORK;
@ -377,6 +387,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
DIR *tasks;
struct dirent dirent, *next;
pid_t tgid, ppid;
int rc = 0;
/* special case: only send one comm event using passed in pid */
if (!full) {
@ -404,38 +415,38 @@ static int __event__synthesize_thread(union perf_event *comm_event,
while (!readdir_r(tasks, &dirent, &next) && next) {
char *end;
int rc = 0;
pid_t _pid;
_pid = strtol(dirent.d_name, &end, 10);
if (*end)
continue;
rc = -1;
if (perf_event__prepare_comm(comm_event, _pid, machine,
&tgid, &ppid) != 0)
return -1;
break;
if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
ppid, process, machine) < 0)
return -1;
break;
/*
* Send the prepared comm event
*/
if (process(tool, comm_event, &synth_sample, machine) != 0)
return -1;
break;
rc = 0;
if (_pid == pid) {
/* process the parent's maps too */
rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
process, machine, mmap_data);
if (rc)
break;
}
if (rc)
return rc;
}
closedir(tasks);
return 0;
return rc;
}
int perf_event__synthesize_thread_map(struct perf_tool *tool,

View File

@ -634,8 +634,8 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
{
struct perf_mmap *md = &evlist->mmap[idx];
unsigned int head = perf_mmap__read_head(md);
unsigned int old = md->prev;
u64 head = perf_mmap__read_head(md);
u64 old = md->prev;
unsigned char *data = md->base + page_size;
union perf_event *event = NULL;
@ -716,7 +716,7 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
struct perf_mmap *md = &evlist->mmap[idx];
if (!evlist->overwrite) {
unsigned int old = md->prev;
u64 old = md->prev;
perf_mmap__write_tail(md, old);
}

View File

@ -27,7 +27,7 @@ struct perf_mmap {
void *base;
int mask;
int refcnt;
unsigned int prev;
u64 prev;
char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
};
@ -189,16 +189,15 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size);
static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
static inline u64 perf_mmap__read_head(struct perf_mmap *mm)
{
struct perf_event_mmap_page *pc = mm->base;
int head = ACCESS_ONCE(pc->data_head);
u64 head = ACCESS_ONCE(pc->data_head);
rmb();
return head;
}
static inline void perf_mmap__write_tail(struct perf_mmap *md,
unsigned long tail)
static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
{
struct perf_event_mmap_page *pc = md->base;

View File

@ -2504,8 +2504,11 @@ int perf_session__read_header(struct perf_session *session)
if (read_attr(fd, header, &f_attr) < 0)
goto out_errno;
if (header->needs_swap)
if (header->needs_swap) {
f_attr.ids.size = bswap_64(f_attr.ids.size);
f_attr.ids.offset = bswap_64(f_attr.ids.offset);
perf_event__attr_swap(&f_attr.attr);
}
tmp = lseek(fd, 0, SEEK_CUR);
evsel = perf_evsel__new(&f_attr.attr);

View File

@ -14,8 +14,6 @@
#include "unwind.h"
#include "linux/hash.h"
static void machine__remove_thread(struct machine *machine, struct thread *th);
static void dsos__init(struct dsos *dsos)
{
INIT_LIST_HEAD(&dsos->head);
@ -1256,7 +1254,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
return 0;
}
static void machine__remove_thread(struct machine *machine, struct thread *th)
void machine__remove_thread(struct machine *machine, struct thread *th)
{
if (machine->last_match == th)
thread__zput(machine->last_match);

View File

@ -120,6 +120,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
void machine__exit(struct machine *machine);
void machine__delete_threads(struct machine *machine);
void machine__delete(struct machine *machine);
void machine__remove_thread(struct machine *machine, struct thread *th);
struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
struct addr_location *al);

View File

@ -1906,6 +1906,7 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
free(pev->event);
free(pev->group);
free(pev->target);
clear_perf_probe_point(&pev->point);
for (i = 0; i < pev->nargs; i++) {
@ -2654,7 +2655,7 @@ struct __event_package {
};
int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
int max_tevs, const char *target, bool force_add)
int max_tevs, bool force_add)
{
int i, j, ret;
struct __event_package *pkgs;
@ -2678,7 +2679,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
ret = convert_to_probe_trace_events(pkgs[i].pev,
&pkgs[i].tevs,
max_tevs,
target);
pkgs[i].pev->target);
if (ret < 0)
goto end;
pkgs[i].ntevs = ret;

View File

@ -73,7 +73,8 @@ struct perf_probe_event {
char *group; /* Group name */
struct perf_probe_point point; /* Probe point */
int nargs; /* Number of arguments */
bool uprobes;
bool uprobes; /* Uprobe event flag */
char *target; /* Target binary */
struct perf_probe_arg *args; /* Arguments */
};
@ -124,8 +125,7 @@ extern int line_range__init(struct line_range *lr);
extern const char *kernel_get_module_path(const char *module);
extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
int max_probe_points, const char *module,
bool force_add);
int max_probe_points, bool force_add);
extern int del_perf_probe_events(struct strlist *dellist);
extern int show_perf_probe_events(void);
extern int show_line_range(struct line_range *lr, const char *module,