Merge branch 'perf/urgent' into perf/core
authorIngo Molnar <mingo@elte.hu>
Thu, 16 Dec 2010 10:22:25 +0000 (11:22 +0100)
committerIngo Molnar <mingo@elte.hu>
Thu, 16 Dec 2010 10:22:27 +0000 (11:22 +0100)
Merge reason: We want to apply a dependent patch.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
include/linux/perf_event.h
kernel/perf_event.c
tools/perf/builtin-record.c
tools/perf/util/header.c
tools/perf/util/symbol.c

index 2814ead4adb83209a0ed537b6427692264e2b28b,4f1279e105ee143e4317219b3cb093bc8bbdd954..30e50e2c7f30e13abce48997617840cab8153283
@@@ -215,9 -215,8 +215,9 @@@ struct perf_event_attr 
                                 */
                                precise_ip     :  2, /* skid constraint       */
                                mmap_data      :  1, /* non-exec mmap data    */
 +                              sample_id_all  :  1, /* sample_type all events */
  
 -                              __reserved_1   : 46;
 +                              __reserved_1   : 45;
  
        union {
                __u32           wakeup_events;    /* wakeup every n events */
@@@ -328,15 -327,6 +328,15 @@@ struct perf_event_header 
  enum perf_event_type {
  
        /*
 +       * If perf_event_attr.sample_id_all is set then all event types will
 +       * have the sample_type selected fields related to where/when
 +       * (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID)
 +       * described in PERF_RECORD_SAMPLE below, it will be stashed just after
 +       * the perf_event_header and the fields already present for the existing
 +       * fields, i.e. at the end of the payload. That way a newer perf.data
 +       * file will be supported by older perf tools, with these new optional
 +       * fields being ignored.
 +       *
         * The MMAP events record the PROT_EXEC mappings so that we can
         * correlate userspace IPs to code. They have the following structure:
         *
@@@ -768,9 -758,6 +768,9 @@@ struct perf_event 
        u64                             shadow_ctx_time;
  
        struct perf_event_attr          attr;
 +      u16                             header_size;
 +      u16                             id_header_size;
 +      u16                             read_size;
        struct hw_perf_event            hw;
  
        struct perf_event_context       *ctx;
@@@ -900,6 -887,7 +900,7 @@@ struct perf_cpu_context 
        int                             exclusive;
        struct list_head                rotation_list;
        int                             jiffies_interval;
+       struct pmu                      *active_pmu;
  };
  
  struct perf_output_handle {
@@@ -982,11 -970,6 +983,11 @@@ extern int perf_event_overflow(struct p
                                 struct perf_sample_data *data,
                                 struct pt_regs *regs);
  
 +static inline bool is_sampling_event(struct perf_event *event)
 +{
 +      return event->attr.sample_period != 0;
 +}
 +
  /*
   * Return 1 for a software event, 0 for a hardware event
   */
diff --combined kernel/perf_event.c
index f9d2645b5546a8f1eb98d4c9bc76d289c06765a6,2870feee81dd7a046703645c9ec50022d4339f39..a3d568fbacc60b8103830c2910c0f0302d2037c5
@@@ -21,7 -21,6 +21,7 @@@
  #include <linux/dcache.h>
  #include <linux/percpu.h>
  #include <linux/ptrace.h>
 +#include <linux/reboot.h>
  #include <linux/vmstat.h>
  #include <linux/vmalloc.h>
  #include <linux/hardirq.h>
@@@ -134,28 -133,6 +134,28 @@@ static void unclone_ctx(struct perf_eve
        }
  }
  
 +static u32 perf_event_pid(struct perf_event *event, struct task_struct *p)
 +{
 +      /*
 +       * only top level events have the pid namespace they were created in
 +       */
 +      if (event->parent)
 +              event = event->parent;
 +
 +      return task_tgid_nr_ns(p, event->ns);
 +}
 +
 +static u32 perf_event_tid(struct perf_event *event, struct task_struct *p)
 +{
 +      /*
 +       * only top level events have the pid namespace they were created in
 +       */
 +      if (event->parent)
 +              event = event->parent;
 +
 +      return task_pid_nr_ns(p, event->ns);
 +}
 +
  /*
   * If we inherit events we want to return the parent event id
   * to userspace.
@@@ -335,84 -312,9 +335,84 @@@ list_add_event(struct perf_event *event
                ctx->nr_stat++;
  }
  
 +/*
 + * Called at perf_event creation and when events are attached/detached from a
 + * group.
 + */
 +static void perf_event__read_size(struct perf_event *event)
 +{
 +      int entry = sizeof(u64); /* value */
 +      int size = 0;
 +      int nr = 1;
 +
 +      if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
 +              size += sizeof(u64);
 +
 +      if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
 +              size += sizeof(u64);
 +
 +      if (event->attr.read_format & PERF_FORMAT_ID)
 +              entry += sizeof(u64);
 +
 +      if (event->attr.read_format & PERF_FORMAT_GROUP) {
 +              nr += event->group_leader->nr_siblings;
 +              size += sizeof(u64);
 +      }
 +
 +      size += entry * nr;
 +      event->read_size = size;
 +}
 +
 +static void perf_event__header_size(struct perf_event *event)
 +{
 +      struct perf_sample_data *data;
 +      u64 sample_type = event->attr.sample_type;
 +      u16 size = 0;
 +
 +      perf_event__read_size(event);
 +
 +      if (sample_type & PERF_SAMPLE_IP)
 +              size += sizeof(data->ip);
 +
 +      if (sample_type & PERF_SAMPLE_ADDR)
 +              size += sizeof(data->addr);
 +
 +      if (sample_type & PERF_SAMPLE_PERIOD)
 +              size += sizeof(data->period);
 +
 +      if (sample_type & PERF_SAMPLE_READ)
 +              size += event->read_size;
 +
 +      event->header_size = size;
 +}
 +
 +static void perf_event__id_header_size(struct perf_event *event)
 +{
 +      struct perf_sample_data *data;
 +      u64 sample_type = event->attr.sample_type;
 +      u16 size = 0;
 +
 +      if (sample_type & PERF_SAMPLE_TID)
 +              size += sizeof(data->tid_entry);
 +
 +      if (sample_type & PERF_SAMPLE_TIME)
 +              size += sizeof(data->time);
 +
 +      if (sample_type & PERF_SAMPLE_ID)
 +              size += sizeof(data->id);
 +
 +      if (sample_type & PERF_SAMPLE_STREAM_ID)
 +              size += sizeof(data->stream_id);
 +
 +      if (sample_type & PERF_SAMPLE_CPU)
 +              size += sizeof(data->cpu_entry);
 +
 +      event->id_header_size = size;
 +}
 +
  static void perf_group_attach(struct perf_event *event)
  {
 -      struct perf_event *group_leader = event->group_leader;
 +      struct perf_event *group_leader = event->group_leader, *pos;
  
        /*
         * We can have double attach due to group movement in perf_event_open.
  
        list_add_tail(&event->group_entry, &group_leader->sibling_list);
        group_leader->nr_siblings++;
 +
 +      perf_event__header_size(group_leader);
 +
 +      list_for_each_entry(pos, &group_leader->sibling_list, group_entry)
 +              perf_event__header_size(pos);
  }
  
  /*
@@@ -494,7 -391,7 +494,7 @@@ static void perf_group_detach(struct pe
        if (event->group_leader != event) {
                list_del_init(&event->group_entry);
                event->group_leader->nr_siblings--;
 -              return;
 +              goto out;
        }
  
        if (!list_empty(&event->group_entry))
                /* Inherit group flags from the previous leader */
                sibling->group_flags = event->group_flags;
        }
 +
 +out:
 +      perf_event__header_size(event->group_leader);
 +
 +      list_for_each_entry(tmp, &event->group_leader->sibling_list, group_entry)
 +              perf_event__header_size(tmp);
  }
  
  static inline int
