diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-08-15 06:06:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-08-15 06:06:12 -0400 |
commit | be750231ce1599b86fbba213e3da8344ece262e2 (patch) | |
tree | a506c461082692bb5bab8b9bb63a762816329454 /tools/perf/builtin-record.c | |
parent | 18408ddc01136f505ae357c03f0d8e50b10e0db6 (diff) | |
parent | 39e6dd73502f64e2ae3236b304e160ae30de9384 (diff) |
Merge branch 'perfcounters/urgent' into perfcounters/core
Conflicts:
kernel/perf_counter.c
Merge reason: update to latest upstream (-rc6) and resolve
the conflict with urgent fixes.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 95 |
1 files changed, 58 insertions, 37 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 106c6abd1c38..65b4115e417d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -35,7 +35,9 @@ static int output; | |||
35 | static const char *output_name = "perf.data"; | 35 | static const char *output_name = "perf.data"; |
36 | static int group = 0; | 36 | static int group = 0; |
37 | static unsigned int realtime_prio = 0; | 37 | static unsigned int realtime_prio = 0; |
38 | static int raw_samples = 0; | ||
38 | static int system_wide = 0; | 39 | static int system_wide = 0; |
40 | static int profile_cpu = -1; | ||
39 | static pid_t target_pid = -1; | 41 | static pid_t target_pid = -1; |
40 | static int inherit = 1; | 42 | static int inherit = 1; |
41 | static int force = 0; | 43 | static int force = 0; |
@@ -185,46 +187,48 @@ static void sig_atexit(void) | |||
185 | kill(getpid(), signr); | 187 | kill(getpid(), signr); |
186 | } | 188 | } |
187 | 189 | ||
188 | static void pid_synthesize_comm_event(pid_t pid, int full) | 190 | static pid_t pid_synthesize_comm_event(pid_t pid, int full) |
189 | { | 191 | { |
190 | struct comm_event comm_ev; | 192 | struct comm_event comm_ev; |
191 | char filename[PATH_MAX]; | 193 | char filename[PATH_MAX]; |
192 | char bf[BUFSIZ]; | 194 | char bf[BUFSIZ]; |
193 | int fd; | 195 | FILE *fp; |
194 | size_t size; | 196 | size_t size = 0; |
195 | char *field, *sep; | ||
196 | DIR *tasks; | 197 | DIR *tasks; |
197 | struct dirent dirent, *next; | 198 | struct dirent dirent, *next; |
199 | pid_t tgid = 0; | ||
198 | 200 | ||
199 | snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); | 201 | snprintf(filename, sizeof(filename), "/proc/%d/status", pid); |
200 | 202 | ||
201 | fd = open(filename, O_RDONLY); | 203 | fp = fopen(filename, "r"); |
202 | if (fd < 0) { | 204 | if (fp == NULL) { |
203 | /* | 205 | /* |
204 | * We raced with a task exiting - just return: | 206 | * We raced with a task exiting - just return: |
205 | */ | 207 | */ |
206 | if (verbose) | 208 | if (verbose) |
207 | fprintf(stderr, "couldn't open %s\n", filename); | 209 | fprintf(stderr, "couldn't open %s\n", filename); |
208 | return; | 210 | return 0; |
209 | } | 211 | } |
210 | if (read(fd, bf, sizeof(bf)) < 0) { | ||
211 | fprintf(stderr, "couldn't read %s\n", filename); | ||
212 | exit(EXIT_FAILURE); | ||
213 | } | ||
214 | close(fd); | ||
215 | 212 | ||
216 | /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */ | ||
217 | memset(&comm_ev, 0, sizeof(comm_ev)); | 213 | memset(&comm_ev, 0, sizeof(comm_ev)); |
218 | field = strchr(bf, '('); | 214 | while (!comm_ev.comm[0] || !comm_ev.pid) { |
219 | if (field == NULL) | 215 | if (fgets(bf, sizeof(bf), fp) == NULL) |
220 | goto out_failure; | 216 | goto out_failure; |
221 | sep = strchr(++field, ')'); | 217 | |
222 | if (sep == NULL) | 218 | if (memcmp(bf, "Name:", 5) == 0) { |
223 | goto out_failure; | 219 | char *name = bf + 5; |
224 | size = sep - field; | 220 | while (*name && isspace(*name)) |
225 | memcpy(comm_ev.comm, field, size++); | 221 | ++name; |
226 | 222 | size = strlen(name) - 1; | |
227 | comm_ev.pid = pid; | 223 | memcpy(comm_ev.comm, name, size++); |
224 | } else if (memcmp(bf, "Tgid:", 5) == 0) { | ||
225 | char *tgids = bf + 5; | ||
226 | while (*tgids && isspace(*tgids)) | ||
227 | ++tgids; | ||
228 | tgid = comm_ev.pid = atoi(tgids); | ||
229 | } | ||
230 | } | ||
231 | |||
228 | comm_ev.header.type = PERF_EVENT_COMM; | 232 | comm_ev.header.type = PERF_EVENT_COMM; |
229 | size = ALIGN(size, sizeof(u64)); | 233 | size = ALIGN(size, sizeof(u64)); |
230 | comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); | 234 | comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); |
@@ -233,7 +237,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
233 | comm_ev.tid = pid; | 237 | comm_ev.tid = pid; |
234 | 238 | ||
235 | write_output(&comm_ev, comm_ev.header.size); | 239 | write_output(&comm_ev, comm_ev.header.size); |
236 | return; | 240 | goto out_fclose; |
237 | } | 241 | } |
238 | 242 | ||
239 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); | 243 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); |
@@ -250,7 +254,10 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
250 | write_output(&comm_ev, comm_ev.header.size); | 254 | write_output(&comm_ev, comm_ev.header.size); |
251 | } | 255 | } |
252 | closedir(tasks); | 256 | closedir(tasks); |
253 | return; | 257 | |
258 | out_fclose: | ||
259 | fclose(fp); | ||
260 | return tgid; | ||
254 | 261 | ||
255 | out_failure: | 262 | out_failure: |
256 | fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", | 263 | fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", |
@@ -258,7 +265,7 @@ out_failure: | |||
258 | exit(EXIT_FAILURE); | 265 | exit(EXIT_FAILURE); |
259 | } | 266 | } |
260 | 267 | ||
261 | static void pid_synthesize_mmap_samples(pid_t pid) | 268 | static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid) |
262 | { | 269 | { |
263 | char filename[PATH_MAX]; | 270 | char filename[PATH_MAX]; |
264 | FILE *fp; | 271 | FILE *fp; |
@@ -310,7 +317,7 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
310 | mmap_ev.len -= mmap_ev.start; | 317 | mmap_ev.len -= mmap_ev.start; |
311 | mmap_ev.header.size = (sizeof(mmap_ev) - | 318 | mmap_ev.header.size = (sizeof(mmap_ev) - |
312 | (sizeof(mmap_ev.filename) - size)); | 319 | (sizeof(mmap_ev.filename) - size)); |
313 | mmap_ev.pid = pid; | 320 | mmap_ev.pid = tgid; |
314 | mmap_ev.tid = pid; | 321 | mmap_ev.tid = pid; |
315 | 322 | ||
316 | write_output(&mmap_ev, mmap_ev.header.size); | 323 | write_output(&mmap_ev, mmap_ev.header.size); |
@@ -329,14 +336,14 @@ static void synthesize_all(void) | |||
329 | 336 | ||
330 | while (!readdir_r(proc, &dirent, &next) && next) { | 337 | while (!readdir_r(proc, &dirent, &next) && next) { |
331 | char *end; | 338 | char *end; |
332 | pid_t pid; | 339 | pid_t pid, tgid; |
333 | 340 | ||
334 | pid = strtol(dirent.d_name, &end, 10); | 341 | pid = strtol(dirent.d_name, &end, 10); |
335 | if (*end) /* only interested in proper numerical dirents */ | 342 | if (*end) /* only interested in proper numerical dirents */ |
336 | continue; | 343 | continue; |
337 | 344 | ||
338 | pid_synthesize_comm_event(pid, 1); | 345 | tgid = pid_synthesize_comm_event(pid, 1); |
339 | pid_synthesize_mmap_samples(pid); | 346 | pid_synthesize_mmap_samples(pid, tgid); |
340 | } | 347 | } |
341 | 348 | ||
342 | closedir(proc); | 349 | closedir(proc); |
@@ -374,7 +381,7 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
374 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 381 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
375 | PERF_FORMAT_ID; | 382 | PERF_FORMAT_ID; |
376 | 383 | ||
377 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 384 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
378 | 385 | ||
379 | if (freq) { | 386 | if (freq) { |
380 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 387 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
@@ -394,6 +401,8 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
394 | if (call_graph) | 401 | if (call_graph) |
395 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 402 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
396 | 403 | ||
404 | if (raw_samples) | ||
405 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
397 | 406 | ||
398 | attr->mmap = track; | 407 | attr->mmap = track; |
399 | attr->comm = track; | 408 | attr->comm = track; |
@@ -408,6 +417,8 @@ try_again: | |||
408 | 417 | ||
409 | if (err == EPERM) | 418 | if (err == EPERM) |
410 | die("Permission error - are you root?\n"); | 419 | die("Permission error - are you root?\n"); |
420 | else if (err == ENODEV && profile_cpu != -1) | ||
421 | die("No such device - did you specify an out-of-range profile CPU?\n"); | ||
411 | 422 | ||
412 | /* | 423 | /* |
413 | * If it's cycles then fall back to hrtimer | 424 | * If it's cycles then fall back to hrtimer |
@@ -541,16 +552,22 @@ static int __cmd_record(int argc, const char **argv) | |||
541 | if (pid == -1) | 552 | if (pid == -1) |
542 | pid = getpid(); | 553 | pid = getpid(); |
543 | 554 | ||
544 | open_counters(-1, pid); | 555 | open_counters(profile_cpu, pid); |
545 | } else for (i = 0; i < nr_cpus; i++) | 556 | } else { |
546 | open_counters(i, target_pid); | 557 | if (profile_cpu != -1) { |
558 | open_counters(profile_cpu, target_pid); | ||
559 | } else { | ||
560 | for (i = 0; i < nr_cpus; i++) | ||
561 | open_counters(i, target_pid); | ||
562 | } | ||
563 | } | ||
547 | 564 | ||
548 | if (file_new) | 565 | if (file_new) |
549 | perf_header__write(header, output); | 566 | perf_header__write(header, output); |
550 | 567 | ||
551 | if (!system_wide) { | 568 | if (!system_wide) { |
552 | pid_synthesize_comm_event(pid, 0); | 569 | pid_t tgid = pid_synthesize_comm_event(pid, 0); |
553 | pid_synthesize_mmap_samples(pid); | 570 | pid_synthesize_mmap_samples(pid, tgid); |
554 | } else | 571 | } else |
555 | synthesize_all(); | 572 | synthesize_all(); |
556 | 573 | ||
@@ -618,10 +635,14 @@ static const struct option options[] = { | |||
618 | "record events on existing pid"), | 635 | "record events on existing pid"), |
619 | OPT_INTEGER('r', "realtime", &realtime_prio, | 636 | OPT_INTEGER('r', "realtime", &realtime_prio, |
620 | "collect data with this RT SCHED_FIFO priority"), | 637 | "collect data with this RT SCHED_FIFO priority"), |
638 | OPT_BOOLEAN('R', "raw-samples", &raw_samples, | ||
639 | "collect raw sample records from all opened counters"), | ||
621 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 640 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
622 | "system-wide collection from all CPUs"), | 641 | "system-wide collection from all CPUs"), |
623 | OPT_BOOLEAN('A', "append", &append_file, | 642 | OPT_BOOLEAN('A', "append", &append_file, |
624 | "append to the output file to do incremental profiling"), | 643 | "append to the output file to do incremental profiling"), |
644 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, | ||
645 | "CPU to profile on"), | ||
625 | OPT_BOOLEAN('f', "force", &force, | 646 | OPT_BOOLEAN('f', "force", &force, |
626 | "overwrite existing data file"), | 647 | "overwrite existing data file"), |
627 | OPT_LONG('c', "count", &default_interval, | 648 | OPT_LONG('c', "count", &default_interval, |