Merge tag 'perf-core-2022-08-01' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 1 Aug 2022 19:24:30 +0000 (12:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 1 Aug 2022 19:24:30 +0000 (12:24 -0700)
Pull perf events updates from Ingo Molnar:

 - Fix Intel Alder Lake PEBS memory access latency & data source
   profiling info bugs.

 - Use Intel large-PEBS hardware feature in more circumstances, to
   reduce PMI overhead & reduce sampling data.

 - Extend the lost-sample profiling output with the PERF_FORMAT_LOST ABI
   variant, which tells tooling the exact number of samples lost.

 - Add new IBS register bits definitions.

 - AMD uncore events: Add PerfMonV2 DF (Data Fabric) enhancements.

* tag 'perf-core-2022-08-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86/ibs: Add new IBS register bits into header
  perf/x86/intel: Fix PEBS data source encoding for ADL
  perf/x86/intel: Fix PEBS memory access info encoding for ADL
  perf/core: Add a new read format to get a number of lost samples
  perf/x86/amd/uncore: Add PerfMonV2 RDPMC assignments
  perf/x86/amd/uncore: Add PerfMonV2 DF event format
  perf/x86/amd/uncore: Detect available DF counters
  perf/x86/amd/uncore: Use attr_update for format attributes
  perf/x86/amd/uncore: Use dynamic events array
  x86/events/intel/ds: Enable large PEBS for PERF_SAMPLE_WEIGHT_TYPE

1  2 
kernel/events/core.c

diff --combined kernel/events/core.c
@@@ -1819,6 -1819,9 +1819,9 @@@ static void __perf_event_read_size(stru
        if (event->attr.read_format & PERF_FORMAT_ID)
                entry += sizeof(u64);
  
+       if (event->attr.read_format & PERF_FORMAT_LOST)
+               entry += sizeof(u64);
        if (event->attr.read_format & PERF_FORMAT_GROUP) {
                nr += nr_siblings;
                size += sizeof(u64);
@@@ -5260,11 -5263,15 +5263,15 @@@ static int __perf_read_group_add(struc
        values[n++] += perf_event_count(leader);
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&leader->lost_samples);
  
        for_each_sibling_event(sub, leader) {
                values[n++] += perf_event_count(sub);
                if (read_format & PERF_FORMAT_ID)
                        values[n++] = primary_event_id(sub);
+               if (read_format & PERF_FORMAT_LOST)
+                       values[n++] = atomic64_read(&sub->lost_samples);
        }
  
        raw_spin_unlock_irqrestore(&ctx->lock, flags);
@@@ -5321,7 -5328,7 +5328,7 @@@ static int perf_read_one(struct perf_ev
                                 u64 read_format, char __user *buf)
  {
        u64 enabled, running;
-       u64 values[4];
+       u64 values[5];
        int n = 0;
  
        values[n++] = __perf_event_read_value(event, &enabled, &running);
                values[n++] = running;
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(event);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&event->lost_samples);
  
        if (copy_to_user(buf, values, n * sizeof(u64)))
                return -EFAULT;
@@@ -6253,10 -6262,10 +6262,10 @@@ again
  
                if (!atomic_inc_not_zero(&event->rb->mmap_count)) {
                        /*
 -                       * Raced against perf_mmap_close() through
 -                       * perf_event_set_output(). Try again, hope for better
 -                       * luck.
 +                       * Raced against perf_mmap_close(); remove the
 +                       * event and try again.
                         */
 +                      ring_buffer_attach(event, NULL);
                        mutex_unlock(&event->mmap_mutex);
                        goto again;
                }
@@@ -6858,7 -6867,7 +6867,7 @@@ static void perf_output_read_one(struc
                                 u64 enabled, u64 running)
  {
        u64 read_format = event->attr.read_format;
-       u64 values[4];
+       u64 values[5];
        int n = 0;
  
        values[n++] = perf_event_count(event);
        }
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(event);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&event->lost_samples);
  
        __output_copy(handle, values, n * sizeof(u64));
  }
@@@ -6882,7 -6893,7 +6893,7 @@@ static void perf_output_read_group(stru
  {
        struct perf_event *leader = event->group_leader, *sub;
        u64 read_format = event->attr.read_format;
-       u64 values[5];
+       u64 values[6];
        int n = 0;
  
        values[n++] = 1 + leader->nr_siblings;
        values[n++] = perf_event_count(leader);
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&leader->lost_samples);
  
        __output_copy(handle, values, n * sizeof(u64));
  
                values[n++] = perf_event_count(sub);
                if (read_format & PERF_FORMAT_ID)
                        values[n++] = primary_event_id(sub);
+               if (read_format & PERF_FORMAT_LOST)
+                       values[n++] = atomic64_read(&sub->lost_samples);
  
                __output_copy(handle, values, n * sizeof(u64));
        }
@@@ -11825,25 -11840,14 +11840,25 @@@ err_size
        goto out;
  }
  
 +static void mutex_lock_double(struct mutex *a, struct mutex *b)
 +{
 +      if (b < a)
 +              swap(a, b);
 +
 +      mutex_lock(a);
 +      mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
 +}
 +
  static int
  perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
  {
        struct perf_buffer *rb = NULL;
        int ret = -EINVAL;
  
 -      if (!output_event)
 +      if (!output_event) {
 +              mutex_lock(&event->mmap_mutex);
                goto set;
 +      }
  
        /* don't allow circular references */
        if (event == output_event)
            event->pmu != output_event->pmu)
                goto out;
  
 +      /*
 +       * Hold both mmap_mutex to serialize against perf_mmap_close().  Since
 +       * output_event is already on rb->event_list, and the list iteration
 +       * restarts after every removal, it is guaranteed this new event is
 +       * observed *OR* if output_event is already removed, it's guaranteed we
 +       * observe !rb->mmap_count.
 +       */
 +      mutex_lock_double(&event->mmap_mutex, &output_event->mmap_mutex);
  set:
 -      mutex_lock(&event->mmap_mutex);
        /* Can't redirect output if we've got an active mmap() */
        if (atomic_read(&event->mmap_count))
                goto unlock;
                rb = ring_buffer_get(output_event);
                if (!rb)
                        goto unlock;
 +
 +              /* did we race against perf_mmap_close() */
 +              if (!atomic_read(&rb->mmap_count)) {
 +                      ring_buffer_put(rb);
 +                      goto unlock;
 +              }
        }
  
        ring_buffer_attach(event, rb);
        ret = 0;
  unlock:
        mutex_unlock(&event->mmap_mutex);
 +      if (output_event)
 +              mutex_unlock(&output_event->mmap_mutex);
  
  out:
        return ret;
  }
  
 -static void mutex_lock_double(struct mutex *a, struct mutex *b)
 -{
 -      if (b < a)
 -              swap(a, b);
 -
 -      mutex_lock(a);
 -      mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
 -}
 -
  static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
  {
        bool nmi_safe = false;