* [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample
@ 2009-08-14 10:04 Frederic Weisbecker
2009-08-14 10:04 ` [PATCH] perf tools: Factorize the thread code in a dedicated file Frederic Weisbecker
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Frederic Weisbecker @ 2009-08-14 10:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: LKML, Frederic Weisbecker, Peter Zijlstra,
Arnaldo Carvalho de Melo, Mike Galbraith
Add a new flag field while opening a tracepoint perf counter:
-e tracepoint_subsystem:tracepoint_name:flags
This is intended to be generic although for now it only supports the
r[e[c[o[r[d]]]]] flag:
./perf record -e workqueue:workqueue_insertion:record
./perf record -e workqueue:workqueue_insertion:r
will have the same effect: enabling the raw samples record for the
given tracepoint counter.
In the future, we may want to support further flags, separated by
commas.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
---
tools/perf/builtin-record.c | 2 +-
tools/perf/util/parse-events.c | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 5aeb632..3be0301 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -380,7 +380,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
PERF_FORMAT_TOTAL_TIME_RUNNING |
PERF_FORMAT_ID;
- attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
+ attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
if (freq) {
attr->sample_type |= PERF_SAMPLE_PERIOD;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a5d661b..4bab278 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -379,6 +379,7 @@ static int parse_tracepoint_event(const char **strp,
struct perf_counter_attr *attr)
{
const char *evt_name;
+ char *flags;
char sys_name[MAX_EVENT_LENGTH];
char id_buf[4];
int fd;
@@ -400,6 +401,15 @@ static int parse_tracepoint_event(const char **strp,
strncpy(sys_name, *strp, sys_length);
sys_name[sys_length] = '\0';
evt_name = evt_name + 1;
+
+ flags = strchr(evt_name, ':');
+ if (flags) {
+ *flags = '\0';
+ flags++;
+ if (!strncmp(flags, "record", strlen(flags)))
+ attr->sample_type |= PERF_SAMPLE_RAW;
+ }
+
evt_length = strlen(evt_name);
if (evt_length >= MAX_EVENT_LENGTH)
return 0;
--
1.6.2.3
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH] perf tools: Factorize the thread code in a dedicated file 2009-08-14 10:04 [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker @ 2009-08-14 10:04 ` Frederic Weisbecker 2009-08-14 10:21 ` [PATCH v2] " Frederic Weisbecker 2009-08-14 10:05 ` [PATCH 2/2] perf tools: Add a general option to enable raw sample records Frederic Weisbecker 2009-08-14 10:07 ` [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker 2 siblings, 1 reply; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-14 10:04 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Frederic Weisbecker, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith Factorize the thread management code used by perf-annotate and perf-report in dedicated source and header files. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> --- tools/perf/Makefile | 1 + tools/perf/builtin-annotate.c | 173 ++++------------------------------- tools/perf/builtin-report.c | 205 ++++------------------------------------ tools/perf/util/thread.c | 143 ++++++++++++++++++++++++++++ tools/perf/util/thread.h | 19 ++++ 5 files changed, 202 insertions(+), 339 deletions(-) create mode 100644 tools/perf/util/thread.c create mode 100644 tools/perf/util/thread.h diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 68218cf..0056405 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -341,6 +341,7 @@ LIB_OBJS += util/callchain.o LIB_OBJS += util/values.o LIB_OBJS += util/debug.o LIB_OBJS += util/map.o +LIB_OBJS += util/thread.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 543c452..dacf0da 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -20,6 +20,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" #define SHOW_KERNEL 1 #define SHOW_USER 2 @@ -44,6 +45,9 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; +static struct rb_root threads; +static struct thread *last_match; + struct sym_ext { struct rb_node node; @@ -51,154 +55,6 @@ struct sym_ext { char *path; }; - -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - return self->comm ? 0 : -ENOMEM; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - list_del_init(&pos->node); - /* XXX leaks dsos */ - free(pos); - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -624,7 +480,7 @@ static void output__resort(void) static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -645,10 +501,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; struct map *map = NULL; + thread = threads__findnew(event->ip.pid, &threads, last_match); + dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -719,9 +577,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, NULL, 0); + thread = threads__findnew(event->mmap.pid, &threads, last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -745,8 +605,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + thread = threads__findnew(event->comm.pid, &threads, last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -765,9 +626,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_fork_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + thread = threads__findnew(event->fork.pid, &threads, last_match); + parent = threads__findnew(event->fork.ppid, &threads, last_match); dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1202,7 +1065,7 @@ more: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6321951..c91ea34 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -25,6 +25,8 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" + #define SHOW_KERNEL 1 #define SHOW_USER 2 #define SHOW_HV 4 @@ -71,6 +73,9 @@ static char __cwd[PATH_MAX]; static char *cwd = __cwd; static int cwdlen; +static struct rb_root threads; +static struct thread *last_match; + static struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, @@ -106,187 +111,10 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) return n; } -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - static unsigned int dsos__col_width, comms__col_width, threads__col_width; -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - if (!self->comm) - return -ENOMEM; - - if (!col_width_list_str && !field_sep && - (!comm_list || strlist__has_entry(comm_list, comm))) { - unsigned int slen = strlen(comm); - if (slen > comms__col_width) { - comms__col_width = slen; - threads__col_width = slen + 6; - } - } - - return 0; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); - } - - if (map->start <= pos->start && map->end > pos->start) - pos->start = map->end; - - if (map->end >= pos->end && map->start < pos->end) - pos->end = map->start; - - if (verbose >= 2) { - printf("after collision:\n"); - map__fprintf(pos, stdout); - } - - if (pos->start >= pos->end) { - list_del_init(&pos->node); - free(pos); - } - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -1228,7 +1056,7 @@ print_entries: static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -1263,7 +1091,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; u64 period = 1; struct map *map = NULL; @@ -1271,6 +1099,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct ip_callchain *chain = NULL; int cpumode; + thread = threads__findnew(event->ip.pid, &threads, last_match); + if (sample_type & PERF_SAMPLE_PERIOD) { period = *(u64 *)more_data; more_data += sizeof(u64); @@ -1360,9 +1190,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, cwd, cwdlen); + thread = threads__findnew(event->mmap.pid, &threads, last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1387,7 +1219,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + + thread = threads__findnew(event->comm.pid, &threads, last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), @@ -1407,8 +1241,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_task_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + + thread = threads__findnew(event->fork.pid, &threads, last_match); + parent = threads__findnew(event->fork.ppid, &threads, last_match); dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", (void *)(offset + head), @@ -1749,7 +1586,7 @@ done: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c new file mode 100644 index 0000000..f2dd40e --- /dev/null +++ b/tools/perf/util/thread.c @@ -0,0 +1,143 @@ +#include "../perf.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "thread.h" +#include "util.h" + +static struct thread *thread__new(pid_t pid) +{ + struct thread *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->pid = pid; + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + INIT_LIST_HEAD(&self->maps); + } + + return self; +} + +int thread__set_comm(struct thread *self, const char *comm) +{ + if (self->comm) + free(self->comm); + self->comm = strdup(comm); + return self->comm ? 0 : -ENOMEM; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + + list_for_each_entry(pos, &self->maps, node) + ret += map__fprintf(pos, fp); + + return ret; +} + +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread *last_match) +{ + struct rb_node **p = &threads->rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + /* + * Font-end cache - PID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: + */ + if (last_match && last_match->pid == pid) + return last_match; + + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); + + if (th->pid == pid) { + last_match = th; + return th; + } + + if (pid < th->pid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + th = thread__new(pid); + if (th != NULL) { + rb_link_node(&th->rb_node, parent, p); + rb_insert_color(&th->rb_node, threads); + last_match = th; + } + + return th; +} + +void thread__insert_map(struct thread *self, struct map *map) +{ + struct map *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &self->maps, node) { + if (map__overlap(pos, map)) { + list_del_init(&pos->node); + /* XXX leaks dsos */ + free(pos); + } + } + + list_add_tail(&map->node, &self->maps); +} + +int thread__fork(struct thread *self, struct thread *parent) +{ + struct map *map; + + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) + return -ENOMEM; + + list_for_each_entry(map, &parent->maps, node) { + struct map *new = map__clone(map); + if (!new) + return -ENOMEM; + thread__insert_map(self, new); + } + + return 0; +} + +struct map *thread__find_map(struct thread *self, u64 ip) +{ + struct map *pos; + + if (self == NULL) + return NULL; + + list_for_each_entry(pos, &self->maps, node) + if (ip >= pos->start && ip <= pos->end) + return pos; + + return NULL; +} + +size_t threads__fprintf(FILE *fp, struct rb_root *threads) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h new file mode 100644 index 0000000..d5edcba --- /dev/null +++ b/tools/perf/util/thread.h @@ -0,0 +1,19 @@ +#include <linux/rbtree.h> +#include <linux/list.h> +#include <unistd.h> +#include "symbol.h" + +struct thread { + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; +}; + +int thread__set_comm(struct thread *self, const char *comm); +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread *last_match); +void thread__insert_map(struct thread *self, struct map *map); +int thread__fork(struct thread *self, struct thread *parent); +struct map *thread__find_map(struct thread *self, u64 ip); +size_t threads__fprintf(FILE *fp, struct rb_root *threads); -- 1.6.2.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2] perf tools: Factorize the thread code in a dedicated file 2009-08-14 10:04 ` [PATCH] perf tools: Factorize the thread code in a dedicated file Frederic Weisbecker @ 2009-08-14 10:21 ` Frederic Weisbecker 2009-08-15 14:12 ` [tip:perfcounters/core] " tip-bot for Frederic Weisbecker 0 siblings, 1 reply; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-14 10:21 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Frederic Weisbecker, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith Factorize the thread management code used by perf-annotate and perf-report in dedicated source and header files. v2: pass last_match by address so that it can actually be modified. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> --- tools/perf/Makefile | 1 + tools/perf/builtin-annotate.c | 173 ++++------------------------------- tools/perf/builtin-report.c | 205 ++++------------------------------------ tools/perf/util/thread.c | 143 ++++++++++++++++++++++++++++ tools/perf/util/thread.h | 19 ++++ 5 files changed, 202 insertions(+), 339 deletions(-) create mode 100644 tools/perf/util/thread.c create mode 100644 tools/perf/util/thread.h diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 68218cf..0056405 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -341,6 +341,7 @@ LIB_OBJS += util/callchain.o LIB_OBJS += util/values.o LIB_OBJS += util/debug.o LIB_OBJS += util/map.o +LIB_OBJS += util/thread.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 543c452..3bedaa5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -20,6 +20,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" #define SHOW_KERNEL 1 #define SHOW_USER 2 @@ -44,6 +45,9 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; +static struct rb_root threads; +static struct thread *last_match; + struct sym_ext { struct rb_node node; @@ -51,154 +55,6 @@ struct sym_ext { char *path; }; - -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - return self->comm ? 0 : -ENOMEM; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - list_del_init(&pos->node); - /* XXX leaks dsos */ - free(pos); - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -624,7 +480,7 @@ static void output__resort(void) static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -645,10 +501,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; struct map *map = NULL; + thread = threads__findnew(event->ip.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -719,9 +577,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, NULL, 0); + thread = threads__findnew(event->mmap.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -745,8 +605,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + thread = threads__findnew(event->comm.pid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -765,9 +626,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_fork_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + thread = threads__findnew(event->fork.pid, &threads, &last_match); + parent = threads__findnew(event->fork.ppid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1202,7 +1065,7 @@ more: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6321951..298f26b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -25,6 +25,8 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" + #define SHOW_KERNEL 1 #define SHOW_USER 2 #define SHOW_HV 4 @@ -71,6 +73,9 @@ static char __cwd[PATH_MAX]; static char *cwd = __cwd; static int cwdlen; +static struct rb_root threads; +static struct thread *last_match; + static struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, @@ -106,187 +111,10 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) return n; } -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - static unsigned int dsos__col_width, comms__col_width, threads__col_width; -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - if (!self->comm) - return -ENOMEM; - - if (!col_width_list_str && !field_sep && - (!comm_list || strlist__has_entry(comm_list, comm))) { - unsigned int slen = strlen(comm); - if (slen > comms__col_width) { - comms__col_width = slen; - threads__col_width = slen + 6; - } - } - - return 0; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); - } - - if (map->start <= pos->start && map->end > pos->start) - pos->start = map->end; - - if (map->end >= pos->end && map->start < pos->end) - pos->end = map->start; - - if (verbose >= 2) { - printf("after collision:\n"); - map__fprintf(pos, stdout); - } - - if (pos->start >= pos->end) { - list_del_init(&pos->node); - free(pos); - } - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -1228,7 +1056,7 @@ print_entries: static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -1263,7 +1091,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; u64 period = 1; struct map *map = NULL; @@ -1271,6 +1099,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct ip_callchain *chain = NULL; int cpumode; + thread = threads__findnew(event->ip.pid, &threads, &last_match); + if (sample_type & PERF_SAMPLE_PERIOD) { period = *(u64 *)more_data; more_data += sizeof(u64); @@ -1360,9 +1190,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, cwd, cwdlen); + thread = threads__findnew(event->mmap.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1387,7 +1219,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + + thread = threads__findnew(event->comm.pid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), @@ -1407,8 +1241,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_task_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + + thread = threads__findnew(event->fork.pid, &threads, &last_match); + parent = threads__findnew(event->fork.ppid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", (void *)(offset + head), @@ -1749,7 +1586,7 @@ done: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c new file mode 100644 index 0000000..00c14b9 --- /dev/null +++ b/tools/perf/util/thread.c @@ -0,0 +1,143 @@ +#include "../perf.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "thread.h" +#include "util.h" + +static struct thread *thread__new(pid_t pid) +{ + struct thread *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->pid = pid; + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + INIT_LIST_HEAD(&self->maps); + } + + return self; +} + +int thread__set_comm(struct thread *self, const char *comm) +{ + if (self->comm) + free(self->comm); + self->comm = strdup(comm); + return self->comm ? 0 : -ENOMEM; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + + list_for_each_entry(pos, &self->maps, node) + ret += map__fprintf(pos, fp); + + return ret; +} + +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) +{ + struct rb_node **p = &threads->rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + /* + * Font-end cache - PID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: + */ + if (*last_match && (*last_match)->pid == pid) + return *last_match; + + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); + + if (th->pid == pid) { + *last_match = th; + return th; + } + + if (pid < th->pid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + th = thread__new(pid); + if (th != NULL) { + rb_link_node(&th->rb_node, parent, p); + rb_insert_color(&th->rb_node, threads); + *last_match = th; + } + + return th; +} + +void thread__insert_map(struct thread *self, struct map *map) +{ + struct map *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &self->maps, node) { + if (map__overlap(pos, map)) { + list_del_init(&pos->node); + /* XXX leaks dsos */ + free(pos); + } + } + + list_add_tail(&map->node, &self->maps); +} + +int thread__fork(struct thread *self, struct thread *parent) +{ + struct map *map; + + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) + return -ENOMEM; + + list_for_each_entry(map, &parent->maps, node) { + struct map *new = map__clone(map); + if (!new) + return -ENOMEM; + thread__insert_map(self, new); + } + + return 0; +} + +struct map *thread__find_map(struct thread *self, u64 ip) +{ + struct map *pos; + + if (self == NULL) + return NULL; + + list_for_each_entry(pos, &self->maps, node) + if (ip >= pos->start && ip <= pos->end) + return pos; + + return NULL; +} + +size_t threads__fprintf(FILE *fp, struct rb_root *threads) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h new file mode 100644 index 0000000..b1c6671 --- /dev/null +++ b/tools/perf/util/thread.h @@ -0,0 +1,19 @@ +#include <linux/rbtree.h> +#include <linux/list.h> +#include <unistd.h> +#include "symbol.h" + +struct thread { + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; +}; + +int thread__set_comm(struct thread *self, const char *comm); +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); +void thread__insert_map(struct thread *self, struct map *map); +int thread__fork(struct thread *self, struct thread *parent); +struct map *thread__find_map(struct thread *self, u64 ip); +size_t threads__fprintf(FILE *fp, struct rb_root *threads); -- 1.6.2.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [tip:perfcounters/core] perf tools: Factorize the thread code in a dedicated file 2009-08-14 10:21 ` [PATCH v2] " Frederic Weisbecker @ 2009-08-15 14:12 ` tip-bot for Frederic Weisbecker 0 siblings, 0 replies; 8+ messages in thread From: tip-bot for Frederic Weisbecker @ 2009-08-15 14:12 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, acme, hpa, mingo, efault, peterz, fweisbec, tglx, mingo Commit-ID: 6baa0a5ae0954fb2486c480a20556a9f1aee0965 Gitweb: http://git.kernel.org/tip/6baa0a5ae0954fb2486c480a20556a9f1aee0965 Author: Frederic Weisbecker <fweisbec@gmail.com> AuthorDate: Fri, 14 Aug 2009 12:21:53 +0200 Committer: Ingo Molnar <mingo@elte.hu> CommitDate: Sat, 15 Aug 2009 16:10:19 +0200 perf tools: Factorize the thread code in a dedicated file Factorize the thread management code used by perf-annotate and perf-report in dedicated source and header files. v2: pass last_match by address so that it can actually be modified. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1250245313-6995-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- tools/perf/Makefile | 1 + tools/perf/builtin-annotate.c | 173 ++++------------------------------- tools/perf/builtin-report.c | 205 ++++------------------------------------ tools/perf/util/thread.c | 143 ++++++++++++++++++++++++++++ tools/perf/util/thread.h | 19 ++++ 5 files changed, 202 insertions(+), 339 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 68218cf..0056405 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -341,6 +341,7 @@ LIB_OBJS += util/callchain.o LIB_OBJS += util/values.o LIB_OBJS += util/debug.o LIB_OBJS += util/map.o +LIB_OBJS += util/thread.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 543c452..3bedaa5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -20,6 +20,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" #define SHOW_KERNEL 1 #define SHOW_USER 2 @@ -44,6 +45,9 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; +static struct rb_root threads; +static struct thread *last_match; + struct sym_ext { struct rb_node node; @@ -51,154 +55,6 @@ struct sym_ext { char *path; }; - -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - return self->comm ? 0 : -ENOMEM; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - list_del_init(&pos->node); - /* XXX leaks dsos */ - free(pos); - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -624,7 +480,7 @@ static void output__resort(void) static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -645,10 +501,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; struct map *map = NULL; + thread = threads__findnew(event->ip.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -719,9 +577,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, NULL, 0); + thread = threads__findnew(event->mmap.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -745,8 +605,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + thread = threads__findnew(event->comm.pid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -765,9 +626,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_fork_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + thread = threads__findnew(event->fork.pid, &threads, &last_match); + parent = threads__findnew(event->fork.ppid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1202,7 +1065,7 @@ more: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6321951..298f26b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -25,6 +25,8 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" + #define SHOW_KERNEL 1 #define SHOW_USER 2 #define SHOW_HV 4 @@ -71,6 +73,9 @@ static char __cwd[PATH_MAX]; static char *cwd = __cwd; static int cwdlen; +static struct rb_root threads; +static struct thread *last_match; + static struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, @@ -106,187 +111,10 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) return n; } -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - static unsigned int dsos__col_width, comms__col_width, threads__col_width; -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - if (!self->comm) - return -ENOMEM; - - if (!col_width_list_str && !field_sep && - (!comm_list || strlist__has_entry(comm_list, comm))) { - unsigned int slen = strlen(comm); - if (slen > comms__col_width) { - comms__col_width = slen; - threads__col_width = slen + 6; - } - } - - return 0; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); - } - - if (map->start <= pos->start && map->end > pos->start) - pos->start = map->end; - - if (map->end >= pos->end && map->start < pos->end) - pos->end = map->start; - - if (verbose >= 2) { - printf("after collision:\n"); - map__fprintf(pos, stdout); - } - - if (pos->start >= pos->end) { - list_del_init(&pos->node); - free(pos); - } - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -1228,7 +1056,7 @@ print_entries: static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -1263,7 +1091,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; u64 period = 1; struct map *map = NULL; @@ -1271,6 +1099,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct ip_callchain *chain = NULL; int cpumode; + thread = threads__findnew(event->ip.pid, &threads, &last_match); + if (sample_type & PERF_SAMPLE_PERIOD) { period = *(u64 *)more_data; more_data += sizeof(u64); @@ -1360,9 +1190,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, cwd, cwdlen); + thread = threads__findnew(event->mmap.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1387,7 +1219,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + + thread = threads__findnew(event->comm.pid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), @@ -1407,8 +1241,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_task_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + + thread = threads__findnew(event->fork.pid, &threads, &last_match); + parent = threads__findnew(event->fork.ppid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", (void *)(offset + head), @@ -1749,7 +1586,7 @@ done: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c new file mode 100644 index 0000000..00c14b9 --- /dev/null +++ b/tools/perf/util/thread.c @@ -0,0 +1,143 @@ +#include "../perf.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "thread.h" +#include "util.h" + +static struct thread *thread__new(pid_t pid) +{ + struct thread *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->pid = pid; + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + INIT_LIST_HEAD(&self->maps); + } + + return self; +} + +int thread__set_comm(struct thread *self, const char *comm) +{ + if (self->comm) + free(self->comm); + self->comm = strdup(comm); + return self->comm ? 0 : -ENOMEM; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + + list_for_each_entry(pos, &self->maps, node) + ret += map__fprintf(pos, fp); + + return ret; +} + +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) +{ + struct rb_node **p = &threads->rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + /* + * Font-end cache - PID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: + */ + if (*last_match && (*last_match)->pid == pid) + return *last_match; + + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); + + if (th->pid == pid) { + *last_match = th; + return th; + } + + if (pid < th->pid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + th = thread__new(pid); + if (th != NULL) { + rb_link_node(&th->rb_node, parent, p); + rb_insert_color(&th->rb_node, threads); + *last_match = th; + } + + return th; +} + +void thread__insert_map(struct thread *self, struct map *map) +{ + struct map *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &self->maps, node) { + if (map__overlap(pos, map)) { + list_del_init(&pos->node); + /* XXX leaks dsos */ + free(pos); + } + } + + list_add_tail(&map->node, &self->maps); +} + +int thread__fork(struct thread *self, struct thread *parent) +{ + struct map *map; + + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) + return -ENOMEM; + + list_for_each_entry(map, &parent->maps, node) { + struct map *new = map__clone(map); + if (!new) + return -ENOMEM; + thread__insert_map(self, new); + } + + return 0; +} + +struct map *thread__find_map(struct thread *self, u64 ip) +{ + struct map *pos; + + if (self == NULL) + return NULL; + + list_for_each_entry(pos, &self->maps, node) + if (ip >= pos->start && ip <= pos->end) + return pos; + + return NULL; +} + +size_t threads__fprintf(FILE *fp, struct rb_root *threads) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h new file mode 100644 index 0000000..b1c6671 --- /dev/null +++ b/tools/perf/util/thread.h @@ -0,0 +1,19 @@ +#include <linux/rbtree.h> +#include <linux/list.h> +#include <unistd.h> +#include "symbol.h" + +struct thread { + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; +}; + +int thread__set_comm(struct thread *self, const char *comm); +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); +void thread__insert_map(struct thread *self, struct map *map); +int thread__fork(struct thread *self, struct thread *parent); +struct map *thread__find_map(struct thread *self, u64 ip); +size_t threads__fprintf(FILE *fp, struct rb_root *threads); ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] perf tools: Add a general option to enable raw sample records 2009-08-14 10:04 [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker 2009-08-14 10:04 ` [PATCH] perf tools: Factorize the thread code in a dedicated file Frederic Weisbecker @ 2009-08-14 10:05 ` Frederic Weisbecker 2009-08-14 10:07 ` Frederic Weisbecker 2009-08-14 10:07 ` [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker 2 siblings, 1 reply; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-14 10:05 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Frederic Weisbecker, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith While we can enable the perf sample records per tracepoint counter, we may also want to enable this option for every tracepoint counters to open, so that we don't need to add a :record flag for all of them. Add the -R, --raw-samples options for this purpose. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> --- tools/perf/builtin-record.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 3be0301..e67c4fa 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,6 +35,7 @@ static int output; static const char *output_name = "perf.data"; static int group = 0; static unsigned int realtime_prio = 0; +static int raw_samples = 0; static int system_wide = 0; static int profile_cpu = -1; static pid_t target_pid = -1; @@ -400,6 +401,8 @@ static void create_counter(int counter, int cpu, pid_t pid) if (call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + if (raw_samples) + attr->sample_type |= PERF_SAMPLE_RAW; attr->mmap = track; attr->comm = track; @@ -632,6 +635,8 @@ static const struct option options[] = { "record events on existing pid"), OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), + OPT_BOOLEAN('R', "raw-samples", &raw_samples, + "collect raw sample records from all opened counters"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_BOOLEAN('A', "append", &append_file, -- 1.6.2.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] perf tools: Add a general option to enable raw sample records 2009-08-14 10:05 ` [PATCH 2/2] perf tools: Add a general option to enable raw sample records Frederic Weisbecker @ 2009-08-14 10:07 ` Frederic Weisbecker 0 siblings, 0 replies; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-14 10:07 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith Sorry, please ignore this one, it has been resent by mistake :-( On Fri, Aug 14, 2009 at 12:05:00PM +0200, Frederic Weisbecker wrote: > While we can enable the perf sample records per tracepoint counter, > we may also want to enable this option for every tracepoint > counters to open, so that we don't need to add a :record flag > for all of them. > > Add the -R, --raw-samples options for this purpose. > > Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Arnaldo Carvalho de Melo <acme@redhat.com> > Cc: Mike Galbraith <efault@gmx.de> > --- > tools/perf/builtin-record.c | 5 +++++ > 1 files changed, 5 insertions(+), 0 deletions(-) > > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c > index 3be0301..e67c4fa 100644 > --- a/tools/perf/builtin-record.c > +++ b/tools/perf/builtin-record.c > @@ -35,6 +35,7 @@ static int output; > static const char *output_name = "perf.data"; > static int group = 0; > static unsigned int realtime_prio = 0; > +static int raw_samples = 0; > static int system_wide = 0; > static int profile_cpu = -1; > static pid_t target_pid = -1; > @@ -400,6 +401,8 @@ static void create_counter(int counter, int cpu, pid_t pid) > if (call_graph) > attr->sample_type |= PERF_SAMPLE_CALLCHAIN; > > + if (raw_samples) > + attr->sample_type |= PERF_SAMPLE_RAW; > > attr->mmap = track; > attr->comm = track; > @@ -632,6 +635,8 @@ static const struct option options[] = { > "record events on existing pid"), > OPT_INTEGER('r', "realtime", &realtime_prio, > "collect data with this RT SCHED_FIFO priority"), > + OPT_BOOLEAN('R', "raw-samples", &raw_samples, > + "collect raw sample records from all opened counters"), > OPT_BOOLEAN('a', "all-cpus", &system_wide, > "system-wide collection from all CPUs"), > OPT_BOOLEAN('A', "append", &append_file, > -- > 1.6.2.3 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample 2009-08-14 10:04 [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker 2009-08-14 10:04 ` [PATCH] perf tools: Factorize the thread code in a dedicated file Frederic Weisbecker 2009-08-14 10:05 ` [PATCH 2/2] perf tools: Add a general option to enable raw sample records Frederic Weisbecker @ 2009-08-14 10:07 ` Frederic Weisbecker 2 siblings, 0 replies; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-14 10:07 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith Sorry, please ignore this one, it has been resent by mistake :-( On Fri, Aug 14, 2009 at 12:04:58PM +0200, Frederic Weisbecker wrote: > Add a new flag field while opening a tracepoint perf counter: > > -e tracepoint_subsystem:tracepoint_name:flags > > This is intended to be generic although for now it only supports the > r[e[c[o[r[d]]]]] flag: > > ./perf record -e workqueue:workqueue_insertion:record > ./perf record -e workqueue:workqueue_insertion:r > > will have the same effect: enabling the raw samples record for the > given tracepoint counter. > > In the future, we may want to support further flags, separated by > commas. > > Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Arnaldo Carvalho de Melo <acme@redhat.com> > Cc: Mike Galbraith <efault@gmx.de> > --- > tools/perf/builtin-record.c | 2 +- > tools/perf/util/parse-events.c | 10 ++++++++++ > 2 files changed, 11 insertions(+), 1 deletions(-) > > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c > index 5aeb632..3be0301 100644 > --- a/tools/perf/builtin-record.c > +++ b/tools/perf/builtin-record.c > @@ -380,7 +380,7 @@ static void create_counter(int counter, int cpu, pid_t pid) > PERF_FORMAT_TOTAL_TIME_RUNNING | > PERF_FORMAT_ID; > > - attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; > + attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; > > if (freq) { > attr->sample_type |= PERF_SAMPLE_PERIOD; > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c > index a5d661b..4bab278 100644 > --- a/tools/perf/util/parse-events.c > +++ b/tools/perf/util/parse-events.c > @@ -379,6 +379,7 @@ static int parse_tracepoint_event(const char **strp, > struct perf_counter_attr *attr) > { > const char *evt_name; > + char *flags; > char sys_name[MAX_EVENT_LENGTH]; > char id_buf[4]; > int fd; > @@ -400,6 +401,15 @@ static int parse_tracepoint_event(const char **strp, > strncpy(sys_name, *strp, sys_length); > sys_name[sys_length] = '\0'; > evt_name = evt_name + 1; > + > + flags = strchr(evt_name, ':'); > + if (flags) { > + *flags = '\0'; > + flags++; > + if (!strncmp(flags, "record", strlen(flags))) > + attr->sample_type |= PERF_SAMPLE_RAW; > + } > + > evt_length = strlen(evt_name); > if (evt_length >= MAX_EVENT_LENGTH) > return 0; > -- > 1.6.2.3 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample @ 2009-08-13 8:27 Frederic Weisbecker 2009-08-13 8:27 ` [PATCH 2/2] perf tools: Add a general option to enable raw sample records Frederic Weisbecker 0 siblings, 1 reply; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-13 8:27 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Frederic Weisbecker, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith Add a new flag field while opening a tracepoint perf counter: -e tracepoint_subsystem:tracepoint_name:flags This is intended to be generic although for now it only supports the r[e[c[o[r[d]]]]] flag: ./perf record -e workqueue:workqueue_insertion:record ./perf record -e workqueue:workqueue_insertion:r will have the same effect: enabling the raw samples record for the given tracepoint counter. In the future, we may want to support further flags, separated by commas. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> --- tools/perf/builtin-record.c | 2 +- tools/perf/util/parse-events.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 5aeb632..3be0301 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -380,7 +380,7 @@ static void create_counter(int counter, int cpu, pid_t pid) PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; - attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; if (freq) { attr->sample_type |= PERF_SAMPLE_PERIOD; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a5d661b..4bab278 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -379,6 +379,7 @@ static int parse_tracepoint_event(const char **strp, struct perf_counter_attr *attr) { const char *evt_name; + char *flags; char sys_name[MAX_EVENT_LENGTH]; char id_buf[4]; int fd; @@ -400,6 +401,15 @@ static int parse_tracepoint_event(const char **strp, strncpy(sys_name, *strp, sys_length); sys_name[sys_length] = '\0'; evt_name = evt_name + 1; + + flags = strchr(evt_name, ':'); + if (flags) { + *flags = '\0'; + flags++; + if (!strncmp(flags, "record", strlen(flags))) + attr->sample_type |= PERF_SAMPLE_RAW; + } + evt_length = strlen(evt_name); if (evt_length >= MAX_EVENT_LENGTH) return 0; -- 1.6.2.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] perf tools: Add a general option to enable raw sample records 2009-08-13 8:27 Frederic Weisbecker @ 2009-08-13 8:27 ` Frederic Weisbecker 0 siblings, 0 replies; 8+ messages in thread From: Frederic Weisbecker @ 2009-08-13 8:27 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Frederic Weisbecker, Peter Zijlstra, Arnaldo Carvalho de Melo, Mike Galbraith While we can enable the perf sample records per tracepoint counter, we may also want to enable this option for every tracepoint counters to open, so that we don't need to add a :record flag for all of them. Add the -R, --raw-samples options for this purpose. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> --- tools/perf/builtin-record.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 3be0301..e67c4fa 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,6 +35,7 @@ static int output; static const char *output_name = "perf.data"; static int group = 0; static unsigned int realtime_prio = 0; +static int raw_samples = 0; static int system_wide = 0; static int profile_cpu = -1; static pid_t target_pid = -1; @@ -400,6 +401,8 @@ static void create_counter(int counter, int cpu, pid_t pid) if (call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + if (raw_samples) + attr->sample_type |= PERF_SAMPLE_RAW; attr->mmap = track; attr->comm = track; @@ -632,6 +635,8 @@ static const struct option options[] = { "record events on existing pid"), OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), + OPT_BOOLEAN('R', "raw-samples", &raw_samples, + "collect raw sample records from all opened counters"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_BOOLEAN('A', "append", &append_file, -- 1.6.2.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2009-08-15 14:13 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-08-14 10:04 [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker 2009-08-14 10:04 ` [PATCH] perf tools: Factorize the thread code in a dedicated file Frederic Weisbecker 2009-08-14 10:21 ` [PATCH v2] " Frederic Weisbecker 2009-08-15 14:12 ` [tip:perfcounters/core] " tip-bot for Frederic Weisbecker 2009-08-14 10:05 ` [PATCH 2/2] perf tools: Add a general option to enable raw sample records Frederic Weisbecker 2009-08-14 10:07 ` Frederic Weisbecker 2009-08-14 10:07 ` [PATCH 1/2] perf tools: Add a per tracepoint counter attribute to get raw sample Frederic Weisbecker -- strict thread matches above, loose matches on Subject: below -- 2009-08-13 8:27 Frederic Weisbecker 2009-08-13 8:27 ` [PATCH 2/2] perf tools: Add a general option to enable raw sample records Frederic Weisbecker
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox