]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-record.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6
[~andy/linux] / tools / perf / builtin-record.c
index 60cac6f92e8b8d17bf165a6a592c6653f6141a96..6febcc168a8cc261e2dc10314ef082d40c717ec8 100644 (file)
 
 #include "util/header.h"
 #include "util/event.h"
+#include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/debug.h"
 #include "util/session.h"
 #include "util/symbol.h"
 #include "util/cpumap.h"
+#include "util/thread_map.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -37,16 +39,14 @@ enum write_mode_t {
 
 static u64                     user_interval                   = ULLONG_MAX;
 static u64                     default_interval                =      0;
-static u64                     sample_type;
 
-static struct cpu_map          *cpus;
 static unsigned int            page_size;
 static unsigned int            mmap_pages                      =    128;
 static unsigned int            user_freq                       = UINT_MAX;
 static int                     freq                            =   1000;
 static int                     output;
 static int                     pipe_output                     =      0;
-static const char              *output_name                    = "perf.data";
+static const char              *output_name                    = NULL;
 static int                     group                           =      0;
 static int                     realtime_prio                   =      0;
 static bool                    nodelay                         =  false;
@@ -55,7 +55,6 @@ static bool                   sample_id_all_avail             =   true;
 static bool                    system_wide                     =  false;
 static pid_t                   target_pid                      =     -1;
 static pid_t                   target_tid                      =     -1;
-static struct thread_map       *threads;
 static pid_t                   child_pid                       =     -1;
 static bool                    no_inherit                      =  false;
 static enum write_mode_t       write_mode                      = WRITE_FORCE;
@@ -66,51 +65,17 @@ static bool                 sample_address                  =  false;
 static bool                    sample_time                     =  false;
 static bool                    no_buildid                      =  false;
 static bool                    no_buildid_cache                =  false;
+static struct perf_evlist      *evsel_list;
 
 static long                    samples                         =      0;
 static u64                     bytes_written                   =      0;
 
-static struct pollfd           *event_array;
-
-static int                     nr_poll                         =      0;
-static int                     nr_cpu                          =      0;
-
 static int                     file_new                        =      1;
 static off_t                   post_processing_offset;
 
 static struct perf_session     *session;
 static const char              *cpu_list;
 
-struct mmap_data {
-       void                    *base;
-       unsigned int            mask;
-       unsigned int            prev;
-};
-
-static struct mmap_data                mmap_array[MAX_NR_CPUS];
-
-static unsigned long mmap_read_head(struct mmap_data *md)
-{
-       struct perf_event_mmap_page *pc = md->base;
-       long head;
-
-       head = pc->data_head;
-       rmb();
-
-       return head;
-}
-
-static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
-{
-       struct perf_event_mmap_page *pc = md->base;
-
-       /*
-        * ensure all reads are done before we write the tail out.
-        */
-       /* mb(); */
-       pc->data_tail = tail;
-}
-
 static void advance_output(size_t size)
 {
        bytes_written += size;
@@ -131,42 +96,26 @@ static void write_output(void *buf, size_t size)
        }
 }
 
-static int process_synthesized_event(event_t *event,
-                                    struct sample_data *sample __used,
+static int process_synthesized_event(union perf_event *event,
+                                    struct perf_sample *sample __used,
                                     struct perf_session *self __used)
 {
        write_output(event, event->header.size);
        return 0;
 }
 
-static void mmap_read(struct mmap_data *md)
+static void mmap_read(struct perf_mmap *md)
 {
-       unsigned int head = mmap_read_head(md);
+       unsigned int head = perf_mmap__read_head(md);
        unsigned int old = md->prev;
        unsigned char *data = md->base + page_size;
        unsigned long size;
        void *buf;
-       int diff;
 
-       /*
-        * If we're further behind than half the buffer, there's a chance
-        * the writer will bite our tail and mess up the samples under us.
-        *
-        * If we somehow ended up ahead of the head, we got messed up.
-        *
-        * In either case, truncate and restart at head.
-        */
-       diff = head - old;
-       if (diff < 0) {
-               fprintf(stderr, "WARNING: failed to keep up with mmap data\n");
-               /*
-                * head points to a known good entry, start there.
-                */
-               old = head;
-       }
+       if (old == head)
+               return;
 
-       if (old != head)
-               samples++;
+       samples++;
 
        size = head - old;
 
@@ -185,7 +134,7 @@ static void mmap_read(struct mmap_data *md)
        write_output(buf, size);
 
        md->prev = old;
-       mmap_write_tail(md, old);
+       perf_mmap__write_tail(md, old);
 }
 
 static volatile int done = 0;
@@ -209,53 +158,10 @@ static void sig_atexit(void)
        kill(getpid(), signr);
 }
 
