aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c64
1 files changed, 50 insertions, 14 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c5a290727a92..201ef2367dcb 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -99,7 +99,7 @@ static u64 runtime_cycles_noise;
99#define ERR_PERF_OPEN \ 99#define ERR_PERF_OPEN \
100"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n" 100"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
101 101
102static void create_perf_stat_counter(int counter) 102static void create_perf_stat_counter(int counter, int pid)
103{ 103{
104 struct perf_counter_attr *attr = attrs + counter; 104 struct perf_counter_attr *attr = attrs + counter;
105 105
@@ -119,7 +119,7 @@ static void create_perf_stat_counter(int counter)
119 attr->inherit = inherit; 119 attr->inherit = inherit;
120 attr->disabled = 1; 120 attr->disabled = 1;
121 121
122 fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0); 122 fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
123 if (fd[0][counter] < 0 && verbose) 123 if (fd[0][counter] < 0 && verbose)
124 fprintf(stderr, ERR_PERF_OPEN, counter, 124 fprintf(stderr, ERR_PERF_OPEN, counter,
125 fd[0][counter], strerror(errno)); 125 fd[0][counter], strerror(errno));
@@ -205,12 +205,58 @@ static int run_perf_stat(int argc, const char **argv)
205 int status = 0; 205 int status = 0;
206 int counter; 206 int counter;
207 int pid; 207 int pid;
208 int child_ready_pipe[2], go_pipe[2];
209 char buf;
208 210
209 if (!system_wide) 211 if (!system_wide)
210 nr_cpus = 1; 212 nr_cpus = 1;
211 213
214 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
215 perror("failed to create pipes");
216 exit(1);
217 }
218
219 if ((pid = fork()) < 0)
220 perror("failed to fork");
221
222 if (!pid) {
223 close(child_ready_pipe[0]);
224 close(go_pipe[1]);
225 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
226
227 /*
228 * Do a dummy execvp to get the PLT entry resolved,
229 * so we avoid the resolver overhead on the real
230 * execvp call.
231 */
232 execvp("", (char **)argv);
233
234 /*
235 * Tell the parent we're ready to go
236 */
237 close(child_ready_pipe[1]);
238
239 /*
240 * Wait until the parent tells us to go.
241 */
242 read(go_pipe[0], &buf, 1);
243
244 execvp(argv[0], (char **)argv);
245
246 perror(argv[0]);
247 exit(-1);
248 }
249
250 /*
251 * Wait for the child to be ready to exec.
252 */
253 close(child_ready_pipe[1]);
254 close(go_pipe[0]);
255 read(child_ready_pipe[0], &buf, 1);
256 close(child_ready_pipe[0]);
257
212 for (counter = 0; counter < nr_counters; counter++) 258 for (counter = 0; counter < nr_counters; counter++)
213 create_perf_stat_counter(counter); 259 create_perf_stat_counter(counter, pid);
214 260
215 /* 261 /*
216 * Enable counters and exec the command: 262 * Enable counters and exec the command:
@@ -218,19 +264,9 @@ static int run_perf_stat(int argc, const char **argv)
218 t0 = rdclock(); 264 t0 = rdclock();
219 prctl(PR_TASK_PERF_COUNTERS_ENABLE); 265 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
220 266
221 if ((pid = fork()) < 0) 267 close(go_pipe[1]);
222 perror("failed to fork");
223
224 if (!pid) {
225 if (execvp(argv[0], (char **)argv)) {
226 perror(argv[0]);
227 exit(-1);
228 }
229 }
230
231 wait(&status); 268 wait(&status);
232 269
233 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
234 t1 = rdclock(); 270 t1 = rdclock();
235 271
236 walltime_nsecs[run_idx] = t1 - t0; 272 walltime_nsecs[run_idx] = t1 - t0;