aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-11 20:06:34 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-11 20:06:34 -0500
commitad5d69899e52792671c1aa6c7360464c7edfe09c (patch)
tree21833c1fdab4b3cf791d4fdc86dd578e4a620514 /tools/perf/builtin-record.c
parentef1417a5a6a400dbc1a2f44da716ab146a29ddc4 (diff)
parentcaea6cf52139116e43e615d87fcbf9823e197fdf (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "As a first remark I'd like to note that the way to build perf tooling has been simplified and sped up, in the future it should be enough for you to build perf via: cd tools/perf/ make install (ie without the -j option.) The build system will figure out the number of CPUs and will do a parallel build+install. The various build system inefficiencies and breakages Linus reported against the v3.12 pull request should now be resolved - please (re-)report any remaining annoyances or bugs. Main changes on the perf kernel side: * Performance optimizations: . perf ring-buffer code optimizations, by Peter Zijlstra . perf ring-buffer code optimizations, by Oleg Nesterov . x86 NMI call-stack processing optimizations, by Peter Zijlstra . perf context-switch optimizations, by Peter Zijlstra . perf sampling speedups, by Peter Zijlstra . x86 Intel PEBS processing speedups, by Peter Zijlstra * Enhanced hardware support: . for Intel Ivy Bridge-EP uncore PMUs, by Zheng Yan . for Haswell transactions, by Andi Kleen, Peter Zijlstra * Core perf events code enhancements and fixes by Oleg Nesterov: . for uprobes, if fork() is called with pending ret-probes . for uprobes platform support code * New ABI details by Andi Kleen: . Report x86 Haswell TSX transaction abort cost as weight Main changes on the perf tooling side (some of these tooling changes utilize the above kernel side changes): * 'perf report/top' enhancements: . Convert callchain children list to rbtree, greatly reducing the time taken for callchain processing, from Namhyung Kim. . Add new COMM infrastructure, further improving histogram processing, from Frédéric Weisbecker, one fix from Namhyung Kim. . Add /proc/kcore based live-annotation improvements, including build-id cache support, multi map 'call' instruction navigation fixes, kcore address validation, objdump workarounds. From Adrian Hunter. . Show progress on histogram collapsing, that can take a long time, from Namhyung Kim. . Add --max-stack option to limit callchain stack scan in 'top' and 'report', improving callchain processing when reducing the stack depth is an option, from Waiman Long. . Add new option --ignore-vmlinux for perf top, from Willy Tarreau. * 'perf trace' enhancements: . 'perf trace' now can can use a 'perf probe' dynamic tracepoints to hook into the userspace -> kernel pathname copy so that it can map fds to pathnames without reading /proc/pid/fd/ symlinks. From Arnaldo Carvalho de Melo. . Show VFS path associated with fd in live sessions, using a 'vfs_getname' 'perf probe' created dynamic tracepoint or by looking at /proc/pid/fd, from Arnaldo Carvalho de Melo. . Add 'trace' beautifiers for lots of syscall arguments, from Arnaldo Carvalho de Melo. . Implement more compact 'trace' output by suppressing zeroed args, from Arnaldo Carvalho de Melo. . Show thread COMM by default in 'trace', from Arnaldo Carvalho de Melo. . Add option to show full timestamp in 'trace', from David Ahern. . Add 'record' command in 'trace', to record raw_syscalls:*, from David Ahern. . Add summary option to dump syscall statistics in 'trace', from David Ahern. . Improve error messages in 'trace', providing hints about system configuration steps needed for using it, from Ramkumar Ramachandra. . 'perf trace' now emits hints as to why tracing is not possible, helping the user to setup the system to allow tracing in the desired permission granularity, telling if the problem is due to debugfs not being mounted or with not enough permission for !root, /proc/sys/kernel/perf_event_paranoit value, etc. From Arnaldo Carvalho de Melo. * 'perf record' enhancements: . Check maximum frequency rate for record/top, emitting better error messages, from Jiri Olsa. . 'perf record' code cleanups, from David Ahern. . Improve write_output error message in 'perf record', from Adrian Hunter. . Allow specifying B/K/M/G unit to the --mmap-pages arguments, from Jiri Olsa. . Fix command line callchain attribute tests to handle the new -g/--call-chain semantics, from Arnaldo Carvalho de Melo. * 'perf kvm' enhancements: . Disable live kvm command if timerfd is not supported, from David Ahern. . Fix detection of non-core features, from David Ahern. * 'perf list' enhancements: . Add usage to 'perf list', from David Ahern. . Show error in 'perf list' if tracepoints not available, from Pekka Enberg. * 'perf probe' enhancements: . Support "$vars" meta argument syntax for local variables, allowing asking for all possible variables at a given probe point to be collected when it hits, from Masami Hiramatsu. * 'perf sched' enhancements: . Address the root cause of that 'perf sched' stack initialization build slowdown, by programmatically setting a big array after moving the global variable back to the stack. Fix from Adrian Hunter. * 'perf script' enhancements: . Set up output options for in-stream attributes, from Adrian Hunter. . Print addr by default for BTS in 'perf script', from Adrian Juntmer * 'perf stat' enhancements: . Improved messages when doing profiling in all or a subset of CPUs using a workload as the session delimitator, as in: 'perf stat --cpu 0,2 sleep 10s' from Arnaldo Carvalho de Melo. . Add units to nanosec-based counters in 'perf stat', from David Ahern. . Remove bogus info when using 'perf stat' -e cycles/instructions, from Ramkumar Ramachandra. * 'perf lock' enhancements: . 'perf lock' fixes and cleanups, from Davidlohr Bueso. * 'perf test' enhancements: . Fixup PERF_SAMPLE_TRANSACTION handling in sample synthesizing and 'perf test', from Adrian Hunter. . Clarify the "sample parsing" test entry, from Arnaldo Carvalho de Melo. . Consider PERF_SAMPLE_TRANSACTION in the "sample parsing" test, from Arnaldo Carvalho de Melo. . Memory leak fixes in 'perf test', from Felipe Pena. * 'perf bench' enhancements: . Change the procps visible command-name of invididual benchmark tests plus cleanups, from Ingo Molnar. * Generic perf tooling infrastructure/plumbing changes: . Separating data file properties from session, code reorganization from Jiri Olsa. . Fix version when building out of tree, as when using one of these: $ make help | grep perf perf-tar-src-pkg - Build perf-3.12.0.tar source tarball perf-targz-src-pkg - Build perf-3.12.0.tar.gz source tarball perf-tarbz2-src-pkg - Build perf-3.12.0.tar.bz2 source tarball perf-tarxz-src-pkg - Build perf-3.12.0.tar.xz source tarball $ from David Ahern. . Enhance option parse error message, showing just the help lines of the options affected, from Namhyung Kim. . libtraceevent updates from upstream trace-cmd repo, from Steven Rostedt. . Always use perf_evsel__set_sample_bit to set sample_type, from Adrian Hunter. . Memory and mmap leak fixes from Chenggang Qin. . Assorted build fixes for from David Ahern and Jiri Olsa. . Speed up and prettify the build system, from Ingo Molnar. . Implement addr2line directly using libbfd, from Roberto Vitillo. . Separate the GTK support in a separate libperf-gtk.so DSO, that is only loaded when --gtk is specified, from Namhyung Kim. . perf bash completion fixes and improvements from Ramkumar Ramachandra. . Support for Openembedded/Yocto -dbg packages, from Ricardo Ribalda Delgado. And lots and lots of other fixes and code reorganizations that did not make it into the list, see the shortlog, diffstat and the Git log for details!" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (300 commits) uprobes: Fix the memory out of bound overwrite in copy_insn() uprobes: Fix the wrong usage of current->utask in uprobe_copy_process() perf tools: Remove unneeded include perf record: Remove post_processing_offset variable perf record: Remove advance_output function perf record: Refactor feature handling into a separate function perf trace: Don't relookup fields by name in each sample perf tools: Fix version when building out of tree perf evsel: Ditch evsel->handler.data field uprobes: Export write_opcode() as uprobe_write_opcode() uprobes: Introduce arch_uprobe->ixol uprobes: Kill module_init() and module_exit() uprobes: Move function declarations out of arch perf/x86/intel: Add Ivy Bridge-EP uncore IRP box support perf/x86/intel/uncore: Add filter support for IvyBridge-EP QPI boxes perf: Factor out strncpy() in perf_event_mmap_event() tools/perf: Add required memory barriers perf: Fix arch_perf_out_copy_user default perf: Update a stale comment perf: Optimize perf_output_begin() -- address calculation ...
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 }