]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blobdiff - tools/perf/builtin-record.c
Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[mirror_ubuntu-eoan-kernel.git] / tools / perf / builtin-record.c
index 4642d38b8d196d0ab0378086eebe9486028e5dbc..0abfb18b911fb93f022f0e6ac1e7b4dda4fb1e4d 100644 (file)
@@ -22,6 +22,7 @@
 #include "util/evsel.h"
 #include "util/debug.h"
 #include "util/session.h"
+#include "util/tool.h"
 #include "util/symbol.h"
 #include "util/cpumap.h"
 #include "util/thread_map.h"
@@ -36,7 +37,7 @@ enum write_mode_t {
 };
 
 struct perf_record {
-       struct perf_event_ops   ops;
+       struct perf_tool        tool;
        struct perf_record_opts opts;
        u64                     bytes_written;
        const char              *output_name;
@@ -76,12 +77,12 @@ static void write_output(struct perf_record *rec, void *buf, size_t size)
        }
 }
 
-static int process_synthesized_event(struct perf_event_ops *ops,
+static int process_synthesized_event(struct perf_tool *tool,
                                     union perf_event *event,
                                     struct perf_sample *sample __used,
-                                    struct perf_session *self __used)
+                                    struct machine *machine __used)
 {
-       struct perf_record *rec = container_of(ops, struct perf_record, ops);
+       struct perf_record *rec = container_of(tool, struct perf_record, tool);
        write_output(rec, event, event->header.size);
        return 0;
 }
@@ -271,8 +272,18 @@ try_again:
                exit(-1);
        }
 
-       if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0)
+       if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
+               if (errno == EPERM)
+                       die("Permission error mapping pages.\n"
+                           "Consider increasing "
+                           "/proc/sys/kernel/perf_event_mlock_kb,\n"
+                           "or try again with a smaller value of -m/--mmap_pages.\n"
+                           "(current value: %d)\n", opts->mmap_pages);
+               else if (!is_power_of_2(opts->mmap_pages))
+                       die("--mmap_pages/-m value must be a power of two.");
+
                die("failed to mmap with %d (%s)\n", errno, strerror(errno));
+       }
 
        if (rec->file_new)
                session->evlist = evlist;
@@ -319,9 +330,7 @@ static void perf_record__exit(int status __used, void *arg)
 static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
 {
        int err;
-       struct perf_event_ops *ops = data;
-       struct perf_record *rec = container_of(ops, struct perf_record, ops);
-       struct perf_session *psession = rec->session;
+       struct perf_tool *tool = data;
 
        if (machine__is_host(machine))
                return;
@@ -334,8 +343,8 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
         *method is used to avoid symbol missing when the first addr is
         *in module instead of in guest kernel.
         */
-       err = perf_event__synthesize_modules(ops, process_synthesized_event,
-                                            psession, machine);
+       err = perf_event__synthesize_modules(tool, process_synthesized_event,
+                                            machine);
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -344,12 +353,11 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
         * We use _stext for guest kernel because guest kernel's /proc/kallsyms
         * have no _text sometimes.
         */
-       err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
-                                                psession, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                machine, "_text");
        if (err < 0)
-               err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
-                                                        psession, machine,
-                                                        "_stext");
+               err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                        machine, "_stext");
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -381,7 +389,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
        unsigned long waking = 0;
        const bool forks = argc > 0;
        struct machine *machine;
-       struct perf_event_ops *ops = &rec->ops;
+       struct perf_tool *tool = &rec->tool;
        struct perf_record_opts *opts = &rec->opts;
        struct perf_evlist *evsel_list = rec->evlist;
        const char *output_name = rec->output_name;
@@ -495,18 +503,31 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                        return err;
        }
 
+       if (!!rec->no_buildid
+           && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
+               pr_err("Couldn't generating buildids. "
+                      "Use --no-buildid to profile anyway.\n");
+               return -1;
+       }
+
        rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
 
+       machine = perf_session__find_host_machine(session);
+       if (!machine) {
+               pr_err("Couldn't find native kernel information.\n");
+               return -1;
+       }
+
        if (opts->pipe_output) {
-               err = perf_event__synthesize_attrs(ops, session,
+               err = perf_event__synthesize_attrs(tool, session,
                                                   process_synthesized_event);
                if (err < 0) {
                        pr_err("Couldn't synthesize attrs.\n");
                        return err;
                }
 
-               err = perf_event__synthesize_event_types(ops, process_synthesized_event,
-                                                        session);
+               err = perf_event__synthesize_event_types(tool, process_synthesized_event,
+                                                        machine);
                if (err < 0) {
                        pr_err("Couldn't synthesize event_types.\n");
                        return err;
@@ -521,9 +542,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                         * return this more properly and also
                         * propagate errors that now are calling die()
                         */
-                       err = perf_event__synthesize_tracing_data(ops, output, evsel_list,
-                                                                 process_synthesized_event,
-                                                                 session);
+                       err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
+                                                                 process_synthesized_event);
                        if (err <= 0) {
                                pr_err("Couldn't record tracing data.\n");
                                return err;
@@ -532,40 +552,34 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                }
        }
 
-       machine = perf_session__find_host_machine(session);
-       if (!machine) {
-               pr_err("Couldn't find native kernel information.\n");
-               return -1;
-       }
-
-       err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
-                                                session, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                machine, "_text");
        if (err < 0)
-               err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
-                                                        session, machine, "_stext");
+               err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                        machine, "_stext");
        if (err < 0)
                pr_err("Couldn't record kernel reference relocation symbol\n"
                       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
                       "Check /proc/kallsyms permission or run as root.\n");
 
-       err = perf_event__synthesize_modules(ops, process_synthesized_event,
-                                            session, machine);
+       err = perf_event__synthesize_modules(tool, process_synthesized_event,
+                                            machine);
        if (err < 0)
                pr_err("Couldn't record kernel module information.\n"
                       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
                       "Check /proc/modules permission or run as root.\n");
 
        if (perf_guest)
-               perf_session__process_machines(session, ops,
+               perf_session__process_machines(session, tool,
                                               perf_event__synthesize_guest_os);
 
        if (!opts->system_wide)
-               perf_event__synthesize_thread_map(ops, evsel_list->threads,
+               perf_event__synthesize_thread_map(tool, evsel_list->threads,
                                                  process_synthesized_event,
-                                                 session);
+                                                 machine);
        else
-               perf_event__synthesize_threads(ops, process_synthesized_event,
-                                              session);
+               perf_event__synthesize_threads(tool, process_synthesized_event,
+                                              machine);
 
        if (rec->realtime_prio) {
                struct sched_param param;
@@ -703,6 +717,7 @@ const struct option record_options[] = {
        OPT_BOOLEAN('d', "data", &record.opts.sample_address,
                    "Sample addresses"),
        OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
+       OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
        OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
                    "don't sample"),
        OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
@@ -781,16 +796,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                usage_with_options(record_usage, record_options);
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
-               if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
-                                        evsel_list->threads->nr) < 0)
-                       goto out_free_fd;
                if (perf_header__push_event(pos->attr.config, event_name(pos)))
                        goto out_free_fd;
        }
 
-       if (perf_evlist__alloc_pollfd(evsel_list) < 0)
-               goto out_free_fd;
-
        if (rec->opts.user_interval != ULLONG_MAX)
                rec->opts.default_interval = rec->opts.user_interval;
        if (rec->opts.user_freq != UINT_MAX)