]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf/aux: Allocate non-contiguous AUX pages by default
authorYabin Cui <yabinc@google.com>
Thu, 8 May 2025 23:26:42 +0000 (16:26 -0700)
committerIngo Molnar <mingo@kernel.org>
Thu, 15 May 2025 16:07:19 +0000 (18:07 +0200)
perf always allocates contiguous AUX pages based on aux_watermark.
However, this contiguous allocation doesn't benefit all PMUs. For
instance, ARM SPE and TRBE operate with virtual pages, and Coresight
ETR allocates a separate buffer. For these PMUs, allocating contiguous
AUX pages unnecessarily exacerbates memory fragmentation. This
fragmentation can prevent their use on long-running devices.

This patch modifies the perf driver to be memory-friendly by default,
by allocating non-contiguous AUX pages. For PMUs requiring contiguous
pages (Intel BTS and some Intel PT), the existing
PERF_PMU_CAP_AUX_NO_SG capability can be used. For PMUs that don't
require but can benefit from contiguous pages (some Intel PT), a new
capability, PERF_PMU_CAP_AUX_PREFER_LARGE, is added to maintain their
existing behavior.

Signed-off-by: Yabin Cui <yabinc@google.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20250508232642.148767-1-yabinc@google.com
arch/x86/events/intel/pt.c
include/linux/perf_event.h
kernel/events/ring_buffer.c

index fa37565f6418632c18cd21eb3f7428e86ee72f15..25ead919fc489483aace49f82373ff2720ae0b38 100644 (file)
@@ -1863,6 +1863,8 @@ static __init int pt_init(void)
 
        if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries))
                pt_pmu.pmu.capabilities = PERF_PMU_CAP_AUX_NO_SG;
+       else
+               pt_pmu.pmu.capabilities = PERF_PMU_CAP_AUX_PREFER_LARGE;
 
        pt_pmu.pmu.capabilities         |= PERF_PMU_CAP_EXCLUSIVE |
                                           PERF_PMU_CAP_ITRACE |
index 947ad12dfdbe4cd920b5c9fd5d267a53939a8998..a96c00e2ceca72480db4185a2afb9d54e92998d7 100644 (file)
@@ -303,6 +303,7 @@ struct perf_event_pmu_context;
 #define PERF_PMU_CAP_AUX_OUTPUT                        0x0080
 #define PERF_PMU_CAP_EXTENDED_HW_TYPE          0x0100
 #define PERF_PMU_CAP_AUX_PAUSE                 0x0200
+#define PERF_PMU_CAP_AUX_PREFER_LARGE          0x0400
 
 /**
  * pmu::scope
index 5130b119d0ae04f1ba73b30d54a4342c5dbc9c98..d2aef87c7e9f8e7c48fd2b6d26f3e6dac7666e9b 100644 (file)
@@ -679,7 +679,15 @@ int rb_alloc_aux(struct perf_buffer *rb, struct perf_event *event,
 {
        bool overwrite = !(flags & RING_BUFFER_WRITABLE);
        int node = (event->cpu == -1) ? -1 : cpu_to_node(event->cpu);
-       int ret = -ENOMEM, max_order;
+       bool use_contiguous_pages = event->pmu->capabilities & (
+               PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE);
+       /*
+        * Initialize max_order to 0 for page allocation. This allocates single
+        * pages to minimize memory fragmentation. This is overridden if the
+        * PMU needs or prefers contiguous pages (use_contiguous_pages = true).
+        */
+       int max_order = 0;
+       int ret = -ENOMEM;
 
        if (!has_aux(event))
                return -EOPNOTSUPP;
@@ -689,8 +697,8 @@ int rb_alloc_aux(struct perf_buffer *rb, struct perf_event *event,
 
        if (!overwrite) {
                /*
-                * Watermark defaults to half the buffer, and so does the
-                * max_order, to aid PMU drivers in double buffering.
+                * Watermark defaults to half the buffer, to aid PMU drivers
+                * in double buffering.
                 */
                if (!watermark)
                        watermark = min_t(unsigned long,
@@ -698,16 +706,19 @@ int rb_alloc_aux(struct perf_buffer *rb, struct perf_event *event,
                                          (unsigned long)nr_pages << (PAGE_SHIFT - 1));
 
                /*
-                * Use aux_watermark as the basis for chunking to
-                * help PMU drivers honor the watermark.
+                * If using contiguous pages, use aux_watermark as the basis
+                * for chunking to help PMU drivers honor the watermark.
                 */
-               max_order = get_order(watermark);
+               if (use_contiguous_pages)
+                       max_order = get_order(watermark);
        } else {
                /*
-                * We need to start with the max_order that fits in nr_pages,
-                * not the other way around, hence ilog2() and not get_order.
+                * If using contiguous pages, we need to start with the
+                * max_order that fits in nr_pages, not the other way around,
+                * hence ilog2() and not get_order.
                 */
-               max_order = ilog2(nr_pages);
+               if (use_contiguous_pages)
+                       max_order = ilog2(nr_pages);
                watermark = 0;
        }