aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);