aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 13:28:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 13:28:49 -0400
commit7e92daaefa68e5ef1e1732e45231e73adbb724e7 (patch)
tree8e7f8ac9d82654df4c65939c6682f95510e22977 /tools/perf/builtin-record.c
parent7a68294278ae714ce2632a54f0f46916dca64f56 (diff)
parent1d787d37c8ff6612b8151c6dff15bfa7347bcbdf (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf update from Ingo Molnar: "Lots of changes in this cycle as well, with hundreds of commits from over 30 contributors. Most of the activity was on the tooling side. Higher level changes: - New 'perf kvm' analysis tool, from Xiao Guangrong. - New 'perf trace' system-wide tracing tool - uprobes fixes + cleanups from Oleg Nesterov. - Lots of patches to make perf build on Android out of box, from Irina Tirdea - Extend ftrace function tracing utility to be more dynamic for its users. It allows for data passing to the callback functions, as well as reading regs as if a breakpoint were to trigger at function entry. The main goal of this patch series was to allow kprobes to use ftrace as an optimized probe point when a probe is placed on an ftrace nop. With lots of help from Masami Hiramatsu, and going through lots of iterations, we finally came up with a good solution. - Add cpumask for uncore pmu, use it in 'stat', from Yan, Zheng. - Various tracing updates from Steve Rostedt - Clean up and improve 'perf sched' performance by elliminating lots of needless calls to libtraceevent. - Event group parsing support, from Jiri Olsa - UI/gtk refactorings and improvements from Namhyung Kim - Add support for non-tracepoint events in perf script python, from Feng Tang - Add --symbols to 'script', similar to the one in 'report', from Feng Tang. Infrastructure enhancements and fixes: - Convert the trace builtins to use the growing evsel/evlist tracepoint infrastructure, removing several open coded constructs like switch like series of strcmp to dispatch events, etc. Basically what had already been showcased in 'perf sched'. - Add evsel constructor for tracepoints, that uses libtraceevent just to parse the /format events file, use it in a new 'perf test' to make sure the libtraceevent format parsing regressions can be more readily caught. - Some strange errors were happening in some builds, but not on the next, reported by several people, problem was some parser related files, generated during the build, didn't had proper make deps, fix from Eric Sandeen. - Introduce struct and cache information about the environment where a perf.data file was captured, from Namhyung Kim. - Fix handling of unresolved samples when --symbols is used in 'report', from Feng Tang. - Add union member access support to 'probe', from Hyeoncheol Lee. - Fixups to die() removal, from Namhyung Kim. - Render fixes for the TUI, from Namhyung Kim. - Don't enable annotation in non symbolic view, from Namhyung Kim. - Fix pipe mode in 'report', from Namhyung Kim. - Move related stats code from stat to util/, will be used by the 'stat' kvm tool, from Xiao Guangrong. - Remove die()/exit() calls from several tools. - Resolve vdso callchains, from Jiri Olsa - Don't pass const char pointers to basename, so that we can unconditionally use libgen.h and thus avoid ifdef BIONIC lines, from David Ahern - Refactor hist formatting so that it can be reused with the GTK browser, From Namhyung Kim - Fix build for another rbtree.c change, from Adrian Hunter. - Make 'perf diff' command work with evsel hists, from Jiri Olsa. - Use the only field_sep var that is set up: symbol_conf.field_sep, fix from Jiri Olsa. - .gitignore compiled python binaries, from Namhyung Kim. - Get rid of die() in more libtraceevent places, from Namhyung Kim. - Rename libtraceevent 'private' struct member to 'priv' so that it works in C++, from Steven Rostedt - Remove lots of exit()/die() calls from tools so that the main perf exit routine can take place, from David Ahern - Fix x86 build on x86-64, from David Ahern. - {int,str,rb}list fixes from Suzuki K Poulose - perf.data header fixes from Namhyung Kim - Allow user to indicate objdump path, needed in cross environments, from Maciek Borzecki - Fix hardware cache event name generation, fix from Jiri Olsa - Add round trip test for sw, hw and cache event names, catching the problem Jiri fixed, after Jiri's patch, the test passes successfully. - Clean target should do clean for lib/traceevent too, fix from David Ahern - Check the right variable for allocation failure, fix from Namhyung Kim - Set up evsel->tp_format regardless of evsel->name being set already, fix from Namhyung Kim - Oprofile fixes from Robert Richter. - Remove perf_event_attr needless version inflation, from Jiri Olsa - Introduce libtraceevent strerror like error reporting facility, from Namhyung Kim - Add pmu mappings to perf.data header and use event names from cmd line, from Robert Richter - Fix include order for bison/flex-generated C files, from Ben Hutchings - Build fixes and documentation corrections from David Ahern - Assorted cleanups from Robert Richter - Let O= makes handle relative paths, from Steven Rostedt - perf script python fixes, from Feng Tang. - Initial bash completion support, from Frederic Weisbecker - Allow building without libelf, from Namhyung Kim. - Support DWARF CFI based unwind to have callchains when %bp based unwinding is not possible, from Jiri Olsa. - Symbol resolution fixes, while fixing support PPC64 files with an .opt ELF section was the end goal, several fixes for code that handles all architectures and cleanups are included, from Cody Schafer. - Assorted fixes for Documentation and build in 32 bit, from Robert Richter - Cache the libtraceevent event_format associated to each evsel early, so that we avoid relookups, i.e. calling pevent_find_event repeatedly when processing tracepoint events. [ This is to reduce the surface contact with libtraceevents and make clear what is that the perf tools needs from that lib: so far parsing the common and per event fields. ] - Don't stop the build if the audit libraries are not installed, fix from Namhyung Kim. - Fix bfd.h/libbfd detection with recent binutils, from Markus Trippelsdorf. - Improve warning message when libunwind devel packages not present, from Jiri Olsa" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (282 commits) perf trace: Add aliases for some syscalls perf probe: Print an enum type variable in "enum variable-name" format when showing accessible variables perf tools: Check libaudit availability for perf-trace builtin perf hists: Add missing period_* fields when collapsing a hist entry perf trace: New tool perf evsel: Export the event_format constructor perf evsel: Introduce rawptr() method perf tools: Use perf_evsel__newtp in the event parser perf evsel: The tracepoint constructor should store sys:name perf evlist: Introduce set_filter() method perf evlist: Renane set_filters method to apply_filters perf test: Add test to check we correctly parse and match syscall open parms perf evsel: Handle endianity in intval method perf evsel: Know if byte swap is needed perf tools: Allow handling a NULL cpu_map as meaning "all cpus" perf evsel: Improve tracepoint constructor setup tools lib traceevent: Fix error path on pevent_parse_event perf test: Fix build failure trace: Move trace event enable from fs_initcall to core_initcall tracing: Add an option for disabling markers ...
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c305
1 files changed, 237 insertions, 68 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4db6e1ba54e3..f14cb5fdb91f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,6 +31,15 @@
31#include <sched.h> 31#include <sched.h>
32#include <sys/mman.h> 32#include <sys/mman.h>
33 33
34#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
35
36#ifdef NO_LIBUNWIND_SUPPORT
37static char callchain_help[] = CALLCHAIN_HELP "[fp]";
38#else
39static unsigned long default_stack_dump_size = 8192;
40static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
41#endif
42
34enum write_mode_t { 43enum write_mode_t {
35 WRITE_FORCE, 44 WRITE_FORCE,
36 WRITE_APPEND 45 WRITE_APPEND
@@ -62,32 +71,38 @@ static void advance_output(struct perf_record *rec, size_t size)
62 rec->bytes_written += size; 71 rec->bytes_written += size;
63} 72}
64 73
65static void write_output(struct perf_record *rec, void *buf, size_t size) 74static int write_output(struct perf_record *rec, void *buf, size_t size)
66{ 75{
67 while (size) { 76 while (size) {
68 int ret = write(rec->output, buf, size); 77 int ret = write(rec->output, buf, size);
69 78
70 if (ret < 0) 79 if (ret < 0) {
71 die("failed to write"); 80 pr_err("failed to write\n");
81 return -1;
82 }
72 83
73 size -= ret; 84 size -= ret;
74 buf += ret; 85 buf += ret;
75 86
76 rec->bytes_written += ret; 87 rec->bytes_written += ret;
77 } 88 }
89
90 return 0;
78} 91}
79 92
80static int process_synthesized_event(struct perf_tool *tool, 93static int process_synthesized_event(struct perf_tool *tool,
81 union perf_event *event, 94 union perf_event *event,
82 struct perf_sample *sample __used, 95 struct perf_sample *sample __maybe_unused,
83 struct machine *machine __used) 96 struct machine *machine __maybe_unused)
84{ 97{
85 struct perf_record *rec = container_of(tool, struct perf_record, tool); 98 struct perf_record *rec = container_of(tool, struct perf_record, tool);
86 write_output(rec, event, event->header.size); 99 if (write_output(rec, event, event->header.size) < 0)
100 return -1;
101
87 return 0; 102 return 0;
88} 103}
89 104
90static void perf_record__mmap_read(struct perf_record *rec, 105static int perf_record__mmap_read(struct perf_record *rec,
91 struct perf_mmap *md) 106 struct perf_mmap *md)
92{ 107{
93 unsigned int head = perf_mmap__read_head(md); 108 unsigned int head = perf_mmap__read_head(md);
@@ -95,9 +110,10 @@ static void perf_record__mmap_read(struct perf_record *rec,
95 unsigned char *data = md->base + rec->page_size; 110 unsigned char *data = md->base + rec->page_size;
96 unsigned long size; 111 unsigned long size;
97 void *buf; 112 void *buf;
113 int rc = 0;
98 114
99 if (old == head) 115 if (old == head)
100 return; 116 return 0;
101 117
102 rec->samples++; 118 rec->samples++;
103 119
@@ -108,17 +124,26 @@ static void perf_record__mmap_read(struct perf_record *rec,
108 size = md->mask + 1 - (old & md->mask); 124 size = md->mask + 1 - (old & md->mask);
109 old += size; 125 old += size;
110 126
111 write_output(rec, buf, size); 127 if (write_output(rec, buf, size) < 0) {
128 rc = -1;
129 goto out;
130 }
112 } 131 }
113 132
114 buf = &data[old & md->mask]; 133 buf = &data[old & md->mask];
115 size = head - old; 134 size = head - old;
116 old += size; 135 old += size;
117 136
118 write_output(rec, buf, size); 137 if (write_output(rec, buf, size) < 0) {
138 rc = -1;
139 goto out;
140 }
119 141
120 md->prev = old; 142 md->prev = old;
121 perf_mmap__write_tail(md, old); 143 perf_mmap__write_tail(md, old);
144
145out:
146 return rc;
122} 147}
123 148
124static volatile int done = 0; 149static volatile int done = 0;
@@ -134,7 +159,7 @@ static void sig_handler(int sig)
134 signr = sig; 159 signr = sig;
135} 160}
136 161
137static void perf_record__sig_exit(int exit_status __used, void *arg) 162static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
138{ 163{
139 struct perf_record *rec = arg; 164 struct perf_record *rec = arg;
140 int status; 165 int status;
@@ -163,31 +188,32 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
163 if (evlist->nr_entries != other->nr_entries) 188 if (evlist->nr_entries != other->nr_entries)
164 return false; 189 return false;
165 190
166 pair = list_entry(other->entries.next, struct perf_evsel, node); 191 pair = perf_evlist__first(other);
167 192
168 list_for_each_entry(pos, &evlist->entries, node) { 193 list_for_each_entry(pos, &evlist->entries, node) {
169 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0)) 194 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
170 return false; 195 return false;
171 pair = list_entry(pair->node.next, struct perf_evsel, node); 196 pair = perf_evsel__next(pair);
172 } 197 }
173 198
174 return true; 199 return true;
175} 200}
176 201
177static void perf_record__open(struct perf_record *rec) 202static int perf_record__open(struct perf_record *rec)
178{ 203{
179 struct perf_evsel *pos, *first; 204 struct perf_evsel *pos;
180 struct perf_evlist *evlist = rec->evlist; 205 struct perf_evlist *evlist = rec->evlist;
181 struct perf_session *session = rec->session; 206 struct perf_session *session = rec->session;
182 struct perf_record_opts *opts = &rec->opts; 207 struct perf_record_opts *opts = &rec->opts;
183 208 int rc = 0;
184 first = list_entry(evlist->entries.next, struct perf_evsel, node);
185 209
186 perf_evlist__config_attrs(evlist, opts); 210 perf_evlist__config_attrs(evlist, opts);
187 211
212 if (opts->group)
213 perf_evlist__set_leader(evlist);
214
188 list_for_each_entry(pos, &evlist->entries, node) { 215 list_for_each_entry(pos, &evlist->entries, node) {
189 struct perf_event_attr *attr = &pos->attr; 216 struct perf_event_attr *attr = &pos->attr;
190 struct xyarray *group_fd = NULL;
191 /* 217 /*
192 * Check if parse_single_tracepoint_event has already asked for 218 * Check if parse_single_tracepoint_event has already asked for
193 * PERF_SAMPLE_TIME. 219 * PERF_SAMPLE_TIME.
@@ -202,24 +228,24 @@ static void perf_record__open(struct perf_record *rec)
202 */ 228 */
203 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 229 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
204 230
205 if (opts->group && pos != first)
206 group_fd = first->fd;
207fallback_missing_features: 231fallback_missing_features:
208 if (opts->exclude_guest_missing) 232 if (opts->exclude_guest_missing)
209 attr->exclude_guest = attr->exclude_host = 0; 233 attr->exclude_guest = attr->exclude_host = 0;
210retry_sample_id: 234retry_sample_id:
211 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 235 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
212try_again: 236try_again:
213 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, 237 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
214 opts->group, group_fd) < 0) {
215 int err = errno; 238 int err = errno;
216 239
217 if (err == EPERM || err == EACCES) { 240 if (err == EPERM || err == EACCES) {
218 ui__error_paranoid(); 241 ui__error_paranoid();
219 exit(EXIT_FAILURE); 242 rc = -err;
243 goto out;
220 } else if (err == ENODEV && opts->target.cpu_list) { 244 } else if (err == ENODEV && opts->target.cpu_list) {
221 die("No such device - did you specify" 245 pr_err("No such device - did you specify"
222 " an out-of-range profile CPU?\n"); 246 " an out-of-range profile CPU?\n");
247 rc = -err;
248 goto out;
223 } else if (err == EINVAL) { 249 } else if (err == EINVAL) {
224 if (!opts->exclude_guest_missing && 250 if (!opts->exclude_guest_missing &&
225 (attr->exclude_guest || attr->exclude_host)) { 251 (attr->exclude_guest || attr->exclude_host)) {
@@ -266,42 +292,57 @@ try_again:
266 if (err == ENOENT) { 292 if (err == ENOENT) {
267 ui__error("The %s event is not supported.\n", 293 ui__error("The %s event is not supported.\n",
268 perf_evsel__name(pos)); 294 perf_evsel__name(pos));
269 exit(EXIT_FAILURE); 295 rc = -err;
296 goto out;
270 } 297 }
271 298
272 printf("\n"); 299 printf("\n");
273 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 300 error("sys_perf_event_open() syscall returned with %d "
274 err, strerror(err)); 301 "(%s) for event %s. /bin/dmesg may provide "
302 "additional information.\n",
303 err, strerror(err), perf_evsel__name(pos));
275 304
276#if defined(__i386__) || defined(__x86_64__) 305#if defined(__i386__) || defined(__x86_64__)
277 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 306 if (attr->type == PERF_TYPE_HARDWARE &&
278 die("No hardware sampling interrupt available." 307 err == EOPNOTSUPP) {
279 " No APIC? If so then you can boot the kernel" 308 pr_err("No hardware sampling interrupt available."
280 " with the \"lapic\" boot parameter to" 309 " No APIC? If so then you can boot the kernel"
281 " force-enable it.\n"); 310 " with the \"lapic\" boot parameter to"
311 " force-enable it.\n");
312 rc = -err;
313 goto out;
314 }
282#endif 315#endif
283 316
284 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 317 pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
318 rc = -err;
319 goto out;
285 } 320 }
286 } 321 }
287 322
288 if (perf_evlist__set_filters(evlist)) { 323 if (perf_evlist__apply_filters(evlist)) {
289 error("failed to set filter with %d (%s)\n", errno, 324 error("failed to set filter with %d (%s)\n", errno,
290 strerror(errno)); 325 strerror(errno));
291 exit(-1); 326 rc = -1;
327 goto out;
292 } 328 }
293 329
294 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 330 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
295 if (errno == EPERM) 331 if (errno == EPERM) {
296 die("Permission error mapping pages.\n" 332 pr_err("Permission error mapping pages.\n"
297 "Consider increasing " 333 "Consider increasing "
298 "/proc/sys/kernel/perf_event_mlock_kb,\n" 334 "/proc/sys/kernel/perf_event_mlock_kb,\n"
299 "or try again with a smaller value of -m/--mmap_pages.\n" 335 "or try again with a smaller value of -m/--mmap_pages.\n"
300 "(current value: %d)\n", opts->mmap_pages); 336 "(current value: %d)\n", opts->mmap_pages);
301 else if (!is_power_of_2(opts->mmap_pages)) 337 rc = -errno;
302 die("--mmap_pages/-m value must be a power of two."); 338 } else if (!is_power_of_2(opts->mmap_pages)) {
303 339 pr_err("--mmap_pages/-m value must be a power of two.");
304 die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 340 rc = -EINVAL;
341 } else {
342 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
343 rc = -errno;
344 }
345 goto out;
305 } 346 }
306 347
307 if (rec->file_new) 348 if (rec->file_new)
@@ -309,11 +350,14 @@ try_again:
309 else { 350 else {
310 if (!perf_evlist__equal(session->evlist, evlist)) { 351 if (!perf_evlist__equal(session->evlist, evlist)) {
311 fprintf(stderr, "incompatible append\n"); 352 fprintf(stderr, "incompatible append\n");
312 exit(-1); 353 rc = -1;
354 goto out;
313 } 355 }
314 } 356 }
315 357
316 perf_session__set_id_hdr_size(session); 358 perf_session__set_id_hdr_size(session);
359out:
360 return rc;
317} 361}
318 362
319static int process_buildids(struct perf_record *rec) 363static int process_buildids(struct perf_record *rec)
@@ -329,10 +373,13 @@ static int process_buildids(struct perf_record *rec)
329 size, &build_id__mark_dso_hit_ops); 373 size, &build_id__mark_dso_hit_ops);
330} 374}
331 375
332static void perf_record__exit(int status __used, void *arg) 376static void perf_record__exit(int status, void *arg)
333{ 377{
334 struct perf_record *rec = arg; 378 struct perf_record *rec = arg;
335 379
380 if (status != 0)
381 return;
382
336 if (!rec->opts.pipe_output) { 383 if (!rec->opts.pipe_output) {
337 rec->session->header.data_size += rec->bytes_written; 384 rec->session->header.data_size += rec->bytes_written;
338 385
@@ -387,17 +434,26 @@ static struct perf_event_header finished_round_event = {
387 .type = PERF_RECORD_FINISHED_ROUND, 434 .type = PERF_RECORD_FINISHED_ROUND,
388}; 435};
389 436
390static void perf_record__mmap_read_all(struct perf_record *rec) 437static int perf_record__mmap_read_all(struct perf_record *rec)
391{ 438{
392 int i; 439 int i;
440 int rc = 0;
393 441
394 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 442 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
395 if (rec->evlist->mmap[i].base) 443 if (rec->evlist->mmap[i].base) {
396 perf_record__mmap_read(rec, &rec->evlist->mmap[i]); 444 if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
445 rc = -1;
446 goto out;
447 }
448 }
397 } 449 }
398 450
399 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 451 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
400 write_output(rec, &finished_round_event, sizeof(finished_round_event)); 452 rc = write_output(rec, &finished_round_event,
453 sizeof(finished_round_event));
454
455out:
456 return rc;
401} 457}
402 458
403static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 459static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
@@ -457,7 +513,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
457 output = open(output_name, flags, S_IRUSR | S_IWUSR); 513 output = open(output_name, flags, S_IRUSR | S_IWUSR);
458 if (output < 0) { 514 if (output < 0) {
459 perror("failed to create output file"); 515 perror("failed to create output file");
460 exit(-1); 516 return -1;
461 } 517 }
462 518
463 rec->output = output; 519 rec->output = output;
@@ -497,7 +553,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
497 } 553 }
498 } 554 }
499 555
500 perf_record__open(rec); 556 if (perf_record__open(rec) != 0) {
557 err = -1;
558 goto out_delete_session;
559 }
501 560
502 /* 561 /*
503 * perf_session__delete(session) will be called at perf_record__exit() 562 * perf_session__delete(session) will be called at perf_record__exit()
@@ -507,19 +566,20 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
507 if (opts->pipe_output) { 566 if (opts->pipe_output) {
508 err = perf_header__write_pipe(output); 567 err = perf_header__write_pipe(output);
509 if (err < 0) 568 if (err < 0)
510 return err; 569 goto out_delete_session;
511 } else if (rec->file_new) { 570 } else if (rec->file_new) {
512 err = perf_session__write_header(session, evsel_list, 571 err = perf_session__write_header(session, evsel_list,
513 output, false); 572 output, false);
514 if (err < 0) 573 if (err < 0)
515 return err; 574 goto out_delete_session;
516 } 575 }
517 576
518 if (!rec->no_buildid 577 if (!rec->no_buildid
519 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { 578 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
520 pr_err("Couldn't generate buildids. " 579 pr_err("Couldn't generate buildids. "
521 "Use --no-buildid to profile anyway.\n"); 580 "Use --no-buildid to profile anyway.\n");
522 return -1; 581 err = -1;
582 goto out_delete_session;
523 } 583 }
524 584
525 rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 585 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
@@ -527,7 +587,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
527 machine = perf_session__find_host_machine(session); 587 machine = perf_session__find_host_machine(session);
528 if (!machine) { 588 if (!machine) {
529 pr_err("Couldn't find native kernel information.\n"); 589 pr_err("Couldn't find native kernel information.\n");
530 return -1; 590 err = -1;
591 goto out_delete_session;
531 } 592 }
532 593
533 if (opts->pipe_output) { 594 if (opts->pipe_output) {
@@ -535,14 +596,14 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
535 process_synthesized_event); 596 process_synthesized_event);
536 if (err < 0) { 597 if (err < 0) {
537 pr_err("Couldn't synthesize attrs.\n"); 598 pr_err("Couldn't synthesize attrs.\n");
538 return err; 599 goto out_delete_session;
539 } 600 }
540 601
541 err = perf_event__synthesize_event_types(tool, process_synthesized_event, 602 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
542 machine); 603 machine);
543 if (err < 0) { 604 if (err < 0) {
544 pr_err("Couldn't synthesize event_types.\n"); 605 pr_err("Couldn't synthesize event_types.\n");
545 return err; 606 goto out_delete_session;
546 } 607 }
547 608
548 if (have_tracepoints(&evsel_list->entries)) { 609 if (have_tracepoints(&evsel_list->entries)) {
@@ -558,7 +619,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
558 process_synthesized_event); 619 process_synthesized_event);
559 if (err <= 0) { 620 if (err <= 0) {
560 pr_err("Couldn't record tracing data.\n"); 621 pr_err("Couldn't record tracing data.\n");
561 return err; 622 goto out_delete_session;
562 } 623 }
563 advance_output(rec, err); 624 advance_output(rec, err);
564 } 625 }
@@ -586,20 +647,24 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
586 perf_event__synthesize_guest_os); 647 perf_event__synthesize_guest_os);
587 648
588 if (!opts->target.system_wide) 649 if (!opts->target.system_wide)
589 perf_event__synthesize_thread_map(tool, evsel_list->threads, 650 err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
590 process_synthesized_event, 651 process_synthesized_event,
591 machine); 652 machine);
592 else 653 else
593 perf_event__synthesize_threads(tool, process_synthesized_event, 654 err = perf_event__synthesize_threads(tool, process_synthesized_event,
594 machine); 655 machine);
595 656
657 if (err != 0)
658 goto out_delete_session;
659
596 if (rec->realtime_prio) { 660 if (rec->realtime_prio) {
597 struct sched_param param; 661 struct sched_param param;
598 662
599 param.sched_priority = rec->realtime_prio; 663 param.sched_priority = rec->realtime_prio;
600 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 664 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
601 pr_err("Could not set realtime priority.\n"); 665 pr_err("Could not set realtime priority.\n");
602 exit(-1); 666 err = -1;
667 goto out_delete_session;
603 } 668 }
604 } 669 }
605 670
@@ -614,7 +679,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
614 for (;;) { 679 for (;;) {
615 int hits = rec->samples; 680 int hits = rec->samples;
616 681
617 perf_record__mmap_read_all(rec); 682 if (perf_record__mmap_read_all(rec) < 0) {
683 err = -1;
684 goto out_delete_session;
685 }
618 686
619 if (hits == rec->samples) { 687 if (hits == rec->samples) {
620 if (done) 688 if (done)
@@ -732,6 +800,106 @@ error:
732 return ret; 800 return ret;
733} 801}
734 802
803#ifndef NO_LIBUNWIND_SUPPORT
804static int get_stack_size(char *str, unsigned long *_size)
805{
806 char *endptr;
807 unsigned long size;
808 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
809
810 size = strtoul(str, &endptr, 0);
811
812 do {
813 if (*endptr)
814 break;
815
816 size = round_up(size, sizeof(u64));
817 if (!size || size > max_size)
818 break;
819
820 *_size = size;
821 return 0;
822
823 } while (0);
824
825 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
826 max_size, str);
827 return -1;
828}
829#endif /* !NO_LIBUNWIND_SUPPORT */
830
831static int
832parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
833 int unset)
834{
835 struct perf_record *rec = (struct perf_record *)opt->value;
836 char *tok, *name, *saveptr = NULL;
837 char *buf;
838 int ret = -1;
839
840 /* --no-call-graph */
841 if (unset)
842 return 0;
843
844 /* We specified default option if none is provided. */
845 BUG_ON(!arg);
846
847 /* We need buffer that we know we can write to. */
848 buf = malloc(strlen(arg) + 1);
849 if (!buf)
850 return -ENOMEM;
851
852 strcpy(buf, arg);
853
854 tok = strtok_r((char *)buf, ",", &saveptr);
855 name = tok ? : (char *)buf;
856
857 do {
858 /* Framepointer style */
859 if (!strncmp(name, "fp", sizeof("fp"))) {
860 if (!strtok_r(NULL, ",", &saveptr)) {
861 rec->opts.call_graph = CALLCHAIN_FP;
862 ret = 0;
863 } else
864 pr_err("callchain: No more arguments "
865 "needed for -g fp\n");
866 break;
867
868#ifndef NO_LIBUNWIND_SUPPORT
869 /* Dwarf style */
870 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
871 ret = 0;
872 rec->opts.call_graph = CALLCHAIN_DWARF;
873 rec->opts.stack_dump_size = default_stack_dump_size;
874
875 tok = strtok_r(NULL, ",", &saveptr);
876 if (tok) {
877 unsigned long size = 0;
878
879 ret = get_stack_size(tok, &size);
880 rec->opts.stack_dump_size = size;
881 }
882
883 if (!ret)
884 pr_debug("callchain: stack dump size %d\n",
885 rec->opts.stack_dump_size);
886#endif /* !NO_LIBUNWIND_SUPPORT */
887 } else {
888 pr_err("callchain: Unknown -g option "
889 "value: %s\n", arg);
890 break;
891 }
892
893 } while (0);
894
895 free(buf);
896
897 if (!ret)
898 pr_debug("callchain: type %d\n", rec->opts.call_graph);
899
900 return ret;
901}
902
735static const char * const record_usage[] = { 903static const char * const record_usage[] = {
736 "perf record [<options>] [<command>]", 904 "perf record [<options>] [<command>]",
737 "perf record [<options>] -- <command> [<options>]", 905 "perf record [<options>] -- <command> [<options>]",
@@ -803,8 +971,9 @@ const struct option record_options[] = {
803 "number of mmap data pages"), 971 "number of mmap data pages"),
804 OPT_BOOLEAN(0, "group", &record.opts.group, 972 OPT_BOOLEAN(0, "group", &record.opts.group,
805 "put the counters into a counter group"), 973 "put the counters into a counter group"),
806 OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph, 974 OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]",
807 "do call-graph (stack chain/backtrace) recording"), 975 callchain_help, &parse_callchain_opt,
976 "fp"),
808 OPT_INCR('v', "verbose", &verbose, 977 OPT_INCR('v', "verbose", &verbose,
809 "be more verbose (show counter open errors, etc)"), 978 "be more verbose (show counter open errors, etc)"),
810 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 979 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
@@ -836,7 +1005,7 @@ const struct option record_options[] = {
836 OPT_END() 1005 OPT_END()
837}; 1006};
838 1007
839int cmd_record(int argc, const char **argv, const char *prefix __used) 1008int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
840{ 1009{
841 int err = -ENOMEM; 1010 int err = -ENOMEM;
842 struct perf_evsel *pos; 1011 struct perf_evsel *pos;