@@@ -1182,7 -1073,7 +1182,7 @@@ static int perf_event_refresh(struct pe
        /*
         * not supported on inherited events
         */
 -      if (event->attr.inherit)
 +      if (event->attr.inherit || !is_sampling_event(event))
                return -EINVAL;
  
        atomic_add(refresh, &event->event_limit);
@@@ -2398,6 -2289,31 +2398,6 @@@ static int perf_release(struct inode *i
        return perf_event_release_kernel(event);
  }
  
 -static int perf_event_read_size(struct perf_event *event)
 -{
 -      int entry = sizeof(u64); /* value */
 -      int size = 0;
 -      int nr = 1;
 -
 -      if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
 -              size += sizeof(u64);
 -
 -      if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
 -              size += sizeof(u64);
 -
 -      if (event->attr.read_format & PERF_FORMAT_ID)
 -              entry += sizeof(u64);
 -
 -      if (event->attr.read_format & PERF_FORMAT_GROUP) {
 -              nr += event->group_leader->nr_siblings;
 -              size += sizeof(u64);
 -      }
 -
 -      size += entry * nr;
 -
 -      return size;
 -}
 -
  u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
  {
        struct perf_event *child;
@@@ -2512,7 -2428,7 +2512,7 @@@ perf_read_hw(struct perf_event *event, 
        if (event->state == PERF_EVENT_STATE_ERROR)
                return 0;
  
 -      if (count < perf_event_read_size(event))
 +      if (count < event->read_size)
                return -ENOSPC;
  
        WARN_ON_ONCE(event->ctx->parent_ctx);
@@@ -2598,7 -2514,7 +2598,7 @@@ static int perf_event_period(struct per
        int ret = 0;
        u64 value;
  
 -      if (!event->attr.sample_period)
 +      if (!is_sampling_event(event))
                return -EINVAL;
  
        if (copy_from_user(&value, arg, sizeof(value)))
@@@ -3389,73 -3305,6 +3389,73 @@@ __always_inline void perf_output_copy(s
        } while (len);
  }
  
 +static void __perf_event_header__init_id(struct perf_event_header *header,
 +                                       struct perf_sample_data *data,
 +                                       struct perf_event *event)
 +{
 +      u64 sample_type = event->attr.sample_type;
 +
 +      data->type = sample_type;
 +      header->size += event->id_header_size;
 +
 +      if (sample_type & PERF_SAMPLE_TID) {
 +              /* namespace issues */
 +              data->tid_entry.pid = perf_event_pid(event, current);
 +              data->tid_entry.tid = perf_event_tid(event, current);
 +      }
 +
 +      if (sample_type & PERF_SAMPLE_TIME)
 +              data->time = perf_clock();
 +
 +      if (sample_type & PERF_SAMPLE_ID)
 +              data->id = primary_event_id(event);
 +
 +      if (sample_type & PERF_SAMPLE_STREAM_ID)
 +              data->stream_id = event->id;
 +
 +      if (sample_type & PERF_SAMPLE_CPU) {
 +              data->cpu_entry.cpu      = raw_smp_processor_id();
 +              data->cpu_entry.reserved = 0;
 +      }
 +}
 +
 +static void perf_event_header__init_id(struct perf_event_header *header,
 +                                     struct perf_sample_data *data,
 +                                     struct perf_event *event)
 +{
 +      if (event->attr.sample_id_all)
 +              __perf_event_header__init_id(header, data, event);
 +}
 +
 +static void __perf_event__output_id_sample(struct perf_output_handle *handle,
 +                                         struct perf_sample_data *data)
 +{
 +      u64 sample_type = data->type;
 +
 +      if (sample_type & PERF_SAMPLE_TID)
 +              perf_output_put(handle, data->tid_entry);
 +
 +      if (sample_type & PERF_SAMPLE_TIME)
 +              perf_output_put(handle, data->time);
 +
 +      if (sample_type & PERF_SAMPLE_ID)
 +              perf_output_put(handle, data->id);
 +
 +      if (sample_type & PERF_SAMPLE_STREAM_ID)
 +              perf_output_put(handle, data->stream_id);
 +
 +      if (sample_type & PERF_SAMPLE_CPU)
 +              perf_output_put(handle, data->cpu_entry);
 +}
 +
 +static void perf_event__output_id_sample(struct perf_event *event,
 +                                       struct perf_output_handle *handle,
 +                                       struct perf_sample_data *sample)
 +{
 +      if (event->attr.sample_id_all)
 +              __perf_event__output_id_sample(handle, sample);
 +}
 +
  int perf_output_begin(struct perf_output_handle *handle,
                      struct perf_event *event, unsigned int size,
                      int nmi, int sample)
        struct perf_buffer *buffer;
        unsigned long tail, offset, head;
        int have_lost;
 +      struct perf_sample_data sample_data;
        struct {
                struct perf_event_header header;
                u64                      id;
                goto out;
  
        have_lost = local_read(&buffer->lost);
 -      if (have_lost)
 -              size += sizeof(lost_event);
 +      if (have_lost) {
 +              lost_event.header.size = sizeof(lost_event);
 +              perf_event_header__init_id(&lost_event.header, &sample_data,
 +                                         event);
 +              size += lost_event.header.size;
 +      }
  
        perf_output_get_handle(handle);
  
        if (have_lost) {
                lost_event.header.type = PERF_RECORD_LOST;
                lost_event.header.misc = 0;
 -              lost_event.header.size = sizeof(lost_event);
                lost_event.id          = event->id;
                lost_event.lost        = local_xchg(&buffer->lost, 0);
  
                perf_output_put(handle, lost_event);
 +              perf_event__output_id_sample(event, handle, &sample_data);
        }
  
        return 0;
@@@ -3563,6 -3407,28 +3563,6 @@@ void perf_output_end(struct perf_output
        rcu_read_unlock();
  }
  
 -static u32 perf_event_pid(struct perf_event *event, struct task_struct *p)
 -{
 -      /*
 -       * only top level events have the pid namespace they were created in
 -       */
 -      if (event->parent)
 -              event = event->parent;
 -
 -      return task_tgid_nr_ns(p, event->ns);
 -}
 -
 -static u32 perf_event_tid(struct perf_event *event, struct task_struct *p)
 -{
 -      /*
 -       * only top level events have the pid namespace they were created in
 -       */
 -      if (event->parent)
 -              event = event->parent;
 -
 -      return task_pid_nr_ns(p, event->ns);
 -}
 -
  static void perf_output_read_one(struct perf_output_handle *handle,
                                 struct perf_event *event,
                                 u64 enabled, u64 running)
@@@ -3737,16 -3603,61 +3737,16 @@@ void perf_prepare_sample(struct perf_ev
  {
        u64 sample_type = event->attr.sample_type;
  
 -      data->type = sample_type;
 -
        header->type = PERF_RECORD_SAMPLE;
 -      header->size = sizeof(*header);
 +      header->size = sizeof(*header) + event->header_size;
  
        header->misc = 0;
        header->misc |= perf_misc_flags(regs);
  
 -      if (sample_type & PERF_SAMPLE_IP) {
 -              data->ip = perf_instruction_pointer(regs);
 -
 -              header->size += sizeof(data->ip);
 -      }
 -
 -      if (sample_type & PERF_SAMPLE_TID) {
 -              /* namespace issues */
 -              data->tid_entry.pid = perf_event_pid(event, current);
 -              data->tid_entry.tid = perf_event_tid(event, current);
 -
 -              header->size += sizeof(data->tid_entry);
 -      }
 -
 -      if (sample_type & PERF_SAMPLE_TIME) {
 -              data->time = perf_clock();
 -
 -              header->size += sizeof(data->time);
 -      }
 -
 -      if (sample_type & PERF_SAMPLE_ADDR)
 -              header->size += sizeof(data->addr);
 -
 -      if (sample_type & PERF_SAMPLE_ID) {
 -              data->id = primary_event_id(event);
 -
 -              header->size += sizeof(data->id);
 -      }
 -
 -      if (sample_type & PERF_SAMPLE_STREAM_ID) {
 -              data->stream_id = event->id;
 -
 -              header->size += sizeof(data->stream_id);
 -      }
 +      __perf_event_header__init_id(header, data, event);
  
 -      if (sample_type & PERF_SAMPLE_CPU) {
 -              data->cpu_entry.cpu             = raw_smp_processor_id();
 -              data->cpu_entry.reserved        = 0;
 -
 -              header->size += sizeof(data->cpu_entry);
 -      }
 -
 -      if (sample_type & PERF_SAMPLE_PERIOD)
 -              header->size += sizeof(data->period);
 -
 -      if (sample_type & PERF_SAMPLE_READ)
 -              header->size += perf_event_read_size(event);
 +      if (sample_type & PERF_SAMPLE_IP)
 +              data->ip = perf_instruction_pointer(regs);
  
        if (sample_type & PERF_SAMPLE_CALLCHAIN) {
                int size = 1;
@@@ -3811,26 -3722,23 +3811,26 @@@ perf_event_read_event(struct perf_even
                        struct task_struct *task)
  {
        struct perf_output_handle handle;
 +      struct perf_sample_data sample;
        struct perf_read_event read_event = {
                .header = {
                        .type = PERF_RECORD_READ,
                        .misc = 0,
 -                      .size = sizeof(read_event) + perf_event_read_size(event),
 +                      .size = sizeof(read_event) + event->read_size,
                },
                .pid = perf_event_pid(event, task),
                .tid = perf_event_tid(event, task),
        };
        int ret;
  
 +      perf_event_header__init_id(&read_event.header, &sample, event);
        ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0);
        if (ret)
                return;
  
        perf_output_put(&handle, read_event);
        perf_output_read(&handle, event);
 +      perf_event__output_id_sample(event, &handle, &sample);
  
        perf_output_end(&handle);
  }
@@@ -3860,16 -3768,14 +3860,16 @@@ static void perf_event_task_output(stru
                                     struct perf_task_event *task_event)
  {
        struct perf_output_handle handle;
 +      struct perf_sample_data sample;
        struct task_struct *task = task_event->task;
 -      int size, ret;
 +      int ret, size = task_event->event_id.header.size;
  
 -      size  = task_event->event_id.header.size;
 -      ret = perf_output_begin(&handle, event, size, 0, 0);
 +      perf_event_header__init_id(&task_event->event_id.header, &sample, event);
  
 +      ret = perf_output_begin(&handle, event,
 +                              task_event->event_id.header.size, 0, 0);
        if (ret)
 -              return;
 +              goto out;
  
        task_event->event_id.pid = perf_event_pid(event, task);
        task_event->event_id.ppid = perf_event_pid(event, current);
  
        perf_output_put(&handle, task_event->event_id);
  
 +      perf_event__output_id_sample(event, &handle, &sample);
 +
        perf_output_end(&handle);
 +out:
 +      task_event->event_id.header.size = size;
  }
  
  static int perf_event_task_match(struct perf_event *event)
@@@ -3922,6 -3824,8 +3922,8 @@@ static void perf_event_task_event(struc
        rcu_read_lock();
        list_for_each_entry_rcu(pmu, &pmus, entry) {
                cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+               if (cpuctx->active_pmu != pmu)
+                       goto next;
                perf_event_task_ctx(&cpuctx->ctx, task_event);
  
                ctx = task_event->task_ctx;
@@@ -3996,16 -3900,11 +3998,16 @@@ static void perf_event_comm_output(stru
                                     struct perf_comm_event *comm_event)
  {
        struct perf_output_handle handle;
 +      struct perf_sample_data sample;
        int size = comm_event->event_id.header.size;
 -      int ret = perf_output_begin(&handle, event, size, 0, 0);
 +      int ret;
 +
 +      perf_event_header__init_id(&comm_event->event_id.header, &sample, event);
 +      ret = perf_output_begin(&handle, event,
 +                              comm_event->event_id.header.size, 0, 0);
  
        if (ret)
 -              return;
 +              goto out;
  
        comm_event->event_id.pid = perf_event_pid(event, comm_event->task);
        comm_event->event_id.tid = perf_event_tid(event, comm_event->task);
        perf_output_put(&handle, comm_event->event_id);
        perf_output_copy(&handle, comm_event->comm,
                                   comm_event->comm_size);
 +
 +      perf_event__output_id_sample(event, &handle, &sample);
 +
        perf_output_end(&handle);
 +out:
 +      comm_event->event_id.header.size = size;
  }
  
  static int perf_event_comm_match(struct perf_event *event)
@@@ -4063,9 -3957,12 +4065,11 @@@ static void perf_event_comm_event(struc
        comm_event->comm_size = size;
  
        comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
 -
        rcu_read_lock();
        list_for_each_entry_rcu(pmu, &pmus, entry) {
                cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+               if (cpuctx->active_pmu != pmu)
+                       goto next;
                perf_event_comm_ctx(&cpuctx->ctx, comm_event);
  
                ctxn = pmu->task_ctx_nr;
@@@ -4141,15 -4038,11 +4145,15 @@@ static void perf_event_mmap_output(stru
                                     struct perf_mmap_event *mmap_event)
  {
        struct perf_output_handle handle;
 +      struct perf_sample_data sample;
        int size = mmap_event->event_id.header.size;
 -      int ret = perf_output_begin(&handle, event, size, 0, 0);
 +      int ret;
  
 +      perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
 +      ret = perf_output_begin(&handle, event,
 +                              mmap_event->event_id.header.size, 0, 0);
        if (ret)
 -              return;
 +              goto out;
  
        mmap_event->event_id.pid = perf_event_pid(event, current);
        mmap_event->event_id.tid = perf_event_tid(event, current);
        perf_output_put(&handle, mmap_event->event_id);
        perf_output_copy(&handle, mmap_event->file_name,
                                   mmap_event->file_size);
 +
 +      perf_event__output_id_sample(event, &handle, &sample);
 +
        perf_output_end(&handle);
 +out:
 +      mmap_event->event_id.header.size = size;
  }
  
  static int perf_event_mmap_match(struct perf_event *event,
@@@ -4260,6 -4148,8 +4264,8 @@@ got_name
        rcu_read_lock();
        list_for_each_entry_rcu(pmu, &pmus, entry) {
                cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+               if (cpuctx->active_pmu != pmu)
+                       goto next;
                perf_event_mmap_ctx(&cpuctx->ctx, mmap_event,
                                        vma->vm_flags & VM_EXEC);
  
@@@ -4315,7 -4205,6 +4321,7 @@@ void perf_event_mmap(struct vm_area_str
  static void perf_log_throttle(struct perf_event *event, int enable)
  {
        struct perf_output_handle handle;
 +      struct perf_sample_data sample;
        int ret;
  
        struct {
        if (enable)
                throttle_event.header.type = PERF_RECORD_UNTHROTTLE;
  
 -      ret = perf_output_begin(&handle, event, sizeof(throttle_event), 1, 0);
 +      perf_event_header__init_id(&throttle_event.header, &sample, event);
 +
 +      ret = perf_output_begin(&handle, event,
 +                              throttle_event.header.size, 1, 0);
        if (ret)
                return;
  
        perf_output_put(&handle, throttle_event);
 +      perf_event__output_id_sample(event, &handle, &sample);
        perf_output_end(&handle);
  }
  
@@@ -4361,13 -4246,6 +4367,13 @@@ static int __perf_event_overflow(struc
        struct hw_perf_event *hwc = &event->hw;
        int ret = 0;
  
 +      /*
 +       * Non-sampling counters might still use the PMI to fold short
 +       * hardware counters, ignore those.
 +       */
 +      if (unlikely(!is_sampling_event(event)))
 +              return 0;
 +
        if (!throttle) {
                hwc->interrupts++;
        } else {
@@@ -4513,7 -4391,7 +4519,7 @@@ static void perf_swevent_event(struct p
        if (!regs)
                return;
  
 -      if (!hwc->sample_period)
 +      if (!is_sampling_event(event))
                return;
  
        if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq)
@@@ -4676,7 -4554,7 +4682,7 @@@ static int perf_swevent_add(struct perf
        struct hw_perf_event *hwc = &event->hw;
        struct hlist_head *head;
  
 -      if (hwc->sample_period) {
 +      if (is_sampling_event(event)) {
                hwc->last_period = hwc->sample_period;
                perf_swevent_set_period(event);
        }
@@@ -4841,7 -4719,7 +4847,7 @@@ static int perf_swevent_init(struct per
                break;
        }
  
-       if (event_id > PERF_COUNT_SW_MAX)
+       if (event_id >= PERF_COUNT_SW_MAX)
                return -ENOENT;
  
        if (!event->parent) {
@@@ -4933,6 -4811,15 +4939,6 @@@ static int perf_tp_event_init(struct pe
        if (event->attr.type != PERF_TYPE_TRACEPOINT)
                return -ENOENT;
  
 -      /*
 -       * Raw tracepoint data is a severe data leak, only allow root to
 -       * have these.
 -       */
 -      if ((event->attr.sample_type & PERF_SAMPLE_RAW) &&
 -                      perf_paranoid_tracepoint_raw() &&
 -                      !capable(CAP_SYS_ADMIN))
 -              return -EPERM;
 -
        err = perf_trace_init(event);
        if (err)
                return err;
@@@ -5045,33 -4932,31 +5051,33 @@@ static enum hrtimer_restart perf_sweven
  static void perf_swevent_start_hrtimer(struct perf_event *event)
  {
        struct hw_perf_event *hwc = &event->hw;
 +      s64 period;
 +
 +      if (!is_sampling_event(event))
 +              return;
  
        hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        hwc->hrtimer.function = perf_swevent_hrtimer;
 -      if (hwc->sample_period) {
 -              s64 period = local64_read(&hwc->period_left);
  
 -              if (period) {
 -                      if (period < 0)
 -                              period = 10000;
 +      period = local64_read(&hwc->period_left);
 +      if (period) {
 +              if (period < 0)
 +                      period = 10000;
  
 -                      local64_set(&hwc->period_left, 0);
 -              } else {
 -                      period = max_t(u64, 10000, hwc->sample_period);
 -              }
 -              __hrtimer_start_range_ns(&hwc->hrtimer,
 +              local64_set(&hwc->period_left, 0);
 +      } else {
 +              period = max_t(u64, 10000, hwc->sample_period);
 +      }
 +      __hrtimer_start_range_ns(&hwc->hrtimer,
                                ns_to_ktime(period), 0,
                                HRTIMER_MODE_REL_PINNED, 0);
 -      }
  }
  
  static void perf_swevent_cancel_hrtimer(struct perf_event *event)
  {
        struct hw_perf_event *hwc = &event->hw;
  
 -      if (hwc->sample_period) {
 +      if (is_sampling_event(event)) {
                ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer);
                local64_set(&hwc->period_left, ktime_to_ns(remaining));
  
@@@ -5266,20 -5151,36 +5272,36 @@@ static void *find_pmu_context(int ctxn
        return NULL;
  }
  
- static void free_pmu_context(void * __percpu cpu_context)
+ static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
  {
-       struct pmu *pmu;
+       int cpu;
+       for_each_possible_cpu(cpu) {
+               struct perf_cpu_context *cpuctx;
+               cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+               if (cpuctx->active_pmu == old_pmu)
+                       cpuctx->active_pmu = pmu;
+       }
+ }
+ static void free_pmu_context(struct pmu *pmu)
+ {
+       struct pmu *i;
  
        mutex_lock(&pmus_lock);
        /*
         * Like a real lame refcount.
         */
-       list_for_each_entry(pmu, &pmus, entry) {
-               if (pmu->pmu_cpu_context == cpu_context)
+       list_for_each_entry(i, &pmus, entry) {
+               if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
+                       update_pmu_context(i, pmu);
                        goto out;
+               }
        }
  
-       free_percpu(cpu_context);
+       free_percpu(pmu->pmu_cpu_context);
  out:
        mutex_unlock(&pmus_lock);
  }
@@@ -5311,6 -5212,7 +5333,7 @@@ int perf_pmu_register(struct pmu *pmu
                cpuctx->ctx.pmu = pmu;
                cpuctx->jiffies_interval = 1;
                INIT_LIST_HEAD(&cpuctx->rotation_list);
+               cpuctx->active_pmu = pmu;
        }
  
  got_cpu_context:
@@@ -5362,7 -5264,7 +5385,7 @@@ void perf_pmu_unregister(struct pmu *pm
        synchronize_rcu();
  
        free_percpu(pmu->pmu_disable_count);
-       free_pmu_context(pmu->pmu_cpu_context);
+       free_pmu_context(pmu);
  }
  
  struct pmu *perf_init_event(struct perf_event *event)
@@@ -5835,12 -5737,6 +5858,12 @@@ SYSCALL_DEFINE5(perf_event_open
        list_add_tail(&event->owner_entry, &current->perf_event_list);
        mutex_unlock(&current->perf_event_mutex);
  
 +      /*
 +       * Precalculate sample_data sizes
 +       */
 +      perf_event__header_size(event);
 +      perf_event__id_header_size(event);
 +
        /*
         * Drop the reference on the group_event after placing the
         * new event on the sibling_list. This ensures destruction
@@@ -6193,12 -6089,6 +6216,12 @@@ inherit_event(struct perf_event *parent
        child_event->ctx = child_ctx;
        child_event->overflow_handler = parent_event->overflow_handler;
  
 +      /*
 +       * Precalculate sample_data sizes
 +       */
 +      perf_event__header_size(child_event);
 +      perf_event__id_header_size(child_event);
 +
        /*
         * Link it up in the child's context:
         */
@@@ -6430,7 -6320,7 +6453,7 @@@ static void __cpuinit perf_event_init_c
        mutex_unlock(&swhash->hlist_mutex);
  }
  
 -#ifdef CONFIG_HOTPLUG_CPU
 +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC
  static void perf_pmu_rotate_stop(struct pmu *pmu)
  {
        struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
@@@ -6484,26 -6374,6 +6507,26 @@@ static void perf_event_exit_cpu(int cpu
  static inline void perf_event_exit_cpu(int cpu) { }
  #endif
  
 +static int
 +perf_reboot(struct notifier_block *notifier, unsigned long val, void *v)
 +{
 +      int cpu;
 +
 +      for_each_online_cpu(cpu)
 +              perf_event_exit_cpu(cpu);
 +
 +      return NOTIFY_OK;
 +}
 +
 +/*
 + * Run the perf reboot notifier at the very last possible moment so that
 + * the generic watchdog code runs as long as possible.
 + */
 +static struct notifier_block perf_reboot_notifier = {
 +      .notifier_call = perf_reboot,
 +      .priority = INT_MIN,
 +};
 +
  static int __cpuinit
  perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
  {
@@@ -6539,7 -6409,6 +6562,7 @@@ void __init perf_event_init(void
        perf_pmu_register(&perf_task_clock);
        perf_tp_register();
        perf_cpu_notifier(perf_cpu_notify);
 +      register_reboot_notifier(&perf_reboot_notifier);
  
        ret = init_hw_breakpoint();
        WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
index 699dd2149c4b5fffd1a9ffa2f863e4be661532a6,564491fa18b27838dd79125954bc744f51f7fe2c..e9be6ae87a278dd5230d04eeb5c1fe29771016fb
@@@ -36,7 -36,6 +36,7 @@@ static int                    *fd[MAX_NR_CPUS][MAX_COUNT
  
  static u64                    user_interval                   = ULLONG_MAX;
  static u64                    default_interval                =      0;
 +static u64                    sample_type;
  
  static int                    nr_cpus                         =      0;
  static unsigned int           page_size;
@@@ -49,7 -48,6 +49,7 @@@ static const char             *output_name                    = "pe
  static int                    group                           =      0;
  static int                    realtime_prio                   =      0;
  static bool                   raw_samples                     =  false;
 +static bool                   sample_id_all_avail             =   true;
  static bool                   system_wide                     =  false;
  static pid_t                  target_pid                      =     -1;
  static pid_t                  target_tid                      =     -1;
@@@ -62,9 -60,7 +62,9 @@@ static bool                   call_graph                      =  false
  static bool                   inherit_stat                    =  false;
  static bool                   no_samples                      =  false;
  static bool                   sample_address                  =  false;
 +static bool                   sample_time                     =  false;
  static bool                   no_buildid                      =  false;
 +static bool                   no_buildid_cache                =  false;
  
  static long                   samples                         =      0;
  static u64                    bytes_written                   =      0;
@@@ -132,7 -128,6 +132,7 @@@ static void write_output(void *buf, siz
  }
  
  static int process_synthesized_event(event_t *event,
 +                                   struct sample_data *sample __used,
                                     struct perf_session *self __used)
  {
        write_output(event, event->header.size);
@@@ -202,7 -197,7 +202,7 @@@ static void sig_atexit(void
        if (child_pid > 0)
                kill(child_pid, SIGTERM);
  
-       if (signr == -1)
+       if (signr == -1 || signr == SIGUSR1)
                return;
  
        signal(signr, SIG_DFL);
@@@ -285,18 -280,12 +285,18 @@@ static void create_counter(int counter
        if (system_wide)
                attr->sample_type       |= PERF_SAMPLE_CPU;
  
 +      if (sample_time)
 +              attr->sample_type       |= PERF_SAMPLE_TIME;
 +
        if (raw_samples) {
                attr->sample_type       |= PERF_SAMPLE_TIME;
                attr->sample_type       |= PERF_SAMPLE_RAW;
                attr->sample_type       |= PERF_SAMPLE_CPU;
        }
  
 +      if (!sample_type)
 +              sample_type = attr->sample_type;
 +
        attr->mmap              = track;
        attr->comm              = track;
        attr->inherit           = !no_inherit;
                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 < thread_num; thread_index++) {
  try_again:
                        else if (err ==  ENODEV && cpu_list) {
                                die("No such device - did you specify"
                                        " an out-of-range profile CPU?\n");
 +                      } else if (err == EINVAL && sample_id_all_avail) {
 +                              /*
 +                               * Old kernel, no attr->sample_id_type_all field
 +                               */
 +                              sample_id_all_avail = false;
 +                              goto retry_sample_id;
                        }
  
                        /*
                                goto try_again;
                        }
                        printf("\n");
 -                      error("perfcounter syscall returned with %d (%s)\n",
 +                      error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
                                        fd[nr_cpu][counter][thread_index], strerror(err));
  
  #if defined(__i386__) || defined(__x86_64__)
@@@ -456,8 -437,7 +456,8 @@@ static void atexit_header(void
        if (!pipe_output) {
                session->header.data_size += bytes_written;
  
 -              process_buildids();
 +              if (!no_buildid)
 +                      process_buildids();
                perf_header__write(&session->header, output, true);
                perf_session__delete(session);
                symbol__exit();
@@@ -535,6 -515,7 +535,7 @@@ static int __cmd_record(int argc, cons
        atexit(sig_atexit);
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
+       signal(SIGUSR1, sig_handler);
  
        if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
                perror("failed to create pipes");
                return -1;
        }
  
 +      if (!no_buildid)
 +              perf_header__set_feat(&session->header, HEADER_BUILD_ID);
 +
        if (!file_new) {
                err = perf_header__read(session, output);
                if (err < 0)
                        execvp(argv[0], (char **)argv);
  
                        perror(argv[0]);
+                       kill(getppid(), SIGUSR1);
                        exit(-1);
                }
  
                        open_counters(cpumap[i]);
        }
  
 +      perf_session__set_sample_type(session, sample_type);
 +
        if (pipe_output) {
                err = perf_header__write_pipe(output);
                if (err < 0)
  
        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,
                }
        }
  
-       if (quiet)
+       if (quiet || signr == SIGUSR1)
                return 0;
  
        fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
@@@ -856,13 -831,10 +858,13 @@@ const struct option record_options[] = 
                    "per thread counts"),
        OPT_BOOLEAN('d', "data", &sample_address,
                    "Sample addresses"),
 +      OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
        OPT_BOOLEAN('n', "no-samples", &no_samples,
                    "don't sample"),
 -      OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid,
 +      OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
                    "do not update the buildid cache"),
 +      OPT_BOOLEAN('B', "no-buildid", &no_buildid,
 +                  "do not collect buildids in perf.data"),
        OPT_END()
  };
  
@@@ -887,8 -859,7 +889,8 @@@ int cmd_record(int argc, const char **a
        }
  
        symbol__init();
 -      if (no_buildid)
 +
 +      if (no_buildid_cache || no_buildid)
                disable_buildid_cache();
  
        if (!nr_counters) {
diff --combined tools/perf/util/header.c
index 76e949a59ea497529ad1f6ab1d5e8d4db486c6c4,64a85bafde63a1c6f05451a32b31eec521c799d9..16a16021eaa68bc1e586acd2c730fd54994cfc12
@@@ -152,11 -152,6 +152,11 @@@ void perf_header__set_feat(struct perf_
        set_bit(feat, self->adds_features);
  }
  
 +void perf_header__clear_feat(struct perf_header *self, int feat)
 +{
 +      clear_bit(feat, self->adds_features);
 +}
 +
  bool perf_header__has_feat(const struct perf_header *self, int feat)
  {
        return test_bit(feat, self->adds_features);
@@@ -436,10 -431,8 +436,10 @@@ static int perf_header__adds_write(stru
        int idx = 0, err;
  
        session = container_of(self, struct perf_session, header);
 -      if (perf_session__read_build_ids(session, true))
 -              perf_header__set_feat(self, HEADER_BUILD_ID);
 +
 +      if (perf_header__has_feat(self, HEADER_BUILD_ID &&
 +          !perf_session__read_build_ids(session, true)))
 +              perf_header__clear_feat(self, HEADER_BUILD_ID);
  
        nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
        if (!nr_sections)
@@@ -946,24 -939,6 +946,24 @@@ u64 perf_header__sample_type(struct per
        return type;
  }
  
 +bool perf_header__sample_id_all(const struct perf_header *header)
 +{
 +      bool value = false, first = true;
 +      int i;
 +
 +      for (i = 0; i < header->attrs; i++) {
 +              struct perf_header_attr *attr = header->attr[i];
 +
 +              if (first) {
 +                      value = attr->attr.sample_id_all;
 +                      first = false;
 +              } else if (value != attr->attr.sample_id_all)
 +                      die("non matching sample_id_all");
 +      }
 +
 +      return value;
 +}
 +
  struct perf_event_attr *
  perf_header__find_attr(u64 id, struct perf_header *header)
  {
  
        /*
         * We set id to -1 if the data file doesn't contain sample
-        * ids. Check for this and avoid walking through the entire
-        * list of ids which may be large.
+        * ids. This can happen when the data file contains one type
+        * of event and in that case, the header can still store the
+        * event attribute information. Check for this and avoid
+        * walking through the entire list of ids which may be large.
         */
-       if (id == -1ULL)
+       if (id == -1ULL) {
+               if (header->attrs > 0)
+                       return &header->attr[0]->attr;
                return NULL;
+       }
  
        for (i = 0; i < header->attrs; i++) {
                struct perf_header_attr *attr = header->attr[i];
@@@ -1005,23 -985,21 +1010,23 @@@ int event__synthesize_attr(struct perf_
  
        ev = malloc(size);
  
 +      if (ev == NULL)
 +              return -ENOMEM;
 +
        ev->attr.attr = *attr;
        memcpy(ev->attr.id, id, ids * sizeof(u64));
  
        ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
        ev->attr.header.size = size;
  
 -      err = process(ev, session);
 +      err = process(ev, NULL, session);
  
        free(ev);
  
        return err;
  }
  
 -int event__synthesize_attrs(struct perf_header *self,
 -                          event__handler_t process,
 +int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
                            struct perf_session *session)
  {
        struct perf_header_attr *attr;
@@@ -1091,7 -1069,7 +1096,7 @@@ int event__synthesize_event_type(u64 ev
        ev.event_type.header.size = sizeof(ev.event_type) -
                (sizeof(ev.event_type.event_type.name) - size);
  
 -      err = process(&ev, session);
 +      err = process(&ev, NULL, session);
  
        return err;
  }
@@@ -1146,7 -1124,7 +1151,7 @@@ int event__synthesize_tracing_data(int 
        ev.tracing_data.header.size = sizeof(ev.tracing_data);
        ev.tracing_data.size = aligned_size;
  
 -      process(&ev, session);
 +      process(&ev, NULL, session);
  
        err = read_tracing_data(fd, pattrs, nb_events);
        write_padded(fd, NULL, 0, padding);
@@@ -1206,7 -1184,7 +1211,7 @@@ int event__synthesize_build_id(struct d
        ev.build_id.header.size = sizeof(ev.build_id) + len;
        memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
  
 -      err = process(&ev, session);
 +      err = process(&ev, NULL, session);
  
        return err;
  }
diff --combined tools/perf/util/symbol.c
index f40c076aeb7b0e705e53ac139d27ce5fa4379d8c,d628c8d1cf5ec11111ab3b750da0d14f6d8fff7f..ceefa6568def788d4495b815a953b3b2d8dd1fe9
@@@ -121,7 -121,7 +121,7 @@@ static void __map_groups__fixup_end(str
         * We still haven't the actual symbols, so guess the
         * last map final address.
         */
 -      curr->end = ~0UL;
 +      curr->end = ~0ULL;
  }
  
  static void map_groups__fixup_end(struct map_groups *self)
@@@ -532,7 -532,7 +532,7 @@@ static int dso__split_kallsyms(struct d
        struct machine *machine = kmaps->machine;
        struct map *curr_map = map;
        struct symbol *pos;
-       int count = 0;
+       int count = 0, moved = 0;       
        struct rb_root *root = &self->symbols[map->type];
        struct rb_node *next = rb_first(root);
        int kernel_range = 0;
                        char dso_name[PATH_MAX];
                        struct dso *dso;
  
+                       if (count == 0) {
+                               curr_map = map;
+                               goto filter_symbol;
+                       }
                        if (self->kernel == DSO_TYPE_GUEST_KERNEL)
                                snprintf(dso_name, sizeof(dso_name),
                                        "[guest.kernel].%d",
                        map_groups__insert(kmaps, curr_map);
                        ++kernel_range;
                }
+ filter_symbol:
                if (filter && filter(curr_map, pos)) {
  discard_symbol:               rb_erase(&pos->rb_node, root);
                        symbol__delete(pos);
                        if (curr_map != map) {
                                rb_erase(&pos->rb_node, root);
                                symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
-                       }
-                       count++;
+                               ++moved;
+                       } else
+                               ++count;
                }
        }
  
                dso__set_loaded(curr_map->dso, curr_map->type);
        }
  
-       return count;
+       return count + moved;
  }
  
  int dso__load_kallsyms(struct dso *self, const char *filename,
@@@ -1830,8 -1836,8 +1836,8 @@@ static int dso__load_kernel_sym(struct 
        const char *kallsyms_filename = NULL;
        char *kallsyms_allocated_filename = NULL;
        /*
 -       * Step 1: if the user specified a vmlinux filename, use it and only
 -       * it, reporting errors to the user if it cannot be used.
 +       * Step 1: if the user specified a kallsyms or vmlinux filename, use
 +       * it and only it, reporting errors to the user if it cannot be used.
         *
         * For instance, try to analyse an ARM perf.data file _without_ a
         * build-id, or if the user specifies the wrong path to the right
         * validation in dso__load_vmlinux and will bail out if they don't
         * match.
         */
 +      if (symbol_conf.kallsyms_name != NULL) {
 +              kallsyms_filename = symbol_conf.kallsyms_name;
 +              goto do_kallsyms;
 +      }
 +
        if (symbol_conf.vmlinux_name != NULL) {
                err = dso__load_vmlinux(self, map,
                                        symbol_conf.vmlinux_name, filter);
@@@ -2130,14 -2131,55 +2136,55 @@@ static struct dso *machine__create_kern
        return kernel;
  }
  
+ struct process_args {
+       u64 start;
+ };
+ static int symbol__in_kernel(void *arg, const char *name,
+                            char type __used, u64 start)
+ {
+       struct process_args *args = arg;
+       if (strchr(name, '['))
+               return 0;
+       args->start = start;
+       return 1;
+ }
+ /* Figure out the start address of kernel map from /proc/kallsyms */
+ static u64 machine__get_kernel_start_addr(struct machine *machine)
+ {
+       const char *filename;
+       char path[PATH_MAX];
+       struct process_args args;
+       if (machine__is_host(machine)) {
+               filename = "/proc/kallsyms";
+       } else {
+               if (machine__is_default_guest(machine))
+                       filename = (char *)symbol_conf.default_guest_kallsyms;
+               else {
+                       sprintf(path, "%s/proc/kallsyms", machine->root_dir);
+                       filename = path;
+               }
+       }
+       if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
+               return 0;
+       return args.start;
+ }
  int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
  {
        enum map_type type;
+       u64 start = machine__get_kernel_start_addr(self);
  
        for (type = 0; type < MAP__NR_TYPES; ++type) {
                struct kmap *kmap;
  
-               self->vmlinux_maps[type] = map__new2(0, kernel, type);
+               self->vmlinux_maps[type] = map__new2(start, kernel, type);
                if (self->vmlinux_maps[type] == NULL)
                        return -1;
  
This page took 0.319 seconds and 5 git commands to generate.