FROMGIT: perf/aux: Allocate non-contiguous AUX pages by default
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. Bug: 393467632 (cherry picked from commit 18049c8cff9cc89daadc4df6975f7d9069638926 git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core) Change-Id: Iaff554201726bf271c7625a6df59fb35c6cfbc5d 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
This commit is contained in:
@@ -1793,6 +1793,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;
|
||||
pt_pmu.pmu.attr_groups = pt_attr_groups;
|
||||
|
@@ -291,6 +291,7 @@ struct perf_event_pmu_context;
|
||||
#define PERF_PMU_CAP_NO_EXCLUDE 0x0040
|
||||
#define PERF_PMU_CAP_AUX_OUTPUT 0x0080
|
||||
#define PERF_PMU_CAP_EXTENDED_HW_TYPE 0x0100
|
||||
#define PERF_PMU_CAP_AUX_PREFER_LARGE 0x0400
|
||||
|
||||
struct perf_output_handle;
|
||||
|
||||
|
@@ -673,15 +673,23 @@ 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;
|
||||
|
||||
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,
|
||||
@@ -689,16 +697,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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user