aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-08-15 06:06:12 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-15 06:06:12 -0400
commitbe750231ce1599b86fbba213e3da8344ece262e2 (patch)
treea506c461082692bb5bab8b9bb63a762816329454 /tools/perf/builtin-record.c
parent18408ddc01136f505ae357c03f0d8e50b10e0db6 (diff)
parent39e6dd73502f64e2ae3236b304e160ae30de9384 (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.c95
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;
35static const char *output_name = "perf.data"; 35static const char *output_name = "perf.data";
36static int group = 0; 36static int group = 0;
37static unsigned int realtime_prio = 0; 37static unsigned int realtime_prio = 0;
38static int raw_samples = 0;
38static int system_wide = 0; 39static int system_wide = 0;
40static int profile_cpu = -1;
39static pid_t target_pid = -1; 41static pid_t target_pid = -1;
40static int inherit = 1; 42static int inherit = 1;
41static int force = 0; 43static int force = 0;
@@ -185,46 +187,48 @@ static void sig_atexit(void)
185 kill(getpid(), signr); 187 kill(getpid(), signr);
186} 188}
187 189
188static void pid_synthesize_comm_event(pid_t pid, int full) 190static 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
258out_fclose:
259 fclose(fp);
260 return tgid;
254 261
255out_failure: 262out_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
261static void pid_synthesize_mmap_samples(pid_t pid) 268static 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,