aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c168
1 files changed, 63 insertions, 105 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index d04651484640..15280b5e5574 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -24,12 +24,13 @@
24#include "util/symbol.h" 24#include "util/symbol.h"
25#include "util/cpumap.h" 25#include "util/cpumap.h"
26#include "util/thread_map.h" 26#include "util/thread_map.h"
27#include "util/data.h"
27 28
28#include <unistd.h> 29#include <unistd.h>
29#include <sched.h> 30#include <sched.h>
30#include <sys/mman.h> 31#include <sys/mman.h>
31 32
32#ifndef HAVE_ON_EXIT 33#ifndef HAVE_ON_EXIT_SUPPORT
33#ifndef ATEXIT_MAX 34#ifndef ATEXIT_MAX
34#define ATEXIT_MAX 32 35#define ATEXIT_MAX 32
35#endif 36#endif
@@ -65,31 +66,25 @@ struct perf_record {
65 struct perf_tool tool; 66 struct perf_tool tool;
66 struct perf_record_opts opts; 67 struct perf_record_opts opts;
67 u64 bytes_written; 68 u64 bytes_written;
68 const char *output_name; 69 struct perf_data_file file;
69 struct perf_evlist *evlist; 70 struct perf_evlist *evlist;
70 struct perf_session *session; 71 struct perf_session *session;
71 const char *progname; 72 const char *progname;
72 int output;
73 unsigned int page_size;
74 int realtime_prio; 73 int realtime_prio;
75 bool no_buildid; 74 bool no_buildid;
76 bool no_buildid_cache; 75 bool no_buildid_cache;
77 long samples; 76 long samples;
78 off_t post_processing_offset;
79}; 77};
80 78
81static void advance_output(struct perf_record *rec, size_t size)
82{
83 rec->bytes_written += size;
84}
85
86static int write_output(struct perf_record *rec, void *buf, size_t size) 79static int write_output(struct perf_record *rec, void *buf, size_t size)
87{ 80{
81 struct perf_data_file *file = &rec->file;
82
88 while (size) { 83 while (size) {
89 int ret = write(rec->output, buf, size); 84 int ret = write(file->fd, buf, size);
90 85
91 if (ret < 0) { 86 if (ret < 0) {
92 pr_err("failed to write\n"); 87 pr_err("failed to write perf data, error: %m\n");
93 return -1; 88 return -1;
94 } 89 }
95 90
@@ -119,7 +114,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
119{ 114{
120 unsigned int head = perf_mmap__read_head(md); 115 unsigned int head = perf_mmap__read_head(md);
121 unsigned int old = md->prev; 116 unsigned int old = md->prev;
122 unsigned char *data = md->base + rec->page_size; 117 unsigned char *data = md->base + page_size;
123 unsigned long size; 118 unsigned long size;
124 void *buf; 119 void *buf;
125 int rc = 0; 120 int rc = 0;
@@ -234,10 +229,6 @@ try_again:
234 "or try again with a smaller value of -m/--mmap_pages.\n" 229 "or try again with a smaller value of -m/--mmap_pages.\n"
235 "(current value: %d)\n", opts->mmap_pages); 230 "(current value: %d)\n", opts->mmap_pages);
236 rc = -errno; 231 rc = -errno;
237 } else if (!is_power_of_2(opts->mmap_pages) &&
238 (opts->mmap_pages != UINT_MAX)) {
239 pr_err("--mmap_pages/-m value must be a power of two.");
240 rc = -EINVAL;
241 } else { 232 } else {
242 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 233 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
243 rc = -errno; 234 rc = -errno;
@@ -253,31 +244,34 @@ out:
253 244
254static int process_buildids(struct perf_record *rec) 245static int process_buildids(struct perf_record *rec)
255{ 246{
256 u64 size = lseek(rec->output, 0, SEEK_CUR); 247 struct perf_data_file *file = &rec->file;
248 struct perf_session *session = rec->session;
249 u64 start = session->header.data_offset;
257 250
251 u64 size = lseek(file->fd, 0, SEEK_CUR);
258 if (size == 0) 252 if (size == 0)
259 return 0; 253 return 0;
260 254
261 rec->session->fd = rec->output; 255 return __perf_session__process_events(session, start,
262 return __perf_session__process_events(rec->session, rec->post_processing_offset, 256 size - start,
263 size - rec->post_processing_offset,
264 size, &build_id__mark_dso_hit_ops); 257 size, &build_id__mark_dso_hit_ops);
265} 258}
266 259
267static void perf_record__exit(int status, void *arg) 260static void perf_record__exit(int status, void *arg)
268{ 261{
269 struct perf_record *rec = arg; 262 struct perf_record *rec = arg;
263 struct perf_data_file *file = &rec->file;
270 264
271 if (status != 0) 265 if (status != 0)
272 return; 266 return;
273 267
274 if (!rec->opts.pipe_output) { 268 if (!file->is_pipe) {
275 rec->session->header.data_size += rec->bytes_written; 269 rec->session->header.data_size += rec->bytes_written;
276 270
277 if (!rec->no_buildid) 271 if (!rec->no_buildid)
278 process_buildids(rec); 272 process_buildids(rec);
279 perf_session__write_header(rec->session, rec->evlist, 273 perf_session__write_header(rec->session, rec->evlist,
280 rec->output, true); 274 file->fd, true);
281 perf_session__delete(rec->session); 275 perf_session__delete(rec->session);
282 perf_evlist__delete(rec->evlist); 276 perf_evlist__delete(rec->evlist);
283 symbol__exit(); 277 symbol__exit();
@@ -343,64 +337,47 @@ out:
343 return rc; 337 return rc;
344} 338}
345 339
340static void perf_record__init_features(struct perf_record *rec)
341{
342 struct perf_evlist *evsel_list = rec->evlist;
343 struct perf_session *session = rec->session;
344 int feat;
345
346 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
347 perf_header__set_feat(&session->header, feat);
348
349 if (rec->no_buildid)
350 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
351
352 if (!have_tracepoints(&evsel_list->entries))
353 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
354
355 if (!rec->opts.branch_stack)
356 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
357}
358
346static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 359static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
347{ 360{
348 struct stat st; 361 int err;
349 int flags;
350 int err, output, feat;
351 unsigned long waking = 0; 362 unsigned long waking = 0;
352 const bool forks = argc > 0; 363 const bool forks = argc > 0;
353 struct machine *machine; 364 struct machine *machine;
354 struct perf_tool *tool = &rec->tool; 365 struct perf_tool *tool = &rec->tool;
355 struct perf_record_opts *opts = &rec->opts; 366 struct perf_record_opts *opts = &rec->opts;
356 struct perf_evlist *evsel_list = rec->evlist; 367 struct perf_evlist *evsel_list = rec->evlist;
357 const char *output_name = rec->output_name; 368 struct perf_data_file *file = &rec->file;
358 struct perf_session *session; 369 struct perf_session *session;
359 bool disabled = false; 370 bool disabled = false;
360 371
361 rec->progname = argv[0]; 372 rec->progname = argv[0];
362 373
363 rec->page_size = sysconf(_SC_PAGE_SIZE);
364
365 on_exit(perf_record__sig_exit, rec); 374 on_exit(perf_record__sig_exit, rec);
366 signal(SIGCHLD, sig_handler); 375 signal(SIGCHLD, sig_handler);
367 signal(SIGINT, sig_handler); 376 signal(SIGINT, sig_handler);
368 signal(SIGUSR1, sig_handler); 377 signal(SIGUSR1, sig_handler);
369 signal(SIGTERM, sig_handler); 378 signal(SIGTERM, sig_handler);
370 379
371 if (!output_name) { 380 session = perf_session__new(file, false, NULL);
372 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
373 opts->pipe_output = true;
374 else
375 rec->output_name = output_name = "perf.data";
376 }
377 if (output_name) {
378 if (!strcmp(output_name, "-"))
379 opts->pipe_output = true;
380 else if (!stat(output_name, &st) && st.st_size) {
381 char oldname[PATH_MAX];
382 snprintf(oldname, sizeof(oldname), "%s.old",
383 output_name);
384 unlink(oldname);
385 rename(output_name, oldname);
386 }
387 }
388
389 flags = O_CREAT|O_RDWR|O_TRUNC;
390
391 if (opts->pipe_output)
392 output = STDOUT_FILENO;
393 else
394 output = open(output_name, flags, S_IRUSR | S_IWUSR);
395 if (output < 0) {
396 perror("failed to create output file");
397 return -1;
398 }
399
400 rec->output = output;
401
402 session = perf_session__new(output_name, O_WRONLY,
403 true, false, NULL);
404 if (session == NULL) { 381 if (session == NULL) {
405 pr_err("Not enough memory for reading perf file header\n"); 382 pr_err("Not enough memory for reading perf file header\n");
406 return -1; 383 return -1;
@@ -408,21 +385,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
408 385
409 rec->session = session; 386 rec->session = session;
410 387
411 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 388 perf_record__init_features(rec);
412 perf_header__set_feat(&session->header, feat);
413
414 if (rec->no_buildid)
415 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
416
417 if (!have_tracepoints(&evsel_list->entries))
418 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
419
420 if (!rec->opts.branch_stack)
421 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
422 389
423 if (forks) { 390 if (forks) {
424 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 391 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
425 argv, opts->pipe_output, 392 argv, file->is_pipe,
426 true); 393 true);
427 if (err < 0) { 394 if (err < 0) {
428 pr_err("Couldn't run the workload!\n"); 395 pr_err("Couldn't run the workload!\n");
@@ -443,13 +410,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
443 */ 410 */
444 on_exit(perf_record__exit, rec); 411 on_exit(perf_record__exit, rec);
445 412
446 if (opts->pipe_output) { 413 if (file->is_pipe) {
447 err = perf_header__write_pipe(output); 414 err = perf_header__write_pipe(file->fd);
448 if (err < 0) 415 if (err < 0)
449 goto out_delete_session; 416 goto out_delete_session;
450 } else { 417 } else {
451 err = perf_session__write_header(session, evsel_list, 418 err = perf_session__write_header(session, evsel_list,
452 output, false); 419 file->fd, false);
453 if (err < 0) 420 if (err < 0)
454 goto out_delete_session; 421 goto out_delete_session;
455 } 422 }
@@ -462,11 +429,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
462 goto out_delete_session; 429 goto out_delete_session;
463 } 430 }
464 431
465 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
466
467 machine = &session->machines.host; 432 machine = &session->machines.host;
468 433
469 if (opts->pipe_output) { 434 if (file->is_pipe) {
470 err = perf_event__synthesize_attrs(tool, session, 435 err = perf_event__synthesize_attrs(tool, session,
471 process_synthesized_event); 436 process_synthesized_event);
472 if (err < 0) { 437 if (err < 0) {
@@ -483,13 +448,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
483 * return this more properly and also 448 * return this more properly and also
484 * propagate errors that now are calling die() 449 * propagate errors that now are calling die()
485 */ 450 */
486 err = perf_event__synthesize_tracing_data(tool, output, evsel_list, 451 err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
487 process_synthesized_event); 452 process_synthesized_event);
488 if (err <= 0) { 453 if (err <= 0) {
489 pr_err("Couldn't record tracing data.\n"); 454 pr_err("Couldn't record tracing data.\n");
490 goto out_delete_session; 455 goto out_delete_session;
491 } 456 }
492 advance_output(rec, err); 457 rec->bytes_written += err;
493 } 458 }
494 } 459 }
495 460
@@ -590,7 +555,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
590 fprintf(stderr, 555 fprintf(stderr,
591 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 556 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
592 (double)rec->bytes_written / 1024.0 / 1024.0, 557 (double)rec->bytes_written / 1024.0 / 1024.0,
593 output_name, 558 file->path,
594 rec->bytes_written / 24); 559 rec->bytes_written / 24);
595 560
596 return 0; 561 return 0;
@@ -618,6 +583,9 @@ static const struct branch_mode branch_modes[] = {
618 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 583 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
619 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 584 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
620 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 585 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
586 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
587 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
588 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
621 BRANCH_END 589 BRANCH_END
622}; 590};
623 591
@@ -684,7 +652,7 @@ error:
684 return ret; 652 return ret;
685} 653}
686 654
687#ifdef LIBUNWIND_SUPPORT 655#ifdef HAVE_LIBUNWIND_SUPPORT
688static int get_stack_size(char *str, unsigned long *_size) 656static int get_stack_size(char *str, unsigned long *_size)
689{ 657{
690 char *endptr; 658 char *endptr;
@@ -710,7 +678,7 @@ static int get_stack_size(char *str, unsigned long *_size)
710 max_size, str); 678 max_size, str);
711 return -1; 679 return -1;
712} 680}
713#endif /* LIBUNWIND_SUPPORT */ 681#endif /* HAVE_LIBUNWIND_SUPPORT */
714 682
715int record_parse_callchain(const char *arg, struct perf_record_opts *opts) 683int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
716{ 684{
@@ -739,7 +707,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
739 "needed for -g fp\n"); 707 "needed for -g fp\n");
740 break; 708 break;
741 709
742#ifdef LIBUNWIND_SUPPORT 710#ifdef HAVE_LIBUNWIND_SUPPORT
743 /* Dwarf style */ 711 /* Dwarf style */
744 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 712 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
745 const unsigned long default_stack_dump_size = 8192; 713 const unsigned long default_stack_dump_size = 8192;
@@ -755,7 +723,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
755 ret = get_stack_size(tok, &size); 723 ret = get_stack_size(tok, &size);
756 opts->stack_dump_size = size; 724 opts->stack_dump_size = size;
757 } 725 }
758#endif /* LIBUNWIND_SUPPORT */ 726#endif /* HAVE_LIBUNWIND_SUPPORT */
759 } else { 727 } else {
760 pr_err("callchain: Unknown --call-graph option " 728 pr_err("callchain: Unknown --call-graph option "
761 "value: %s\n", arg); 729 "value: %s\n", arg);
@@ -841,7 +809,7 @@ static struct perf_record record = {
841 809
842#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " 810#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
843 811
844#ifdef LIBUNWIND_SUPPORT 812#ifdef HAVE_LIBUNWIND_SUPPORT
845const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf"; 813const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
846#else 814#else
847const char record_callchain_help[] = CALLCHAIN_HELP "fp"; 815const char record_callchain_help[] = CALLCHAIN_HELP "fp";
@@ -875,13 +843,14 @@ const struct option record_options[] = {
875 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 843 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
876 "list of cpus to monitor"), 844 "list of cpus to monitor"),
877 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 845 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
878 OPT_STRING('o', "output", &record.output_name, "file", 846 OPT_STRING('o', "output", &record.file.path, "file",
879 "output file name"), 847 "output file name"),
880 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 848 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
881 "child tasks do not inherit counters"), 849 "child tasks do not inherit counters"),
882 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 850 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
883 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, 851 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
884 "number of mmap data pages"), 852 "number of mmap data pages",
853 perf_evlist__parse_mmap_pages),
885 OPT_BOOLEAN(0, "group", &record.opts.group, 854 OPT_BOOLEAN(0, "group", &record.opts.group,
886 "put the counters into a counter group"), 855 "put the counters into a counter group"),
887 OPT_CALLBACK_NOOPT('g', NULL, &record.opts, 856 OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
@@ -920,6 +889,8 @@ const struct option record_options[] = {
920 parse_branch_stack), 889 parse_branch_stack),
921 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 890 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
922 "sample by weight (on special events only)"), 891 "sample by weight (on special events only)"),
892 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
893 "sample transaction flags (special events only)"),
923 OPT_END() 894 OPT_END()
924}; 895};
925 896
@@ -989,20 +960,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
989 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 960 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
990 usage_with_options(record_usage, record_options); 961 usage_with_options(record_usage, record_options);
991 962
992 if (rec->opts.user_interval != ULLONG_MAX) 963 if (perf_record_opts__config(&rec->opts)) {
993 rec->opts.default_interval = rec->opts.user_interval;
994 if (rec->opts.user_freq != UINT_MAX)
995 rec->opts.freq = rec->opts.user_freq;
996
997 /*
998 * User specified count overrides default frequency.
999 */
1000 if (rec->opts.default_interval)
1001 rec->opts.freq = 0;
1002 else if (rec->opts.freq) {
1003 rec->opts.default_interval = rec->opts.freq;
1004 } else {
1005 ui__error("frequency and count are zero, aborting\n");
1006 err = -EINVAL; 964 err = -EINVAL;
1007 goto out_free_fd; 965 goto out_free_fd;
1008 } 966 }