-static int group_fd;
-
-static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
-{
-       struct perf_header_attr *h_attr;
-
-       if (nr < session->header.attrs) {
-               h_attr = session->header.attr[nr];
-       } else {
-               h_attr = perf_header_attr__new(a);
-               if (h_attr != NULL)
-                       if (perf_header__add_attr(&session->header, h_attr) < 0) {
-                               perf_header_attr__delete(h_attr);
-                               h_attr = NULL;
-                       }
-       }
-
-       return h_attr;
-}
-
-static void create_counter(struct perf_evsel *evsel, int cpu)
+static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
 {
-       char *filter = evsel->filter;
        struct perf_event_attr *attr = &evsel->attr;
-       struct perf_header_attr *h_attr;
        int track = !evsel->idx; /* only the first counter needs these */
-       int thread_index;
-       int ret;
-       struct {
-               u64 count;
-               u64 time_enabled;
-               u64 time_running;
-               u64 id;
-       } read_data;
-       /*
-        * Check if parse_single_tracepoint_event has already asked for
-        * PERF_SAMPLE_TIME.
-        *
-        * XXX this is kludgy but short term fix for problems introduced by
-        * eac23d1c that broke 'perf script' by having different sample_types
-        * when using multiple tracepoint events when we use a perf binary
-        * that tries to use sample_id_all on an older kernel.
-        *
-        * We need to move counter creation to perf_session, support
-        * different sample_types, etc.
-        */
-       bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
 
        attr->read_format       = PERF_FORMAT_TOTAL_TIME_ENABLED |
                                  PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -263,7 +169,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
 
        attr->sample_type       |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
-       if (nr_counters > 1)
+       if (evlist->nr_entries > 1)
                attr->sample_type |= PERF_SAMPLE_ID;
 
        /*
@@ -315,19 +221,58 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
 
        attr->mmap              = track;
        attr->comm              = track;
-       attr->inherit           = !no_inherit;
+
        if (target_pid == -1 && target_tid == -1 && !system_wide) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
-retry_sample_id:
-       attr->sample_id_all = sample_id_all_avail ? 1 : 0;
+}
 
-       for (thread_index = 0; thread_index < threads->nr; thread_index++) {
-try_again:
-               FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
+static bool perf_evlist__equal(struct perf_evlist *evlist,
+                              struct perf_evlist *other)
+{
+       struct perf_evsel *pos, *pair;
+
+       if (evlist->nr_entries != other->nr_entries)
+               return false;
+
+       pair = list_entry(other->entries.next, struct perf_evsel, node);
 
-               if (FD(evsel, nr_cpu, thread_index) < 0) {
+       list_for_each_entry(pos, &evlist->entries, node) {
+               if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
+                       return false;
+               pair = list_entry(pair->node.next, struct perf_evsel, node);
+       }
+
+       return true;
+}
+
+static void open_counters(struct perf_evlist *evlist)
+{
+       struct perf_evsel *pos;
+
+       list_for_each_entry(pos, &evlist->entries, node) {
+               struct perf_event_attr *attr = &pos->attr;
+               /*
+                * Check if parse_single_tracepoint_event has already asked for
+                * PERF_SAMPLE_TIME.
+                *
+                * XXX this is kludgy but short term fix for problems introduced by
+                * eac23d1c that broke 'perf script' by having different sample_types
+                * when using multiple tracepoint events when we use a perf binary
+                * that tries to use sample_id_all on an older kernel.
+                *
+                * We need to move counter creation to perf_session, support
+                * different sample_types, etc.
+                */
+               bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
+
+               config_attr(pos, evlist);
+retry_sample_id:
+               attr->sample_id_all = sample_id_all_avail ? 1 : 0;
+try_again:
+               if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
+                                    !no_inherit) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES)
@@ -364,7 +309,7 @@ try_again:
                        }
                        printf("\n");
                        error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
-                             FD(evsel, nr_cpu, thread_index), strerror(err));
+                             err, strerror(err));
 
 #if defined(__i386__) || defined(__x86_64__)
                        if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +320,28 @@ try_again:
 #endif
 
                        die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
-                       exit(-1);
                }
+       }
 
-               h_attr = get_header_attr(attr, evsel->idx);
-               if (h_attr == NULL)
-                       die("nomem\n");
+       if (perf_evlist__set_filters(evlist)) {
+               error("failed to set filter with %d (%s)\n", errno,
+                       strerror(errno));
+               exit(-1);
+       }
 
-               if (!file_new) {
-                       if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
-                               fprintf(stderr, "incompatible append\n");
-                               exit(-1);
-                       }
-               }
+       if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
+               die("failed to mmap with %d (%s)\n", errno, strerror(errno));
 
-               if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
-                       perror("Unable to read perf file descriptor");
+       if (file_new)
+               session->evlist = evlist;
+       else {
+               if (!perf_evlist__equal(session->evlist, evlist)) {
+                       fprintf(stderr, "incompatible append\n");
                        exit(-1);
                }
+       }
 
-               if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
-                       pr_warning("Not enough memory to add id\n");
-                       exit(-1);
-               }
-
-               assert(FD(evsel, nr_cpu, thread_index) >= 0);
-               fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
-
-               /*
-                * First counter acts as the group leader:
-                */
-               if (group && group_fd == -1)
-                       group_fd = FD(evsel, nr_cpu, thread_index);
-
-               if (evsel->idx || thread_index) {
-                       struct perf_evsel *first;
-                       first = list_entry(evsel_list.next, struct perf_evsel, node);
-                       ret = ioctl(FD(evsel, nr_cpu, thread_index),
-                                   PERF_EVENT_IOC_SET_OUTPUT,
-                                   FD(first, nr_cpu, 0));
-                       if (ret) {
-                               error("failed to set output: %d (%s)\n", errno,
-                                               strerror(errno));
-                               exit(-1);
-                       }
-               } else {
-                       mmap_array[nr_cpu].prev = 0;
-                       mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
-                       mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
-                               PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
-                       if (mmap_array[nr_cpu].base == MAP_FAILED) {
-                               error("failed to mmap with %d (%s)\n", errno, strerror(errno));
-                               exit(-1);
-                       }
-
-                       event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
-                       event_array[nr_poll].events = POLLIN;
-                       nr_poll++;
-               }
-
-               if (filter != NULL) {
-                       ret = ioctl(FD(evsel, nr_cpu, thread_index),
-                                   PERF_EVENT_IOC_SET_FILTER, filter);
-                       if (ret) {
-                               error("failed to set filter with %d (%s)\n", errno,
-                                               strerror(errno));
-                               exit(-1);
-                       }
-               }
-       }
-
-       if (!sample_type)
-               sample_type = attr->sample_type;
-}
-
-static void open_counters(int cpu)
-{
-       struct perf_evsel *pos;
-
-       group_fd = -1;
-
-       list_for_each_entry(pos, &evsel_list, node)
-               create_counter(pos, cpu);
-
-       nr_cpu++;
+       perf_session__update_sample_type(session);
 }
 
 static int process_buildids(void)
@@ -481,14 +364,14 @@ static void atexit_header(void)
 
                if (!no_buildid)
                        process_buildids();
-               perf_header__write(&session->header, output, true);
+               perf_session__write_header(session, evsel_list, output, true);
                perf_session__delete(session);
-               perf_evsel_list__delete();
+               perf_evlist__delete(evsel_list);
                symbol__exit();
        }
 }
 
-static void event__synthesize_guest_os(struct machine *machine, void *data)
+static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
 {
        int err;
        struct perf_session *psession = data;
@@ -504,8 +387,8 @@ static void 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 = event__synthesize_modules(process_synthesized_event,
-                                       psession, machine);
+       err = perf_event__synthesize_modules(process_synthesized_event,
+                                            psession, machine);
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -514,11 +397,12 @@ static void 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 = event__synthesize_kernel_mmap(process_synthesized_event,
-                                           psession, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                psession, machine, "_text");
        if (err < 0)
-               err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                                   psession, machine, "_stext");
+               err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                        psession, machine,
+                                                        "_stext");
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -533,9 +417,9 @@ static void mmap_read_all(void)
 {
        int i;
 
-       for (i = 0; i < nr_cpu; i++) {
-               if (mmap_array[i].base)
-                       mmap_read(&mmap_array[i]);
+       for (i = 0; i < evsel_list->cpus->nr; i++) {
+               if (evsel_list->mmap[i].base)
+                       mmap_read(&evsel_list->mmap[i]);
        }
 
        if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -566,18 +450,26 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       if (!strcmp(output_name, "-"))
-               pipe_output = 1;
-       else if (!stat(output_name, &st) && st.st_size) {
-               if (write_mode == WRITE_FORCE) {
-                       char oldname[PATH_MAX];
-                       snprintf(oldname, sizeof(oldname), "%s.old",
-                                output_name);
-                       unlink(oldname);
-                       rename(output_name, oldname);
+       if (!output_name) {
+               if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
+                       pipe_output = 1;
+               else
+                       output_name = "perf.data";
+       }
+       if (output_name) {
+               if (!strcmp(output_name, "-"))
+                       pipe_output = 1;
+               else if (!stat(output_name, &st) && st.st_size) {
+                       if (write_mode == WRITE_FORCE) {
+                               char oldname[PATH_MAX];
+                               snprintf(oldname, sizeof(oldname), "%s.old",
+                                        output_name);
+                               unlink(oldname);
+                               rename(output_name, oldname);
+                       }
+               } else if (write_mode == WRITE_APPEND) {
+                       write_mode = WRITE_FORCE;
                }
-       } else if (write_mode == WRITE_APPEND) {
-               write_mode = WRITE_FORCE;
        }
 
        flags = O_CREAT|O_RDWR;
@@ -606,19 +498,14 @@ static int __cmd_record(int argc, const char **argv)
                perf_header__set_feat(&session->header, HEADER_BUILD_ID);
 
        if (!file_new) {
-               err = perf_header__read(session, output);
+               err = perf_session__read_header(session, output);
                if (err < 0)
                        goto out_delete_session;
        }
 
-       if (have_tracepoints(&evsel_list))
+       if (have_tracepoints(&evsel_list->entries))
                perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
 
-       /*
-        * perf_session__delete(session) will be called at atexit_header()
-        */
-       atexit(atexit_header);
-
        if (forks) {
                child_pid = fork();
                if (child_pid < 0) {
@@ -659,7 +546,7 @@ static int __cmd_record(int argc, const char **argv)
                }
 
                if (!system_wide && target_tid == -1 && target_pid == -1)
-                       threads->map[0] = child_pid;
+                       evsel_list->threads->map[0] = child_pid;
 
                close(child_ready_pipe[1]);
                close(go_pipe[0]);
@@ -673,46 +560,42 @@ static int __cmd_record(int argc, const char **argv)
                close(child_ready_pipe[0]);
        }
 
-       if (!system_wide && no_inherit && !cpu_list) {
-               open_counters(-1);
-       } else {
-               for (i = 0; i < cpus->nr; i++)
-                       open_counters(cpus->map[i]);
-       }
+       open_counters(evsel_list);
 
-       perf_session__set_sample_type(session, sample_type);
+       /*
+        * perf_session__delete(session) will be called at atexit_header()
+        */
+       atexit(atexit_header);
 
        if (pipe_output) {
                err = perf_header__write_pipe(output);
                if (err < 0)
                        return err;
        } else if (file_new) {
-               err = perf_header__write(&session->header, output, false);
+               err = perf_session__write_header(session, evsel_list,
+                                                output, false);
                if (err < 0)
                        return err;
        }
 
        post_processing_offset = lseek(output, 0, SEEK_CUR);
 
-       perf_session__set_sample_id_all(session, sample_id_all_avail);
-
        if (pipe_output) {
-               err = event__synthesize_attrs(&session->header,
-                                             process_synthesized_event,
-                                             session);
+               err = perf_session__synthesize_attrs(session,
+                                                    process_synthesized_event);
                if (err < 0) {
                        pr_err("Couldn't synthesize attrs.\n");
                        return err;
                }
 
-               err = event__synthesize_event_types(process_synthesized_event,
-                                                   session);
+               err = perf_event__synthesize_event_types(process_synthesized_event,
+                                                        session);
                if (err < 0) {
                        pr_err("Couldn't synthesize event_types.\n");
                        return err;
                }
 
-               if (have_tracepoints(&evsel_list)) {
+               if (have_tracepoints(&evsel_list->entries)) {
                        /*
                         * FIXME err <= 0 here actually means that
                         * there were no tracepoints so its not really
@@ -721,9 +604,9 @@ static int __cmd_record(int argc, const char **argv)
                         * return this more properly and also
                         * propagate errors that now are calling die()
                         */
-                       err = event__synthesize_tracing_data(output, &evsel_list,
-                                                            process_synthesized_event,
-                                                            session);
+                       err = perf_event__synthesize_tracing_data(output, evsel_list,
+                                                                 process_synthesized_event,
+                                                                 session);
                        if (err <= 0) {
                                pr_err("Couldn't record tracing data.\n");
                                return err;
@@ -738,31 +621,34 @@ static int __cmd_record(int argc, const char **argv)
                return -1;
        }
 
-       err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                           session, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                session, machine, "_text");
        if (err < 0)
-               err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                                   session, machine, "_stext");
+               err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                        session, 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 = event__synthesize_modules(process_synthesized_event,
-                                       session, machine);
+       err = perf_event__synthesize_modules(process_synthesized_event,
+                                            session, 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, event__synthesize_guest_os);
+               perf_session__process_machines(session,
+                                              perf_event__synthesize_guest_os);
 
        if (!system_wide)
-               event__synthesize_thread_map(threads, process_synthesized_event,
-                                            session);
+               perf_event__synthesize_thread_map(evsel_list->threads,
+                                                 process_synthesized_event,
+                                                 session);
        else
-               event__synthesize_threads(process_synthesized_event, session);
+               perf_event__synthesize_threads(process_synthesized_event,
+                                              session);
 
        if (realtime_prio) {
                struct sched_param param;
@@ -789,17 +675,17 @@ static int __cmd_record(int argc, const char **argv)
                if (hits == samples) {
                        if (done)
                                break;
-                       err = poll(event_array, nr_poll, -1);
+                       err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
                        waking++;
                }
 
                if (done) {
-                       for (i = 0; i < nr_cpu; i++) {
+                       for (i = 0; i < evsel_list->cpus->nr; i++) {
                                struct perf_evsel *pos;
 
-                               list_for_each_entry(pos, &evsel_list, node) {
+                               list_for_each_entry(pos, &evsel_list->entries, node) {
                                        for (thread = 0;
-                                               thread < threads->nr;
+                                               thread < evsel_list->threads->nr;
                                                thread++)
                                                ioctl(FD(pos, i, thread),
                                                        PERF_EVENT_IOC_DISABLE);
@@ -838,10 +724,10 @@ static const char * const record_usage[] = {
 static bool force, append_file;
 
 const struct option record_options[] = {
-       OPT_CALLBACK('e', "event", NULL, "event",
+       OPT_CALLBACK('e', "event", &evsel_list, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events),
-       OPT_CALLBACK(0, "filter", NULL, "filter",
+       OPT_CALLBACK(0, "filter", &evsel_list, "filter",
                     "event filter", parse_filter),
        OPT_INTEGER('p', "pid", &target_pid,
                    "record events on existing process id"),
@@ -884,6 +770,9 @@ const struct option record_options[] = {
                    "do not update the buildid cache"),
        OPT_BOOLEAN('B', "no-buildid", &no_buildid,
                    "do not collect buildids in perf.data"),
+       OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
+                    "monitor event in cgroup name only",
+                    parse_cgroups),
        OPT_END()
 };
 
@@ -892,6 +781,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        int err = -ENOMEM;
        struct perf_evsel *pos;
 
+       evsel_list = perf_evlist__new(NULL, NULL);
+       if (evsel_list == NULL)
+               return -ENOMEM;
+
        argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && target_tid == -1 &&
@@ -908,12 +801,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                write_mode = WRITE_FORCE;
        }
 
+       if (nr_cgroups && !system_wide) {
+               fprintf(stderr, "cgroup monitoring only available in"
+                       " system-wide mode\n");
+               usage_with_options(record_usage, record_options);
+       }
+
        symbol__init();
 
        if (no_buildid_cache || no_buildid)
                disable_buildid_cache();
 
-       if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) {
+       if (evsel_list->nr_entries == 0 &&
+           perf_evlist__add_default(evsel_list) < 0) {
                pr_err("Not enough memory for event selector list\n");
                goto out_symbol_exit;
        }
@@ -921,27 +821,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        if (target_pid != -1)
                target_tid = target_pid;
 
-       threads = thread_map__new(target_pid, target_tid);
-       if (threads == NULL) {
-               pr_err("Problems finding threads of monitor\n");
+       if (perf_evlist__create_maps(evsel_list, target_pid,
+                                    target_tid, cpu_list) < 0)
                usage_with_options(record_usage, record_options);
-       }
 
-       cpus = cpu_map__new(cpu_list);
-       if (cpus == NULL) {
-               perror("failed to parse CPUs map");
-               return -1;
-       }
-
-       list_for_each_entry(pos, &evsel_list, node) {
-               if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
+       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;
        }
-       event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
-                             MAX_COUNTERS * threads->nr));
-       if (!event_array)
+
+       if (perf_evlist__alloc_pollfd(evsel_list) < 0)
                goto out_free_fd;
 
        if (user_interval != ULLONG_MAX)
@@ -959,16 +851,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        } else {
                fprintf(stderr, "frequency and count are zero, aborting\n");
                err = -EINVAL;
-               goto out_free_event_array;
+               goto out_free_fd;
        }
 
        err = __cmd_record(argc, argv);
-
-out_free_event_array:
-       free(event_array);
 out_free_fd:
-       thread_map__delete(threads);
-       threads = NULL;
+       perf_evlist__delete_maps(evsel_list);
 out_symbol_exit:
        symbol__exit();
        return err;