aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrice Goglin <Brice.Goglin@inria.fr>2009-08-07 07:55:24 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-09 07:04:20 -0400
commit8d51327090ac025d7f4ce6c059786b5e93513321 (patch)
tree32576a197af970ac698c7888c67235e8f723fa67
parent30dd568c912602b7dbd609a45d053e01b13422bb (diff)
perf report: Fix and improve the displaying of per-thread event counters
Improve and fix the handling of per-thread counter stats recorded via perf record -s. Previously we only displayed it in debug printouts (-D) and even that output was hard to disambiguate. I moved everything to utils/values.[ch] so that we may reuse it in perf stat. We get something like this now: # PID TID cache-misses cache-references 4658 4659 495581 3238779 4658 4662 498246 3236823 4658 4663 499531 3243162 Then it'll be easy to add --pretty=raw to display a single line per thread/event. By the way, -S was also used for --symbol... So I used -T/--thread here. perf report: Add -T/--threads to display per-thread counter values We get something like this now: # PID TID cache-misses cache-references 4658 4659 495581 3238779 4658 4662 498246 3236823 4658 4663 499531 3243162 Per-thread arrays of counter values are managed in utils/values.[ch] Signed-off-by: Brice Goglin <Brice.Goglin@inria.fr> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: paulus@samba.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--tools/perf/Documentation/perf-report.txt3
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/builtin-report.c25
-rw-r--r--tools/perf/util/values.c171
-rw-r--r--tools/perf/util/values.h26
5 files changed, 227 insertions, 0 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index e72e93110782..370344afb5b2 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -27,6 +27,9 @@ OPTIONS
27-n 27-n
28--show-nr-samples 28--show-nr-samples
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T
31--threads
32 Show per-thread event counters
30-C:: 33-C::
31--comms=:: 34--comms=::
32 Only consider symbols in these comms. CSV that understands 35 Only consider symbols in these comms. CSV that understands
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 60411e94113b..de7beac1095e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -310,6 +310,7 @@ LIB_H += util/sigchain.h
310LIB_H += util/symbol.h 310LIB_H += util/symbol.h
311LIB_H += util/module.h 311LIB_H += util/module.h
312LIB_H += util/color.h 312LIB_H += util/color.h
313LIB_H += util/values.h
313 314
314LIB_OBJS += util/abspath.o 315LIB_OBJS += util/abspath.o
315LIB_OBJS += util/alias.o 316LIB_OBJS += util/alias.o
@@ -337,6 +338,7 @@ LIB_OBJS += util/color.o
337LIB_OBJS += util/pager.o 338LIB_OBJS += util/pager.o
338LIB_OBJS += util/header.o 339LIB_OBJS += util/header.o
339LIB_OBJS += util/callchain.o 340LIB_OBJS += util/callchain.o
341LIB_OBJS += util/values.o
340 342
341BUILTIN_OBJS += builtin-annotate.o 343BUILTIN_OBJS += builtin-annotate.o
342BUILTIN_OBJS += builtin-help.o 344BUILTIN_OBJS += builtin-help.o
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 99274cec0adb..41639182fb3f 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -17,6 +17,7 @@
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h" 18#include "util/callchain.h"
19#include "util/strlist.h" 19#include "util/strlist.h"
20#include "util/values.h"
20 21
21#include "perf.h" 22#include "perf.h"
22#include "util/header.h" 23#include "util/header.h"
@@ -53,6 +54,9 @@ static int modules;
53static int full_paths; 54static int full_paths;
54static int show_nr_samples; 55static int show_nr_samples;
55 56
57static int show_threads;
58static struct perf_read_values show_threads_values;
59
56static unsigned long page_size; 60static unsigned long page_size;
57static unsigned long mmap_window = 32; 61static unsigned long mmap_window = 32;
58 62
@@ -1473,6 +1477,9 @@ print_entries:
1473 1477
1474 free(rem_sq_bracket); 1478 free(rem_sq_bracket);
1475 1479
1480 if (show_threads)
1481 perf_read_values_display(fp, &show_threads_values);
1482
1476 return ret; 1483 return ret;
1477} 1484}
1478 1485
@@ -1758,6 +1765,16 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1758{ 1765{
1759 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); 1766 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1760 1767
1768 if (show_threads) {
1769 char *name = attr ? __event_name(attr->type, attr->config)
1770 : "unknown";
1771 perf_read_values_add_value(&show_threads_values,
1772 event->read.pid, event->read.tid,
1773 event->read.id,
1774 name,
1775 event->read.value);
1776 }
1777
1761 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", 1778 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1762 (void *)(offset + head), 1779 (void *)(offset + head),
1763 (void *)(long)(event->header.size), 1780 (void *)(long)(event->header.size),
@@ -1839,6 +1856,9 @@ static int __cmd_report(void)
1839 1856
1840 register_idle_thread(); 1857 register_idle_thread();
1841 1858
1859 if (show_threads)
1860 perf_read_values_init(&show_threads_values);
1861
1842 input = open(input_name, O_RDONLY); 1862 input = open(input_name, O_RDONLY);
1843 if (input < 0) { 1863 if (input < 0) {
1844 fprintf(stderr, " failed to open file: %s", input_name); 1864 fprintf(stderr, " failed to open file: %s", input_name);
@@ -1993,6 +2013,9 @@ done:
1993 output__resort(total); 2013 output__resort(total);
1994 output__fprintf(stdout, total); 2014 output__fprintf(stdout, total);
1995 2015
2016 if (show_threads)
2017 perf_read_values_destroy(&show_threads_values);
2018
1996 return rc; 2019 return rc;
1997} 2020}
1998 2021
@@ -2066,6 +2089,8 @@ static const struct option options[] = {
2066 "load module symbols - WARNING: use only with -k and LIVE kernel"), 2089 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2067 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 2090 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2068 "Show a column with the number of samples"), 2091 "Show a column with the number of samples"),
2092 OPT_BOOLEAN('T', "threads", &show_threads,
2093 "Show per-thread event counters"),
2069 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2094 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
2070 "sort by key(s): pid, comm, dso, symbol, parent"), 2095 "sort by key(s): pid, comm, dso, symbol, parent"),
2071 OPT_BOOLEAN('P', "full-paths", &full_paths, 2096 OPT_BOOLEAN('P', "full-paths", &full_paths,
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
new file mode 100644
index 000000000000..8551c0b8b233
--- /dev/null
+++ b/tools/perf/util/values.c
@@ -0,0 +1,171 @@
1#include <stdlib.h>
2
3#include "util.h"
4#include "values.h"
5
6void perf_read_values_init(struct perf_read_values *values)
7{
8 values->threads_max = 16;
9 values->pid = malloc(values->threads_max * sizeof(*values->pid));
10 values->tid = malloc(values->threads_max * sizeof(*values->tid));
11 values->value = malloc(values->threads_max * sizeof(*values->value));
12 if (!values->pid || !values->tid || !values->value)
13 die("failed to allocate read_values threads arrays");
14 values->threads = 0;
15
16 values->counters_max = 16;
17 values->counterrawid = malloc(values->counters_max
18 * sizeof(*values->counterrawid));
19 values->countername = malloc(values->counters_max
20 * sizeof(*values->countername));
21 if (!values->counterrawid || !values->countername)
22 die("failed to allocate read_values counters arrays");
23 values->counters = 0;
24}
25
26void perf_read_values_destroy(struct perf_read_values *values)
27{
28 int i;
29
30 if (!values->threads_max || !values->counters_max)
31 return;
32
33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]);
35 free(values->pid);
36 free(values->tid);
37 free(values->counterrawid);
38 for (i = 0; i < values->counters; i++)
39 free(values->countername[i]);
40 free(values->countername);
41}
42
43static void perf_read_values__enlarge_threads(struct perf_read_values *values)
44{
45 values->threads_max *= 2;
46 values->pid = realloc(values->pid,
47 values->threads_max * sizeof(*values->pid));
48 values->tid = realloc(values->tid,
49 values->threads_max * sizeof(*values->tid));
50 values->value = realloc(values->value,
51 values->threads_max * sizeof(*values->value));
52 if (!values->pid || !values->tid || !values->value)
53 die("failed to enlarge read_values threads arrays");
54}
55
56static int perf_read_values__findnew_thread(struct perf_read_values *values,
57 u32 pid, u32 tid)
58{
59 int i;
60
61 for (i = 0; i < values->threads; i++)
62 if (values->pid[i] == pid && values->tid[i] == tid)
63 return i;
64
65 if (values->threads == values->threads_max)
66 perf_read_values__enlarge_threads(values);
67
68 i = values->threads++;
69 values->pid[i] = pid;
70 values->tid[i] = tid;
71 values->value[i] = malloc(values->counters_max * sizeof(**values->value));
72 if (!values->value[i])
73 die("failed to allocate read_values counters array");
74
75 return i;
76}
77
78static void perf_read_values__enlarge_counters(struct perf_read_values *values)
79{
80 int i;
81
82 values->counters_max *= 2;
83 values->counterrawid = realloc(values->counterrawid,
84 values->counters_max * sizeof(*values->counterrawid));
85 values->countername = realloc(values->countername,
86 values->counters_max * sizeof(*values->countername));
87 if (!values->counterrawid || !values->countername)
88 die("failed to enlarge read_values counters arrays");
89
90 for (i = 0; i < values->threads; i++) {
91 values->value[i] = realloc(values->value[i],
92 values->counters_max * sizeof(**values->value));
93 if (!values->value[i])
94 die("failed to enlarge read_values counters arrays");
95 }
96}
97
98static int perf_read_values__findnew_counter(struct perf_read_values *values,
99 u64 rawid, char *name)
100{
101 int i;
102
103 for (i = 0; i < values->counters; i++)
104 if (values->counterrawid[i] == rawid)
105 return i;
106
107 if (values->counters == values->counters_max)
108 perf_read_values__enlarge_counters(values);
109
110 i = values->counters++;
111 values->counterrawid[i] = rawid;
112 values->countername[i] = strdup(name);
113
114 return i;
115}
116
117void perf_read_values_add_value(struct perf_read_values *values,
118 u32 pid, u32 tid,
119 u64 rawid, char *name, u64 value)
120{
121 int tindex, cindex;
122
123 tindex = perf_read_values__findnew_thread(values, pid, tid);
124 cindex = perf_read_values__findnew_counter(values, rawid, name);
125
126 values->value[tindex][cindex] = value;
127}
128
129void perf_read_values_display(FILE *fp, struct perf_read_values *values)
130{
131 int i, j;
132 int pidwidth, tidwidth;
133 int *counterwidth;
134
135 counterwidth = malloc(values->counters * sizeof(*counterwidth));
136 if (!counterwidth)
137 die("failed to allocate counterwidth array");
138 tidwidth = 3;
139 pidwidth = 3;
140 for (j = 0; j < values->counters; j++)
141 counterwidth[j] = strlen(values->countername[j]);
142 for (i = 0; i < values->threads; i++) {
143 int width;
144
145 width = snprintf(NULL, 0, "%d", values->pid[i]);
146 if (width > pidwidth)
147 pidwidth = width;
148 width = snprintf(NULL, 0, "%d", values->tid[i]);
149 if (width > tidwidth)
150 tidwidth = width;
151 for (j = 0; j < values->counters; j++) {
152 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
153 if (width > counterwidth[j])
154 counterwidth[j] = width;
155 }
156 }
157
158 fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
159 for (j = 0; j < values->counters; j++)
160 fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
161 fprintf(fp, "\n");
162
163 for (i = 0; i < values->threads; i++) {
164 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
165 tidwidth, values->tid[i]);
166 for (j = 0; j < values->counters; j++)
167 fprintf(fp, " %*Lu",
168 counterwidth[j], values->value[i][j]);
169 fprintf(fp, "\n");
170 }
171}
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
new file mode 100644
index 000000000000..e41be5e86e6b
--- /dev/null
+++ b/tools/perf/util/values.h
@@ -0,0 +1,26 @@
1#ifndef _PERF_VALUES_H
2#define _PERF_VALUES_H
3
4#include "types.h"
5
6struct perf_read_values {
7 int threads;
8 int threads_max;
9 u32 *pid, *tid;
10 int counters;
11 int counters_max;
12 u64 *counterrawid;
13 char **countername;
14 u64 **value;
15};
16
17void perf_read_values_init(struct perf_read_values *values);
18void perf_read_values_destroy(struct perf_read_values *values);
19
20void perf_read_values_add_value(struct perf_read_values *values,
21 u32 pid, u32 tid,
22 u64 rawid, char *name, u64 value);
23
24void perf_read_values_display(FILE *fp, struct perf_read_values *values);
25
26#endif /* _PERF_VALUES_H */