diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-09-28 13:48:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-09-30 07:57:56 -0400 |
commit | 1b46cddfccfec4cc67b187fb53d78198de6a057c (patch) | |
tree | 813836ec58396e15008bfb39e7209a6bcc6e2f58 /tools/perf/util/thread.c | |
parent | 3d1d07ecd2009f65cb2091563fa21f9600c36774 (diff) |
perf tools: Use rb_tree for maps
Threads can have many and kernel modules will be represented as a
tree of maps as well.
Ah, and for a perf.data with 146607 samples:
Before:
[root@doppio ~]# perf stat -r 5 perf report > /dev/null
Performance counter stats for 'perf report' (5 runs):
699.823680 task-clock-msecs # 0.991 CPUs ( +- 0.454% )
74 context-switches # 0.000 M/sec ( +- 1.709% )
2 CPU-migrations # 0.000 M/sec ( +- 17.008% )
23114 page-faults # 0.033 M/sec ( +- 0.000% )
1381257019 cycles # 1973.721 M/sec ( +- 0.290% )
1456894438 instructions # 1.055 IPC ( +- 0.007% )
18779818 cache-references # 26.835 M/sec ( +- 0.380% )
641799 cache-misses # 0.917 M/sec ( +- 1.200% )
0.705972729 seconds time elapsed ( +- 0.501% )
[root@doppio ~]#
After
Performance counter stats for 'perf report' (5 runs):
691.261451 task-clock-msecs # 0.993 CPUs ( +- 0.307% )
72 context-switches # 0.000 M/sec ( +- 0.829% )
6 CPU-migrations # 0.000 M/sec ( +- 18.409% )
23127 page-faults # 0.033 M/sec ( +- 0.000% )
1366395876 cycles # 1976.670 M/sec ( +- 0.153% )
1443136016 instructions # 1.056 IPC ( +- 0.012% )
17956402 cache-references # 25.976 M/sec ( +- 0.325% )
661924 cache-misses # 0.958 M/sec ( +- 1.335% )
0.696127275 seconds time elapsed ( +- 0.377% )
I.e. we see some speedup too.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
LKML-Reference: <20090928174846.GA3361@ghostprotocols.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/thread.c')
-rw-r--r-- | tools/perf/util/thread.c | 129 |
1 files changed, 83 insertions, 46 deletions
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45efb5db0d19..9d0945cc66d1 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -15,7 +15,7 @@ static struct thread *thread__new(pid_t pid) | |||
15 | self->comm = malloc(32); | 15 | self->comm = malloc(32); |
16 | if (self->comm) | 16 | if (self->comm) |
17 | snprintf(self->comm, 32, ":%d", self->pid); | 17 | snprintf(self->comm, 32, ":%d", self->pid); |
18 | INIT_LIST_HEAD(&self->maps); | 18 | self->maps = RB_ROOT; |
19 | } | 19 | } |
20 | 20 | ||
21 | return self; | 21 | return self; |
@@ -31,11 +31,13 @@ int thread__set_comm(struct thread *self, const char *comm) | |||
31 | 31 | ||
32 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 32 | static size_t thread__fprintf(struct thread *self, FILE *fp) |
33 | { | 33 | { |
34 | struct map *pos; | 34 | struct rb_node *nd; |
35 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); | 35 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); |
36 | 36 | ||
37 | list_for_each_entry(pos, &self->maps, node) | 37 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { |
38 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
38 | ret += map__fprintf(pos, fp); | 39 | ret += map__fprintf(pos, fp); |
40 | } | ||
39 | 41 | ||
40 | return ret; | 42 | return ret; |
41 | } | 43 | } |
@@ -93,42 +95,90 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match) | |||
93 | return thread; | 95 | return thread; |
94 | } | 96 | } |
95 | 97 | ||
96 | void thread__insert_map(struct thread *self, struct map *map) | 98 | static void thread__remove_overlappings(struct thread *self, struct map *map) |
97 | { | 99 | { |
98 | struct map *pos, *tmp; | 100 | struct rb_node *next = rb_first(&self->maps); |
99 | 101 | ||
100 | list_for_each_entry_safe(pos, tmp, &self->maps, node) { | 102 | while (next) { |
101 | if (map__overlap(pos, map)) { | 103 | struct map *pos = rb_entry(next, struct map, rb_node); |
102 | if (verbose >= 2) { | 104 | next = rb_next(&pos->rb_node); |
103 | printf("overlapping maps:\n"); | 105 | |
104 | map__fprintf(map, stdout); | 106 | if (!map__overlap(pos, map)) |
105 | map__fprintf(pos, stdout); | 107 | continue; |
106 | } | 108 | |
107 | 109 | if (verbose >= 2) { | |
108 | if (map->start <= pos->start && map->end > pos->start) | 110 | printf("overlapping maps:\n"); |
109 | pos->start = map->end; | 111 | map__fprintf(map, stdout); |
110 | 112 | map__fprintf(pos, stdout); | |
111 | if (map->end >= pos->end && map->start < pos->end) | 113 | } |
112 | pos->end = map->start; | 114 | |
113 | 115 | if (map->start <= pos->start && map->end > pos->start) | |
114 | if (verbose >= 2) { | 116 | pos->start = map->end; |
115 | printf("after collision:\n"); | 117 | |
116 | map__fprintf(pos, stdout); | 118 | if (map->end >= pos->end && map->start < pos->end) |
117 | } | 119 | pos->end = map->start; |
118 | 120 | ||
119 | if (pos->start >= pos->end) { | 121 | if (verbose >= 2) { |
120 | list_del_init(&pos->node); | 122 | printf("after collision:\n"); |
121 | free(pos); | 123 | map__fprintf(pos, stdout); |
122 | } | 124 | } |
125 | |||
126 | if (pos->start >= pos->end) { | ||
127 | rb_erase(&pos->rb_node, &self->maps); | ||
128 | free(pos); | ||
123 | } | 129 | } |
124 | } | 130 | } |
131 | } | ||
132 | |||
133 | void maps__insert(struct rb_root *maps, struct map *map) | ||
134 | { | ||
135 | struct rb_node **p = &maps->rb_node; | ||
136 | struct rb_node *parent = NULL; | ||
137 | const u64 ip = map->start; | ||
138 | struct map *m; | ||
139 | |||
140 | while (*p != NULL) { | ||
141 | parent = *p; | ||
142 | m = rb_entry(parent, struct map, rb_node); | ||
143 | if (ip < m->start) | ||
144 | p = &(*p)->rb_left; | ||
145 | else | ||
146 | p = &(*p)->rb_right; | ||
147 | } | ||
148 | |||
149 | rb_link_node(&map->rb_node, parent, p); | ||
150 | rb_insert_color(&map->rb_node, maps); | ||
151 | } | ||
152 | |||
153 | struct map *maps__find(struct rb_root *maps, u64 ip) | ||
154 | { | ||
155 | struct rb_node **p = &maps->rb_node; | ||
156 | struct rb_node *parent = NULL; | ||
157 | struct map *m; | ||
158 | |||
159 | while (*p != NULL) { | ||
160 | parent = *p; | ||
161 | m = rb_entry(parent, struct map, rb_node); | ||
162 | if (ip < m->start) | ||
163 | p = &(*p)->rb_left; | ||
164 | else if (ip > m->end) | ||
165 | p = &(*p)->rb_right; | ||
166 | else | ||
167 | return m; | ||
168 | } | ||
169 | |||
170 | return NULL; | ||
171 | } | ||
125 | 172 | ||
126 | list_add_tail(&map->node, &self->maps); | 173 | void thread__insert_map(struct thread *self, struct map *map) |
174 | { | ||
175 | thread__remove_overlappings(self, map); | ||
176 | maps__insert(&self->maps, map); | ||
127 | } | 177 | } |
128 | 178 | ||
129 | int thread__fork(struct thread *self, struct thread *parent) | 179 | int thread__fork(struct thread *self, struct thread *parent) |
130 | { | 180 | { |
131 | struct map *map; | 181 | struct rb_node *nd; |
132 | 182 | ||
133 | if (self->comm) | 183 | if (self->comm) |
134 | free(self->comm); | 184 | free(self->comm); |
@@ -136,7 +186,8 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
136 | if (!self->comm) | 186 | if (!self->comm) |
137 | return -ENOMEM; | 187 | return -ENOMEM; |
138 | 188 | ||
139 | list_for_each_entry(map, &parent->maps, node) { | 189 | for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { |
190 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
140 | struct map *new = map__clone(map); | 191 | struct map *new = map__clone(map); |
141 | if (!new) | 192 | if (!new) |
142 | return -ENOMEM; | 193 | return -ENOMEM; |
@@ -146,20 +197,6 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
146 | return 0; | 197 | return 0; |
147 | } | 198 | } |
148 | 199 | ||
149 | struct map *thread__find_map(struct thread *self, u64 ip) | ||
150 | { | ||
151 | struct map *pos; | ||
152 | |||
153 | if (self == NULL) | ||
154 | return NULL; | ||
155 | |||
156 | list_for_each_entry(pos, &self->maps, node) | ||
157 | if (ip >= pos->start && ip <= pos->end) | ||
158 | return pos; | ||
159 | |||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | size_t threads__fprintf(FILE *fp, struct rb_root *threads) | 200 | size_t threads__fprintf(FILE *fp, struct rb_root *threads) |
164 | { | 201 | { |
165 | size_t ret = 0; | 202 | size_t ret = 0; |