* [PATCH 1/3] perf record: process can disappear while reading its /proc/pid/tasks @ 2009-10-26 21:23 Arnaldo Carvalho de Melo 2009-10-26 21:23 ` [PATCH 2/3] perf tools: Generalize event synthesizing routines Arnaldo Carvalho de Melo 2009-10-27 13:03 ` [tip:perf/core] perf record: Fix race where process can disappear while reading its /proc/pid/tasks tip-bot for Arnaldo Carvalho de Melo 0 siblings, 2 replies; 7+ messages in thread From: Arnaldo Carvalho de Melo @ 2009-10-26 21:23 UTC (permalink / raw) To: Ingo Molnar Cc: linux-kernel, Arnaldo Carvalho de Melo, Frederic Weisbecker, Peter Zijlstra, Paul Mackerras, Mike Galbraith Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/builtin-record.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ac5ddff..9e1638c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -206,6 +206,7 @@ static pid_t pid_synthesize_comm_event(pid_t pid, int full) fp = fopen(filename, "r"); if (fp == NULL) { +out_race: /* * We raced with a task exiting - just return: */ @@ -247,6 +248,9 @@ static pid_t pid_synthesize_comm_event(pid_t pid, int full) snprintf(filename, sizeof(filename), "/proc/%d/task", pid); tasks = opendir(filename); + if (tasks == NULL) + goto out_race; + while (!readdir_r(tasks, &dirent, &next) && next) { char *end; pid = strtol(dirent.d_name, &end, 10); -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/3] perf tools: Generalize event synthesizing routines 2009-10-26 21:23 [PATCH 1/3] perf record: process can disappear while reading its /proc/pid/tasks Arnaldo Carvalho de Melo @ 2009-10-26 21:23 ` Arnaldo Carvalho de Melo 2009-10-26 21:23 ` [PATCH 3/3] perf top: Support userspace symbols too Arnaldo Carvalho de Melo 2009-10-27 13:03 ` [tip:perf/core] perf tools: Generalize event synthesizing routines tip-bot for Arnaldo Carvalho de Melo 2009-10-27 13:03 ` [tip:perf/core] perf record: Fix race where process can disappear while reading its /proc/pid/tasks tip-bot for Arnaldo Carvalho de Melo 1 sibling, 2 replies; 7+ messages in thread From: Arnaldo Carvalho de Melo @ 2009-10-26 21:23 UTC (permalink / raw) To: Ingo Molnar Cc: linux-kernel, Arnaldo Carvalho de Melo, Frederic Weisbecker, Peter Zijlstra, Paul Mackerras, Mike Galbraith Because we will need it in 'perf top' to support userspace symbols for existing threads. Now we pass a callback that will receive the synthesized event and then write it to the output file in 'perf record' and in the upcoming patch for 'perf top' we will just immediatelly create the in memory representation of threads and maps. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/Makefile | 1 + tools/perf/builtin-record.c | 181 +++---------------------------------------- tools/perf/util/event.c | 177 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 3 + 4 files changed, 191 insertions(+), 171 deletions(-) create mode 100644 tools/perf/util/event.c diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 39a84be..800783d 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -380,6 +380,7 @@ LIB_OBJS += util/alias.o LIB_OBJS += util/config.o LIB_OBJS += util/ctype.o LIB_OBJS += util/environment.o +LIB_OBJS += util/event.o LIB_OBJS += util/exec_cmd.o LIB_OBJS += util/help.o LIB_OBJS += util/levenshtein.o diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9e1638c..4a73d89 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -109,6 +109,12 @@ static void write_output(void *buf, size_t size) } } +static int process_synthesized_event(event_t *event) +{ + write_output(event, event->header.size); + return 0; +} + static void mmap_read(struct mmap_data *md) { unsigned int head = mmap_read_head(md); @@ -191,172 +197,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -static pid_t pid_synthesize_comm_event(pid_t pid, int full) -{ - struct comm_event comm_ev; - char filename[PATH_MAX]; - char bf[BUFSIZ]; - FILE *fp; - size_t size = 0; - DIR *tasks; - struct dirent dirent, *next; - pid_t tgid = 0; - - snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { -out_race: - /* - * We raced with a task exiting - just return: - */ - if (verbose) - fprintf(stderr, "couldn't open %s\n", filename); - return 0; - } - - memset(&comm_ev, 0, sizeof(comm_ev)); - while (!comm_ev.comm[0] || !comm_ev.pid) { - if (fgets(bf, sizeof(bf), fp) == NULL) - goto out_failure; - - if (memcmp(bf, "Name:", 5) == 0) { - char *name = bf + 5; - while (*name && isspace(*name)) - ++name; - size = strlen(name) - 1; - memcpy(comm_ev.comm, name, size++); - } else if (memcmp(bf, "Tgid:", 5) == 0) { - char *tgids = bf + 5; - while (*tgids && isspace(*tgids)) - ++tgids; - tgid = comm_ev.pid = atoi(tgids); - } - } - - comm_ev.header.type = PERF_RECORD_COMM; - size = ALIGN(size, sizeof(u64)); - comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); - - if (!full) { - comm_ev.tid = pid; - - write_output(&comm_ev, comm_ev.header.size); - goto out_fclose; - } - - snprintf(filename, sizeof(filename), "/proc/%d/task", pid); - - tasks = opendir(filename); - if (tasks == NULL) - goto out_race; - - while (!readdir_r(tasks, &dirent, &next) && next) { - char *end; - pid = strtol(dirent.d_name, &end, 10); - if (*end) - continue; - - comm_ev.tid = pid; - - write_output(&comm_ev, comm_ev.header.size); - } - closedir(tasks); - -out_fclose: - fclose(fp); - return tgid; - -out_failure: - fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", - filename); - exit(EXIT_FAILURE); -} - -static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid) -{ - char filename[PATH_MAX]; - FILE *fp; - - snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { - /* - * We raced with a task exiting - just return: - */ - if (verbose) - fprintf(stderr, "couldn't open %s\n", filename); - return; - } - while (1) { - char bf[BUFSIZ], *pbf = bf; - struct mmap_event mmap_ev = { - .header = { .type = PERF_RECORD_MMAP }, - }; - int n; - size_t size; - if (fgets(bf, sizeof(bf), fp) == NULL) - break; - - /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = hex2u64(pbf, &mmap_ev.start); - if (n < 0) - continue; - pbf += n + 1; - n = hex2u64(pbf, &mmap_ev.len); - if (n < 0) - continue; - pbf += n + 3; - if (*pbf == 'x') { /* vm_exec */ - char *execname = strchr(bf, '/'); - - /* Catch VDSO */ - if (execname == NULL) - execname = strstr(bf, "[vdso]"); - - if (execname == NULL) - continue; - - size = strlen(execname); - execname[size - 1] = '\0'; /* Remove \n */ - memcpy(mmap_ev.filename, execname, size); - size = ALIGN(size, sizeof(u64)); - mmap_ev.len -= mmap_ev.start; - mmap_ev.header.size = (sizeof(mmap_ev) - - (sizeof(mmap_ev.filename) - size)); - mmap_ev.pid = tgid; - mmap_ev.tid = pid; - - write_output(&mmap_ev, mmap_ev.header.size); - } - } - - fclose(fp); -} - -static void synthesize_all(void) -{ - DIR *proc; - struct dirent dirent, *next; - - proc = opendir("/proc"); - - while (!readdir_r(proc, &dirent, &next) && next) { - char *end; - pid_t pid, tgid; - - pid = strtol(dirent.d_name, &end, 10); - if (*end) /* only interested in proper numerical dirents */ - continue; - - tgid = pid_synthesize_comm_event(pid, 1); - pid_synthesize_mmap_samples(pid, tgid); - } - - closedir(proc); -} - static int group_fd; static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) @@ -608,11 +448,10 @@ static int __cmd_record(int argc, const char **argv) if (file_new) perf_header__write(header, output); - if (!system_wide) { - pid_t tgid = pid_synthesize_comm_event(pid, 0); - pid_synthesize_mmap_samples(pid, tgid); - } else - synthesize_all(); + if (!system_wide) + event__synthesize_thread(pid, process_synthesized_event); + else + event__synthesize_threads(process_synthesized_event); if (target_pid == -1 && argc) { pid = fork(); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c new file mode 100644 index 0000000..1dae7e3 --- /dev/null +++ b/tools/perf/util/event.c @@ -0,0 +1,177 @@ +#include <linux/types.h> +#include "event.h" +#include "debug.h" +#include "string.h" + +static pid_t event__synthesize_comm(pid_t pid, int full, + int (*process)(event_t *event)) +{ + event_t ev; + char filename[PATH_MAX]; + char bf[BUFSIZ]; + FILE *fp; + size_t size = 0; + DIR *tasks; + struct dirent dirent, *next; + pid_t tgid = 0; + + snprintf(filename, sizeof(filename), "/proc/%d/status", pid); + + fp = fopen(filename, "r"); + if (fp == NULL) { +out_race: + /* + * We raced with a task exiting - just return: + */ + pr_debug("couldn't open %s\n", filename); + return 0; + } + + memset(&ev.comm, 0, sizeof(ev.comm)); + while (!ev.comm.comm[0] || !ev.comm.pid) { + if (fgets(bf, sizeof(bf), fp) == NULL) + goto out_failure; + + if (memcmp(bf, "Name:", 5) == 0) { + char *name = bf + 5; + while (*name && isspace(*name)) + ++name; + size = strlen(name) - 1; + memcpy(ev.comm.comm, name, size++); + } else if (memcmp(bf, "Tgid:", 5) == 0) { + char *tgids = bf + 5; + while (*tgids && isspace(*tgids)) + ++tgids; + tgid = ev.comm.pid = atoi(tgids); + } + } + + ev.comm.header.type = PERF_RECORD_COMM; + size = ALIGN(size, sizeof(u64)); + ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); + + if (!full) { + ev.comm.tid = pid; + + process(&ev); + goto out_fclose; + } + + snprintf(filename, sizeof(filename), "/proc/%d/task", pid); + + tasks = opendir(filename); + if (tasks == NULL) + goto out_race; + + while (!readdir_r(tasks, &dirent, &next) && next) { + char *end; + pid = strtol(dirent.d_name, &end, 10); + if (*end) + continue; + + ev.comm.tid = pid; + + process(&ev); + } + closedir(tasks); + +out_fclose: + fclose(fp); + return tgid; + +out_failure: + pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); + return -1; +} + +static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, + int (*process)(event_t *event)) +{ + char filename[PATH_MAX]; + FILE *fp; + + snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); + + fp = fopen(filename, "r"); + if (fp == NULL) { + /* + * We raced with a task exiting - just return: + */ + pr_debug("couldn't open %s\n", filename); + return -1; + } + + while (1) { + char bf[BUFSIZ], *pbf = bf; + event_t ev = { + .header = { .type = PERF_RECORD_MMAP }, + }; + int n; + size_t size; + if (fgets(bf, sizeof(bf), fp) == NULL) + break; + + /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ + n = hex2u64(pbf, &ev.mmap.start); + if (n < 0) + continue; + pbf += n + 1; + n = hex2u64(pbf, &ev.mmap.len); + if (n < 0) + continue; + pbf += n + 3; + if (*pbf == 'x') { /* vm_exec */ + char *execname = strchr(bf, '/'); + + /* Catch VDSO */ + if (execname == NULL) + execname = strstr(bf, "[vdso]"); + + if (execname == NULL) + continue; + + size = strlen(execname); + execname[size - 1] = '\0'; /* Remove \n */ + memcpy(ev.mmap.filename, execname, size); + size = ALIGN(size, sizeof(u64)); + ev.mmap.len -= ev.mmap.start; + ev.mmap.header.size = (sizeof(ev.mmap) - + (sizeof(ev.mmap.filename) - size)); + ev.mmap.pid = tgid; + ev.mmap.tid = pid; + + process(&ev); + } + } + + fclose(fp); + return 0; +} + +int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) +{ + pid_t tgid = event__synthesize_comm(pid, 1, process); + if (tgid == -1) + return -1; + return event__synthesize_mmap_events(pid, tgid, process); +} + +void event__synthesize_threads(int (*process)(event_t *event)) +{ + DIR *proc; + struct dirent dirent, *next; + + proc = opendir("/proc"); + + while (!readdir_r(proc, &dirent, &next) && next) { + char *end; + pid_t pid = strtol(dirent.d_name, &end, 10); + + if (*end) /* only interested in proper numerical dirents */ + continue; + + event__synthesize_thread(pid, process); + } + + closedir(proc); +} diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index d972b4b..2ae1177 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -111,4 +111,7 @@ struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); +int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); +void event__synthesize_threads(int (*process)(event_t *event)); + #endif /* __PERF_RECORD_H */ -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/3] perf top: Support userspace symbols too 2009-10-26 21:23 ` [PATCH 2/3] perf tools: Generalize event synthesizing routines Arnaldo Carvalho de Melo @ 2009-10-26 21:23 ` Arnaldo Carvalho de Melo 2009-10-27 13:00 ` Ingo Molnar 2009-10-27 13:04 ` [tip:perf/core] " tip-bot for Arnaldo Carvalho de Melo 2009-10-27 13:03 ` [tip:perf/core] perf tools: Generalize event synthesizing routines tip-bot for Arnaldo Carvalho de Melo 1 sibling, 2 replies; 7+ messages in thread From: Arnaldo Carvalho de Melo @ 2009-10-26 21:23 UTC (permalink / raw) To: Ingo Molnar Cc: linux-kernel, Arnaldo Carvalho de Melo, Frederic Weisbecker, Peter Zijlstra, Paul Mackerras, Mike Galbraith Example: Compiling the kernel with 'make -k 22 allyesconfig' [root@emilia linux-2.6-tip]# perf top -r 90 ------------------------------------------------------------------------------ PerfTop: 3669 irqs/sec kernel:59.9% [1000Hz cycles], (all, 8 CPUs) ------------------------------------------------------------------------------ samples pcnt function DSO _______ _____ ________________________________ ________________ 3062.00 6.5% clear_page_c [kernel] 2233.00 4.8% _int_malloc /lib64/libc-2.5.so 2100.00 4.5% yylex /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms 2029.00 4.3% memset /lib64/libc-2.5.so 1224.00 2.6% page_fault [kernel] 1075.00 2.3% __GI_strlen /lib64/libc-2.5.so 863.00 1.8% sub_preempt_count [kernel] 822.00 1.8% __GI_memcpy /lib64/libc-2.5.so 810.00 1.7% __GI_vfprintf /lib64/libc-2.5.so 786.00 1.7% _int_free /lib64/libc-2.5.so 775.00 1.7% __GI_strcmp /lib64/libc-2.5.so 748.00 1.6% _spin_lock [kernel] 699.00 1.5% main /home/acme/git/build/allyesconfig/scripts/basic/fixdep 659.00 1.4% add_preempt_count [kernel] 649.00 1.4% yyparse /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms 645.00 1.4% preempt_trace [kernel] 635.00 1.4% __GI___libc_free /lib64/libc-2.5.so 597.00 1.3% trace_preempt_on [kernel] 551.00 1.2% __GI___libc_malloc /lib64/libc-2.5.so 516.00 1.1% _spin_lock_irqsave [kernel] 481.00 1.0% copy_user_generic_string [kernel] 479.00 1.0% unmap_vmas [kernel] 429.00 0.9% _IO_file_xsputn_internal /lib64/libc-2.5.so 425.00 0.9% __GI_strncpy /lib64/libc-2.5.so 416.00 0.9% get_page_from_freelist [kernel] 414.00 0.9% malloc_consolidate /lib64/libc-2.5.so 406.00 0.9% get_parent_ip [kernel] 362.00 0.8% __rmqueue [kernel] 347.00 0.7% in_lock_functions [kernel] 316.00 0.7% __d_lookup [kernel] [root@emilia linux-2.6-tip]# More polishing is needed to print just DSO basename when not --verbose, etc. Supporting a 'comm' column requires some more reworking of 'perf top' internals as we will need to use something like the hist entries 'perf report' uses and will be done in another patch. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/builtin-top.c | 143 ++++++++++++++++++++++++++++++++------------- 1 files changed, 101 insertions(+), 42 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4a9fe22..a02fc41 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -318,7 +318,7 @@ static void show_details(struct sym_entry *syme) } /* - * Symbols will be added here in record_ip and will get out + * Symbols will be added here in event__process_sample and will get out * after decayed. */ static LIST_HEAD(active_symbols); @@ -459,18 +459,18 @@ static void print_sym_table(void) } if (nr_counters == 1) - printf(" samples pcnt"); + printf(" samples pcnt"); else - printf(" weight samples pcnt"); + printf(" weight samples pcnt"); if (verbose) printf(" RIP "); - printf(" kernel function\n"); - printf(" %s _______ _____", + printf(" function DSO\n"); + printf(" %s _______ _____", nr_counters == 1 ? " " : "______"); if (verbose) - printf(" ________________"); - printf(" _______________\n\n"); + printf(" ________________"); + printf(" ________________________________ ________________\n\n"); for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { struct symbol *sym; @@ -486,16 +486,15 @@ static void print_sym_table(void) sum_ksamples)); if (nr_counters == 1 || !display_weighted) - printf("%20.2f - ", syme->weight); + printf("%20.2f ", syme->weight); else - printf("%9.1f %10ld - ", syme->weight, syme->snap_count); + printf("%9.1f %10ld ", syme->weight, syme->snap_count); percent_color_fprintf(stdout, "%4.1f%%", pcnt); if (verbose) - printf(" - %016llx", sym->start); - printf(" : %s", sym->name); - if (syme->map->dso->name[0] == '[') - printf(" \t%s", syme->map->dso->name); + printf(" %016llx", sym->start); + printf(" %-32s", sym->name); + printf(" %s", syme->map->dso->short_name); printf("\n"); } } @@ -818,41 +817,97 @@ static int parse_symbols(void) return 0; } -/* - * Binary search in the histogram table and record the hit: - */ -static void record_ip(u64 ip, int counter) +static void event__process_sample(const event_t *self, int counter) { + u64 ip = self->ip.ip; struct map *map; - struct symbol *sym = kernel_maps__find_symbol(ip, &map); - - if (sym != NULL) { - struct sym_entry *syme = dso__sym_priv(map->dso, sym); - - if (!syme->skip) { - syme->count[counter]++; - record_precise_ip(syme, counter, ip); - pthread_mutex_lock(&active_symbols_lock); - if (list_empty(&syme->node) || !syme->node.next) - __list_insert_active_sym(syme); - pthread_mutex_unlock(&active_symbols_lock); + struct sym_entry *syme; + struct symbol *sym; + + switch (self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) { + case PERF_RECORD_MISC_USER: { + struct thread *thread = threads__findnew(self->ip.pid); + + if (thread == NULL) return; + + map = thread__find_map(thread, ip); + if (map != NULL) { + ip = map->map_ip(map, ip); + sym = map->dso->find_symbol(map->dso, ip); + if (sym == NULL) + return; + userspace_samples++; + break; } } + /* + * If this is outside of all known maps, + * and is a negative address, try to look it + * up in the kernel dso, as it might be a + * vsyscall or vdso (which executes in user-mode). + */ + if ((long long)ip >= 0) + return; + /* Fall thru */ + case PERF_RECORD_MISC_KERNEL: + sym = kernel_maps__find_symbol(ip, &map); + if (sym == NULL) + return; + break; + default: + return; + } + + syme = dso__sym_priv(map->dso, sym); - samples--; + if (!syme->skip) { + syme->count[counter]++; + record_precise_ip(syme, counter, ip); + pthread_mutex_lock(&active_symbols_lock); + if (list_empty(&syme->node) || !syme->node.next) + __list_insert_active_sym(syme); + pthread_mutex_unlock(&active_symbols_lock); + ++samples; + return; + } } -static void process_event(u64 ip, int counter, int user) +static void event__process_mmap(event_t *self) { - samples++; + struct thread *thread = threads__findnew(self->mmap.pid); + + if (thread != NULL) { + struct map *map = map__new(&self->mmap, NULL, 0, + sizeof(struct sym_entry), + symbol_filter); + if (map != NULL) + thread__insert_map(thread, map); + } +} - if (user) { - userspace_samples++; - return; +static void event__process_comm(event_t *self) +{ + struct thread *thread = threads__findnew(self->comm.pid); + + if (thread != NULL) + thread__set_comm(thread, self->comm.comm); +} + +static int event__process(event_t *event) +{ + switch (event->header.type) { + case PERF_RECORD_COMM: + event__process_comm(event); + break; + case PERF_RECORD_MMAP: + event__process_mmap(event); + break; + default: + break; } - record_ip(ip, counter); + return 0; } struct mmap_data { @@ -925,13 +980,11 @@ static void mmap_read_counter(struct mmap_data *md) event = &event_copy; } + if (event->header.type == PERF_RECORD_SAMPLE) + event__process_sample(event, md->counter); + else + event__process(event); old += size; - - if (event->header.type == PERF_RECORD_SAMPLE) { - int user = - (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER; - process_event(event->ip.ip, md->counter, user); - } } md->prev = old; @@ -973,6 +1026,7 @@ static void start_counter(int i, int counter) } attr->inherit = (cpu < 0) && inherit; + attr->mmap = 1; try_again: fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); @@ -1031,6 +1085,11 @@ static int __cmd_top(void) int i, counter; int ret; + if (target_pid != -1) + event__synthesize_thread(target_pid, event__process); + else + event__synthesize_threads(event__process); + for (i = 0; i < nr_cpus; i++) { group_fd = -1; for (counter = 0; counter < nr_counters; counter++) -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 3/3] perf top: Support userspace symbols too 2009-10-26 21:23 ` [PATCH 3/3] perf top: Support userspace symbols too Arnaldo Carvalho de Melo @ 2009-10-27 13:00 ` Ingo Molnar 2009-10-27 13:04 ` [tip:perf/core] " tip-bot for Arnaldo Carvalho de Melo 1 sibling, 0 replies; 7+ messages in thread From: Ingo Molnar @ 2009-10-27 13:00 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: linux-kernel, Frederic Weisbecker, Peter Zijlstra, Paul Mackerras, Mike Galbraith * Arnaldo Carvalho de Melo <acme@redhat.com> wrote: > Example: > > Compiling the kernel with 'make -k 22 allyesconfig' > > [root@emilia linux-2.6-tip]# perf top -r 90 > ------------------------------------------------------------------------------ > PerfTop: 3669 irqs/sec kernel:59.9% [1000Hz cycles], (all, 8 CPUs) > ------------------------------------------------------------------------------ > > samples pcnt function DSO > _______ _____ ________________________________ ________________ > > 3062.00 6.5% clear_page_c [kernel] > 2233.00 4.8% _int_malloc /lib64/libc-2.5.so > 2100.00 4.5% yylex /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms > 2029.00 4.3% memset /lib64/libc-2.5.so > 1224.00 2.6% page_fault [kernel] > 1075.00 2.3% __GI_strlen /lib64/libc-2.5.so > 863.00 1.8% sub_preempt_count [kernel] > 822.00 1.8% __GI_memcpy /lib64/libc-2.5.so > 810.00 1.7% __GI_vfprintf /lib64/libc-2.5.so > 786.00 1.7% _int_free /lib64/libc-2.5.so > 775.00 1.7% __GI_strcmp /lib64/libc-2.5.so > 748.00 1.6% _spin_lock [kernel] > 699.00 1.5% main /home/acme/git/build/allyesconfig/scripts/basic/fixdep > 659.00 1.4% add_preempt_count [kernel] > 649.00 1.4% yyparse /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms > 645.00 1.4% preempt_trace [kernel] > 635.00 1.4% __GI___libc_free /lib64/libc-2.5.so > 597.00 1.3% trace_preempt_on [kernel] > 551.00 1.2% __GI___libc_malloc /lib64/libc-2.5.so > 516.00 1.1% _spin_lock_irqsave [kernel] > 481.00 1.0% copy_user_generic_string [kernel] > 479.00 1.0% unmap_vmas [kernel] > 429.00 0.9% _IO_file_xsputn_internal /lib64/libc-2.5.so > 425.00 0.9% __GI_strncpy /lib64/libc-2.5.so > 416.00 0.9% get_page_from_freelist [kernel] > 414.00 0.9% malloc_consolidate /lib64/libc-2.5.so > 406.00 0.9% get_parent_ip [kernel] > 362.00 0.8% __rmqueue [kernel] > 347.00 0.7% in_lock_functions [kernel] > 316.00 0.7% __d_lookup [kernel] > > [root@emilia linux-2.6-tip]# That's a really nice feature! I tried it and works well here too. Ingo ^ permalink raw reply [flat|nested] 7+ messages in thread
* [tip:perf/core] perf top: Support userspace symbols too 2009-10-26 21:23 ` [PATCH 3/3] perf top: Support userspace symbols too Arnaldo Carvalho de Melo 2009-10-27 13:00 ` Ingo Molnar @ 2009-10-27 13:04 ` tip-bot for Arnaldo Carvalho de Melo 1 sibling, 0 replies; 7+ messages in thread From: tip-bot for Arnaldo Carvalho de Melo @ 2009-10-27 13:04 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, paulus, acme, hpa, mingo, efault, peterz, fweisbec, tglx, mingo Commit-ID: 5b2bb75a0d4b08cd16bc35ecd674f957fc3b0eb7 Gitweb: http://git.kernel.org/tip/5b2bb75a0d4b08cd16bc35ecd674f957fc3b0eb7 Author: Arnaldo Carvalho de Melo <acme@redhat.com> AuthorDate: Mon, 26 Oct 2009 19:23:19 -0200 Committer: Ingo Molnar <mingo@elte.hu> CommitDate: Tue, 27 Oct 2009 13:51:54 +0100 perf top: Support userspace symbols too Example: Compiling the kernel with 'make -k 22 allyesconfig' [root@emilia linux-2.6-tip]# perf top -r 90 ------------------------------------------------------------------------------ PerfTop: 3669 irqs/sec kernel:59.9% [1000Hz cycles], (all, 8 CPUs) ------------------------------------------------------------------------------ samples pcnt function DSO _______ _____ ________________________________ ________________ 3062.00 6.5% clear_page_c [kernel] 2233.00 4.8% _int_malloc /lib64/libc-2.5.so 2100.00 4.5% yylex /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms 2029.00 4.3% memset /lib64/libc-2.5.so 1224.00 2.6% page_fault [kernel] 1075.00 2.3% __GI_strlen /lib64/libc-2.5.so 863.00 1.8% sub_preempt_count [kernel] 822.00 1.8% __GI_memcpy /lib64/libc-2.5.so 810.00 1.7% __GI_vfprintf /lib64/libc-2.5.so 786.00 1.7% _int_free /lib64/libc-2.5.so 775.00 1.7% __GI_strcmp /lib64/libc-2.5.so 748.00 1.6% _spin_lock [kernel] 699.00 1.5% main /home/acme/git/build/allyesconfig/scripts/basic/fixdep 659.00 1.4% add_preempt_count [kernel] 649.00 1.4% yyparse /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms 645.00 1.4% preempt_trace [kernel] 635.00 1.4% __GI___libc_free /lib64/libc-2.5.so 597.00 1.3% trace_preempt_on [kernel] 551.00 1.2% __GI___libc_malloc /lib64/libc-2.5.so 516.00 1.1% _spin_lock_irqsave [kernel] 481.00 1.0% copy_user_generic_string [kernel] 479.00 1.0% unmap_vmas [kernel] 429.00 0.9% _IO_file_xsputn_internal /lib64/libc-2.5.so 425.00 0.9% __GI_strncpy /lib64/libc-2.5.so 416.00 0.9% get_page_from_freelist [kernel] 414.00 0.9% malloc_consolidate /lib64/libc-2.5.so 406.00 0.9% get_parent_ip [kernel] 362.00 0.8% __rmqueue [kernel] 347.00 0.7% in_lock_functions [kernel] 316.00 0.7% __d_lookup [kernel] [root@emilia linux-2.6-tip]# More polishing is needed to print just DSO basename when not --verbose, etc. Supporting a 'comm' column requires some more reworking of 'perf top' internals as we will need to use something like the hist entries 'perf report' uses and will be done in another patch. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1256592199-9608-3-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- tools/perf/builtin-top.c | 143 ++++++++++++++++++++++++++++++++------------- 1 files changed, 101 insertions(+), 42 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4a9fe22..a02fc41 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -318,7 +318,7 @@ static void show_details(struct sym_entry *syme) } /* - * Symbols will be added here in record_ip and will get out + * Symbols will be added here in event__process_sample and will get out * after decayed. */ static LIST_HEAD(active_symbols); @@ -459,18 +459,18 @@ static void print_sym_table(void) } if (nr_counters == 1) - printf(" samples pcnt"); + printf(" samples pcnt"); else - printf(" weight samples pcnt"); + printf(" weight samples pcnt"); if (verbose) printf(" RIP "); - printf(" kernel function\n"); - printf(" %s _______ _____", + printf(" function DSO\n"); + printf(" %s _______ _____", nr_counters == 1 ? " " : "______"); if (verbose) - printf(" ________________"); - printf(" _______________\n\n"); + printf(" ________________"); + printf(" ________________________________ ________________\n\n"); for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { struct symbol *sym; @@ -486,16 +486,15 @@ static void print_sym_table(void) sum_ksamples)); if (nr_counters == 1 || !display_weighted) - printf("%20.2f - ", syme->weight); + printf("%20.2f ", syme->weight); else - printf("%9.1f %10ld - ", syme->weight, syme->snap_count); + printf("%9.1f %10ld ", syme->weight, syme->snap_count); percent_color_fprintf(stdout, "%4.1f%%", pcnt); if (verbose) - printf(" - %016llx", sym->start); - printf(" : %s", sym->name); - if (syme->map->dso->name[0] == '[') - printf(" \t%s", syme->map->dso->name); + printf(" %016llx", sym->start); + printf(" %-32s", sym->name); + printf(" %s", syme->map->dso->short_name); printf("\n"); } } @@ -818,41 +817,97 @@ static int parse_symbols(void) return 0; } -/* - * Binary search in the histogram table and record the hit: - */ -static void record_ip(u64 ip, int counter) +static void event__process_sample(const event_t *self, int counter) { + u64 ip = self->ip.ip; struct map *map; - struct symbol *sym = kernel_maps__find_symbol(ip, &map); - - if (sym != NULL) { - struct sym_entry *syme = dso__sym_priv(map->dso, sym); - - if (!syme->skip) { - syme->count[counter]++; - record_precise_ip(syme, counter, ip); - pthread_mutex_lock(&active_symbols_lock); - if (list_empty(&syme->node) || !syme->node.next) - __list_insert_active_sym(syme); - pthread_mutex_unlock(&active_symbols_lock); + struct sym_entry *syme; + struct symbol *sym; + + switch (self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) { + case PERF_RECORD_MISC_USER: { + struct thread *thread = threads__findnew(self->ip.pid); + + if (thread == NULL) return; + + map = thread__find_map(thread, ip); + if (map != NULL) { + ip = map->map_ip(map, ip); + sym = map->dso->find_symbol(map->dso, ip); + if (sym == NULL) + return; + userspace_samples++; + break; } } + /* + * If this is outside of all known maps, + * and is a negative address, try to look it + * up in the kernel dso, as it might be a + * vsyscall or vdso (which executes in user-mode). + */ + if ((long long)ip >= 0) + return; + /* Fall thru */ + case PERF_RECORD_MISC_KERNEL: + sym = kernel_maps__find_symbol(ip, &map); + if (sym == NULL) + return; + break; + default: + return; + } + + syme = dso__sym_priv(map->dso, sym); - samples--; + if (!syme->skip) { + syme->count[counter]++; + record_precise_ip(syme, counter, ip); + pthread_mutex_lock(&active_symbols_lock); + if (list_empty(&syme->node) || !syme->node.next) + __list_insert_active_sym(syme); + pthread_mutex_unlock(&active_symbols_lock); + ++samples; + return; + } } -static void process_event(u64 ip, int counter, int user) +static void event__process_mmap(event_t *self) { - samples++; + struct thread *thread = threads__findnew(self->mmap.pid); + + if (thread != NULL) { + struct map *map = map__new(&self->mmap, NULL, 0, + sizeof(struct sym_entry), + symbol_filter); + if (map != NULL) + thread__insert_map(thread, map); + } +} - if (user) { - userspace_samples++; - return; +static void event__process_comm(event_t *self) +{ + struct thread *thread = threads__findnew(self->comm.pid); + + if (thread != NULL) + thread__set_comm(thread, self->comm.comm); +} + +static int event__process(event_t *event) +{ + switch (event->header.type) { + case PERF_RECORD_COMM: + event__process_comm(event); + break; + case PERF_RECORD_MMAP: + event__process_mmap(event); + break; + default: + break; } - record_ip(ip, counter); + return 0; } struct mmap_data { @@ -925,13 +980,11 @@ static void mmap_read_counter(struct mmap_data *md) event = &event_copy; } + if (event->header.type == PERF_RECORD_SAMPLE) + event__process_sample(event, md->counter); + else + event__process(event); old += size; - - if (event->header.type == PERF_RECORD_SAMPLE) { - int user = - (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER; - process_event(event->ip.ip, md->counter, user); - } } md->prev = old; @@ -973,6 +1026,7 @@ static void start_counter(int i, int counter) } attr->inherit = (cpu < 0) && inherit; + attr->mmap = 1; try_again: fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); @@ -1031,6 +1085,11 @@ static int __cmd_top(void) int i, counter; int ret; + if (target_pid != -1) + event__synthesize_thread(target_pid, event__process); + else + event__synthesize_threads(event__process); + for (i = 0; i < nr_cpus; i++) { group_fd = -1; for (counter = 0; counter < nr_counters; counter++) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [tip:perf/core] perf tools: Generalize event synthesizing routines 2009-10-26 21:23 ` [PATCH 2/3] perf tools: Generalize event synthesizing routines Arnaldo Carvalho de Melo 2009-10-26 21:23 ` [PATCH 3/3] perf top: Support userspace symbols too Arnaldo Carvalho de Melo @ 2009-10-27 13:03 ` tip-bot for Arnaldo Carvalho de Melo 1 sibling, 0 replies; 7+ messages in thread From: tip-bot for Arnaldo Carvalho de Melo @ 2009-10-27 13:03 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, paulus, acme, hpa, mingo, efault, peterz, fweisbec, tglx, mingo Commit-ID: 234fbbf508c58c5084292b11b242377553897459 Gitweb: http://git.kernel.org/tip/234fbbf508c58c5084292b11b242377553897459 Author: Arnaldo Carvalho de Melo <acme@redhat.com> AuthorDate: Mon, 26 Oct 2009 19:23:18 -0200 Committer: Ingo Molnar <mingo@elte.hu> CommitDate: Tue, 27 Oct 2009 13:51:53 +0100 perf tools: Generalize event synthesizing routines Because we will need it in 'perf top' to support userspace symbols for existing threads. Now we pass a callback that will receive the synthesized event and then write it to the output file in 'perf record' and in the upcoming patch for 'perf top' we will just immediatelly create the in memory representation of threads and maps. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1256592199-9608-2-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- tools/perf/Makefile | 1 + tools/perf/builtin-record.c | 181 +++---------------------------------------- tools/perf/util/event.c | 177 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 3 + 4 files changed, 191 insertions(+), 171 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 0a40c29..9f4488d 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -380,6 +380,7 @@ LIB_OBJS += util/alias.o LIB_OBJS += util/config.o LIB_OBJS += util/ctype.o LIB_OBJS += util/environment.o +LIB_OBJS += util/event.o LIB_OBJS += util/exec_cmd.o LIB_OBJS += util/help.o LIB_OBJS += util/levenshtein.o diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9e1638c..4a73d89 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -109,6 +109,12 @@ static void write_output(void *buf, size_t size) } } +static int process_synthesized_event(event_t *event) +{ + write_output(event, event->header.size); + return 0; +} + static void mmap_read(struct mmap_data *md) { unsigned int head = mmap_read_head(md); @@ -191,172 +197,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -static pid_t pid_synthesize_comm_event(pid_t pid, int full) -{ - struct comm_event comm_ev; - char filename[PATH_MAX]; - char bf[BUFSIZ]; - FILE *fp; - size_t size = 0; - DIR *tasks; - struct dirent dirent, *next; - pid_t tgid = 0; - - snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { -out_race: - /* - * We raced with a task exiting - just return: - */ - if (verbose) - fprintf(stderr, "couldn't open %s\n", filename); - return 0; - } - - memset(&comm_ev, 0, sizeof(comm_ev)); - while (!comm_ev.comm[0] || !comm_ev.pid) { - if (fgets(bf, sizeof(bf), fp) == NULL) - goto out_failure; - - if (memcmp(bf, "Name:", 5) == 0) { - char *name = bf + 5; - while (*name && isspace(*name)) - ++name; - size = strlen(name) - 1; - memcpy(comm_ev.comm, name, size++); - } else if (memcmp(bf, "Tgid:", 5) == 0) { - char *tgids = bf + 5; - while (*tgids && isspace(*tgids)) - ++tgids; - tgid = comm_ev.pid = atoi(tgids); - } - } - - comm_ev.header.type = PERF_RECORD_COMM; - size = ALIGN(size, sizeof(u64)); - comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); - - if (!full) { - comm_ev.tid = pid; - - write_output(&comm_ev, comm_ev.header.size); - goto out_fclose; - } - - snprintf(filename, sizeof(filename), "/proc/%d/task", pid); - - tasks = opendir(filename); - if (tasks == NULL) - goto out_race; - - while (!readdir_r(tasks, &dirent, &next) && next) { - char *end; - pid = strtol(dirent.d_name, &end, 10); - if (*end) - continue; - - comm_ev.tid = pid; - - write_output(&comm_ev, comm_ev.header.size); - } - closedir(tasks); - -out_fclose: - fclose(fp); - return tgid; - -out_failure: - fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", - filename); - exit(EXIT_FAILURE); -} - -static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid) -{ - char filename[PATH_MAX]; - FILE *fp; - - snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { - /* - * We raced with a task exiting - just return: - */ - if (verbose) - fprintf(stderr, "couldn't open %s\n", filename); - return; - } - while (1) { - char bf[BUFSIZ], *pbf = bf; - struct mmap_event mmap_ev = { - .header = { .type = PERF_RECORD_MMAP }, - }; - int n; - size_t size; - if (fgets(bf, sizeof(bf), fp) == NULL) - break; - - /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = hex2u64(pbf, &mmap_ev.start); - if (n < 0) - continue; - pbf += n + 1; - n = hex2u64(pbf, &mmap_ev.len); - if (n < 0) - continue; - pbf += n + 3; - if (*pbf == 'x') { /* vm_exec */ - char *execname = strchr(bf, '/'); - - /* Catch VDSO */ - if (execname == NULL) - execname = strstr(bf, "[vdso]"); - - if (execname == NULL) - continue; - - size = strlen(execname); - execname[size - 1] = '\0'; /* Remove \n */ - memcpy(mmap_ev.filename, execname, size); - size = ALIGN(size, sizeof(u64)); - mmap_ev.len -= mmap_ev.start; - mmap_ev.header.size = (sizeof(mmap_ev) - - (sizeof(mmap_ev.filename) - size)); - mmap_ev.pid = tgid; - mmap_ev.tid = pid; - - write_output(&mmap_ev, mmap_ev.header.size); - } - } - - fclose(fp); -} - -static void synthesize_all(void) -{ - DIR *proc; - struct dirent dirent, *next; - - proc = opendir("/proc"); - - while (!readdir_r(proc, &dirent, &next) && next) { - char *end; - pid_t pid, tgid; - - pid = strtol(dirent.d_name, &end, 10); - if (*end) /* only interested in proper numerical dirents */ - continue; - - tgid = pid_synthesize_comm_event(pid, 1); - pid_synthesize_mmap_samples(pid, tgid); - } - - closedir(proc); -} - static int group_fd; static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) @@ -608,11 +448,10 @@ static int __cmd_record(int argc, const char **argv) if (file_new) perf_header__write(header, output); - if (!system_wide) { - pid_t tgid = pid_synthesize_comm_event(pid, 0); - pid_synthesize_mmap_samples(pid, tgid); - } else - synthesize_all(); + if (!system_wide) + event__synthesize_thread(pid, process_synthesized_event); + else + event__synthesize_threads(process_synthesized_event); if (target_pid == -1 && argc) { pid = fork(); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c new file mode 100644 index 0000000..1dae7e3 --- /dev/null +++ b/tools/perf/util/event.c @@ -0,0 +1,177 @@ +#include <linux/types.h> +#include "event.h" +#include "debug.h" +#include "string.h" + +static pid_t event__synthesize_comm(pid_t pid, int full, + int (*process)(event_t *event)) +{ + event_t ev; + char filename[PATH_MAX]; + char bf[BUFSIZ]; + FILE *fp; + size_t size = 0; + DIR *tasks; + struct dirent dirent, *next; + pid_t tgid = 0; + + snprintf(filename, sizeof(filename), "/proc/%d/status", pid); + + fp = fopen(filename, "r"); + if (fp == NULL) { +out_race: + /* + * We raced with a task exiting - just return: + */ + pr_debug("couldn't open %s\n", filename); + return 0; + } + + memset(&ev.comm, 0, sizeof(ev.comm)); + while (!ev.comm.comm[0] || !ev.comm.pid) { + if (fgets(bf, sizeof(bf), fp) == NULL) + goto out_failure; + + if (memcmp(bf, "Name:", 5) == 0) { + char *name = bf + 5; + while (*name && isspace(*name)) + ++name; + size = strlen(name) - 1; + memcpy(ev.comm.comm, name, size++); + } else if (memcmp(bf, "Tgid:", 5) == 0) { + char *tgids = bf + 5; + while (*tgids && isspace(*tgids)) + ++tgids; + tgid = ev.comm.pid = atoi(tgids); + } + } + + ev.comm.header.type = PERF_RECORD_COMM; + size = ALIGN(size, sizeof(u64)); + ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); + + if (!full) { + ev.comm.tid = pid; + + process(&ev); + goto out_fclose; + } + + snprintf(filename, sizeof(filename), "/proc/%d/task", pid); + + tasks = opendir(filename); + if (tasks == NULL) + goto out_race; + + while (!readdir_r(tasks, &dirent, &next) && next) { + char *end; + pid = strtol(dirent.d_name, &end, 10); + if (*end) + continue; + + ev.comm.tid = pid; + + process(&ev); + } + closedir(tasks); + +out_fclose: + fclose(fp); + return tgid; + +out_failure: + pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); + return -1; +} + +static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, + int (*process)(event_t *event)) +{ + char filename[PATH_MAX]; + FILE *fp; + + snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); + + fp = fopen(filename, "r"); + if (fp == NULL) { + /* + * We raced with a task exiting - just return: + */ + pr_debug("couldn't open %s\n", filename); + return -1; + } + + while (1) { + char bf[BUFSIZ], *pbf = bf; + event_t ev = { + .header = { .type = PERF_RECORD_MMAP }, + }; + int n; + size_t size; + if (fgets(bf, sizeof(bf), fp) == NULL) + break; + + /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ + n = hex2u64(pbf, &ev.mmap.start); + if (n < 0) + continue; + pbf += n + 1; + n = hex2u64(pbf, &ev.mmap.len); + if (n < 0) + continue; + pbf += n + 3; + if (*pbf == 'x') { /* vm_exec */ + char *execname = strchr(bf, '/'); + + /* Catch VDSO */ + if (execname == NULL) + execname = strstr(bf, "[vdso]"); + + if (execname == NULL) + continue; + + size = strlen(execname); + execname[size - 1] = '\0'; /* Remove \n */ + memcpy(ev.mmap.filename, execname, size); + size = ALIGN(size, sizeof(u64)); + ev.mmap.len -= ev.mmap.start; + ev.mmap.header.size = (sizeof(ev.mmap) - + (sizeof(ev.mmap.filename) - size)); + ev.mmap.pid = tgid; + ev.mmap.tid = pid; + + process(&ev); + } + } + + fclose(fp); + return 0; +} + +int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) +{ + pid_t tgid = event__synthesize_comm(pid, 1, process); + if (tgid == -1) + return -1; + return event__synthesize_mmap_events(pid, tgid, process); +} + +void event__synthesize_threads(int (*process)(event_t *event)) +{ + DIR *proc; + struct dirent dirent, *next; + + proc = opendir("/proc"); + + while (!readdir_r(proc, &dirent, &next) && next) { + char *end; + pid_t pid = strtol(dirent.d_name, &end, 10); + + if (*end) /* only interested in proper numerical dirents */ + continue; + + event__synthesize_thread(pid, process); + } + + closedir(proc); +} diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index d972b4b..2ae1177 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -111,4 +111,7 @@ struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); +int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); +void event__synthesize_threads(int (*process)(event_t *event)); + #endif /* __PERF_RECORD_H */ ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [tip:perf/core] perf record: Fix race where process can disappear while reading its /proc/pid/tasks 2009-10-26 21:23 [PATCH 1/3] perf record: process can disappear while reading its /proc/pid/tasks Arnaldo Carvalho de Melo 2009-10-26 21:23 ` [PATCH 2/3] perf tools: Generalize event synthesizing routines Arnaldo Carvalho de Melo @ 2009-10-27 13:03 ` tip-bot for Arnaldo Carvalho de Melo 1 sibling, 0 replies; 7+ messages in thread From: tip-bot for Arnaldo Carvalho de Melo @ 2009-10-27 13:03 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, paulus, acme, hpa, mingo, efault, peterz, fweisbec, tglx, mingo Commit-ID: 7f3bedcc93f935631d2363f23de1cc80f04fdf3e Gitweb: http://git.kernel.org/tip/7f3bedcc93f935631d2363f23de1cc80f04fdf3e Author: Arnaldo Carvalho de Melo <acme@redhat.com> AuthorDate: Mon, 26 Oct 2009 19:23:17 -0200 Committer: Ingo Molnar <mingo@elte.hu> CommitDate: Tue, 27 Oct 2009 13:51:53 +0100 perf record: Fix race where process can disappear while reading its /proc/pid/tasks Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1256592199-9608-1-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- tools/perf/builtin-record.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ac5ddff..9e1638c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -206,6 +206,7 @@ static pid_t pid_synthesize_comm_event(pid_t pid, int full) fp = fopen(filename, "r"); if (fp == NULL) { +out_race: /* * We raced with a task exiting - just return: */ @@ -247,6 +248,9 @@ static pid_t pid_synthesize_comm_event(pid_t pid, int full) snprintf(filename, sizeof(filename), "/proc/%d/task", pid); tasks = opendir(filename); + if (tasks == NULL) + goto out_race; + while (!readdir_r(tasks, &dirent, &next) && next) { char *end; pid = strtol(dirent.d_name, &end, 10); ^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-10-27 13:04 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-10-26 21:23 [PATCH 1/3] perf record: process can disappear while reading its /proc/pid/tasks Arnaldo Carvalho de Melo 2009-10-26 21:23 ` [PATCH 2/3] perf tools: Generalize event synthesizing routines Arnaldo Carvalho de Melo 2009-10-26 21:23 ` [PATCH 3/3] perf top: Support userspace symbols too Arnaldo Carvalho de Melo 2009-10-27 13:00 ` Ingo Molnar 2009-10-27 13:04 ` [tip:perf/core] " tip-bot for Arnaldo Carvalho de Melo 2009-10-27 13:03 ` [tip:perf/core] perf tools: Generalize event synthesizing routines tip-bot for Arnaldo Carvalho de Melo 2009-10-27 13:03 ` [tip:perf/core] perf record: Fix race where process can disappear while reading its /proc/pid/tasks tip-bot for Arnaldo Carvalho de Melo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox