]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - tools/perf/builtin-record.c
Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge
[mirror_ubuntu-bionic-kernel.git] / tools / perf / builtin-record.c
CommitLineData
abaff32a 1/*
bf9e1876
IM
2 * builtin-record.c
3 *
4 * Builtin record command: Record the profile of a workload
5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report.
abaff32a 7 */
b8f46c5a
XG
8#define _FILE_OFFSET_BITS 64
9
16f762a2 10#include "builtin.h"
bf9e1876
IM
11
12#include "perf.h"
13
6122e4e4 14#include "util/build-id.h"
6eda5838 15#include "util/util.h"
0e9b20b8 16#include "util/parse-options.h"
8ad8db37 17#include "util/parse-events.h"
6eda5838 18
7c6a1c65 19#include "util/header.h"
66e274f3 20#include "util/event.h"
361c99a6 21#include "util/evlist.h"
69aad6f1 22#include "util/evsel.h"
8f28827a 23#include "util/debug.h"
94c744b6 24#include "util/session.h"
45694aa7 25#include "util/tool.h"
8d06367f 26#include "util/symbol.h"
a12b51c4 27#include "util/cpumap.h"
fd78260b 28#include "util/thread_map.h"
7c6a1c65 29
97124d5e 30#include <unistd.h>
de9ac07b 31#include <sched.h>
a41794cd 32#include <sys/mman.h>
de9ac07b 33
7865e817
FW
34enum write_mode_t {
35 WRITE_FORCE,
36 WRITE_APPEND
37};
38
d20deb64 39struct perf_record {
45694aa7 40 struct perf_tool tool;
d20deb64
ACM
41 struct perf_record_opts opts;
42 u64 bytes_written;
43 const char *output_name;
44 struct perf_evlist *evlist;
45 struct perf_session *session;
46 const char *progname;
47 int output;
48 unsigned int page_size;
49 int realtime_prio;
50 enum write_mode_t write_mode;
51 bool no_buildid;
52 bool no_buildid_cache;
53 bool force;
54 bool file_new;
55 bool append_file;
56 long samples;
57 off_t post_processing_offset;
0f82ebc4 58};
a21ca2ca 59
d20deb64 60static void advance_output(struct perf_record *rec, size_t size)
9215545e 61{
d20deb64 62 rec->bytes_written += size;
9215545e
TZ
63}
64
d20deb64 65static void write_output(struct perf_record *rec, void *buf, size_t size)
f5970550
PZ
66{
67 while (size) {
d20deb64 68 int ret = write(rec->output, buf, size);
f5970550
PZ
69
70 if (ret < 0)
71 die("failed to write");
72
73 size -= ret;
74 buf += ret;
75
d20deb64 76 rec->bytes_written += ret;
f5970550
PZ
77 }
78}
79
45694aa7 80static int process_synthesized_event(struct perf_tool *tool,
d20deb64 81 union perf_event *event,
8d50e5b4 82 struct perf_sample *sample __used,
743eb868 83 struct machine *machine __used)
234fbbf5 84{
45694aa7 85 struct perf_record *rec = container_of(tool, struct perf_record, tool);
d20deb64 86 write_output(rec, event, event->header.size);
234fbbf5
ACM
87 return 0;
88}
89
d20deb64
ACM
90static void perf_record__mmap_read(struct perf_record *rec,
91 struct perf_mmap *md)
de9ac07b 92{
744bd8aa 93 unsigned int head = perf_mmap__read_head(md);
de9ac07b 94 unsigned int old = md->prev;
d20deb64 95 unsigned char *data = md->base + rec->page_size;
de9ac07b
PZ
96 unsigned long size;
97 void *buf;
de9ac07b 98
dc82009a
ACM
99 if (old == head)
100 return;
101
d20deb64 102 rec->samples++;
de9ac07b
PZ
103
104 size = head - old;
105
106 if ((old & md->mask) + size != (head & md->mask)) {
107 buf = &data[old & md->mask];
108 size = md->mask + 1 - (old & md->mask);
109 old += size;
021e9f47 110
d20deb64 111 write_output(rec, buf, size);
de9ac07b
PZ
112 }
113
114 buf = &data[old & md->mask];
115 size = head - old;
116 old += size;
021e9f47 117
d20deb64 118 write_output(rec, buf, size);
de9ac07b
PZ
119
120 md->prev = old;
115d2d89 121 perf_mmap__write_tail(md, old);
de9ac07b
PZ
122}
123
124static volatile int done = 0;
f7b7c26e 125static volatile int signr = -1;
33e49ea7 126static volatile int child_finished = 0;
de9ac07b 127
16c8a109 128static void sig_handler(int sig)
de9ac07b 129{
33e49ea7
AK
130 if (sig == SIGCHLD)
131 child_finished = 1;
132
16c8a109 133 done = 1;
f7b7c26e
PZ
134 signr = sig;
135}
136
d20deb64 137static void perf_record__sig_exit(int exit_status __used, void *arg)
f7b7c26e 138{
d20deb64 139 struct perf_record *rec = arg;
33e49ea7
AK
140 int status;
141
d20deb64 142 if (rec->evlist->workload.pid > 0) {
33e49ea7 143 if (!child_finished)
d20deb64 144 kill(rec->evlist->workload.pid, SIGTERM);
33e49ea7
AK
145
146 wait(&status);
147 if (WIFSIGNALED(status))
d20deb64 148 psignal(WTERMSIG(status), rec->progname);
33e49ea7 149 }
933da83a 150
18483b81 151 if (signr == -1 || signr == SIGUSR1)
f7b7c26e
PZ
152 return;
153
154 signal(signr, SIG_DFL);
155 kill(getpid(), signr);
de9ac07b
PZ
156}
157
a91e5431
ACM
158static bool perf_evlist__equal(struct perf_evlist *evlist,
159 struct perf_evlist *other)
160{
161 struct perf_evsel *pos, *pair;
162
163 if (evlist->nr_entries != other->nr_entries)
164 return false;
165
166 pair = list_entry(other->entries.next, struct perf_evsel, node);
167
168 list_for_each_entry(pos, &evlist->entries, node) {
169 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
170 return false;
171 pair = list_entry(pair->node.next, struct perf_evsel, node);
172 }
173
174 return true;
175}
176
d20deb64 177static void perf_record__open(struct perf_record *rec)
dd7927f4 178{
727ab04e 179 struct perf_evsel *pos, *first;
d20deb64
ACM
180 struct perf_evlist *evlist = rec->evlist;
181 struct perf_session *session = rec->session;
182 struct perf_record_opts *opts = &rec->opts;
dd7927f4 183
727ab04e
ACM
184 first = list_entry(evlist->entries.next, struct perf_evsel, node);
185
d20deb64 186 perf_evlist__config_attrs(evlist, opts);
0f82ebc4 187
dd7927f4
ACM
188 list_for_each_entry(pos, &evlist->entries, node) {
189 struct perf_event_attr *attr = &pos->attr;
727ab04e 190 struct xyarray *group_fd = NULL;
dd7927f4
ACM
191 /*
192 * Check if parse_single_tracepoint_event has already asked for
193 * PERF_SAMPLE_TIME.
194 *
195 * XXX this is kludgy but short term fix for problems introduced by
196 * eac23d1c that broke 'perf script' by having different sample_types
197 * when using multiple tracepoint events when we use a perf binary
198 * that tries to use sample_id_all on an older kernel.
199 *
200 * We need to move counter creation to perf_session, support
201 * different sample_types, etc.
202 */
203 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
d6d901c2 204
d20deb64 205 if (opts->group && pos != first)
727ab04e 206 group_fd = first->fd;
bc76efe6
ACM
207fallback_missing_features:
208 if (opts->exclude_guest_missing)
209 attr->exclude_guest = attr->exclude_host = 0;
dd7927f4 210retry_sample_id:
d20deb64 211 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
dd7927f4 212try_again:
ed80f581 213 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
d20deb64 214 opts->group, group_fd) < 0) {
d6d901c2
ZY
215 int err = errno;
216
c286c419 217 if (err == EPERM || err == EACCES) {
b8631e6e 218 ui__error_paranoid();
c286c419 219 exit(EXIT_FAILURE);
d20deb64 220 } else if (err == ENODEV && opts->cpu_list) {
d6d901c2
ZY
221 die("No such device - did you specify"
222 " an out-of-range profile CPU?\n");
bc76efe6
ACM
223 } else if (err == EINVAL) {
224 if (!opts->exclude_guest_missing &&
225 (attr->exclude_guest || attr->exclude_host)) {
226 pr_debug("Old kernel, cannot exclude "
227 "guest or host samples.\n");
228 opts->exclude_guest_missing = true;
229 goto fallback_missing_features;
230 } else if (opts->sample_id_all_avail) {
231 /*
232 * Old kernel, no attr->sample_id_type_all field
233 */
234 opts->sample_id_all_avail = false;
235 if (!opts->sample_time && !opts->raw_samples && !time_needed)
236 attr->sample_type &= ~PERF_SAMPLE_TIME;
237
238 goto retry_sample_id;
239 }
d6d901c2 240 }
3da297a6 241
d6d901c2
ZY
242 /*
243 * If it's cycles then fall back to hrtimer
244 * based cpu-clock-tick sw counter, which
245 * is always available even if no PMU support:
246 */
247 if (attr->type == PERF_TYPE_HARDWARE
248 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
249
250 if (verbose)
ca6a4258
DA
251 ui__warning("The cycles event is not supported, "
252 "trying to fall back to cpu-clock-ticks\n");
d6d901c2
ZY
253 attr->type = PERF_TYPE_SOFTWARE;
254 attr->config = PERF_COUNT_SW_CPU_CLOCK;
255 goto try_again;
256 }
ca6a4258
DA
257
258 if (err == ENOENT) {
259 ui__warning("The %s event is not supported.\n",
260 event_name(pos));
261 exit(EXIT_FAILURE);
262 }
263
d6d901c2 264 printf("\n");
d9cf837e 265 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
dd7927f4 266 err, strerror(err));
bfd45118
SK
267
268#if defined(__i386__) || defined(__x86_64__)
d6d901c2
ZY
269 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
270 die("No hardware sampling interrupt available."
271 " No APIC? If so then you can boot the kernel"
272 " with the \"lapic\" boot parameter to"
273 " force-enable it.\n");
bfd45118
SK
274#endif
275
d6d901c2 276 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
c171b552
LZ
277 }
278 }
a43d3f08 279
0a102479
FW
280 if (perf_evlist__set_filters(evlist)) {
281 error("failed to set filter with %d (%s)\n", errno,
282 strerror(errno));
283 exit(-1);
284 }
285
18e60939
NE
286 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
287 if (errno == EPERM)
288 die("Permission error mapping pages.\n"
289 "Consider increasing "
290 "/proc/sys/kernel/perf_event_mlock_kb,\n"
291 "or try again with a smaller value of -m/--mmap_pages.\n"
292 "(current value: %d)\n", opts->mmap_pages);
41d0d933
NE
293 else if (!is_power_of_2(opts->mmap_pages))
294 die("--mmap_pages/-m value must be a power of two.");
295
0a27d7f9 296 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
18e60939 297 }
0a27d7f9 298
d20deb64 299 if (rec->file_new)
a91e5431
ACM
300 session->evlist = evlist;
301 else {
302 if (!perf_evlist__equal(session->evlist, evlist)) {
303 fprintf(stderr, "incompatible append\n");
304 exit(-1);
305 }
306 }
307
308 perf_session__update_sample_type(session);
16c8a109
PZ
309}
310
d20deb64 311static int process_buildids(struct perf_record *rec)
6122e4e4 312{
d20deb64 313 u64 size = lseek(rec->output, 0, SEEK_CUR);
6122e4e4 314
9f591fd7
ACM
315 if (size == 0)
316 return 0;
317
d20deb64
ACM
318 rec->session->fd = rec->output;
319 return __perf_session__process_events(rec->session, rec->post_processing_offset,
320 size - rec->post_processing_offset,
6122e4e4
ACM
321 size, &build_id__mark_dso_hit_ops);
322}
323
d20deb64 324static void perf_record__exit(int status __used, void *arg)
f5970550 325{
d20deb64
ACM
326 struct perf_record *rec = arg;
327
328 if (!rec->opts.pipe_output) {
329 rec->session->header.data_size += rec->bytes_written;
330
331 if (!rec->no_buildid)
332 process_buildids(rec);
333 perf_session__write_header(rec->session, rec->evlist,
334 rec->output, true);
335 perf_session__delete(rec->session);
336 perf_evlist__delete(rec->evlist);
d65a458b 337 symbol__exit();
c7929e47 338 }
f5970550
PZ
339}
340
8115d60c 341static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
a1645ce1
ZY
342{
343 int err;
45694aa7 344 struct perf_tool *tool = data;
a1645ce1 345
23346f21 346 if (machine__is_host(machine))
a1645ce1
ZY
347 return;
348
349 /*
350 *As for guest kernel when processing subcommand record&report,
351 *we arrange module mmap prior to guest kernel mmap and trigger
352 *a preload dso because default guest module symbols are loaded
353 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
354 *method is used to avoid symbol missing when the first addr is
355 *in module instead of in guest kernel.
356 */
45694aa7 357 err = perf_event__synthesize_modules(tool, process_synthesized_event,
743eb868 358 machine);
a1645ce1
ZY
359 if (err < 0)
360 pr_err("Couldn't record guest kernel [%d]'s reference"
23346f21 361 " relocation symbol.\n", machine->pid);
a1645ce1 362
a1645ce1
ZY
363 /*
364 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
365 * have no _text sometimes.
366 */
45694aa7 367 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
743eb868 368 machine, "_text");
a1645ce1 369 if (err < 0)
45694aa7 370 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
743eb868 371 machine, "_stext");
a1645ce1
ZY
372 if (err < 0)
373 pr_err("Couldn't record guest kernel [%d]'s reference"
23346f21 374 " relocation symbol.\n", machine->pid);
a1645ce1
ZY
375}
376
98402807
FW
377static struct perf_event_header finished_round_event = {
378 .size = sizeof(struct perf_event_header),
379 .type = PERF_RECORD_FINISHED_ROUND,
380};
381
d20deb64 382static void perf_record__mmap_read_all(struct perf_record *rec)
98402807 383{
0e2e63dd 384 int i;
98402807 385
d20deb64
ACM
386 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
387 if (rec->evlist->mmap[i].base)
388 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
98402807
FW
389 }
390
d20deb64
ACM
391 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
392 write_output(rec, &finished_round_event, sizeof(finished_round_event));
98402807
FW
393}
394
d20deb64 395static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
16c8a109 396{
abaff32a 397 struct stat st;
abaff32a 398 int flags;
d20deb64 399 int err, output;
8b412664 400 unsigned long waking = 0;
46be604b 401 const bool forks = argc > 0;
23346f21 402 struct machine *machine;
45694aa7 403 struct perf_tool *tool = &rec->tool;
d20deb64
ACM
404 struct perf_record_opts *opts = &rec->opts;
405 struct perf_evlist *evsel_list = rec->evlist;
406 const char *output_name = rec->output_name;
407 struct perf_session *session;
de9ac07b 408
d20deb64 409 rec->progname = argv[0];
33e49ea7 410
d20deb64 411 rec->page_size = sysconf(_SC_PAGE_SIZE);
de9ac07b 412
d20deb64 413 on_exit(perf_record__sig_exit, rec);
f5970550
PZ
414 signal(SIGCHLD, sig_handler);
415 signal(SIGINT, sig_handler);
18483b81 416 signal(SIGUSR1, sig_handler);
f5970550 417
d7065adb
FBH
418 if (!output_name) {
419 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
d20deb64 420 opts->pipe_output = true;
d7065adb 421 else
d20deb64 422 rec->output_name = output_name = "perf.data";
d7065adb
FBH
423 }
424 if (output_name) {
425 if (!strcmp(output_name, "-"))
d20deb64 426 opts->pipe_output = true;
d7065adb 427 else if (!stat(output_name, &st) && st.st_size) {
d20deb64 428 if (rec->write_mode == WRITE_FORCE) {
d7065adb
FBH
429 char oldname[PATH_MAX];
430 snprintf(oldname, sizeof(oldname), "%s.old",
431 output_name);
432 unlink(oldname);
433 rename(output_name, oldname);
434 }
d20deb64
ACM
435 } else if (rec->write_mode == WRITE_APPEND) {
436 rec->write_mode = WRITE_FORCE;
266e0e21 437 }
97124d5e
PZ
438 }
439
f887f301 440 flags = O_CREAT|O_RDWR;
d20deb64
ACM
441 if (rec->write_mode == WRITE_APPEND)
442 rec->file_new = 0;
abaff32a
IM
443 else
444 flags |= O_TRUNC;
445
d20deb64 446 if (opts->pipe_output)
529870e3
TZ
447 output = STDOUT_FILENO;
448 else
449 output = open(output_name, flags, S_IRUSR | S_IWUSR);
de9ac07b
PZ
450 if (output < 0) {
451 perror("failed to create output file");
452 exit(-1);
453 }
454
d20deb64
ACM
455 rec->output = output;
456
7865e817 457 session = perf_session__new(output_name, O_WRONLY,
d20deb64 458 rec->write_mode == WRITE_FORCE, false, NULL);
94c744b6 459 if (session == NULL) {
a9a70bbc
ACM
460 pr_err("Not enough memory for reading perf file header\n");
461 return -1;
462 }
463
d20deb64
ACM
464 rec->session = session;
465
466 if (!rec->no_buildid)
baa2f6ce
ACM
467 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
468
d20deb64 469 if (!rec->file_new) {
a91e5431 470 err = perf_session__read_header(session, output);
4dc0a04b 471 if (err < 0)
39d17dac 472 goto out_delete_session;
4dc0a04b
ACM
473 }
474
361c99a6 475 if (have_tracepoints(&evsel_list->entries))
94c744b6 476 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
03456a15 477
fbe96f29
SE
478 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
479 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
480 perf_header__set_feat(&session->header, HEADER_ARCH);
481 perf_header__set_feat(&session->header, HEADER_CPUDESC);
482 perf_header__set_feat(&session->header, HEADER_NRCPUS);
483 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
484 perf_header__set_feat(&session->header, HEADER_CMDLINE);
485 perf_header__set_feat(&session->header, HEADER_VERSION);
486 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
487 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
488 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
489 perf_header__set_feat(&session->header, HEADER_CPUID);
490
d4db3f16 491 if (forks) {
d20deb64 492 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
35b9d88e
ACM
493 if (err < 0) {
494 pr_err("Couldn't run the workload!\n");
495 goto out_delete_session;
856e9660 496 }
856e9660
PZ
497 }
498
d20deb64 499 perf_record__open(rec);
de9ac07b 500
712a4b60 501 /*
d20deb64 502 * perf_session__delete(session) will be called at perf_record__exit()
712a4b60 503 */
d20deb64 504 on_exit(perf_record__exit, rec);
712a4b60 505
d20deb64 506 if (opts->pipe_output) {
529870e3
TZ
507 err = perf_header__write_pipe(output);
508 if (err < 0)
509 return err;
d20deb64 510 } else if (rec->file_new) {
a91e5431
ACM
511 err = perf_session__write_header(session, evsel_list,
512 output, false);
d5eed904
ACM
513 if (err < 0)
514 return err;
56b03f3c
ACM
515 }
516
6e557a6a 517 if (!rec->no_buildid
e20960c0 518 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
6e557a6a 519 pr_err("Couldn't generate buildids. "
e20960c0
RR
520 "Use --no-buildid to profile anyway.\n");
521 return -1;
522 }
523
d20deb64 524 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
6122e4e4 525
743eb868
ACM
526 machine = perf_session__find_host_machine(session);
527 if (!machine) {
528 pr_err("Couldn't find native kernel information.\n");
529 return -1;
530 }
531
d20deb64 532 if (opts->pipe_output) {
45694aa7 533 err = perf_event__synthesize_attrs(tool, session,
d20deb64 534 process_synthesized_event);
2c46dbb5
TZ
535 if (err < 0) {
536 pr_err("Couldn't synthesize attrs.\n");
537 return err;
538 }
cd19a035 539
45694aa7 540 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
743eb868 541 machine);
cd19a035
TZ
542 if (err < 0) {
543 pr_err("Couldn't synthesize event_types.\n");
544 return err;
545 }
9215545e 546
361c99a6 547 if (have_tracepoints(&evsel_list->entries)) {
63e0c771
TZ
548 /*
549 * FIXME err <= 0 here actually means that
550 * there were no tracepoints so its not really
551 * an error, just that we don't need to
552 * synthesize anything. We really have to
553 * return this more properly and also
554 * propagate errors that now are calling die()
555 */
45694aa7 556 err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
743eb868 557 process_synthesized_event);
63e0c771
TZ
558 if (err <= 0) {
559 pr_err("Couldn't record tracing data.\n");
560 return err;
561 }
d20deb64 562 advance_output(rec, err);
63e0c771 563 }
2c46dbb5
TZ
564 }
565
45694aa7 566 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
743eb868 567 machine, "_text");
70162138 568 if (err < 0)
45694aa7 569 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
743eb868 570 machine, "_stext");
c1a3a4b9
ACM
571 if (err < 0)
572 pr_err("Couldn't record kernel reference relocation symbol\n"
573 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
574 "Check /proc/kallsyms permission or run as root.\n");
b7cece76 575
45694aa7 576 err = perf_event__synthesize_modules(tool, process_synthesized_event,
743eb868 577 machine);
c1a3a4b9
ACM
578 if (err < 0)
579 pr_err("Couldn't record kernel module information.\n"
580 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
581 "Check /proc/modules permission or run as root.\n");
582
a1645ce1 583 if (perf_guest)
45694aa7 584 perf_session__process_machines(session, tool,
8115d60c 585 perf_event__synthesize_guest_os);
7c6a1c65 586
d20deb64 587 if (!opts->system_wide)
45694aa7 588 perf_event__synthesize_thread_map(tool, evsel_list->threads,
7c940c18 589 process_synthesized_event,
743eb868 590 machine);
234fbbf5 591 else
45694aa7 592 perf_event__synthesize_threads(tool, process_synthesized_event,
743eb868 593 machine);
7c6a1c65 594
d20deb64 595 if (rec->realtime_prio) {
de9ac07b
PZ
596 struct sched_param param;
597
d20deb64 598 param.sched_priority = rec->realtime_prio;
de9ac07b 599 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6beba7ad 600 pr_err("Could not set realtime priority.\n");
de9ac07b
PZ
601 exit(-1);
602 }
603 }
604
764e16a3
DA
605 perf_evlist__enable(evsel_list);
606
856e9660
PZ
607 /*
608 * Let the child rip
609 */
d4db3f16 610 if (forks)
35b9d88e 611 perf_evlist__start_workload(evsel_list);
856e9660 612
649c48a9 613 for (;;) {
d20deb64 614 int hits = rec->samples;
de9ac07b 615
d20deb64 616 perf_record__mmap_read_all(rec);
de9ac07b 617
d20deb64 618 if (hits == rec->samples) {
649c48a9
PZ
619 if (done)
620 break;
5c581041 621 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
8b412664
PZ
622 waking++;
623 }
624
4152ab37
ACM
625 if (done)
626 perf_evlist__disable(evsel_list);
de9ac07b
PZ
627 }
628
18483b81 629 if (quiet || signr == SIGUSR1)
b44308f5
ACM
630 return 0;
631
8b412664
PZ
632 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
633
021e9f47
IM
634 /*
635 * Approximate RIP event size: 24 bytes.
636 */
637 fprintf(stderr,
9486aa38 638 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
d20deb64 639 (double)rec->bytes_written / 1024.0 / 1024.0,
021e9f47 640 output_name,
d20deb64 641 rec->bytes_written / 24);
addc2785 642
de9ac07b 643 return 0;
39d17dac
ACM
644
645out_delete_session:
646 perf_session__delete(session);
647 return err;
de9ac07b 648}
0e9b20b8 649
0e9b20b8 650static const char * const record_usage[] = {
9e096753
MG
651 "perf record [<options>] [<command>]",
652 "perf record [<options>] -- <command> [<options>]",
0e9b20b8
IM
653 NULL
654};
655
d20deb64
ACM
656/*
657 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
658 * because we need to have access to it in perf_record__exit, that is called
659 * after cmd_record() exits, but since record_options need to be accessible to
660 * builtin-script, leave it here.
661 *
662 * At least we don't ouch it in all the other functions here directly.
663 *
664 * Just say no to tons of global variables, sigh.
665 */
666static struct perf_record record = {
667 .opts = {
668 .target_pid = -1,
669 .target_tid = -1,
670 .mmap_pages = UINT_MAX,
671 .user_freq = UINT_MAX,
672 .user_interval = ULLONG_MAX,
673 .freq = 1000,
674 .sample_id_all_avail = true,
675 },
676 .write_mode = WRITE_FORCE,
677 .file_new = true,
678};
7865e817 679
d20deb64
ACM
680/*
681 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
682 * with it and switch to use the library functions in perf_evlist that came
683 * from builtin-record.c, i.e. use perf_record_opts,
684 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
685 * using pipes, etc.
686 */
bca647aa 687const struct option record_options[] = {
d20deb64 688 OPT_CALLBACK('e', "event", &record.evlist, "event",
86847b62 689 "event selector. use 'perf list' to list available events",
f120f9d5 690 parse_events_option),
d20deb64 691 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
c171b552 692 "event filter", parse_filter),
d20deb64 693 OPT_INTEGER('p', "pid", &record.opts.target_pid,
d6d901c2 694 "record events on existing process id"),
d20deb64 695 OPT_INTEGER('t', "tid", &record.opts.target_tid,
d6d901c2 696 "record events on existing thread id"),
d20deb64 697 OPT_INTEGER('r', "realtime", &record.realtime_prio,
0e9b20b8 698 "collect data with this RT SCHED_FIFO priority"),
d20deb64 699 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
acac03fa 700 "collect data without buffering"),
d20deb64 701 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
daac07b2 702 "collect raw sample records from all opened counters"),
d20deb64 703 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
0e9b20b8 704 "system-wide collection from all CPUs"),
d20deb64 705 OPT_BOOLEAN('A', "append", &record.append_file,
abaff32a 706 "append to the output file to do incremental profiling"),
d20deb64 707 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
c45c6ea2 708 "list of cpus to monitor"),
d20deb64 709 OPT_BOOLEAN('f', "force", &record.force,
7865e817 710 "overwrite existing data file (deprecated)"),
d20deb64
ACM
711 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
712 OPT_STRING('o', "output", &record.output_name, "file",
abaff32a 713 "output file name"),
d20deb64 714 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
2e6cdf99 715 "child tasks do not inherit counters"),
d20deb64
ACM
716 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
717 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
01c2d99b 718 "number of mmap data pages"),
d20deb64 719 OPT_BOOLEAN(0, "group", &record.opts.group,
43bece79 720 "put the counters into a counter group"),
d20deb64 721 OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
3efa1cc9 722 "do call-graph (stack chain/backtrace) recording"),
c0555642 723 OPT_INCR('v', "verbose", &verbose,
3da297a6 724 "be more verbose (show counter open errors, etc)"),
b44308f5 725 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
d20deb64 726 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
649c48a9 727 "per thread counts"),
d20deb64 728 OPT_BOOLEAN('d', "data", &record.opts.sample_address,
4bba828d 729 "Sample addresses"),
d20deb64 730 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
3e76ac78 731 OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
d20deb64 732 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
649c48a9 733 "don't sample"),
d20deb64 734 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
a1ac1d3c 735 "do not update the buildid cache"),
d20deb64 736 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
baa2f6ce 737 "do not collect buildids in perf.data"),
d20deb64 738 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
023695d9
SE
739 "monitor event in cgroup name only",
740 parse_cgroups),
0e9b20b8
IM
741 OPT_END()
742};
743
f37a291c 744int cmd_record(int argc, const char **argv, const char *prefix __used)
0e9b20b8 745{
69aad6f1
ACM
746 int err = -ENOMEM;
747 struct perf_evsel *pos;
d20deb64
ACM
748 struct perf_evlist *evsel_list;
749 struct perf_record *rec = &record;
0e9b20b8 750
fbe96f29
SE
751 perf_header__set_cmdline(argc, argv);
752
7e2ed097 753 evsel_list = perf_evlist__new(NULL, NULL);
361c99a6
ACM
754 if (evsel_list == NULL)
755 return -ENOMEM;
756
d20deb64
ACM
757 rec->evlist = evsel_list;
758
bca647aa 759 argc = parse_options(argc, argv, record_options, record_usage,
655000e7 760 PARSE_OPT_STOP_AT_NON_OPTION);
d20deb64
ACM
761 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
762 !rec->opts.system_wide && !rec->opts.cpu_list)
bca647aa 763 usage_with_options(record_usage, record_options);
0e9b20b8 764
d20deb64 765 if (rec->force && rec->append_file) {
7865e817
FW
766 fprintf(stderr, "Can't overwrite and append at the same time."
767 " You need to choose between -f and -A");
bca647aa 768 usage_with_options(record_usage, record_options);
d20deb64
ACM
769 } else if (rec->append_file) {
770 rec->write_mode = WRITE_APPEND;
7865e817 771 } else {
d20deb64 772 rec->write_mode = WRITE_FORCE;
7865e817
FW
773 }
774
d20deb64 775 if (nr_cgroups && !rec->opts.system_wide) {
023695d9
SE
776 fprintf(stderr, "cgroup monitoring only available in"
777 " system-wide mode\n");
778 usage_with_options(record_usage, record_options);
779 }
780
655000e7 781 symbol__init();
baa2f6ce 782
ec80fde7 783 if (symbol_conf.kptr_restrict)
646aaea6
ACM
784 pr_warning(
785"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
786"check /proc/sys/kernel/kptr_restrict.\n\n"
787"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
788"file is not found in the buildid cache or in the vmlinux path.\n\n"
789"Samples in kernel modules won't be resolved at all.\n\n"
790"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
791"even with a suitable vmlinux or kallsyms file.\n\n");
ec80fde7 792
d20deb64 793 if (rec->no_buildid_cache || rec->no_buildid)
a1ac1d3c 794 disable_buildid_cache();
655000e7 795
361c99a6
ACM
796 if (evsel_list->nr_entries == 0 &&
797 perf_evlist__add_default(evsel_list) < 0) {
69aad6f1
ACM
798 pr_err("Not enough memory for event selector list\n");
799 goto out_symbol_exit;
bbd36e5e 800 }
0e9b20b8 801
d20deb64
ACM
802 if (rec->opts.target_pid != -1)
803 rec->opts.target_tid = rec->opts.target_pid;
d6d901c2 804
d20deb64
ACM
805 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
806 rec->opts.target_tid, rec->opts.cpu_list) < 0)
dd7927f4 807 usage_with_options(record_usage, record_options);
69aad6f1 808
361c99a6 809 list_for_each_entry(pos, &evsel_list->entries, node) {
ad7f4e3f
ACM
810 if (perf_header__push_event(pos->attr.config, event_name(pos)))
811 goto out_free_fd;
d6d901c2 812 }
5c581041 813
d20deb64
ACM
814 if (rec->opts.user_interval != ULLONG_MAX)
815 rec->opts.default_interval = rec->opts.user_interval;
816 if (rec->opts.user_freq != UINT_MAX)
817 rec->opts.freq = rec->opts.user_freq;
f9212819 818
7e4ff9e3
MG
819 /*
820 * User specified count overrides default frequency.
821 */
d20deb64
ACM
822 if (rec->opts.default_interval)
823 rec->opts.freq = 0;
824 else if (rec->opts.freq) {
825 rec->opts.default_interval = rec->opts.freq;
7e4ff9e3
MG
826 } else {
827 fprintf(stderr, "frequency and count are zero, aborting\n");
39d17dac 828 err = -EINVAL;
5c581041 829 goto out_free_fd;
7e4ff9e3
MG
830 }
831
d20deb64 832 err = __cmd_record(&record, argc, argv);
39d17dac 833out_free_fd:
7e2ed097 834 perf_evlist__delete_maps(evsel_list);
d65a458b
ACM
835out_symbol_exit:
836 symbol__exit();
39d17dac 837 return err;
0e9b20b8 838}