From nobody Thu Dec 18 14:48:43 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id F37E2155C97; Tue, 8 Apr 2025 17:16:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132572; cv=none; b=F8ALvJxBpG/WD/lA40cfUPBCC/XeL9hq4B8pXaXu8m6eOHZsMSCCrFYnHWwfwOcj+nTYy2RAvSfUobL3BXoR3vws2AxRTe2ahgk6nA4yLsIFShOfqlzsj3E7XHAfcFHXsRqfhKVkbIt9DI0BLwJ+w+J8cW4S6rJMuUgle/NEKtM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132572; c=relaxed/simple; bh=rHCubxc1msTzsG2HlJu6c1MUgiLHik11Q1jR8Fwi4jY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=C3gEmQXIBG2E2g9o33ATup4H+R6mSTGNiPQRHI5UJYi6Zaze9a4loExrqhmSNf89nBVbuZ0bvUcZ0KYTpck90ViIfLZj07j80IuCiTOqit3PoFgNbE+bmGQa4t//xMDAsyoVCMh7xxftMIy1IcWFvSX+Qk6NOZoVyhuJqbQKqWQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DA4BC1688; Tue, 8 Apr 2025 10:16:09 -0700 (PDT) Received: from e128066.cambridge.arm.com (e128066.cambridge.arm.com [10.1.26.81]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 71F743F59E; Tue, 8 Apr 2025 10:16:05 -0700 (PDT) From: mark.barnett@arm.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, irogers@google.com Cc: ben.gainey@arm.com, deepak.surti@arm.com, ak@linux.intel.com, will@kernel.org, james.clark@arm.com, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mark Barnett Subject: [PATCH v4 1/5] perf: Record sample last_period before updating Date: Tue, 8 Apr 2025 18:15:26 +0100 Message-Id: <20250408171530.140858-2-mark.barnett@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250408171530.140858-1-mark.barnett@arm.com> References: <20250408171530.140858-1-mark.barnett@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Mark Barnett This change alters the PowerPC and x86 driver implementations to record the last sample period before the event is updated for the next period. A common pattern in PMU driver implementations is to have a "*_event_set_period" function which takes care of updating the various period-related fields in a perf_event structure. In most cases, the drivers choose to call this function after initializing a sample data structure with perf_sample_data_init. The x86 and PowerPC drivers deviate from this, choosing to update the period before initializing the sample data. When using an event with an alternate sample period, this causes an incorrect period to be written to the sample data that gets reported to userspace. Link: https://lore.kernel.org/r/20240515193610.2350456-4-yabinc@google.com Signed-off-by: Mark Barnett Acked-by: Peter Zijlstra (Intel) --- arch/powerpc/perf/core-book3s.c | 3 ++- arch/powerpc/perf/core-fsl-emb.c | 3 ++- arch/x86/events/core.c | 4 +++- arch/x86/events/intel/core.c | 5 ++++- arch/x86/events/intel/knc.c | 4 +++- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3= s.c index b906d28f74fd..42ff4d167acc 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -2239,6 +2239,7 @@ static void record_and_restart(struct perf_event *eve= nt, unsigned long val, struct pt_regs *regs) { u64 period =3D event->hw.sample_period; + const u64 last_period =3D event->hw.last_period; s64 prev, delta, left; int record =3D 0; =20 @@ -2320,7 +2321,7 @@ static void record_and_restart(struct perf_event *eve= nt, unsigned long val, if (record) { struct perf_sample_data data; =20 - perf_sample_data_init(&data, ~0ULL, event->hw.last_period); + perf_sample_data_init(&data, ~0ULL, last_period); =20 if (event->attr.sample_type & PERF_SAMPLE_ADDR_TYPE) perf_get_data_addr(event, regs, &data.addr); diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-= emb.c index 1a53ab08447c..d2ffcc7021c5 100644 --- a/arch/powerpc/perf/core-fsl-emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c @@ -590,6 +590,7 @@ static void record_and_restart(struct perf_event *event= , unsigned long val, struct pt_regs *regs) { u64 period =3D event->hw.sample_period; + const u64 last_period =3D event->hw.last_period; s64 prev, delta, left; int record =3D 0; =20 @@ -632,7 +633,7 @@ static void record_and_restart(struct perf_event *event= , unsigned long val, if (record) { struct perf_sample_data data; =20 - perf_sample_data_init(&data, 0, event->hw.last_period); + perf_sample_data_init(&data, 0, last_period); =20 if (perf_event_overflow(event, &data, regs)) fsl_emb_pmu_stop(event, 0); diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 6866cc5acb0b..4ccf44943370 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1683,6 +1683,7 @@ int x86_pmu_handle_irq(struct pt_regs *regs) struct cpu_hw_events *cpuc; struct perf_event *event; int idx, handled =3D 0; + u64 last_period; u64 val; =20 cpuc =3D this_cpu_ptr(&cpu_hw_events); @@ -1702,6 +1703,7 @@ int x86_pmu_handle_irq(struct pt_regs *regs) continue; =20 event =3D cpuc->events[idx]; + last_period =3D event->hw.last_period; =20 val =3D static_call(x86_pmu_update)(event); if (val & (1ULL << (x86_pmu.cntval_bits - 1))) @@ -1715,7 +1717,7 @@ int x86_pmu_handle_irq(struct pt_regs *regs) if (!static_call(x86_pmu_set_period)(event)) continue; =20 - perf_sample_data_init(&data, 0, event->hw.last_period); + perf_sample_data_init(&data, 0, last_period); =20 perf_sample_save_brstack(&data, event, &cpuc->lbr_stack, NULL); =20 diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 09d2d66c9f21..9c0afdbf9d78 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3132,6 +3132,7 @@ static int handle_pmi_common(struct pt_regs *regs, u6= 4 status) =20 for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { struct perf_event *event =3D cpuc->events[bit]; + u64 last_period; =20 handled++; =20 @@ -3159,10 +3160,12 @@ static int handle_pmi_common(struct pt_regs *regs, = u64 status) if (is_pebs_counter_event_group(event)) x86_pmu.drain_pebs(regs, &data); =20 + last_period =3D event->hw.last_period; + if (!intel_pmu_save_and_restart(event)) continue; =20 - perf_sample_data_init(&data, 0, event->hw.last_period); + perf_sample_data_init(&data, 0, last_period); =20 if (has_branch_stack(event)) intel_pmu_lbr_save_brstack(&data, cpuc, event); diff --git a/arch/x86/events/intel/knc.c b/arch/x86/events/intel/knc.c index 034a1f6a457c..3e8ec049b46d 100644 --- a/arch/x86/events/intel/knc.c +++ b/arch/x86/events/intel/knc.c @@ -241,16 +241,18 @@ static int knc_pmu_handle_irq(struct pt_regs *regs) =20 for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { struct perf_event *event =3D cpuc->events[bit]; + u64 last_period; =20 handled++; =20 if (!test_bit(bit, cpuc->active_mask)) continue; =20 + last_period =3D event->hw.last_period; if (!intel_pmu_save_and_restart(event)) continue; =20 - perf_sample_data_init(&data, 0, event->hw.last_period); + perf_sample_data_init(&data, 0, last_period); =20 if (perf_event_overflow(event, &data, regs)) x86_pmu_stop(event, 0); --=20 2.43.0 From nobody Thu Dec 18 14:48:43 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 464C023770C; Tue, 8 Apr 2025 17:16:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132579; cv=none; b=gDhlgT2KtZzG5GE9gaBbcdnQcaKl21GVy92X9lAj0Oq90t6y5YuDHt2Gccqps44UnxJ+z5gQLeMuIpBZokaLBI5w7f24S/UioFQZSdr34nL02HJXNJ7/E7qxwcx6e5azy90bPiFve6xnQRk3yNMNcEGoU99oasBserupmZ0sgOo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132579; c=relaxed/simple; bh=kpWE9KqTaUxoD6IXFCeMvaJmdjSMQ2ap7Hg9aCkbi80=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kyhyepxv+bYfLOWPDxAkmpa6SNX2mBJXrRVVyiciU16FSjJ5N5q+0gAV3iYJiKkNFYOHOOtFVuvuTr1awK/sEqaQCnpP3cirdMtZEx05mEF2+GEZ7xcgnJmTh9FkMjClBb0crx8mFteFgE0g7PORBkTNfMlQD+n9Bc9Qk1U+zjM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3D4E71688; Tue, 8 Apr 2025 10:16:17 -0700 (PDT) Received: from e128066.cambridge.arm.com (e128066.cambridge.arm.com [10.1.26.81]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id EFB703F59E; Tue, 8 Apr 2025 10:16:12 -0700 (PDT) From: mark.barnett@arm.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, irogers@google.com Cc: ben.gainey@arm.com, deepak.surti@arm.com, ak@linux.intel.com, will@kernel.org, james.clark@arm.com, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mark Barnett Subject: [PATCH v4 2/5] perf: Allow periodic events to alternate between two sample periods Date: Tue, 8 Apr 2025 18:15:27 +0100 Message-Id: <20250408171530.140858-3-mark.barnett@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250408171530.140858-1-mark.barnett@arm.com> References: <20250408171530.140858-1-mark.barnett@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ben Gainey This change modifies perf_event_attr to add a second, alternative sample period field, and modifies the core perf overflow handling such that when specified an event will alternate between two sample periods. Currently, perf does not provide a mechanism for decoupling the period over which counters are counted from the period between samples. This is problematic for building a tool to measure per-function metrics derived from a sampled counter group. Ideally such a tool wants a very small sample window in order to correctly attribute the metrics to a given function, but prefers a larger sample period that provides representative coverage without excessive probe effect, triggering throttling, or generating excessive amounts of data. By alternating between a long and short sample_period and subsequently discarding the long samples, tools may decouple the period between samples that the tool cares about from the window of time over which interesting counts are collected. It is expected that typically tools would use this feature with the cycles or instructions events as an approximation for time, but no restrictions are applied to which events this can be applied to. Signed-off-by: Ben Gainey Signed-off-by: Mark Barnett Acked-by: Peter Zijlstra (Intel) --- include/linux/perf_event.h | 12 +++++- include/uapi/linux/perf_event.h | 10 +++++ kernel/events/core.c | 69 +++++++++++++++++++++++++++++---- 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 5a9bf15d4461..be006965054e 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -229,7 +229,11 @@ struct hw_perf_event { #define PERF_HES_UPTODATE 0x02 /* event->count up-to-date */ #define PERF_HES_ARCH 0x04 =20 - int state; + u32 state; + +#define PERF_SPS_HF_ON 0x00000001 +#define PERF_SPS_HF_SAMPLE 0x00000002 + u32 sample_period_state; =20 /* * The last observed hardware counter value, updated with a @@ -242,6 +246,12 @@ struct hw_perf_event { */ u64 sample_period; =20 + /* + * The original sample_period value before being modified with + * a high-frequency sampling window. + */ + u64 sample_period_base; + union { struct { /* Sampling */ /* diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_even= t.h index 5fc753c23734..1529f97fb15d 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -379,6 +379,7 @@ enum perf_event_read_format { #define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */ #define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */ #define PERF_ATTR_SIZE_VER8 136 /* add: config3 */ +#define PERF_ATTR_SIZE_VER9 144 /* add: hf_sample */ =20 /* * Hardware event_id to monitor via a performance monitoring event: @@ -533,6 +534,15 @@ struct perf_event_attr { __u64 sig_data; =20 __u64 config3; /* extension of config2 */ + + union { + __u64 hf_sample; + struct { + __u64 hf_sample_period : 32, + hf_sample_rand : 4, + __reserved_4 : 28; + }; + }; }; =20 /* diff --git a/kernel/events/core.c b/kernel/events/core.c index 128db74e9eab..5752ac7408b1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4195,19 +4195,19 @@ static void perf_adjust_period(struct perf_event *e= vent, u64 nsec, u64 count, bo =20 period =3D perf_calculate_period(event, nsec, count); =20 - delta =3D (s64)(period - hwc->sample_period); + delta =3D (s64)(period - hwc->sample_period_base); if (delta >=3D 0) delta +=3D 7; else delta -=3D 7; delta /=3D 8; /* low pass filter */ =20 - sample_period =3D hwc->sample_period + delta; + sample_period =3D hwc->sample_period_base + delta; =20 if (!sample_period) sample_period =3D 1; =20 - hwc->sample_period =3D sample_period; + hwc->sample_period_base =3D sample_period; =20 if (local64_read(&hwc->period_left) > 8*sample_period) { if (disable) @@ -6179,7 +6179,7 @@ static void __perf_event_period(struct perf_event *ev= ent, event->attr.sample_freq =3D value; } else { event->attr.sample_period =3D value; - event->hw.sample_period =3D value; + event->hw.sample_period_base =3D value; } =20 active =3D (event->state =3D=3D PERF_EVENT_STATE_ACTIVE); @@ -10064,7 +10064,7 @@ __perf_event_account_interrupt(struct perf_event *e= vent, int throttle) } } =20 - if (event->attr.freq) { + if (event->attr.freq && !(hwc->sample_period_state & PERF_SPS_HF_SAMPLE))= { u64 now =3D perf_clock(); s64 delta =3D now - hwc->freq_time_stamp; =20 @@ -10197,6 +10197,8 @@ static int __perf_event_overflow(struct perf_event = *event, int throttle, struct perf_sample_data *data, struct pt_regs *regs) { + struct hw_perf_event *hwc =3D &event->hw; + u64 sample_period; int events =3D atomic_read(&event->event_limit); int ret =3D 0; =20 @@ -10212,6 +10214,33 @@ static int __perf_event_overflow(struct perf_event= *event, if (event->attr.aux_pause) perf_event_aux_pause(event->aux_event, true); =20 + sample_period =3D hwc->sample_period_base; + + /* + * High Freq samples are injected inside the larger period: + * + * |------------|-|------------|-| + * P0 HF P1 HF + * + * By ignoring the HF samples, we measure the actual period. + */ + if (hwc->sample_period_state & PERF_SPS_HF_ON) { + u64 hf_sample_period =3D event->attr.hf_sample_period; + + if (sample_period <=3D hf_sample_period) + goto set_period; + + if (hwc->sample_period_state & PERF_SPS_HF_SAMPLE) + sample_period =3D hf_sample_period; + else + sample_period -=3D hf_sample_period; + + hwc->sample_period_state ^=3D PERF_SPS_HF_SAMPLE; + } + +set_period: + hwc->sample_period =3D sample_period; + if (event->prog && event->prog->type =3D=3D BPF_PROG_TYPE_PERF_EVENT && !bpf_overflow_handler(event, data, regs)) goto out; @@ -11694,6 +11723,7 @@ static void perf_swevent_init_hrtimer(struct perf_e= vent *event) long freq =3D event->attr.sample_freq; =20 event->attr.sample_period =3D NSEC_PER_SEC / freq; + hwc->sample_period_base =3D event->attr.sample_period; hwc->sample_period =3D event->attr.sample_period; local64_set(&hwc->period_left, hwc->sample_period); hwc->last_period =3D hwc->sample_period; @@ -12675,12 +12705,25 @@ perf_event_alloc(struct perf_event_attr *attr, in= t cpu, pmu =3D NULL; =20 hwc =3D &event->hw; + hwc->sample_period_base =3D attr->sample_period; hwc->sample_period =3D attr->sample_period; - if (attr->freq && attr->sample_freq) + if (attr->freq && attr->sample_freq) { hwc->sample_period =3D 1; - hwc->last_period =3D hwc->sample_period; + hwc->sample_period_base =3D 1; + } =20 - local64_set(&hwc->period_left, hwc->sample_period); + /* + * If the user requested a high-frequency sample period subtract that + * from the first period (the larger one), and set the high-frequency + * value to be used next. + */ + u64 first_sample_period =3D hwc->sample_period; + if (attr->hf_sample_period && attr->hf_sample_period < hwc->sample_period= ) { + first_sample_period -=3D attr->hf_sample_period; + hwc->sample_period =3D attr->hf_sample_period; + } + hwc->last_period =3D first_sample_period; + local64_set(&hwc->period_left, first_sample_period); =20 /* * We do not support PERF_SAMPLE_READ on inherited events unless @@ -12710,6 +12753,9 @@ perf_event_alloc(struct perf_event_attr *attr, int = cpu, return ERR_PTR(err); } =20 + if (attr->hf_sample_period) + hwc->sample_period_state |=3D PERF_SPS_HF_ON; + /* * Disallow uncore-task events. Similarly, disallow uncore-cgroup * events (they don't make sense as the cgroup will be different @@ -13131,6 +13177,12 @@ SYSCALL_DEFINE5(perf_event_open, } else { if (attr.sample_period & (1ULL << 63)) return -EINVAL; + if (attr.hf_sample_period) { + if (!attr.sample_period) + return -EINVAL; + if (attr.hf_sample_period >=3D attr.sample_period) + return -EINVAL; + } } =20 /* Only privileged users can get physical addresses */ @@ -14054,6 +14106,7 @@ inherit_event(struct perf_event *parent_event, struct hw_perf_event *hwc =3D &child_event->hw; =20 hwc->sample_period =3D sample_period; + hwc->sample_period_base =3D sample_period; hwc->last_period =3D sample_period; =20 local64_set(&hwc->period_left, sample_period); --=20 2.43.0 From nobody Thu Dec 18 14:48:43 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1861423A99F; Tue, 8 Apr 2025 17:16:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132584; cv=none; b=ZAB5zeWbW8+Jrlxi2aP2VYHzCQqD7Ah70GoY49WNY8MAEwgL+l2lxB9Ah5vMRxx/rrCNFg1IyBD+wxzwKweN2J5rjTRdc057q+nT4bYKi2mr8/v+Q3O4rW4G4kx30kjhsE8i+7qKNon7ZUlNYbXymk44GH7bWJqNLsKmA/aCjUg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132584; c=relaxed/simple; bh=HhiiV26Eyq2LUq6YKxY+qxDFYUBLI5AgAMAbAOeeP68=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=CIAcwAAAHm/bt3aIduSpZZoltpBhqYl6rOmbF6zhT5exoAt/Omu/zsKtU+2nrmmmUPb8ixxjFdmvy7SQE77ac+Dpmsi9GkmqkQBgvGe9V0zXhW3oGIe+rLquJ3pEJcdel83xRl6HitPakLtoelLDnclZBJ07tvREcV+VsBUoFko= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0062A1688; Tue, 8 Apr 2025 10:16:23 -0700 (PDT) Received: from e128066.cambridge.arm.com (e128066.cambridge.arm.com [10.1.26.81]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7EA4F3F59E; Tue, 8 Apr 2025 10:16:18 -0700 (PDT) From: mark.barnett@arm.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, irogers@google.com Cc: ben.gainey@arm.com, deepak.surti@arm.com, ak@linux.intel.com, will@kernel.org, james.clark@arm.com, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mark Barnett Subject: [PATCH v4 3/5] perf: Allow adding fixed random jitter to the sampling period Date: Tue, 8 Apr 2025 18:15:28 +0100 Message-Id: <20250408171530.140858-4-mark.barnett@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250408171530.140858-1-mark.barnett@arm.com> References: <20250408171530.140858-1-mark.barnett@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ben Gainey This change modifies the core perf overflow handler, adding some small random jitter to each sample period when the high-frequency sample period is in use. A new flag is added to perf_event_attr to opt into this behaviour. This change follows the discussion in [1], where it is recognized that it may be possible for certain patterns of execution to end up with biased results. [1] https://lore.kernel.org/linux-perf-users/Zc24eLqZycmIg3d2@tassilo/ Signed-off-by: Ben Gainey Signed-off-by: Mark Barnett Acked-by: Peter Zijlstra (Intel) --- include/linux/perf_event.h | 1 + kernel/events/core.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index be006965054e..78a6fd14b412 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -233,6 +233,7 @@ struct hw_perf_event { =20 #define PERF_SPS_HF_ON 0x00000001 #define PERF_SPS_HF_SAMPLE 0x00000002 +#define PERF_SPS_HF_RAND 0x00000004 u32 sample_period_state; =20 /* diff --git a/kernel/events/core.c b/kernel/events/core.c index 5752ac7408b1..bc6991a33048 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -56,6 +56,7 @@ #include #include #include +#include =20 #include "internal.h" =20 @@ -472,6 +473,8 @@ static int perf_sample_period_ns __read_mostly =3D DEFA= ULT_SAMPLE_PERIOD_NS; static int perf_sample_allowed_ns __read_mostly =3D DEFAULT_SAMPLE_PERIOD_NS * DEFAULT_CPU_TIME_MAX_PERCENT / 100; =20 +static DEFINE_PER_CPU(struct rnd_state, sample_period_jitter_rnd); + static void update_perf_cpu_limits(void) { u64 tmp =3D perf_sample_period_ns; @@ -10224,6 +10227,19 @@ static int __perf_event_overflow(struct perf_event= *event, * * By ignoring the HF samples, we measure the actual period. */ + + /* + * Apply optional jitter to the overall sample period + */ + if (hwc->sample_period_state & PERF_SPS_HF_RAND + && !(hwc->sample_period_state & PERF_SPS_HF_SAMPLE)) { + struct rnd_state *state =3D &get_cpu_var(sample_period_jitter_rnd); + u64 rand_period =3D 1 << event->attr.hf_sample_rand; + + sample_period -=3D rand_period / 2; + sample_period +=3D prandom_u32_state(state) & (rand_period - 1); + } + if (hwc->sample_period_state & PERF_SPS_HF_ON) { u64 hf_sample_period =3D event->attr.hf_sample_period; =20 @@ -12756,6 +12772,14 @@ perf_event_alloc(struct perf_event_attr *attr, int= cpu, if (attr->hf_sample_period) hwc->sample_period_state |=3D PERF_SPS_HF_ON; =20 + if (attr->hf_sample_rand) { + /* high-frequency jitter is only valid with a high-freq period */ + if (!attr->hf_sample_period) + return ERR_PTR(-EINVAL); + + hwc->sample_period_state |=3D PERF_SPS_HF_RAND; + } + /* * Disallow uncore-task events. Similarly, disallow uncore-cgroup * events (they don't make sense as the cgroup will be different @@ -14367,6 +14391,7 @@ static void __init perf_event_init_all_cpus(void) zalloc_cpumask_var(&perf_online_pkg_mask, GFP_KERNEL); zalloc_cpumask_var(&perf_online_sys_mask, GFP_KERNEL); =20 + prandom_seed_full_state(&sample_period_jitter_rnd); =20 for_each_possible_cpu(cpu) { swhash =3D &per_cpu(swevent_htable, cpu); @@ -14384,6 +14409,7 @@ static void __init perf_event_init_all_cpus(void) cpuctx->online =3D cpumask_test_cpu(cpu, perf_online_mask); cpuctx->heap_size =3D ARRAY_SIZE(cpuctx->heap_default); cpuctx->heap =3D cpuctx->heap_default; + } } =20 --=20 2.43.0 From nobody Thu Dec 18 14:48:43 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E32652356CC; Tue, 8 Apr 2025 17:16:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132594; cv=none; b=d4xln2PIfqJfQprug/Y7IyjfQQKJhWbt/u0q6Whd0Wr89hSUUVCZA9bwJcfjTgt8NHVBWl8eAVM8zn+eJRXEWOr+v8KzcstBknyjwW0TO6iVlfXwWOajiNN8ypTxjHAA3kiUXxuYCdPg9oczLD75WD5KMsdWPXvk5Zu4uj7p5Zs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132594; c=relaxed/simple; bh=HzNfzNrhhEGtHEAmmwegS0Lov/OL0xRdpo39lr3yU7Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Y9d0MmogM5WLv9D4ZE+CG02o/vaFv3XYrCkRFqjxL6wx5EpuVNbclJYyburU1D3b1CHt1GnG2mGrQFBzonZogUq5xlD2X5rnQGvFRUuRS+QcXSyv52rBzr1VlvfrppihwSh8rz2zFtm9PnqunyXM4isW2KImJEV7uIapIfuFryY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 08C241688; Tue, 8 Apr 2025 10:16:33 -0700 (PDT) Received: from e128066.cambridge.arm.com (e128066.cambridge.arm.com [10.1.26.81]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 840AF3F59E; Tue, 8 Apr 2025 10:16:28 -0700 (PDT) From: mark.barnett@arm.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, irogers@google.com Cc: ben.gainey@arm.com, deepak.surti@arm.com, ak@linux.intel.com, will@kernel.org, james.clark@arm.com, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mark Barnett Subject: [PATCH v4 4/5] tools/perf: Modify event parser to support hf-period term Date: Tue, 8 Apr 2025 18:15:29 +0100 Message-Id: <20250408171530.140858-5-mark.barnett@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250408171530.140858-1-mark.barnett@arm.com> References: <20250408171530.140858-1-mark.barnett@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ben Gainey parse-events is modified, adding the "hf-period" term which can be used to specify the high-frequency sampling period. Signed-off-by: Ben Gainey Signed-off-by: Mark Barnett Acked-by: Peter Zijlstra (Intel) --- tools/include/uapi/linux/perf_event.h | 10 ++++++++++ tools/perf/tests/shell/attr/base-record | 3 ++- tools/perf/tests/shell/attr/base-record-spe | 1 + tools/perf/tests/shell/attr/base-stat | 3 ++- tools/perf/tests/shell/attr/system-wide-dummy | 3 ++- tools/perf/tests/shell/attr/test-record-dummy-C0 | 3 ++- .../tests/shell/attr/test-record-hf-period-term | 12 ++++++++++++ tools/perf/tests/shell/lib/attr.py | 1 + tools/perf/util/evsel.c | 1 + tools/perf/util/parse-events.c | 15 +++++++++++++++ tools/perf/util/parse-events.h | 3 ++- tools/perf/util/parse-events.l | 1 + tools/perf/util/perf_event_attr_fprintf.c | 1 + tools/perf/util/pmu.c | 3 ++- 14 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 tools/perf/tests/shell/attr/test-record-hf-period-term diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/lin= ux/perf_event.h index 0524d541d4e3..2a6cc543df0e 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h @@ -379,6 +379,7 @@ enum perf_event_read_format { #define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */ #define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */ #define PERF_ATTR_SIZE_VER8 136 /* add: config3 */ +#define PERF_ATTR_SIZE_VER9 144 /* add: hf_sample */ =20 /* * Hardware event_id to monitor via a performance monitoring event: @@ -531,6 +532,15 @@ struct perf_event_attr { __u64 sig_data; =20 __u64 config3; /* extension of config2 */ + + union { + __u64 hf_sample; + struct { + __u64 hf_sample_period : 32, + hf_sample_rand : 4, + __reserved_4 : 28; + }; + }; }; =20 /* diff --git a/tools/perf/tests/shell/attr/base-record b/tools/perf/tests/she= ll/attr/base-record index b44e4e6e4443..8369f505dfb2 100644 --- a/tools/perf/tests/shell/attr/base-record +++ b/tools/perf/tests/shell/attr/base-record @@ -5,7 +5,7 @@ group_fd=3D-1 flags=3D0|8 cpu=3D* type=3D0|1 -size=3D136 +size=3D144 config=3D0|1 sample_period=3D* sample_type=3D263 @@ -39,3 +39,4 @@ config2=3D0 branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 +hf_sample_period=3D0 diff --git a/tools/perf/tests/shell/attr/base-record-spe b/tools/perf/tests= /shell/attr/base-record-spe index 08fa96b59240..2b4f051b6717 100644 --- a/tools/perf/tests/shell/attr/base-record-spe +++ b/tools/perf/tests/shell/attr/base-record-spe @@ -38,3 +38,4 @@ config2=3D* branch_sample_type=3D* sample_regs_user=3D* sample_stack_user=3D* +hf_sample_period=3D0 diff --git a/tools/perf/tests/shell/attr/base-stat b/tools/perf/tests/shell= /attr/base-stat index fccd8ec4d1b0..499c44c6216c 100644 --- a/tools/perf/tests/shell/attr/base-stat +++ b/tools/perf/tests/shell/attr/base-stat @@ -5,7 +5,7 @@ group_fd=3D-1 flags=3D0|8 cpu=3D* type=3D0 -size=3D136 +size=3D144 config=3D0 sample_period=3D0 sample_type=3D65536 @@ -39,3 +39,4 @@ config2=3D0 branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 +hf_sample_period=3D0 diff --git a/tools/perf/tests/shell/attr/system-wide-dummy b/tools/perf/tes= ts/shell/attr/system-wide-dummy index a1e1d6a263bf..1dad060d304a 100644 --- a/tools/perf/tests/shell/attr/system-wide-dummy +++ b/tools/perf/tests/shell/attr/system-wide-dummy @@ -7,7 +7,7 @@ cpu=3D* pid=3D-1 flags=3D8 type=3D1 -size=3D136 +size=3D144 config=3D9 sample_period=3D1 # PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | @@ -50,3 +50,4 @@ config2=3D0 branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 +hf_sample_period=3D0 diff --git a/tools/perf/tests/shell/attr/test-record-dummy-C0 b/tools/perf/= tests/shell/attr/test-record-dummy-C0 index 91499405fff4..18f0e3766389 100644 --- a/tools/perf/tests/shell/attr/test-record-dummy-C0 +++ b/tools/perf/tests/shell/attr/test-record-dummy-C0 @@ -10,7 +10,7 @@ cpu=3D0 pid=3D-1 flags=3D8 type=3D1 -size=3D136 +size=3D144 config=3D9 sample_period=3D4000 # PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | @@ -53,3 +53,4 @@ config2=3D0 branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 +hf_sample_period=3D0 diff --git a/tools/perf/tests/shell/attr/test-record-hf-period-term b/tools= /perf/tests/shell/attr/test-record-hf-period-term new file mode 100644 index 000000000000..539b9946c8cc --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-hf-period-term @@ -0,0 +1,12 @@ +[config] +command =3D record +args =3D --no-bpf-event -e cycles/period=3D3,hf-period=3D2/ -- kill >/d= ev/null 2>&1 +ret =3D 1 +kernel_since =3D 6.15 + +[event-10:base-record] +sample_period=3D3 +hf_sample_period=3D2 + +freq=3D0 +sample_type=3D7 diff --git a/tools/perf/tests/shell/lib/attr.py b/tools/perf/tests/shell/li= b/attr.py index bfccc727d9b2..80c99758bd86 100644 --- a/tools/perf/tests/shell/lib/attr.py +++ b/tools/perf/tests/shell/lib/attr.py @@ -85,6 +85,7 @@ class Event(dict): 'branch_sample_type', 'sample_regs_user', 'sample_stack_user', + 'hf_sample_period', ] =20 def add(self, data): diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1974395492d7..6e8eb34ef957 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -180,6 +180,7 @@ static int store_event(struct perf_event_attr *attr, pi= d_t pid, struct perf_cpu WRITE_ASS(branch_sample_type, "llu"); WRITE_ASS(sample_regs_user, "llu"); WRITE_ASS(sample_stack_user, PRIu32); + WRITE_ASS(hf_sample_period, PRIu32); =20 fclose(file); return 0; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5152fd5a6ead..c0943eb7f171 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -805,6 +805,7 @@ const char *parse_events__term_type_str(enum parse_even= ts__term_type term_type) [PARSE_EVENTS__TERM_TYPE_RAW] =3D "raw", [PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE] =3D "legacy-cache", [PARSE_EVENTS__TERM_TYPE_HARDWARE] =3D "hardware", + [PARSE_EVENTS__TERM_TYPE_HF_PERIOD] =3D "hf-period", }; if ((unsigned int)term_type >=3D __PARSE_EVENTS__TERM_TYPE_NR) return "unknown term"; @@ -833,6 +834,7 @@ config_term_avail(enum parse_events__term_type term_typ= e, struct parse_events_er case PARSE_EVENTS__TERM_TYPE_NAME: case PARSE_EVENTS__TERM_TYPE_METRIC_ID: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: + case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: case PARSE_EVENTS__TERM_TYPE_PERCORE: return true; case PARSE_EVENTS__TERM_TYPE_USER: @@ -981,6 +983,16 @@ do { \ return -EINVAL; } break; + case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: + CHECK_TYPE_VAL(NUM); + if (term->val.num =3D=3D 0) { + parse_events_error__handle(err, term->err_val, + strdup("expected a non-zero value"), + NULL); + return -EINVAL; + } + attr->hf_sample_period =3D term->val.num; + break; case PARSE_EVENTS__TERM_TYPE_DRV_CFG: case PARSE_EVENTS__TERM_TYPE_USER: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: @@ -1108,6 +1120,7 @@ static int config_term_tracepoint(struct perf_event_a= ttr *attr, case PARSE_EVENTS__TERM_TYPE_RAW: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: + case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: default: if (err) { parse_events_error__handle(err, term->err_term, @@ -1242,6 +1255,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_RAW: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: + case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: default: break; } @@ -1296,6 +1310,7 @@ static int get_config_chgs(struct perf_pmu *pmu, stru= ct parse_events_terms *head case PARSE_EVENTS__TERM_TYPE_RAW: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: + case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index e176a34ab088..a6c4f81d5989 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -80,7 +80,8 @@ enum parse_events__term_type { PARSE_EVENTS__TERM_TYPE_RAW, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE, PARSE_EVENTS__TERM_TYPE_HARDWARE, -#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_HARDWARE + 1) + PARSE_EVENTS__TERM_TYPE_HF_PERIOD, +#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_HF_PERIOD + = 1) }; =20 struct parse_events_term { diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 7ed86e3e34e3..482321ace228 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -335,6 +335,7 @@ aux-output { return term(yyscanner, PARSE_EVENTS__TERM= _TYPE_AUX_OUTPUT); } aux-action { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_ACTION); } aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMP= LE_SIZE); } metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } +hf-period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_HF_PERIOD); } cpu-cycles|cycles { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES)= ; } stalled-cycles-frontend|idle-cycles-frontend { return hw_term(yyscanner, P= ERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } stalled-cycles-backend|idle-cycles-backend { return hw_term(yyscanner, PER= F_COUNT_HW_STALLED_CYCLES_BACKEND); } diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/pe= rf_event_attr_fprintf.c index 66b666d9ce64..c93904a299af 100644 --- a/tools/perf/util/perf_event_attr_fprintf.c +++ b/tools/perf/util/perf_event_attr_fprintf.c @@ -360,6 +360,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_even= t_attr *attr, PRINT_ATTRf(aux_start_paused, p_unsigned); PRINT_ATTRf(aux_pause, p_unsigned); PRINT_ATTRf(aux_resume, p_unsigned); + PRINT_ATTRf(hf_sample_period, p_unsigned); =20 return ret; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index b7ebac5ab1d1..f90c59e29371 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1429,7 +1429,7 @@ static int pmu_config_term(const struct perf_pmu *pmu, break; case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */ return -EINVAL; - case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HARDWARE: + case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HF_PERIOD: /* Skip non-config terms. */ break; default: @@ -1804,6 +1804,7 @@ int perf_pmu__for_each_format(struct perf_pmu *pmu, v= oid *state, pmu_format_call "aux-output", "aux-action=3D(pause|resume|start-paused)", "aux-sample-size=3Dnumber", + "hf-period=3Dnumber", }; struct perf_pmu_format *format; int ret; --=20 2.43.0 From nobody Thu Dec 18 14:48:43 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 96A8323C8C1; Tue, 8 Apr 2025 17:16:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132602; cv=none; b=MjWjBjmH2ql3bu+BzmVisft1TbhBtcbW4ZR66g6T0AkVRK19CCiUj9dd6RNMBWr4kt5x4+m5EOkmVzeNjMsj0fXWxYIN0W0yEd/RXammT47tBWEXykSZ72ejeyuh9qtvOwkmDHMUVAIw5IcuQM2SbzXJbMrqZBhOCZrF1di9v0o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744132602; c=relaxed/simple; bh=JmMelrEjPWF3FZuZVbwJYwcQY5UYZuRHJy+E+JTBJ1A=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=c0R+5rG2cHGtNYnF219mNgYWjV9qopUzr05kQgiduxrheVZBgUMzHPs2Wt4GAwT7KGDUlVSEY/LN4evvsA2q+HvTSIHeOsO+c5HjQ273Skn1LsfSwkbMA16tM1uOsV7GCZzgkmuVJF6T3wjcXledUvqbs2DoC3wAnYlnck5q+dE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 960591688; Tue, 8 Apr 2025 10:16:40 -0700 (PDT) Received: from e128066.cambridge.arm.com (e128066.cambridge.arm.com [10.1.26.81]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id E23EA3F59E; Tue, 8 Apr 2025 10:16:35 -0700 (PDT) From: mark.barnett@arm.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, irogers@google.com Cc: ben.gainey@arm.com, deepak.surti@arm.com, ak@linux.intel.com, will@kernel.org, james.clark@arm.com, mark.rutland@arm.com, alexander.shishkin@linux.intel.com, jolsa@kernel.org, adrian.hunter@intel.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mark Barnett Subject: [PATCH v4 5/5] tools/perf: Modify event parser to support hf-rand term Date: Tue, 8 Apr 2025 18:15:30 +0100 Message-Id: <20250408171530.140858-6-mark.barnett@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250408171530.140858-1-mark.barnett@arm.com> References: <20250408171530.140858-1-mark.barnett@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ben Gainey parse-events is modified, adding the "hf-rand" term which can be used to enable enable random jitter of the sample period. Signed-off-by: Ben Gainey Signed-off-by: Mark Barnett Acked-by: Peter Zijlstra (Intel) --- tools/perf/tests/shell/attr/base-record | 1 + tools/perf/tests/shell/attr/base-record-spe | 1 + tools/perf/tests/shell/attr/base-stat | 1 + tools/perf/tests/shell/attr/system-wide-dummy | 1 + tools/perf/tests/shell/attr/test-record-dummy-C0 | 1 + .../tests/shell/attr/test-record-hf-period-rand | 13 +++++++++++++ tools/perf/tests/shell/lib/attr.py | 1 + tools/perf/util/evsel.c | 1 + tools/perf/util/parse-events.c | 15 +++++++++++++++ tools/perf/util/parse-events.h | 3 ++- tools/perf/util/parse-events.l | 1 + tools/perf/util/perf_event_attr_fprintf.c | 1 + tools/perf/util/pmu.c | 3 ++- 13 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tools/perf/tests/shell/attr/test-record-hf-period-rand diff --git a/tools/perf/tests/shell/attr/base-record b/tools/perf/tests/she= ll/attr/base-record index 8369f505dfb2..f51a20abde2e 100644 --- a/tools/perf/tests/shell/attr/base-record +++ b/tools/perf/tests/shell/attr/base-record @@ -40,3 +40,4 @@ branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 hf_sample_period=3D0 +hf_sample_rand=3D0 diff --git a/tools/perf/tests/shell/attr/base-record-spe b/tools/perf/tests= /shell/attr/base-record-spe index 2b4f051b6717..d8695abeb2b2 100644 --- a/tools/perf/tests/shell/attr/base-record-spe +++ b/tools/perf/tests/shell/attr/base-record-spe @@ -39,3 +39,4 @@ branch_sample_type=3D* sample_regs_user=3D* sample_stack_user=3D* hf_sample_period=3D0 +hf_sample_rand=3D0 diff --git a/tools/perf/tests/shell/attr/base-stat b/tools/perf/tests/shell= /attr/base-stat index 499c44c6216c..11df6cb36b9a 100644 --- a/tools/perf/tests/shell/attr/base-stat +++ b/tools/perf/tests/shell/attr/base-stat @@ -40,3 +40,4 @@ branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 hf_sample_period=3D0 +hf_sample_rand=3D0 diff --git a/tools/perf/tests/shell/attr/system-wide-dummy b/tools/perf/tes= ts/shell/attr/system-wide-dummy index 1dad060d304a..0439c81c5895 100644 --- a/tools/perf/tests/shell/attr/system-wide-dummy +++ b/tools/perf/tests/shell/attr/system-wide-dummy @@ -51,3 +51,4 @@ branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 hf_sample_period=3D0 +hf_sample_rand=3D0 diff --git a/tools/perf/tests/shell/attr/test-record-dummy-C0 b/tools/perf/= tests/shell/attr/test-record-dummy-C0 index 18f0e3766389..d9eecbd5d246 100644 --- a/tools/perf/tests/shell/attr/test-record-dummy-C0 +++ b/tools/perf/tests/shell/attr/test-record-dummy-C0 @@ -54,3 +54,4 @@ branch_sample_type=3D0 sample_regs_user=3D0 sample_stack_user=3D0 hf_sample_period=3D0 +hf_sample_rand=3D0 diff --git a/tools/perf/tests/shell/attr/test-record-hf-period-rand b/tools= /perf/tests/shell/attr/test-record-hf-period-rand new file mode 100644 index 000000000000..517ff6cbc0e9 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-hf-period-rand @@ -0,0 +1,13 @@ +[config] +command =3D record +args =3D --no-bpf-event -e cycles/period=3D3,hf-period=3D2,hf-rand=3D7/= -- kill >/dev/null 2>&1 +ret =3D 1 +kernel_since =3D 6.15 + +[event-10:base-record] +sample_period=3D3 +hf_sample_period=3D2 +hf_sample_rand=3D7 + +freq=3D0 +sample_type=3D7 diff --git a/tools/perf/tests/shell/lib/attr.py b/tools/perf/tests/shell/li= b/attr.py index 80c99758bd86..a9600997a9ea 100644 --- a/tools/perf/tests/shell/lib/attr.py +++ b/tools/perf/tests/shell/lib/attr.py @@ -86,6 +86,7 @@ class Event(dict): 'sample_regs_user', 'sample_stack_user', 'hf_sample_period', + 'hf_sample_rand', ] =20 def add(self, data): diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 6e8eb34ef957..b0a54d64f616 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -181,6 +181,7 @@ static int store_event(struct perf_event_attr *attr, pi= d_t pid, struct perf_cpu WRITE_ASS(sample_regs_user, "llu"); WRITE_ASS(sample_stack_user, PRIu32); WRITE_ASS(hf_sample_period, PRIu32); + WRITE_ASS(hf_sample_rand, "d"); =20 fclose(file); return 0; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c0943eb7f171..91e5a0d07d58 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -806,6 +806,7 @@ const char *parse_events__term_type_str(enum parse_even= ts__term_type term_type) [PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE] =3D "legacy-cache", [PARSE_EVENTS__TERM_TYPE_HARDWARE] =3D "hardware", [PARSE_EVENTS__TERM_TYPE_HF_PERIOD] =3D "hf-period", + [PARSE_EVENTS__TERM_TYPE_HF_RAND] =3D "hf-rand", }; if ((unsigned int)term_type >=3D __PARSE_EVENTS__TERM_TYPE_NR) return "unknown term"; @@ -835,6 +836,7 @@ config_term_avail(enum parse_events__term_type term_typ= e, struct parse_events_er case PARSE_EVENTS__TERM_TYPE_METRIC_ID: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: + case PARSE_EVENTS__TERM_TYPE_HF_RAND: case PARSE_EVENTS__TERM_TYPE_PERCORE: return true; case PARSE_EVENTS__TERM_TYPE_USER: @@ -993,6 +995,16 @@ do { \ } attr->hf_sample_period =3D term->val.num; break; + case PARSE_EVENTS__TERM_TYPE_HF_RAND: + CHECK_TYPE_VAL(NUM); + if ((unsigned int)term->val.num > 15) { + parse_events_error__handle(err, term->err_val, + strdup("expected a value between 0-15"), + NULL); + return -EINVAL; + } + attr->hf_sample_rand =3D (unsigned int)term->val.num; + break; case PARSE_EVENTS__TERM_TYPE_DRV_CFG: case PARSE_EVENTS__TERM_TYPE_USER: case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: @@ -1121,6 +1133,7 @@ static int config_term_tracepoint(struct perf_event_a= ttr *attr, case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: + case PARSE_EVENTS__TERM_TYPE_HF_RAND: default: if (err) { parse_events_error__handle(err, term->err_term, @@ -1256,6 +1269,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: + case PARSE_EVENTS__TERM_TYPE_HF_RAND: default: break; } @@ -1311,6 +1325,7 @@ static int get_config_chgs(struct perf_pmu *pmu, stru= ct parse_events_terms *head case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_HF_PERIOD: + case PARSE_EVENTS__TERM_TYPE_HF_RAND: default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a6c4f81d5989..4c2e950dcf81 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -81,7 +81,8 @@ enum parse_events__term_type { PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE, PARSE_EVENTS__TERM_TYPE_HARDWARE, PARSE_EVENTS__TERM_TYPE_HF_PERIOD, -#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_HF_PERIOD + = 1) + PARSE_EVENTS__TERM_TYPE_HF_RAND, +#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_HF_RAND + 1) }; =20 struct parse_events_term { diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 482321ace228..b60b5e796d3a 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -336,6 +336,7 @@ aux-action { return term(yyscanner, PARSE_EVENTS__TERM= _TYPE_AUX_ACTION); } aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMP= LE_SIZE); } metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } hf-period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_HF_PERIOD); } +hf-rand { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_HF_RAND); } cpu-cycles|cycles { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES)= ; } stalled-cycles-frontend|idle-cycles-frontend { return hw_term(yyscanner, P= ERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } stalled-cycles-backend|idle-cycles-backend { return hw_term(yyscanner, PER= F_COUNT_HW_STALLED_CYCLES_BACKEND); } diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/pe= rf_event_attr_fprintf.c index c93904a299af..3d769a10304b 100644 --- a/tools/perf/util/perf_event_attr_fprintf.c +++ b/tools/perf/util/perf_event_attr_fprintf.c @@ -361,6 +361,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_even= t_attr *attr, PRINT_ATTRf(aux_pause, p_unsigned); PRINT_ATTRf(aux_resume, p_unsigned); PRINT_ATTRf(hf_sample_period, p_unsigned); + PRINT_ATTRf(hf_sample_rand, p_unsigned); =20 return ret; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index f90c59e29371..f735216e88c1 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1429,7 +1429,7 @@ static int pmu_config_term(const struct perf_pmu *pmu, break; case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */ return -EINVAL; - case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HF_PERIOD: + case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HF_RAND: /* Skip non-config terms. */ break; default: @@ -1805,6 +1805,7 @@ int perf_pmu__for_each_format(struct perf_pmu *pmu, v= oid *state, pmu_format_call "aux-action=3D(pause|resume|start-paused)", "aux-sample-size=3Dnumber", "hf-period=3Dnumber", + "hf-period-rand=3Dnumber", }; struct perf_pmu_format *format; int ret; --=20 2.43.0