aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-10-22 17:23:23 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-23 01:55:18 -0400
commita4fb581b15949cfd10b64c8af37bc106e95307f3 (patch)
tree6c7606626388485266ef527700524e5ad7ea5a9d /tools
parentaf0a6fa46388e1e0c2d1a672aad84f8f6ef0b20b (diff)
perf tools: Bind callchains to the first sort dimension column
Currently, the callchains are displayed using a constant left margin. So depending on the current sort dimension configuration, callchains may appear to be well attached to the first sort dimension column field which is mostly the case, except when the first dimension of sorting is done by comm, because these are right aligned. This patch binds the callchain to the first letter in the first column, whatever type of column it is (dso, comm, symbol). Before: 0.80% perf [k] __lock_acquire __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify | | __fsnotify_parent After: 0.80% perf [k] __lock_acquire __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify | | __fsnotify_parent Also, for clarity, we don't put anymore the callchain as is but: - If we have a top level ancestor in the callchain, start it with a first ascii hook. Before: 0.80% perf [kernel] [k] __lock_acquire __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify [..] [..] After: 0.80% perf [kernel] [k] __lock_acquire | --- __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify [..] [..] - Otherwise, if we have several top level ancestors, then display these like we did before: 1.69% Xorg | |--21.21%-- vread_hpet | 0x7fffd85b46fc | 0x7fffd85b494d | 0x7f4fafb4e54d | |--15.15%-- exaOffscreenAlloc | |--9.09%-- I830WaitLpRing 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> Cc: Paul Mackerras <paulus@samba.org> Cc: Anton Blanchard <anton@samba.org> LKML-Reference: <1256246604-17156-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-report.c82
-rw-r--r--tools/perf/util/sort.c18
-rw-r--r--tools/perf/util/sort.h10
-rw-r--r--tools/perf/util/thread.c11
-rw-r--r--tools/perf/util/thread.h2
5 files changed, 99 insertions, 24 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3d8c52220f1f..72d58421223d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -59,12 +59,28 @@ static struct perf_header *header;
59 59
60static u64 sample_type; 60static u64 sample_type;
61 61
62static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask) 62
63static size_t
64callchain__fprintf_left_margin(FILE *fp, int left_margin)
65{
66 int i;
67 int ret;
68
69 ret = fprintf(fp, " ");
70
71 for (i = 0; i < left_margin; i++)
72 ret += fprintf(fp, " ");
73
74 return ret;
75}
76
77static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
78 int left_margin)
63{ 79{
64 int i; 80 int i;
65 size_t ret = 0; 81 size_t ret = 0;
66 82
67 ret += fprintf(fp, "%s", " "); 83 ret += callchain__fprintf_left_margin(fp, left_margin);
68 84
69 for (i = 0; i < depth; i++) 85 for (i = 0; i < depth; i++)
70 if (depth_mask & (1 << i)) 86 if (depth_mask & (1 << i))
@@ -79,12 +95,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
79static size_t 95static size_t
80ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, 96ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
81 int depth_mask, int count, u64 total_samples, 97 int depth_mask, int count, u64 total_samples,
82 int hits) 98 int hits, int left_margin)
83{ 99{
84 int i; 100 int i;
85 size_t ret = 0; 101 size_t ret = 0;
86 102
87 ret += fprintf(fp, "%s", " "); 103 ret += callchain__fprintf_left_margin(fp, left_margin);
88 for (i = 0; i < depth; i++) { 104 for (i = 0; i < depth; i++) {
89 if (depth_mask & (1 << i)) 105 if (depth_mask & (1 << i))
90 ret += fprintf(fp, "|"); 106 ret += fprintf(fp, "|");
@@ -123,7 +139,8 @@ static void init_rem_hits(void)
123 139
124static size_t 140static size_t
125__callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 141__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
126 u64 total_samples, int depth, int depth_mask) 142 u64 total_samples, int depth, int depth_mask,
143 int left_margin)
127{ 144{
128 struct rb_node *node, *next; 145 struct rb_node *node, *next;
129 struct callchain_node *child; 146 struct callchain_node *child;
@@ -164,7 +181,8 @@ __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
164 * But we keep the older depth mask for the line seperator 181 * But we keep the older depth mask for the line seperator
165 * to keep the level link until we reach the last child 182 * to keep the level link until we reach the last child
166 */ 183 */
167 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask); 184 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
185 left_margin);
168 i = 0; 186 i = 0;
169 list_for_each_entry(chain, &child->val, list) { 187 list_for_each_entry(chain, &child->val, list) {
170 if (chain->ip >= PERF_CONTEXT_MAX) 188 if (chain->ip >= PERF_CONTEXT_MAX)
@@ -172,11 +190,13 @@ __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
172 ret += ipchain__fprintf_graph(fp, chain, depth, 190 ret += ipchain__fprintf_graph(fp, chain, depth,
173 new_depth_mask, i++, 191 new_depth_mask, i++,
174 new_total, 192 new_total,
175 cumul); 193 cumul,
194 left_margin);
176 } 195 }
177 ret += __callchain__fprintf_graph(fp, child, new_total, 196 ret += __callchain__fprintf_graph(fp, child, new_total,
178 depth + 1, 197 depth + 1,
179 new_depth_mask | (1 << depth)); 198 new_depth_mask | (1 << depth),
199 left_margin);
180 node = next; 200 node = next;
181 } 201 }
182 202
@@ -190,17 +210,19 @@ __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
190 210
191 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 211 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
192 new_depth_mask, 0, new_total, 212 new_depth_mask, 0, new_total,
193 remaining); 213 remaining, left_margin);
194 } 214 }
195 215
196 return ret; 216 return ret;
197} 217}
198 218
219
199static size_t 220static size_t
200callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 221callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
201 u64 total_samples) 222 u64 total_samples, int left_margin)
202{ 223{
203 struct callchain_list *chain; 224 struct callchain_list *chain;
225 bool printed = false;
204 int i = 0; 226 int i = 0;
205 int ret = 0; 227 int ret = 0;
206 228
@@ -208,17 +230,27 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
208 if (chain->ip >= PERF_CONTEXT_MAX) 230 if (chain->ip >= PERF_CONTEXT_MAX)
209 continue; 231 continue;
210 232
211 if (!i++ && sort_by_sym_first) 233 if (!i++ && sort__first_dimension == SORT_SYM)
212 continue; 234 continue;
213 235
236 if (!printed) {
237 ret += callchain__fprintf_left_margin(fp, left_margin);
238 ret += fprintf(fp, "|\n");
239 ret += callchain__fprintf_left_margin(fp, left_margin);
240 ret += fprintf(fp, "---");
241
242 left_margin += 3;
243 printed = true;
244 } else
245 ret += callchain__fprintf_left_margin(fp, left_margin);
246
214 if (chain->sym) 247 if (chain->sym)
215 ret += fprintf(fp, " %s\n", chain->sym->name); 248 ret += fprintf(fp, " %s\n", chain->sym->name);
216 else 249 else
217 ret += fprintf(fp, " %p\n", 250 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
218 (void *)(long)chain->ip);
219 } 251 }
220 252
221 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1); 253 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
222 254
223 return ret; 255 return ret;
224} 256}
@@ -251,7 +283,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
251 283
252static size_t 284static size_t
253hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, 285hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
254 u64 total_samples) 286 u64 total_samples, int left_margin)
255{ 287{
256 struct rb_node *rb_node; 288 struct rb_node *rb_node;
257 struct callchain_node *chain; 289 struct callchain_node *chain;
@@ -271,7 +303,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
271 break; 303 break;
272 case CHAIN_GRAPH_ABS: /* Falldown */ 304 case CHAIN_GRAPH_ABS: /* Falldown */
273 case CHAIN_GRAPH_REL: 305 case CHAIN_GRAPH_REL:
274 ret += callchain__fprintf_graph(fp, chain, total_samples); 306 ret += callchain__fprintf_graph(fp, chain, total_samples,
307 left_margin);
275 case CHAIN_NONE: 308 case CHAIN_NONE:
276 default: 309 default:
277 break; 310 break;
@@ -316,8 +349,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
316 349
317 ret += fprintf(fp, "\n"); 350 ret += fprintf(fp, "\n");
318 351
319 if (callchain) 352 if (callchain) {
320 hist_entry_callchain__fprintf(fp, self, total_samples); 353 int left_margin = 0;
354
355 if (sort__first_dimension == SORT_COMM) {
356 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
357 list);
358 left_margin = se->width ? *se->width : 0;
359 left_margin -= thread__comm_len(self->thread);
360 }
361
362 hist_entry_callchain__fprintf(fp, self, total_samples,
363 left_margin);
364 }
321 365
322 return ret; 366 return ret;
323} 367}
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 60ced707bd6b..b490354d1b23 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -7,7 +7,8 @@ char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order; 7char *sort_order = default_sort_order;
8int sort__need_collapse = 0; 8int sort__need_collapse = 0;
9int sort__has_parent = 0; 9int sort__has_parent = 0;
10int sort_by_sym_first; 10
11enum sort_type sort__first_dimension;
11 12
12unsigned int dsos__col_width; 13unsigned int dsos__col_width;
13unsigned int comms__col_width; 14unsigned int comms__col_width;
@@ -266,9 +267,18 @@ int sort_dimension__add(const char *tok)
266 sort__has_parent = 1; 267 sort__has_parent = 1;
267 } 268 }
268 269
269 if (list_empty(&hist_entry__sort_list) && 270 if (list_empty(&hist_entry__sort_list)) {
270 !strcmp(sd->name, "symbol")) 271 if (!strcmp(sd->name, "pid"))
271 sort_by_sym_first = true; 272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
272 282
273 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
274 sd->taken = 1; 284 sd->taken = 1;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 24c2b709f0d3..333e664ff45f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -39,7 +39,7 @@ extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width; 39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width; 40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width; 41extern unsigned int threads__col_width;
42extern int sort_by_sym_first; 42extern enum sort_type sort__first_dimension;
43 43
44struct hist_entry { 44struct hist_entry {
45 struct rb_node rb_node; 45 struct rb_node rb_node;
@@ -54,6 +54,14 @@ struct hist_entry {
54 struct rb_root sorted_chain; 54 struct rb_root sorted_chain;
55}; 55};
56 56
57enum sort_type {
58 SORT_PID,
59 SORT_COMM,
60 SORT_DSO,
61 SORT_SYM,
62 SORT_PARENT
63};
64
57/* 65/*
58 * configurable sorting bits 66 * configurable sorting bits
59 */ 67 */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index f53fad7c0a8d..8cb47f1d8a76 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -33,6 +33,17 @@ int thread__set_comm(struct thread *self, const char *comm)
33 return self->comm ? 0 : -ENOMEM; 33 return self->comm ? 0 : -ENOMEM;
34} 34}
35 35
36int thread__comm_len(struct thread *self)
37{
38 if (!self->comm_len) {
39 if (!self->comm)
40 return 0;
41 self->comm_len = strlen(self->comm);
42 }
43
44 return self->comm_len;
45}
46
36static size_t thread__fprintf(struct thread *self, FILE *fp) 47static size_t thread__fprintf(struct thread *self, FILE *fp)
37{ 48{
38 struct rb_node *nd; 49 struct rb_node *nd;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 1abef3b7455d..53addd77ce8f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -12,9 +12,11 @@ struct thread {
12 pid_t pid; 12 pid_t pid;
13 char shortname[3]; 13 char shortname[3];
14 char *comm; 14 char *comm;
15 int comm_len;
15}; 16};
16 17
17int thread__set_comm(struct thread *self, const char *comm); 18int thread__set_comm(struct thread *self, const char *comm);
19int thread__comm_len(struct thread *self);
18struct thread *threads__findnew(pid_t pid); 20struct thread *threads__findnew(pid_t pid);
19struct thread *register_idle_thread(void); 21struct thread *register_idle_thread(void);
20void thread__insert_map(struct thread *self, struct map *map); 22void thread__insert_map(struct thread *self, struct map *map);