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.c274
1 files changed, 130 insertions, 144 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a41ac41546c9..7c8020a32784 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) 79static int do_write_output(struct perf_record *rec, void *buf, size_t size)
82{ 80{
83 rec->bytes_written += size; 81 struct perf_data_file *file = &rec->file;
84}
85 82
86static int write_output(struct perf_record *rec, void *buf, size_t size)
87{
88 while (size) { 83 while (size) {
89 int ret = write(rec->output, buf, size); 84 ssize_t 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
@@ -102,6 +97,11 @@ static int write_output(struct perf_record *rec, void *buf, size_t size)
102 return 0; 97 return 0;
103} 98}
104 99
100static int write_output(struct perf_record *rec, void *buf, size_t size)
101{
102 return do_write_output(rec, buf, size);
103}
104
105static int process_synthesized_event(struct perf_tool *tool, 105static int process_synthesized_event(struct perf_tool *tool,
106 union perf_event *event, 106 union perf_event *event,
107 struct perf_sample *sample __maybe_unused, 107 struct perf_sample *sample __maybe_unused,
@@ -119,7 +119,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
119{ 119{
120 unsigned int head = perf_mmap__read_head(md); 120 unsigned int head = perf_mmap__read_head(md);
121 unsigned int old = md->prev; 121 unsigned int old = md->prev;
122 unsigned char *data = md->base + rec->page_size; 122 unsigned char *data = md->base + page_size;
123 unsigned long size; 123 unsigned long size;
124 void *buf; 124 void *buf;
125 int rc = 0; 125 int rc = 0;
@@ -234,10 +234,6 @@ try_again:
234 "or try again with a smaller value of -m/--mmap_pages.\n" 234 "or try again with a smaller value of -m/--mmap_pages.\n"
235 "(current value: %d)\n", opts->mmap_pages); 235 "(current value: %d)\n", opts->mmap_pages);
236 rc = -errno; 236 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 { 237 } else {
242 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 238 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
243 rc = -errno; 239 rc = -errno;
@@ -253,31 +249,34 @@ out:
253 249
254static int process_buildids(struct perf_record *rec) 250static int process_buildids(struct perf_record *rec)
255{ 251{
256 u64 size = lseek(rec->output, 0, SEEK_CUR); 252 struct perf_data_file *file = &rec->file;
253 struct perf_session *session = rec->session;
254 u64 start = session->header.data_offset;
257 255
256 u64 size = lseek(file->fd, 0, SEEK_CUR);
258 if (size == 0) 257 if (size == 0)
259 return 0; 258 return 0;
260 259
261 rec->session->fd = rec->output; 260 return __perf_session__process_events(session, start,
262 return __perf_session__process_events(rec->session, rec->post_processing_offset, 261 size - start,
263 size - rec->post_processing_offset,
264 size, &build_id__mark_dso_hit_ops); 262 size, &build_id__mark_dso_hit_ops);
265} 263}
266 264
267static void perf_record__exit(int status, void *arg) 265static void perf_record__exit(int status, void *arg)
268{ 266{
269 struct perf_record *rec = arg; 267 struct perf_record *rec = arg;
268 struct perf_data_file *file = &rec->file;
270 269
271 if (status != 0) 270 if (status != 0)
272 return; 271 return;
273 272
274 if (!rec->opts.pipe_output) { 273 if (!file->is_pipe) {
275 rec->session->header.data_size += rec->bytes_written; 274 rec->session->header.data_size += rec->bytes_written;
276 275
277 if (!rec->no_buildid) 276 if (!rec->no_buildid)
278 process_buildids(rec); 277 process_buildids(rec);
279 perf_session__write_header(rec->session, rec->evlist, 278 perf_session__write_header(rec->session, rec->evlist,
280 rec->output, true); 279 file->fd, true);
281 perf_session__delete(rec->session); 280 perf_session__delete(rec->session);
282 perf_evlist__delete(rec->evlist); 281 perf_evlist__delete(rec->evlist);
283 symbol__exit(); 282 symbol__exit();
@@ -343,64 +342,47 @@ out:
343 return rc; 342 return rc;
344} 343}
345 344
345static void perf_record__init_features(struct perf_record *rec)
346{
347 struct perf_evlist *evsel_list = rec->evlist;
348 struct perf_session *session = rec->session;
349 int feat;
350
351 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
352 perf_header__set_feat(&session->header, feat);
353
354 if (rec->no_buildid)
355 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
356
357 if (!have_tracepoints(&evsel_list->entries))
358 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
359
360 if (!rec->opts.branch_stack)
361 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
362}
363
346static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 364static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
347{ 365{
348 struct stat st; 366 int err;
349 int flags;
350 int err, output, feat;
351 unsigned long waking = 0; 367 unsigned long waking = 0;
352 const bool forks = argc > 0; 368 const bool forks = argc > 0;
353 struct machine *machine; 369 struct machine *machine;
354 struct perf_tool *tool = &rec->tool; 370 struct perf_tool *tool = &rec->tool;
355 struct perf_record_opts *opts = &rec->opts; 371 struct perf_record_opts *opts = &rec->opts;
356 struct perf_evlist *evsel_list = rec->evlist; 372 struct perf_evlist *evsel_list = rec->evlist;
357 const char *output_name = rec->output_name; 373 struct perf_data_file *file = &rec->file;
358 struct perf_session *session; 374 struct perf_session *session;
359 bool disabled = false; 375 bool disabled = false;
360 376
361 rec->progname = argv[0]; 377 rec->progname = argv[0];
362 378
363 rec->page_size = sysconf(_SC_PAGE_SIZE);
364
365 on_exit(perf_record__sig_exit, rec); 379 on_exit(perf_record__sig_exit, rec);
366 signal(SIGCHLD, sig_handler); 380 signal(SIGCHLD, sig_handler);
367 signal(SIGINT, sig_handler); 381 signal(SIGINT, sig_handler);
368 signal(SIGUSR1, sig_handler); 382 signal(SIGUSR1, sig_handler);
369 signal(SIGTERM, sig_handler); 383 signal(SIGTERM, sig_handler);
370 384
371 if (!output_name) { 385 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) { 386 if (session == NULL) {
405 pr_err("Not enough memory for reading perf file header\n"); 387 pr_err("Not enough memory for reading perf file header\n");
406 return -1; 388 return -1;
@@ -408,21 +390,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
408 390
409 rec->session = session; 391 rec->session = session;
410 392
411 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 393 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 394
423 if (forks) { 395 if (forks) {
424 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 396 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
425 argv, opts->pipe_output, 397 argv, file->is_pipe,
426 true); 398 true);
427 if (err < 0) { 399 if (err < 0) {
428 pr_err("Couldn't run the workload!\n"); 400 pr_err("Couldn't run the workload!\n");
@@ -443,13 +415,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
443 */ 415 */
444 on_exit(perf_record__exit, rec); 416 on_exit(perf_record__exit, rec);
445 417
446 if (opts->pipe_output) { 418 if (file->is_pipe) {
447 err = perf_header__write_pipe(output); 419 err = perf_header__write_pipe(file->fd);
448 if (err < 0) 420 if (err < 0)
449 goto out_delete_session; 421 goto out_delete_session;
450 } else { 422 } else {
451 err = perf_session__write_header(session, evsel_list, 423 err = perf_session__write_header(session, evsel_list,
452 output, false); 424 file->fd, false);
453 if (err < 0) 425 if (err < 0)
454 goto out_delete_session; 426 goto out_delete_session;
455 } 427 }
@@ -462,11 +434,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
462 goto out_delete_session; 434 goto out_delete_session;
463 } 435 }
464 436
465 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
466
467 machine = &session->machines.host; 437 machine = &session->machines.host;
468 438
469 if (opts->pipe_output) { 439 if (file->is_pipe) {
470 err = perf_event__synthesize_attrs(tool, session, 440 err = perf_event__synthesize_attrs(tool, session,
471 process_synthesized_event); 441 process_synthesized_event);
472 if (err < 0) { 442 if (err < 0) {
@@ -483,13 +453,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
483 * return this more properly and also 453 * return this more properly and also
484 * propagate errors that now are calling die() 454 * propagate errors that now are calling die()
485 */ 455 */
486 err = perf_event__synthesize_tracing_data(tool, output, evsel_list, 456 err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
487 process_synthesized_event); 457 process_synthesized_event);
488 if (err <= 0) { 458 if (err <= 0) {
489 pr_err("Couldn't record tracing data.\n"); 459 pr_err("Couldn't record tracing data.\n");
490 goto out_delete_session; 460 goto out_delete_session;
491 } 461 }
492 advance_output(rec, err); 462 rec->bytes_written += err;
493 } 463 }
494 } 464 }
495 465
@@ -515,16 +485,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
515 perf_event__synthesize_guest_os, tool); 485 perf_event__synthesize_guest_os, tool);
516 } 486 }
517 487
518 if (perf_target__has_task(&opts->target)) 488 err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
519 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 489 process_synthesized_event, opts->sample_address);
520 process_synthesized_event,
521 machine);
522 else if (perf_target__has_cpu(&opts->target))
523 err = perf_event__synthesize_threads(tool, process_synthesized_event,
524 machine);
525 else /* command specified */
526 err = 0;
527
528 if (err != 0) 490 if (err != 0)
529 goto out_delete_session; 491 goto out_delete_session;
530 492
@@ -544,7 +506,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
544 * (apart from group members) have enable_on_exec=1 set, 506 * (apart from group members) have enable_on_exec=1 set,
545 * so don't spoil it by prematurely enabling them. 507 * so don't spoil it by prematurely enabling them.
546 */ 508 */
547 if (!perf_target__none(&opts->target)) 509 if (!target__none(&opts->target))
548 perf_evlist__enable(evsel_list); 510 perf_evlist__enable(evsel_list);
549 511
550 /* 512 /*
@@ -573,7 +535,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
573 * die with the process and we wait for that. Thus no need to 535 * die with the process and we wait for that. Thus no need to
574 * disable events in this case. 536 * disable events in this case.
575 */ 537 */
576 if (done && !disabled && !perf_target__none(&opts->target)) { 538 if (done && !disabled && !target__none(&opts->target)) {
577 perf_evlist__disable(evsel_list); 539 perf_evlist__disable(evsel_list);
578 disabled = true; 540 disabled = true;
579 } 541 }
@@ -590,7 +552,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
590 fprintf(stderr, 552 fprintf(stderr,
591 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 553 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
592 (double)rec->bytes_written / 1024.0 / 1024.0, 554 (double)rec->bytes_written / 1024.0 / 1024.0,
593 output_name, 555 file->path,
594 rec->bytes_written / 24); 556 rec->bytes_written / 24);
595 557
596 return 0; 558 return 0;
@@ -618,6 +580,9 @@ static const struct branch_mode branch_modes[] = {
618 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 580 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
619 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 581 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
620 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 582 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
583 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
584 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
585 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
621 BRANCH_END 586 BRANCH_END
622}; 587};
623 588
@@ -684,7 +649,7 @@ error:
684 return ret; 649 return ret;
685} 650}
686 651
687#ifdef LIBUNWIND_SUPPORT 652#ifdef HAVE_LIBUNWIND_SUPPORT
688static int get_stack_size(char *str, unsigned long *_size) 653static int get_stack_size(char *str, unsigned long *_size)
689{ 654{
690 char *endptr; 655 char *endptr;
@@ -710,23 +675,14 @@ static int get_stack_size(char *str, unsigned long *_size)
710 max_size, str); 675 max_size, str);
711 return -1; 676 return -1;
712} 677}
713#endif /* LIBUNWIND_SUPPORT */ 678#endif /* HAVE_LIBUNWIND_SUPPORT */
714 679
715int record_parse_callchain_opt(const struct option *opt, 680int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
716 const char *arg, int unset)
717{ 681{
718 struct perf_record_opts *opts = opt->value;
719 char *tok, *name, *saveptr = NULL; 682 char *tok, *name, *saveptr = NULL;
720 char *buf; 683 char *buf;
721 int ret = -1; 684 int ret = -1;
722 685
723 /* --no-call-graph */
724 if (unset)
725 return 0;
726
727 /* We specified default option if none is provided. */
728 BUG_ON(!arg);
729
730 /* We need buffer that we know we can write to. */ 686 /* We need buffer that we know we can write to. */
731 buf = malloc(strlen(arg) + 1); 687 buf = malloc(strlen(arg) + 1);
732 if (!buf) 688 if (!buf)
@@ -748,7 +704,7 @@ int record_parse_callchain_opt(const struct option *opt,
748 "needed for -g fp\n"); 704 "needed for -g fp\n");
749 break; 705 break;
750 706
751#ifdef LIBUNWIND_SUPPORT 707#ifdef HAVE_LIBUNWIND_SUPPORT
752 /* Dwarf style */ 708 /* Dwarf style */
753 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 709 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
754 const unsigned long default_stack_dump_size = 8192; 710 const unsigned long default_stack_dump_size = 8192;
@@ -764,13 +720,9 @@ int record_parse_callchain_opt(const struct option *opt,
764 ret = get_stack_size(tok, &size); 720 ret = get_stack_size(tok, &size);
765 opts->stack_dump_size = size; 721 opts->stack_dump_size = size;
766 } 722 }
767 723#endif /* HAVE_LIBUNWIND_SUPPORT */
768 if (!ret)
769 pr_debug("callchain: stack dump size %d\n",
770 opts->stack_dump_size);
771#endif /* LIBUNWIND_SUPPORT */
772 } else { 724 } else {
773 pr_err("callchain: Unknown -g option " 725 pr_err("callchain: Unknown --call-graph option "
774 "value: %s\n", arg); 726 "value: %s\n", arg);
775 break; 727 break;
776 } 728 }
@@ -778,13 +730,52 @@ int record_parse_callchain_opt(const struct option *opt,
778 } while (0); 730 } while (0);
779 731
780 free(buf); 732 free(buf);
733 return ret;
734}
781 735
736static void callchain_debug(struct perf_record_opts *opts)
737{
738 pr_debug("callchain: type %d\n", opts->call_graph);
739
740 if (opts->call_graph == CALLCHAIN_DWARF)
741 pr_debug("callchain: stack dump size %d\n",
742 opts->stack_dump_size);
743}
744
745int record_parse_callchain_opt(const struct option *opt,
746 const char *arg,
747 int unset)
748{
749 struct perf_record_opts *opts = opt->value;
750 int ret;
751
752 /* --no-call-graph */
753 if (unset) {
754 opts->call_graph = CALLCHAIN_NONE;
755 pr_debug("callchain: disabled\n");
756 return 0;
757 }
758
759 ret = record_parse_callchain(arg, opts);
782 if (!ret) 760 if (!ret)
783 pr_debug("callchain: type %d\n", opts->call_graph); 761 callchain_debug(opts);
784 762
785 return ret; 763 return ret;
786} 764}
787 765
766int record_callchain_opt(const struct option *opt,
767 const char *arg __maybe_unused,
768 int unset __maybe_unused)
769{
770 struct perf_record_opts *opts = opt->value;
771
772 if (opts->call_graph == CALLCHAIN_NONE)
773 opts->call_graph = CALLCHAIN_FP;
774
775 callchain_debug(opts);
776 return 0;
777}
778
788static const char * const record_usage[] = { 779static const char * const record_usage[] = {
789 "perf record [<options>] [<command>]", 780 "perf record [<options>] [<command>]",
790 "perf record [<options>] -- <command> [<options>]", 781 "perf record [<options>] -- <command> [<options>]",
@@ -813,12 +804,12 @@ static struct perf_record record = {
813 }, 804 },
814}; 805};
815 806
816#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 807#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
817 808
818#ifdef LIBUNWIND_SUPPORT 809#ifdef HAVE_LIBUNWIND_SUPPORT
819const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; 810const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
820#else 811#else
821const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; 812const char record_callchain_help[] = CALLCHAIN_HELP "fp";
822#endif 813#endif
823 814
824/* 815/*
@@ -849,18 +840,22 @@ const struct option record_options[] = {
849 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 840 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
850 "list of cpus to monitor"), 841 "list of cpus to monitor"),
851 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 842 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
852 OPT_STRING('o', "output", &record.output_name, "file", 843 OPT_STRING('o', "output", &record.file.path, "file",
853 "output file name"), 844 "output file name"),
854 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 845 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
855 "child tasks do not inherit counters"), 846 "child tasks do not inherit counters"),
856 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 847 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
857 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, 848 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
858 "number of mmap data pages"), 849 "number of mmap data pages",
850 perf_evlist__parse_mmap_pages),
859 OPT_BOOLEAN(0, "group", &record.opts.group, 851 OPT_BOOLEAN(0, "group", &record.opts.group,
860 "put the counters into a counter group"), 852 "put the counters into a counter group"),
861 OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, 853 OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
862 "mode[,dump_size]", record_callchain_help, 854 NULL, "enables call-graph recording" ,
863 &record_parse_callchain_opt, "fp"), 855 &record_callchain_opt),
856 OPT_CALLBACK(0, "call-graph", &record.opts,
857 "mode[,dump_size]", record_callchain_help,
858 &record_parse_callchain_opt),
864 OPT_INCR('v', "verbose", &verbose, 859 OPT_INCR('v', "verbose", &verbose,
865 "be more verbose (show counter open errors, etc)"), 860 "be more verbose (show counter open errors, etc)"),
866 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 861 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
@@ -891,6 +886,10 @@ const struct option record_options[] = {
891 parse_branch_stack), 886 parse_branch_stack),
892 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 887 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
893 "sample by weight (on special events only)"), 888 "sample by weight (on special events only)"),
889 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
890 "sample transaction flags (special events only)"),
891 OPT_BOOLEAN(0, "force-per-cpu", &record.opts.target.force_per_cpu,
892 "force the use of per-cpu mmaps"),
894 OPT_END() 893 OPT_END()
895}; 894};
896 895
@@ -909,7 +908,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
909 908
910 argc = parse_options(argc, argv, record_options, record_usage, 909 argc = parse_options(argc, argv, record_options, record_usage,
911 PARSE_OPT_STOP_AT_NON_OPTION); 910 PARSE_OPT_STOP_AT_NON_OPTION);
912 if (!argc && perf_target__none(&rec->opts.target)) 911 if (!argc && target__none(&rec->opts.target))
913 usage_with_options(record_usage, record_options); 912 usage_with_options(record_usage, record_options);
914 913
915 if (nr_cgroups && !rec->opts.target.system_wide) { 914 if (nr_cgroups && !rec->opts.target.system_wide) {
@@ -939,17 +938,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
939 goto out_symbol_exit; 938 goto out_symbol_exit;
940 } 939 }
941 940
942 err = perf_target__validate(&rec->opts.target); 941 err = target__validate(&rec->opts.target);
943 if (err) { 942 if (err) {
944 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 943 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
945 ui__warning("%s", errbuf); 944 ui__warning("%s", errbuf);
946 } 945 }
947 946
948 err = perf_target__parse_uid(&rec->opts.target); 947 err = target__parse_uid(&rec->opts.target);
949 if (err) { 948 if (err) {
950 int saved_errno = errno; 949 int saved_errno = errno;
951 950
952 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 951 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
953 ui__error("%s", errbuf); 952 ui__error("%s", errbuf);
954 953
955 err = -saved_errno; 954 err = -saved_errno;
@@ -960,20 +959,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
960 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 959 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
961 usage_with_options(record_usage, record_options); 960 usage_with_options(record_usage, record_options);
962 961
963 if (rec->opts.user_interval != ULLONG_MAX) 962 if (perf_record_opts__config(&rec->opts)) {
964 rec->opts.default_interval = rec->opts.user_interval;
965 if (rec->opts.user_freq != UINT_MAX)
966 rec->opts.freq = rec->opts.user_freq;
967
968 /*
969 * User specified count overrides default frequency.
970 */
971 if (rec->opts.default_interval)
972 rec->opts.freq = 0;
973 else if (rec->opts.freq) {
974 rec->opts.default_interval = rec->opts.freq;
975 } else {
976 ui__error("frequency and count are zero, aborting\n");
977 err = -EINVAL; 963 err = -EINVAL;
978 goto out_free_fd; 964 goto out_free_fd;
979 } 965 }