Root/tools/perf/builtin-record.c

Source at commit ec7cab4cbb721bff91ec924ec691efd8daf36579 created 9 years 7 months ago.
By Maarten ter Huurne, MIPS: JZ4740: A320: Updated quickstart documentation.
1/*
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.
7 */
8#define _FILE_OFFSET_BITS 64
9
10#include "builtin.h"
11
12#include "perf.h"
13
14#include "util/build-id.h"
15#include "util/util.h"
16#include "util/parse-options.h"
17#include "util/parse-events.h"
18
19#include "util/header.h"
20#include "util/event.h"
21#include "util/evlist.h"
22#include "util/evsel.h"
23#include "util/debug.h"
24#include "util/session.h"
25#include "util/symbol.h"
26#include "util/cpumap.h"
27#include "util/thread_map.h"
28
29#include <unistd.h>
30#include <sched.h>
31#include <sys/mman.h>
32
33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
34
35enum write_mode_t {
36    WRITE_FORCE,
37    WRITE_APPEND
38};
39
40static u64 user_interval = ULLONG_MAX;
41static u64 default_interval = 0;
42
43static unsigned int page_size;
44static unsigned int mmap_pages = UINT_MAX;
45static unsigned int user_freq = UINT_MAX;
46static int freq = 1000;
47static int output;
48static int pipe_output = 0;
49static const char *output_name = NULL;
50static int group = 0;
51static int realtime_prio = 0;
52static bool nodelay = false;
53static bool raw_samples = false;
54static bool sample_id_all_avail = true;
55static bool system_wide = false;
56static pid_t target_pid = -1;
57static pid_t target_tid = -1;
58static pid_t child_pid = -1;
59static bool no_inherit = false;
60static enum write_mode_t write_mode = WRITE_FORCE;
61static bool call_graph = false;
62static bool inherit_stat = false;
63static bool no_samples = false;
64static bool sample_address = false;
65static bool sample_time = false;
66static bool no_buildid = false;
67static bool no_buildid_cache = false;
68static struct perf_evlist *evsel_list;
69
70static long samples = 0;
71static u64 bytes_written = 0;
72
73static int file_new = 1;
74static off_t post_processing_offset;
75
76static struct perf_session *session;
77static const char *cpu_list;
78
79static void advance_output(size_t size)
80{
81    bytes_written += size;
82}
83
84static void write_output(void *buf, size_t size)
85{
86    while (size) {
87        int ret = write(output, buf, size);
88
89        if (ret < 0)
90            die("failed to write");
91
92        size -= ret;
93        buf += ret;
94
95        bytes_written += ret;
96    }
97}
98
99static int process_synthesized_event(union perf_event *event,
100                     struct perf_sample *sample __used,
101                     struct perf_session *self __used)
102{
103    write_output(event, event->header.size);
104    return 0;
105}
106
107static void mmap_read(struct perf_mmap *md)
108{
109    unsigned int head = perf_mmap__read_head(md);
110    unsigned int old = md->prev;
111    unsigned char *data = md->base + page_size;
112    unsigned long size;
113    void *buf;
114
115    if (old == head)
116        return;
117
118    samples++;
119
120    size = head - old;
121
122    if ((old & md->mask) + size != (head & md->mask)) {
123        buf = &data[old & md->mask];
124        size = md->mask + 1 - (old & md->mask);
125        old += size;
126
127        write_output(buf, size);
128    }
129
130    buf = &data[old & md->mask];
131    size = head - old;
132    old += size;
133
134    write_output(buf, size);
135
136    md->prev = old;
137    perf_mmap__write_tail(md, old);
138}
139
140static volatile int done = 0;
141static volatile int signr = -1;
142
143static void sig_handler(int sig)
144{
145    done = 1;
146    signr = sig;
147}
148
149static void sig_atexit(void)
150{
151    if (child_pid > 0)
152        kill(child_pid, SIGTERM);
153
154    if (signr == -1 || signr == SIGUSR1)
155        return;
156
157    signal(signr, SIG_DFL);
158    kill(getpid(), signr);
159}
160
161static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
162{
163    struct perf_event_attr *attr = &evsel->attr;
164    int track = !evsel->idx; /* only the first counter needs these */
165
166    attr->inherit = !no_inherit;
167    attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
168                  PERF_FORMAT_TOTAL_TIME_RUNNING |
169                  PERF_FORMAT_ID;
170
171    attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
172
173    if (evlist->nr_entries > 1)
174        attr->sample_type |= PERF_SAMPLE_ID;
175
176    /*
177     * We default some events to a 1 default interval. But keep
178     * it a weak assumption overridable by the user.
179     */
180    if (!attr->sample_period || (user_freq != UINT_MAX &&
181                     user_interval != ULLONG_MAX)) {
182        if (freq) {
183            attr->sample_type |= PERF_SAMPLE_PERIOD;
184            attr->freq = 1;
185            attr->sample_freq = freq;
186        } else {
187            attr->sample_period = default_interval;
188        }
189    }
190
191    if (no_samples)
192        attr->sample_freq = 0;
193
194    if (inherit_stat)
195        attr->inherit_stat = 1;
196
197    if (sample_address) {
198        attr->sample_type |= PERF_SAMPLE_ADDR;
199        attr->mmap_data = track;
200    }
201
202    if (call_graph)
203        attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
204
205    if (system_wide)
206        attr->sample_type |= PERF_SAMPLE_CPU;
207
208    if (sample_id_all_avail &&
209        (sample_time || system_wide || !no_inherit || cpu_list))
210        attr->sample_type |= PERF_SAMPLE_TIME;
211
212    if (raw_samples) {
213        attr->sample_type |= PERF_SAMPLE_TIME;
214        attr->sample_type |= PERF_SAMPLE_RAW;
215        attr->sample_type |= PERF_SAMPLE_CPU;
216    }
217
218    if (nodelay) {
219        attr->watermark = 0;
220        attr->wakeup_events = 1;
221    }
222
223    attr->mmap = track;
224    attr->comm = track;
225
226    if (target_pid == -1 && target_tid == -1 && !system_wide) {
227        attr->disabled = 1;
228        attr->enable_on_exec = 1;
229    }
230}
231
232static bool perf_evlist__equal(struct perf_evlist *evlist,
233                   struct perf_evlist *other)
234{
235    struct perf_evsel *pos, *pair;
236
237    if (evlist->nr_entries != other->nr_entries)
238        return false;
239
240    pair = list_entry(other->entries.next, struct perf_evsel, node);
241
242    list_for_each_entry(pos, &evlist->entries, node) {
243        if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
244            return false;
245        pair = list_entry(pair->node.next, struct perf_evsel, node);
246    }
247
248    return true;
249}
250
251static void open_counters(struct perf_evlist *evlist)
252{
253    struct perf_evsel *pos;
254
255    if (evlist->cpus->map[0] < 0)
256        no_inherit = true;
257
258    list_for_each_entry(pos, &evlist->entries, node) {
259        struct perf_event_attr *attr = &pos->attr;
260        /*
261         * Check if parse_single_tracepoint_event has already asked for
262         * PERF_SAMPLE_TIME.
263         *
264         * XXX this is kludgy but short term fix for problems introduced by
265         * eac23d1c that broke 'perf script' by having different sample_types
266         * when using multiple tracepoint events when we use a perf binary
267         * that tries to use sample_id_all on an older kernel.
268         *
269         * We need to move counter creation to perf_session, support
270         * different sample_types, etc.
271         */
272        bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
273
274        config_attr(pos, evlist);
275retry_sample_id:
276        attr->sample_id_all = sample_id_all_avail ? 1 : 0;
277try_again:
278        if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
279            int err = errno;
280
281            if (err == EPERM || err == EACCES) {
282                ui__warning_paranoid();
283                exit(EXIT_FAILURE);
284            } else if (err == ENODEV && cpu_list) {
285                die("No such device - did you specify"
286                    " an out-of-range profile CPU?\n");
287            } else if (err == EINVAL && sample_id_all_avail) {
288                /*
289                 * Old kernel, no attr->sample_id_type_all field
290                 */
291                sample_id_all_avail = false;
292                if (!sample_time && !raw_samples && !time_needed)
293                    attr->sample_type &= ~PERF_SAMPLE_TIME;
294
295                goto retry_sample_id;
296            }
297
298            /*
299             * If it's cycles then fall back to hrtimer
300             * based cpu-clock-tick sw counter, which
301             * is always available even if no PMU support:
302             */
303            if (attr->type == PERF_TYPE_HARDWARE
304                    && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
305
306                if (verbose)
307                    ui__warning("The cycles event is not supported, "
308                            "trying to fall back to cpu-clock-ticks\n");
309                attr->type = PERF_TYPE_SOFTWARE;
310                attr->config = PERF_COUNT_SW_CPU_CLOCK;
311                goto try_again;
312            }
313
314            if (err == ENOENT) {
315                ui__warning("The %s event is not supported.\n",
316                        event_name(pos));
317                exit(EXIT_FAILURE);
318            }
319
320            printf("\n");
321            error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
322                  err, strerror(err));
323
324#if defined(__i386__) || defined(__x86_64__)
325            if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
326                die("No hardware sampling interrupt available."
327                    " No APIC? If so then you can boot the kernel"
328                    " with the \"lapic\" boot parameter to"
329                    " force-enable it.\n");
330#endif
331
332            die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
333        }
334    }
335
336    if (perf_evlist__set_filters(evlist)) {
337        error("failed to set filter with %d (%s)\n", errno,
338            strerror(errno));
339        exit(-1);
340    }
341
342    if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
343        die("failed to mmap with %d (%s)\n", errno, strerror(errno));
344
345    if (file_new)
346        session->evlist = evlist;
347    else {
348        if (!perf_evlist__equal(session->evlist, evlist)) {
349            fprintf(stderr, "incompatible append\n");
350            exit(-1);
351        }
352     }
353
354    perf_session__update_sample_type(session);
355}
356
357static int process_buildids(void)
358{
359    u64 size = lseek(output, 0, SEEK_CUR);
360
361    if (size == 0)
362        return 0;
363
364    session->fd = output;
365    return __perf_session__process_events(session, post_processing_offset,
366                          size - post_processing_offset,
367                          size, &build_id__mark_dso_hit_ops);
368}
369
370static void atexit_header(void)
371{
372    if (!pipe_output) {
373        session->header.data_size += bytes_written;
374
375        if (!no_buildid)
376            process_buildids();
377        perf_session__write_header(session, evsel_list, output, true);
378        perf_session__delete(session);
379        perf_evlist__delete(evsel_list);
380        symbol__exit();
381    }
382}
383
384static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
385{
386    int err;
387    struct perf_session *psession = data;
388
389    if (machine__is_host(machine))
390        return;
391
392    /*
393     *As for guest kernel when processing subcommand record&report,
394     *we arrange module mmap prior to guest kernel mmap and trigger
395     *a preload dso because default guest module symbols are loaded
396     *from guest kallsyms instead of /lib/modules/XXX/XXX. This
397     *method is used to avoid symbol missing when the first addr is
398     *in module instead of in guest kernel.
399     */
400    err = perf_event__synthesize_modules(process_synthesized_event,
401                         psession, machine);
402    if (err < 0)
403        pr_err("Couldn't record guest kernel [%d]'s reference"
404               " relocation symbol.\n", machine->pid);
405
406    /*
407     * We use _stext for guest kernel because guest kernel's /proc/kallsyms
408     * have no _text sometimes.
409     */
410    err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
411                         psession, machine, "_text");
412    if (err < 0)
413        err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
414                             psession, machine,
415                             "_stext");
416    if (err < 0)
417        pr_err("Couldn't record guest kernel [%d]'s reference"
418               " relocation symbol.\n", machine->pid);
419}
420
421static struct perf_event_header finished_round_event = {
422    .size = sizeof(struct perf_event_header),
423    .type = PERF_RECORD_FINISHED_ROUND,
424};
425
426static void mmap_read_all(void)
427{
428    int i;
429
430    for (i = 0; i < evsel_list->nr_mmaps; i++) {
431        if (evsel_list->mmap[i].base)
432            mmap_read(&evsel_list->mmap[i]);
433    }
434
435    if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
436        write_output(&finished_round_event, sizeof(finished_round_event));
437}
438
439static int __cmd_record(int argc, const char **argv)
440{
441    int i;
442    struct stat st;
443    int flags;
444    int err;
445    unsigned long waking = 0;
446    int child_ready_pipe[2], go_pipe[2];
447    const bool forks = argc > 0;
448    char buf;
449    struct machine *machine;
450
451    page_size = sysconf(_SC_PAGE_SIZE);
452
453    atexit(sig_atexit);
454    signal(SIGCHLD, sig_handler);
455    signal(SIGINT, sig_handler);
456    signal(SIGUSR1, sig_handler);
457
458    if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
459        perror("failed to create pipes");
460        exit(-1);
461    }
462
463    if (!output_name) {
464        if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
465            pipe_output = 1;
466        else
467            output_name = "perf.data";
468    }
469    if (output_name) {
470        if (!strcmp(output_name, "-"))
471            pipe_output = 1;
472        else if (!stat(output_name, &st) && st.st_size) {
473            if (write_mode == WRITE_FORCE) {
474                char oldname[PATH_MAX];
475                snprintf(oldname, sizeof(oldname), "%s.old",
476                     output_name);
477                unlink(oldname);
478                rename(output_name, oldname);
479            }
480        } else if (write_mode == WRITE_APPEND) {
481            write_mode = WRITE_FORCE;
482        }
483    }
484
485    flags = O_CREAT|O_RDWR;
486    if (write_mode == WRITE_APPEND)
487        file_new = 0;
488    else
489        flags |= O_TRUNC;
490
491    if (pipe_output)
492        output = STDOUT_FILENO;
493    else
494        output = open(output_name, flags, S_IRUSR | S_IWUSR);
495    if (output < 0) {
496        perror("failed to create output file");
497        exit(-1);
498    }
499
500    session = perf_session__new(output_name, O_WRONLY,
501                    write_mode == WRITE_FORCE, false, NULL);
502    if (session == NULL) {
503        pr_err("Not enough memory for reading perf file header\n");
504        return -1;
505    }
506
507    if (!no_buildid)
508        perf_header__set_feat(&session->header, HEADER_BUILD_ID);
509
510    if (!file_new) {
511        err = perf_session__read_header(session, output);
512        if (err < 0)
513            goto out_delete_session;
514    }
515
516    if (have_tracepoints(&evsel_list->entries))
517        perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
518
519    /* 512 kiB: default amount of unprivileged mlocked memory */
520    if (mmap_pages == UINT_MAX)
521        mmap_pages = (512 * 1024) / page_size;
522
523    if (forks) {
524        child_pid = fork();
525        if (child_pid < 0) {
526            perror("failed to fork");
527            exit(-1);
528        }
529
530        if (!child_pid) {
531            if (pipe_output)
532                dup2(2, 1);
533            close(child_ready_pipe[0]);
534            close(go_pipe[1]);
535            fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
536
537            /*
538             * Do a dummy execvp to get the PLT entry resolved,
539             * so we avoid the resolver overhead on the real
540             * execvp call.
541             */
542            execvp("", (char **)argv);
543
544            /*
545             * Tell the parent we're ready to go
546             */
547            close(child_ready_pipe[1]);
548
549            /*
550             * Wait until the parent tells us to go.
551             */
552            if (read(go_pipe[0], &buf, 1) == -1)
553                perror("unable to read pipe");
554
555            execvp(argv[0], (char **)argv);
556
557            perror(argv[0]);
558            kill(getppid(), SIGUSR1);
559            exit(-1);
560        }
561
562        if (!system_wide && target_tid == -1 && target_pid == -1)
563            evsel_list->threads->map[0] = child_pid;
564
565        close(child_ready_pipe[1]);
566        close(go_pipe[0]);
567        /*
568         * wait for child to settle
569         */
570        if (read(child_ready_pipe[0], &buf, 1) == -1) {
571            perror("unable to read pipe");
572            exit(-1);
573        }
574        close(child_ready_pipe[0]);
575    }
576
577    open_counters(evsel_list);
578
579    /*
580     * perf_session__delete(session) will be called at atexit_header()
581     */
582    atexit(atexit_header);
583
584    if (pipe_output) {
585        err = perf_header__write_pipe(output);
586        if (err < 0)
587            return err;
588    } else if (file_new) {
589        err = perf_session__write_header(session, evsel_list,
590                         output, false);
591        if (err < 0)
592            return err;
593    }
594
595    post_processing_offset = lseek(output, 0, SEEK_CUR);
596
597    if (pipe_output) {
598        err = perf_session__synthesize_attrs(session,
599                             process_synthesized_event);
600        if (err < 0) {
601            pr_err("Couldn't synthesize attrs.\n");
602            return err;
603        }
604
605        err = perf_event__synthesize_event_types(process_synthesized_event,
606                             session);
607        if (err < 0) {
608            pr_err("Couldn't synthesize event_types.\n");
609            return err;
610        }
611
612        if (have_tracepoints(&evsel_list->entries)) {
613            /*
614             * FIXME err <= 0 here actually means that
615             * there were no tracepoints so its not really
616             * an error, just that we don't need to
617             * synthesize anything. We really have to
618             * return this more properly and also
619             * propagate errors that now are calling die()
620             */
621            err = perf_event__synthesize_tracing_data(output, evsel_list,
622                                  process_synthesized_event,
623                                  session);
624            if (err <= 0) {
625                pr_err("Couldn't record tracing data.\n");
626                return err;
627            }
628            advance_output(err);
629        }
630    }
631
632    machine = perf_session__find_host_machine(session);
633    if (!machine) {
634        pr_err("Couldn't find native kernel information.\n");
635        return -1;
636    }
637
638    err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
639                         session, machine, "_text");
640    if (err < 0)
641        err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
642                             session, machine, "_stext");
643    if (err < 0)
644        pr_err("Couldn't record kernel reference relocation symbol\n"
645               "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
646               "Check /proc/kallsyms permission or run as root.\n");
647
648    err = perf_event__synthesize_modules(process_synthesized_event,
649                         session, machine);
650    if (err < 0)
651        pr_err("Couldn't record kernel module information.\n"
652               "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
653               "Check /proc/modules permission or run as root.\n");
654
655    if (perf_guest)
656        perf_session__process_machines(session,
657                           perf_event__synthesize_guest_os);
658
659    if (!system_wide)
660        perf_event__synthesize_thread_map(evsel_list->threads,
661                          process_synthesized_event,
662                          session);
663    else
664        perf_event__synthesize_threads(process_synthesized_event,
665                           session);
666
667    if (realtime_prio) {
668        struct sched_param param;
669
670        param.sched_priority = realtime_prio;
671        if (sched_setscheduler(0, SCHED_FIFO, &param)) {
672            pr_err("Could not set realtime priority.\n");
673            exit(-1);
674        }
675    }
676
677    /*
678     * Let the child rip
679     */
680    if (forks)
681        close(go_pipe[1]);
682
683    for (;;) {
684        int hits = samples;
685        int thread;
686
687        mmap_read_all();
688
689        if (hits == samples) {
690            if (done)
691                break;
692            err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
693            waking++;
694        }
695
696        if (done) {
697            for (i = 0; i < evsel_list->cpus->nr; i++) {
698                struct perf_evsel *pos;
699
700                list_for_each_entry(pos, &evsel_list->entries, node) {
701                    for (thread = 0;
702                        thread < evsel_list->threads->nr;
703                        thread++)
704                        ioctl(FD(pos, i, thread),
705                            PERF_EVENT_IOC_DISABLE);
706                }
707            }
708        }
709    }
710
711    if (quiet || signr == SIGUSR1)
712        return 0;
713
714    fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
715
716    /*
717     * Approximate RIP event size: 24 bytes.
718     */
719    fprintf(stderr,
720        "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
721        (double)bytes_written / 1024.0 / 1024.0,
722        output_name,
723        bytes_written / 24);
724
725    return 0;
726
727out_delete_session:
728    perf_session__delete(session);
729    return err;
730}
731
732static const char * const record_usage[] = {
733    "perf record [<options>] [<command>]",
734    "perf record [<options>] -- <command> [<options>]",
735    NULL
736};
737
738static bool force, append_file;
739
740const struct option record_options[] = {
741    OPT_CALLBACK('e', "event", &evsel_list, "event",
742             "event selector. use 'perf list' to list available events",
743             parse_events),
744    OPT_CALLBACK(0, "filter", &evsel_list, "filter",
745             "event filter", parse_filter),
746    OPT_INTEGER('p', "pid", &target_pid,
747            "record events on existing process id"),
748    OPT_INTEGER('t', "tid", &target_tid,
749            "record events on existing thread id"),
750    OPT_INTEGER('r', "realtime", &realtime_prio,
751            "collect data with this RT SCHED_FIFO priority"),
752    OPT_BOOLEAN('D', "no-delay", &nodelay,
753            "collect data without buffering"),
754    OPT_BOOLEAN('R', "raw-samples", &raw_samples,
755            "collect raw sample records from all opened counters"),
756    OPT_BOOLEAN('a', "all-cpus", &system_wide,
757                "system-wide collection from all CPUs"),
758    OPT_BOOLEAN('A', "append", &append_file,
759                "append to the output file to do incremental profiling"),
760    OPT_STRING('C', "cpu", &cpu_list, "cpu",
761            "list of cpus to monitor"),
762    OPT_BOOLEAN('f', "force", &force,
763            "overwrite existing data file (deprecated)"),
764    OPT_U64('c', "count", &user_interval, "event period to sample"),
765    OPT_STRING('o', "output", &output_name, "file",
766            "output file name"),
767    OPT_BOOLEAN('i', "no-inherit", &no_inherit,
768            "child tasks do not inherit counters"),
769    OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
770    OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
771    OPT_BOOLEAN('g', "call-graph", &call_graph,
772            "do call-graph (stack chain/backtrace) recording"),
773    OPT_INCR('v', "verbose", &verbose,
774            "be more verbose (show counter open errors, etc)"),
775    OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
776    OPT_BOOLEAN('s', "stat", &inherit_stat,
777            "per thread counts"),
778    OPT_BOOLEAN('d', "data", &sample_address,
779            "Sample addresses"),
780    OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
781    OPT_BOOLEAN('n', "no-samples", &no_samples,
782            "don't sample"),
783    OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
784            "do not update the buildid cache"),
785    OPT_BOOLEAN('B', "no-buildid", &no_buildid,
786            "do not collect buildids in perf.data"),
787    OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
788             "monitor event in cgroup name only",
789             parse_cgroups),
790    OPT_END()
791};
792
793int cmd_record(int argc, const char **argv, const char *prefix __used)
794{
795    int err = -ENOMEM;
796    struct perf_evsel *pos;
797
798    evsel_list = perf_evlist__new(NULL, NULL);
799    if (evsel_list == NULL)
800        return -ENOMEM;
801
802    argc = parse_options(argc, argv, record_options, record_usage,
803                PARSE_OPT_STOP_AT_NON_OPTION);
804    if (!argc && target_pid == -1 && target_tid == -1 &&
805        !system_wide && !cpu_list)
806        usage_with_options(record_usage, record_options);
807
808    if (force && append_file) {
809        fprintf(stderr, "Can't overwrite and append at the same time."
810                " You need to choose between -f and -A");
811        usage_with_options(record_usage, record_options);
812    } else if (append_file) {
813        write_mode = WRITE_APPEND;
814    } else {
815        write_mode = WRITE_FORCE;
816    }
817
818    if (nr_cgroups && !system_wide) {
819        fprintf(stderr, "cgroup monitoring only available in"
820            " system-wide mode\n");
821        usage_with_options(record_usage, record_options);
822    }
823
824    symbol__init();
825
826    if (no_buildid_cache || no_buildid)
827        disable_buildid_cache();
828
829    if (evsel_list->nr_entries == 0 &&
830        perf_evlist__add_default(evsel_list) < 0) {
831        pr_err("Not enough memory for event selector list\n");
832        goto out_symbol_exit;
833    }
834
835    if (target_pid != -1)
836        target_tid = target_pid;
837
838    if (perf_evlist__create_maps(evsel_list, target_pid,
839                     target_tid, cpu_list) < 0)
840        usage_with_options(record_usage, record_options);
841
842    list_for_each_entry(pos, &evsel_list->entries, node) {
843        if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
844                     evsel_list->threads->nr) < 0)
845            goto out_free_fd;
846        if (perf_header__push_event(pos->attr.config, event_name(pos)))
847            goto out_free_fd;
848    }
849
850    if (perf_evlist__alloc_pollfd(evsel_list) < 0)
851        goto out_free_fd;
852
853    if (user_interval != ULLONG_MAX)
854        default_interval = user_interval;
855    if (user_freq != UINT_MAX)
856        freq = user_freq;
857
858    /*
859     * User specified count overrides default frequency.
860     */
861    if (default_interval)
862        freq = 0;
863    else if (freq) {
864        default_interval = freq;
865    } else {
866        fprintf(stderr, "frequency and count are zero, aborting\n");
867        err = -EINVAL;
868        goto out_free_fd;
869    }
870
871    err = __cmd_record(argc, argv);
872out_free_fd:
873    perf_evlist__delete_maps(evsel_list);
874out_symbol_exit:
875    symbol__exit();
876    return err;
877}
878

Archive Download this file



interactive