From f62d3f0f4596f983ec00495d91c8ddb30268d878 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 6 Oct 2012 15:44:59 -0300 Subject: perf event: No need to create a thread when handling PERF_RECORD_EXIT When we were processing a PERF_RECORD_EXIT event we first used machine__findnew_thread for both the thread exiting and for its parent, only to use just the thread struct associated with the one exiting, and to just delete it. If it existed, i.e. not created at this very moment in machine__findnew_thread, it will be moved to the machine->dead_threads linked list, because we may have hist_entries pointing to it, but if it was created just do be deleted, it will just sit there with no references at all. Use the new machine__find_thread() method so that if it is not there, we don't create it. As a bonus the parent thread will also not be created at this point. Create process_fork() and process_exit() helpers to use this and make the builtins use it instead of the generic process_task(), ditched by this patch. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-z7n2y98ebjyrvmytaope4vdl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'tools/perf/util/event.c') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6715b1938725..eaaee22628ea 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,6 +1,7 @@ #include #include "event.h" #include "debug.h" +#include "machine.h" #include "sort.h" #include "string.h" #include "strlist.h" @@ -702,10 +703,10 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) event->fork.ppid, event->fork.ptid); } -int perf_event__process_task(struct perf_tool *tool __maybe_unused, +int perf_event__process_fork(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused, - struct machine *machine) + struct machine *machine) { struct thread *thread = machine__findnew_thread(machine, event->fork.tid); struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); @@ -713,11 +714,6 @@ int perf_event__process_task(struct perf_tool *tool __maybe_unused, if (dump_trace) perf_event__fprintf_task(event, stdout); - if (event->header.type == PERF_RECORD_EXIT) { - machine__remove_thread(machine, thread); - return 0; - } - if (thread == NULL || parent == NULL || thread__fork(thread, parent) < 0) { dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); @@ -727,6 +723,22 @@ int perf_event__process_task(struct perf_tool *tool __maybe_unused, return 0; } +int perf_event__process_exit(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine) +{ + struct thread *thread = machine__find_thread(machine, event->fork.tid); + + if (dump_trace) + perf_event__fprintf_task(event, stdout); + + if (thread != NULL) + machine__remove_thread(machine, thread); + + return 0; +} + size_t perf_event__fprintf(union perf_event *event, FILE *fp) { size_t ret = fprintf(fp, "PERF_RECORD_%s", @@ -761,8 +773,10 @@ int perf_event__process(struct perf_tool *tool, union perf_event *event, perf_event__process_mmap(tool, event, sample, machine); break; case PERF_RECORD_FORK: + perf_event__process_fork(tool, event, sample, machine); + break; case PERF_RECORD_EXIT: - perf_event__process_task(tool, event, sample, machine); + perf_event__process_exit(tool, event, sample, machine); break; case PERF_RECORD_LOST: perf_event__process_lost(tool, event, sample, machine); -- cgit v1.2.3 From b0a7d1a0cd2e228dc06d099db2e1bb02f1b7d591 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 6 Oct 2012 16:26:02 -0300 Subject: perf machine: Carve up event processing specific from perf_tool The perf_tool vtable expects methods that receive perf_tool and perf_sample entries, but for tools not interested in doing any special processing on non PERF_RECORD_SAMPLE events, like 'perf top', and for those not using perf_session, like 'perf trace', they were using perf_event__process passing tool and sample paramenters that were just not used. Provide 'machine' methods for this purpose and make the perf_event ones use them. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ot9cc6mt025o8kbngzckcrx9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 211 +++--------------------------------------------- 1 file changed, 12 insertions(+), 199 deletions(-) (limited to 'tools/perf/util/event.c') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index eaaee22628ea..0ae444ef1429 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -520,134 +520,15 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, event->comm.tid); - - if (dump_trace) - perf_event__fprintf_comm(event, stdout); - - if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { - dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); - return -1; - } - - return 0; + return machine__process_comm_event(machine, event); } int perf_event__process_lost(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused, - struct machine *machine __maybe_unused) -{ - dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", - event->lost.id, event->lost.lost); - return 0; -} - -static void perf_event__set_kernel_mmap_len(union perf_event *event, - struct map **maps) -{ - maps[MAP__FUNCTION]->start = event->mmap.start; - maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len; - /* - * Be a bit paranoid here, some perf.data file came with - * a zero sized synthesized MMAP event for the kernel. - */ - if (maps[MAP__FUNCTION]->end == 0) - maps[MAP__FUNCTION]->end = ~0ULL; -} - -static int perf_event__process_kernel_mmap(struct perf_tool *tool - __maybe_unused, - union perf_event *event, - struct machine *machine) + struct machine *machine) { - struct map *map; - char kmmap_prefix[PATH_MAX]; - enum dso_kernel_type kernel_type; - bool is_kernel_mmap; - - machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); - if (machine__is_host(machine)) - kernel_type = DSO_TYPE_KERNEL; - else - kernel_type = DSO_TYPE_GUEST_KERNEL; - - is_kernel_mmap = memcmp(event->mmap.filename, - kmmap_prefix, - strlen(kmmap_prefix) - 1) == 0; - if (event->mmap.filename[0] == '/' || - (!is_kernel_mmap && event->mmap.filename[0] == '[')) { - - char short_module_name[1024]; - char *name, *dot; - - if (event->mmap.filename[0] == '/') { - name = strrchr(event->mmap.filename, '/'); - if (name == NULL) - goto out_problem; - - ++name; /* skip / */ - dot = strrchr(name, '.'); - if (dot == NULL) - goto out_problem; - snprintf(short_module_name, sizeof(short_module_name), - "[%.*s]", (int)(dot - name), name); - strxfrchar(short_module_name, '-', '_'); - } else - strcpy(short_module_name, event->mmap.filename); - - map = machine__new_module(machine, event->mmap.start, - event->mmap.filename); - if (map == NULL) - goto out_problem; - - name = strdup(short_module_name); - if (name == NULL) - goto out_problem; - - map->dso->short_name = name; - map->dso->sname_alloc = 1; - map->end = map->start + event->mmap.len; - } else if (is_kernel_mmap) { - const char *symbol_name = (event->mmap.filename + - strlen(kmmap_prefix)); - /* - * Should be there already, from the build-id table in - * the header. - */ - struct dso *kernel = __dsos__findnew(&machine->kernel_dsos, - kmmap_prefix); - if (kernel == NULL) - goto out_problem; - - kernel->kernel = kernel_type; - if (__machine__create_kernel_maps(machine, kernel) < 0) - goto out_problem; - - perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps); - - /* - * Avoid using a zero address (kptr_restrict) for the ref reloc - * symbol. Effectively having zero here means that at record - * time /proc/sys/kernel/kptr_restrict was non zero. - */ - if (event->mmap.pgoff != 0) { - maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, - symbol_name, - event->mmap.pgoff); - } - - if (machine__is_default_guest(machine)) { - /* - * preload dso of guest kernel and modules - */ - dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION], - NULL); - } - } - return 0; -out_problem: - return -1; + return machine__process_lost_event(machine, event); } size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) @@ -657,43 +538,12 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) event->mmap.len, event->mmap.pgoff, event->mmap.filename); } -int perf_event__process_mmap(struct perf_tool *tool, +int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused, struct machine *machine) { - struct thread *thread; - struct map *map; - u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - int ret = 0; - - if (dump_trace) - perf_event__fprintf_mmap(event, stdout); - - if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || - cpumode == PERF_RECORD_MISC_KERNEL) { - ret = perf_event__process_kernel_mmap(tool, event, machine); - if (ret < 0) - goto out_problem; - return 0; - } - - thread = machine__findnew_thread(machine, event->mmap.pid); - if (thread == NULL) - goto out_problem; - map = map__new(&machine->user_dsos, event->mmap.start, - event->mmap.len, event->mmap.pgoff, - event->mmap.pid, event->mmap.filename, - MAP__FUNCTION); - if (map == NULL) - goto out_problem; - - thread__insert_map(thread, map); - return 0; - -out_problem: - dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); - return 0; + return machine__process_mmap_event(machine, event); } size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) @@ -708,19 +558,7 @@ int perf_event__process_fork(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine) { - struct thread *thread = machine__findnew_thread(machine, event->fork.tid); - struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); - - if (dump_trace) - perf_event__fprintf_task(event, stdout); - - if (thread == NULL || parent == NULL || - thread__fork(thread, parent) < 0) { - dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); - return -1; - } - - return 0; + return machine__process_fork_event(machine, event); } int perf_event__process_exit(struct perf_tool *tool __maybe_unused, @@ -728,15 +566,7 @@ int perf_event__process_exit(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine) { - struct thread *thread = machine__find_thread(machine, event->fork.tid); - - if (dump_trace) - perf_event__fprintf_task(event, stdout); - - if (thread != NULL) - machine__remove_thread(machine, thread); - - return 0; + return machine__process_exit_event(machine, event); } size_t perf_event__fprintf(union perf_event *event, FILE *fp) @@ -762,29 +592,12 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) return ret; } -int perf_event__process(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample, struct machine *machine) +int perf_event__process(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine) { - switch (event->header.type) { - case PERF_RECORD_COMM: - perf_event__process_comm(tool, event, sample, machine); - break; - case PERF_RECORD_MMAP: - perf_event__process_mmap(tool, event, sample, machine); - break; - case PERF_RECORD_FORK: - perf_event__process_fork(tool, event, sample, machine); - break; - case PERF_RECORD_EXIT: - perf_event__process_exit(tool, event, sample, machine); - break; - case PERF_RECORD_LOST: - perf_event__process_lost(tool, event, sample, machine); - default: - break; - } - - return 0; + return machine__process_event(machine, event); } void thread__find_addr_map(struct thread *self, -- cgit v1.2.3 From ba361c92e73c771fcbbbd24c2c03c322e2de2e31 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 17 Oct 2012 18:50:13 -0300 Subject: perf tools: Don't stop synthesizing threads when one vanishes The perf_event__synthesize_threads routine synthesizes all the existing threads in the system, because we don't have any kernel facilities to ask for PERF_RECORD_{FORK,MMAP,COMM} for existing threads. It was returning an error as soon as one thread couldn't be synthesized, which is a bit extreme when, for instance, a forkish workload is running, like a kernel compile. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-i7oas1eodpoer2bx38fwyasv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/event.c') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 0ae444ef1429..ca9ca285406a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -405,16 +405,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (*end) /* only interested in proper numerical dirents */ continue; - - if (__event__synthesize_thread(comm_event, mmap_event, pid, 1, - process, tool, machine) != 0) { - err = -1; - goto out_closedir; - } + /* + * We may race with exiting thread, so don't stop just because + * one thread couldn't be synthesized. + */ + __event__synthesize_thread(comm_event, mmap_event, pid, 1, + process, tool, machine); } err = 0; -out_closedir: closedir(proc); out_free_mmap: free(mmap_event); -- cgit v1.2.3 From 6064803313bad9ae4cae233a9d56678adb2b6e7c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 11 Nov 2012 23:20:50 +0900 Subject: perf tools: Use sscanf for parsing /proc/pid/maps When reading those files to synthesize MMAP events. It makes the code shorter and cleaner. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1352643651-13891-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 74 +++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 43 deletions(-) (limited to 'tools/perf/util/event.c') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index ca9ca285406a..3cf2c3e0605f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -193,55 +193,43 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, event->header.misc = PERF_RECORD_MISC_USER; while (1) { - char bf[BUFSIZ], *pbf = bf; - int n; + char bf[BUFSIZ]; + char prot[5]; + char execname[PATH_MAX]; + char anonstr[] = "//anon"; size_t size; + if (fgets(bf, sizeof(bf), fp) == NULL) break; + /* ensure null termination since stack will be reused. */ + strcpy(execname, ""); + /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = hex2u64(pbf, &event->mmap.start); - if (n < 0) - continue; - pbf += n + 1; - n = hex2u64(pbf, &event->mmap.len); - if (n < 0) + sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", + &event->mmap.start, &event->mmap.len, prot, + &event->mmap.pgoff, execname); + + if (prot[2] != 'x') continue; - pbf += n + 3; - if (*pbf == 'x') { /* vm_exec */ - char anonstr[] = "//anon\n"; - char *execname = strchr(bf, '/'); - - /* Catch VDSO */ - if (execname == NULL) - execname = strstr(bf, "[vdso]"); - - /* Catch anonymous mmaps */ - if ((execname == NULL) && !strstr(bf, "[")) - execname = anonstr; - - if (execname == NULL) - continue; - - pbf += 3; - n = hex2u64(pbf, &event->mmap.pgoff); - - size = strlen(execname); - execname[size - 1] = '\0'; /* Remove \n */ - memcpy(event->mmap.filename, execname, size); - size = PERF_ALIGN(size, sizeof(u64)); - event->mmap.len -= event->mmap.start; - event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, machine->id_hdr_size); - event->mmap.header.size += machine->id_hdr_size; - event->mmap.pid = tgid; - event->mmap.tid = pid; - - if (process(tool, event, &synth_sample, machine) != 0) { - rc = -1; - break; - } + + if (!strcmp(execname, "")) + strcpy(execname, anonstr); + + size = strlen(execname) + 1; + memcpy(event->mmap.filename, execname, size); + size = PERF_ALIGN(size, sizeof(u64)); + event->mmap.len -= event->mmap.start; + event->mmap.header.size = (sizeof(event->mmap) - + (sizeof(event->mmap.filename) - size)); + memset(event->mmap.filename + size, 0, machine->id_hdr_size); + event->mmap.header.size += machine->id_hdr_size; + event->mmap.pid = tgid; + event->mmap.tid = pid; + + if (process(tool, event, &synth_sample, machine) != 0) { + rc = -1; + break; } } -- cgit v1.2.3