diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-08-14 06:21:53 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-08-15 10:10:19 -0400 |
commit | 6baa0a5ae0954fb2486c480a20556a9f1aee0965 (patch) | |
tree | b85e485562b34b222153d41414dec655724e26b8 /tools/perf/builtin-annotate.c | |
parent | be750231ce1599b86fbba213e3da8344ece262e2 (diff) |
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>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 173 |
1 files changed, 18 insertions, 155 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 543c4524f8c2..3bedaa5d21d2 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include "util/parse-options.h" | 21 | #include "util/parse-options.h" |
22 | #include "util/parse-events.h" | 22 | #include "util/parse-events.h" |
23 | #include "util/thread.h" | ||
23 | 24 | ||
24 | #define SHOW_KERNEL 1 | 25 | #define SHOW_KERNEL 1 |
25 | #define SHOW_USER 2 | 26 | #define SHOW_USER 2 |
@@ -44,6 +45,9 @@ static int print_line; | |||
44 | static unsigned long page_size; | 45 | static unsigned long page_size; |
45 | static unsigned long mmap_window = 32; | 46 | static unsigned long mmap_window = 32; |
46 | 47 | ||
48 | static struct rb_root threads; | ||
49 | static struct thread *last_match; | ||
50 | |||
47 | 51 | ||
48 | struct sym_ext { | 52 | struct sym_ext { |
49 | struct rb_node node; | 53 | struct rb_node node; |
@@ -51,154 +55,6 @@ struct sym_ext { | |||
51 | char *path; | 55 | char *path; |
52 | }; | 56 | }; |
53 | 57 | ||
54 | |||
55 | struct thread { | ||
56 | struct rb_node rb_node; | ||
57 | struct list_head maps; | ||
58 | pid_t pid; | ||
59 | char *comm; | ||
60 | }; | ||
61 | |||
62 | static struct thread *thread__new(pid_t pid) | ||
63 | { | ||
64 | struct thread *self = malloc(sizeof(*self)); | ||
65 | |||
66 | if (self != NULL) { | ||
67 | self->pid = pid; | ||
68 | self->comm = malloc(32); | ||
69 | if (self->comm) | ||
70 | snprintf(self->comm, 32, ":%d", self->pid); | ||
71 | INIT_LIST_HEAD(&self->maps); | ||
72 | } | ||
73 | |||
74 | return self; | ||
75 | } | ||
76 | |||
77 | static int thread__set_comm(struct thread *self, const char *comm) | ||
78 | { | ||
79 | if (self->comm) | ||
80 | free(self->comm); | ||
81 | self->comm = strdup(comm); | ||
82 | return self->comm ? 0 : -ENOMEM; | ||
83 | } | ||
84 | |||
85 | static size_t thread__fprintf(struct thread *self, FILE *fp) | ||
86 | { | ||
87 | struct map *pos; | ||
88 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); | ||
89 | |||
90 | list_for_each_entry(pos, &self->maps, node) | ||
91 | ret += map__fprintf(pos, fp); | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | |||
97 | static struct rb_root threads; | ||
98 | static struct thread *last_match; | ||
99 | |||
100 | static struct thread *threads__findnew(pid_t pid) | ||
101 | { | ||
102 | struct rb_node **p = &threads.rb_node; | ||
103 | struct rb_node *parent = NULL; | ||
104 | struct thread *th; | ||
105 | |||
106 | /* | ||
107 | * Font-end cache - PID lookups come in blocks, | ||
108 | * so most of the time we dont have to look up | ||
109 | * the full rbtree: | ||
110 | */ | ||
111 | if (last_match && last_match->pid == pid) | ||
112 | return last_match; | ||
113 | |||
114 | while (*p != NULL) { | ||
115 | parent = *p; | ||
116 | th = rb_entry(parent, struct thread, rb_node); | ||
117 | |||
118 | if (th->pid == pid) { | ||
119 | last_match = th; | ||
120 | return th; | ||
121 | } | ||
122 | |||
123 | if (pid < th->pid) | ||
124 | p = &(*p)->rb_left; | ||
125 | else | ||
126 | p = &(*p)->rb_right; | ||
127 | } | ||
128 | |||
129 | th = thread__new(pid); | ||
130 | if (th != NULL) { | ||
131 | rb_link_node(&th->rb_node, parent, p); | ||
132 | rb_insert_color(&th->rb_node, &threads); | ||
133 | last_match = th; | ||
134 | } | ||
135 | |||
136 | return th; | ||
137 | } | ||
138 | |||
139 | static void thread__insert_map(struct thread *self, struct map *map) | ||
140 | { | ||
141 | struct map *pos, *tmp; | ||
142 | |||
143 | list_for_each_entry_safe(pos, tmp, &self->maps, node) { | ||
144 | if (map__overlap(pos, map)) { | ||
145 | list_del_init(&pos->node); | ||
146 | /* XXX leaks dsos */ | ||
147 | free(pos); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | list_add_tail(&map->node, &self->maps); | ||
152 | } | ||
153 | |||
154 | static int thread__fork(struct thread *self, struct thread *parent) | ||
155 | { | ||
156 | struct map *map; | ||
157 | |||
158 | if (self->comm) | ||
159 | free(self->comm); | ||
160 | self->comm = strdup(parent->comm); | ||
161 | if (!self->comm) | ||
162 | return -ENOMEM; | ||
163 | |||
164 | list_for_each_entry(map, &parent->maps, node) { | ||
165 | struct map *new = map__clone(map); | ||
166 | if (!new) | ||
167 | return -ENOMEM; | ||
168 | thread__insert_map(self, new); | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static struct map *thread__find_map(struct thread *self, u64 ip) | ||
175 | { | ||
176 | struct map *pos; | ||
177 | |||
178 | if (self == NULL) | ||
179 | return NULL; | ||
180 | |||
181 | list_for_each_entry(pos, &self->maps, node) | ||
182 | if (ip >= pos->start && ip <= pos->end) | ||
183 | return pos; | ||
184 | |||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | static size_t threads__fprintf(FILE *fp) | ||
189 | { | ||
190 | size_t ret = 0; | ||
191 | struct rb_node *nd; | ||
192 | |||
193 | for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { | ||
194 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | ||
195 | |||
196 | ret += thread__fprintf(pos, fp); | ||
197 | } | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | /* | 58 | /* |
203 | * histogram, sorted on item, collects counts | 59 | * histogram, sorted on item, collects counts |
204 | */ | 60 | */ |
@@ -624,7 +480,7 @@ static void output__resort(void) | |||
624 | 480 | ||
625 | static void register_idle_thread(void) | 481 | static void register_idle_thread(void) |
626 | { | 482 | { |
627 | struct thread *thread = threads__findnew(0); | 483 | struct thread *thread = threads__findnew(0, &threads, &last_match); |
628 | 484 | ||
629 | if (thread == NULL || | 485 | if (thread == NULL || |
630 | thread__set_comm(thread, "[idle]")) { | 486 | thread__set_comm(thread, "[idle]")) { |
@@ -645,10 +501,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
645 | char level; | 501 | char level; |
646 | int show = 0; | 502 | int show = 0; |
647 | struct dso *dso = NULL; | 503 | struct dso *dso = NULL; |
648 | struct thread *thread = threads__findnew(event->ip.pid); | 504 | struct thread *thread; |
649 | u64 ip = event->ip.ip; | 505 | u64 ip = event->ip.ip; |
650 | struct map *map = NULL; | 506 | struct map *map = NULL; |
651 | 507 | ||
508 | thread = threads__findnew(event->ip.pid, &threads, &last_match); | ||
509 | |||
652 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", | 510 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", |
653 | (void *)(offset + head), | 511 | (void *)(offset + head), |
654 | (void *)(long)(event->header.size), | 512 | (void *)(long)(event->header.size), |
@@ -719,9 +577,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
719 | static int | 577 | static int |
720 | process_mmap_event(event_t *event, unsigned long offset, unsigned long head) | 578 | process_mmap_event(event_t *event, unsigned long offset, unsigned long head) |
721 | { | 579 | { |
722 | struct thread *thread = threads__findnew(event->mmap.pid); | 580 | struct thread *thread; |
723 | struct map *map = map__new(&event->mmap, NULL, 0); | 581 | struct map *map = map__new(&event->mmap, NULL, 0); |
724 | 582 | ||
583 | thread = threads__findnew(event->mmap.pid, &threads, &last_match); | ||
584 | |||
725 | dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", | 585 | dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", |
726 | (void *)(offset + head), | 586 | (void *)(offset + head), |
727 | (void *)(long)(event->header.size), | 587 | (void *)(long)(event->header.size), |
@@ -745,8 +605,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) | |||
745 | static int | 605 | static int |
746 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 606 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) |
747 | { | 607 | { |
748 | struct thread *thread = threads__findnew(event->comm.pid); | 608 | struct thread *thread; |
749 | 609 | ||
610 | thread = threads__findnew(event->comm.pid, &threads, &last_match); | ||
750 | dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", | 611 | dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", |
751 | (void *)(offset + head), | 612 | (void *)(offset + head), |
752 | (void *)(long)(event->header.size), | 613 | (void *)(long)(event->header.size), |
@@ -765,9 +626,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) | |||
765 | static int | 626 | static int |
766 | process_fork_event(event_t *event, unsigned long offset, unsigned long head) | 627 | process_fork_event(event_t *event, unsigned long offset, unsigned long head) |
767 | { | 628 | { |
768 | struct thread *thread = threads__findnew(event->fork.pid); | 629 | struct thread *thread; |
769 | struct thread *parent = threads__findnew(event->fork.ppid); | 630 | struct thread *parent; |
770 | 631 | ||
632 | thread = threads__findnew(event->fork.pid, &threads, &last_match); | ||
633 | parent = threads__findnew(event->fork.ppid, &threads, &last_match); | ||
771 | dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", | 634 | dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", |
772 | (void *)(offset + head), | 635 | (void *)(offset + head), |
773 | (void *)(long)(event->header.size), | 636 | (void *)(long)(event->header.size), |
@@ -1202,7 +1065,7 @@ more: | |||
1202 | return 0; | 1065 | return 0; |
1203 | 1066 | ||
1204 | if (verbose >= 3) | 1067 | if (verbose >= 3) |
1205 | threads__fprintf(stdout); | 1068 | threads__fprintf(stdout, &threads); |
1206 | 1069 | ||
1207 | if (verbose >= 2) | 1070 | if (verbose >= 2) |
1208 | dsos__fprintf(stdout); | 1071 | dsos__fprintf(stdout); |