diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-01-03 14:48:12 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-01-03 21:23:27 -0500 |
commit | 48290609c0d265f5dac0fca6fd4e3c5732542f67 (patch) | |
tree | 7fc8099ae02b78562cca245364cd44197d3ae9a3 /tools/perf | |
parent | c52b12ed2511e6c031a0295fd903ea72b93701fb (diff) |
perf evsel: Introduce per cpu and per thread open helpers
Abstracting away the loops needed to create the various event fd handlers.
The users have to pass a confiruged perf->evsel.attr field, which is already
usable after perf_evsel__new (constructor) time, using defaults.
Comes out of the ad-hoc routines in builtin-stat, that now uses it.
Fixed a small silly bug where we were die()ing before killing our
children, dysfunctional family this one 8-)
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-stat.c | 84 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 52 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 5 |
3 files changed, 83 insertions, 58 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a8b00b44b3cd..065e79eb2142 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -53,8 +53,6 @@ | |||
53 | #include <math.h> | 53 | #include <math.h> |
54 | #include <locale.h> | 54 | #include <locale.h> |
55 | 55 | ||
56 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | ||
57 | |||
58 | #define DEFAULT_SEPARATOR " " | 56 | #define DEFAULT_SEPARATOR " " |
59 | 57 | ||
60 | static struct perf_event_attr default_attrs[] = { | 58 | static struct perf_event_attr default_attrs[] = { |
@@ -160,56 +158,24 @@ struct stats runtime_cycles_stats[MAX_NR_CPUS]; | |||
160 | struct stats runtime_branches_stats[MAX_NR_CPUS]; | 158 | struct stats runtime_branches_stats[MAX_NR_CPUS]; |
161 | struct stats walltime_nsecs_stats; | 159 | struct stats walltime_nsecs_stats; |
162 | 160 | ||
163 | #define ERR_PERF_OPEN \ | 161 | static int create_perf_stat_counter(struct perf_evsel *evsel) |
164 | "counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information." | ||
165 | |||
166 | static int create_perf_stat_counter(struct perf_evsel *evsel, bool *perm_err) | ||
167 | { | 162 | { |
168 | struct perf_event_attr *attr = &evsel->attr; | 163 | struct perf_event_attr *attr = &evsel->attr; |
169 | int thread; | ||
170 | int ncreated = 0; | ||
171 | 164 | ||
172 | if (scale) | 165 | if (scale) |
173 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 166 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
174 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 167 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
175 | 168 | ||
176 | if (system_wide) { | 169 | if (system_wide) |
177 | int cpu; | 170 | return perf_evsel__open_per_cpu(evsel, nr_cpus, cpumap); |
178 | 171 | ||
179 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 172 | attr->inherit = !no_inherit; |
180 | FD(evsel, cpu, 0) = sys_perf_event_open(attr, | 173 | if (target_pid == -1 && target_tid == -1) { |
181 | -1, cpumap[cpu], -1, 0); | 174 | attr->disabled = 1; |
182 | if (FD(evsel, cpu, 0) < 0) { | 175 | attr->enable_on_exec = 1; |
183 | if (errno == EPERM || errno == EACCES) | ||
184 | *perm_err = true; | ||
185 | error(ERR_PERF_OPEN, evsel->idx, | ||
186 | FD(evsel, cpu, 0), strerror(errno)); | ||
187 | } else { | ||
188 | ++ncreated; | ||
189 | } | ||
190 | } | ||
191 | } else { | ||
192 | attr->inherit = !no_inherit; | ||
193 | if (target_pid == -1 && target_tid == -1) { | ||
194 | attr->disabled = 1; | ||
195 | attr->enable_on_exec = 1; | ||
196 | } | ||
197 | for (thread = 0; thread < thread_num; thread++) { | ||
198 | FD(evsel, 0, thread) = sys_perf_event_open(attr, | ||
199 | all_tids[thread], -1, -1, 0); | ||
200 | if (FD(evsel, 0, thread) < 0) { | ||
201 | if (errno == EPERM || errno == EACCES) | ||
202 | *perm_err = true; | ||
203 | error(ERR_PERF_OPEN, evsel->idx, | ||
204 | FD(evsel, 0, thread), | ||
205 | strerror(errno)); | ||
206 | } else { | ||
207 | ++ncreated; | ||
208 | } | ||
209 | } | ||
210 | } | 176 | } |
211 | 177 | ||
212 | return ncreated; | 178 | return perf_evsel__open_per_thread(evsel, thread_num, all_tids); |
213 | } | 179 | } |
214 | 180 | ||
215 | /* | 181 | /* |
@@ -289,9 +255,7 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
289 | unsigned long long t0, t1; | 255 | unsigned long long t0, t1; |
290 | struct perf_evsel *counter; | 256 | struct perf_evsel *counter; |
291 | int status = 0; | 257 | int status = 0; |
292 | int ncreated = 0; | ||
293 | int child_ready_pipe[2], go_pipe[2]; | 258 | int child_ready_pipe[2], go_pipe[2]; |
294 | bool perm_err = false; | ||
295 | const bool forks = (argc > 0); | 259 | const bool forks = (argc > 0); |
296 | char buf; | 260 | char buf; |
297 | 261 | ||
@@ -349,19 +313,23 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
349 | close(child_ready_pipe[0]); | 313 | close(child_ready_pipe[0]); |
350 | } | 314 | } |
351 | 315 | ||
352 | list_for_each_entry(counter, &evsel_list, node) | 316 | list_for_each_entry(counter, &evsel_list, node) { |
353 | ncreated += create_perf_stat_counter(counter, &perm_err); | 317 | if (create_perf_stat_counter(counter) < 0) { |
354 | 318 | if (errno == -EPERM || errno == -EACCES) { | |
355 | if (ncreated < nr_counters) { | 319 | error("You may not have permission to collect %sstats.\n" |
356 | if (perm_err) | 320 | "\t Consider tweaking" |
357 | error("You may not have permission to collect %sstats.\n" | 321 | " /proc/sys/kernel/perf_event_paranoid or running as root.", |
358 | "\t Consider tweaking" | 322 | system_wide ? "system-wide " : ""); |
359 | " /proc/sys/kernel/perf_event_paranoid or running as root.", | 323 | } else { |
360 | system_wide ? "system-wide " : ""); | 324 | error("open_counter returned with %d (%s). " |
361 | die("Not all events could be opened.\n"); | 325 | "/bin/dmesg may provide additional information.\n", |
362 | if (child_pid != -1) | 326 | errno, strerror(errno)); |
363 | kill(child_pid, SIGTERM); | 327 | } |
364 | return -1; | 328 | if (child_pid != -1) |
329 | kill(child_pid, SIGTERM); | ||
330 | die("Not all events could be opened.\n"); | ||
331 | return -1; | ||
332 | } | ||
365 | } | 333 | } |
366 | 334 | ||
367 | /* | 335 | /* |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3f5de5196231..e62cc5e050ab 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include "evsel.h" | 1 | #include "evsel.h" |
2 | #include "../perf.h" | ||
2 | #include "util.h" | 3 | #include "util.h" |
3 | 4 | ||
4 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 5 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
@@ -121,3 +122,54 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
121 | 122 | ||
122 | return 0; | 123 | return 0; |
123 | } | 124 | } |
125 | |||
126 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, int ncpus, int *cpu_map) | ||
127 | { | ||
128 | int cpu; | ||
129 | |||
130 | for (cpu = 0; cpu < ncpus; cpu++) { | ||
131 | FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1, | ||
132 | cpu_map[cpu], -1, 0); | ||
133 | if (FD(evsel, cpu, 0) < 0) | ||
134 | goto out_close; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | |||
139 | out_close: | ||
140 | while (--cpu >= 0) { | ||
141 | close(FD(evsel, cpu, 0)); | ||
142 | FD(evsel, cpu, 0) = -1; | ||
143 | } | ||
144 | return -1; | ||
145 | } | ||
146 | |||
147 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, int nthreads, int *thread_map) | ||
148 | { | ||
149 | int thread; | ||
150 | |||
151 | for (thread = 0; thread < nthreads; thread++) { | ||
152 | FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr, | ||
153 | thread_map[thread], -1, -1, 0); | ||
154 | if (FD(evsel, 0, thread) < 0) | ||
155 | goto out_close; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | |||
160 | out_close: | ||
161 | while (--thread >= 0) { | ||
162 | close(FD(evsel, 0, thread)); | ||
163 | FD(evsel, 0, thread) = -1; | ||
164 | } | ||
165 | return -1; | ||
166 | } | ||
167 | |||
168 | int perf_evsel__open(struct perf_evsel *evsel, int ncpus, int nthreads, | ||
169 | int *cpu_map, int *thread_map) | ||
170 | { | ||
171 | if (nthreads < 0) | ||
172 | return perf_evsel__open_per_cpu(evsel, ncpus, cpu_map); | ||
173 | |||
174 | return perf_evsel__open_per_thread(evsel, nthreads, thread_map); | ||
175 | } | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 8b48ef1e672c..a62fb55cffa7 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -42,6 +42,11 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | |||
42 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 42 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
43 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 43 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
44 | 44 | ||
45 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, int ncpus, int *cpu_map); | ||
46 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, int nthreads, int *thread_map); | ||
47 | int perf_evsel__open(struct perf_evsel *evsel, int ncpus, int nthreads, | ||
48 | int *cpu_map, int *thread_map); | ||
49 | |||
45 | #define perf_evsel__match(evsel, t, c) \ | 50 | #define perf_evsel__match(evsel, t, c) \ |
46 | (evsel->attr.type == PERF_TYPE_##t && \ | 51 | (evsel->attr.type == PERF_TYPE_##t && \ |
47 | evsel->attr.config == PERF_COUNT_##c) | 52 | evsel->attr.config == PERF_COUNT_##c) |