The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Sandipan Das <sandipan.das@amd.com>
To: Stephane Eranian <eranian@google.com>
Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org,
	peterz@infradead.org, mingo@redhat.com, acme@kernel.org,
	namhyung@kernel.org, mark.rutland@arm.com,
	alexander.shishkin@linux.intel.com, jolsa@kernel.org,
	irogers@google.com, adrian.hunter@intel.com,
	kan.liang@linux.intel.com, tglx@linutronix.de, bp@alien8.de,
	dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com,
	songliubraving@meta.com, ravi.bangoria@amd.com,
	ananth.narayan@amd.com
Subject: Re: [PATCH v2 3/5] perf/x86/amd/uncore: Use hrtimer for handling overflows
Date: Fri, 18 Apr 2025 10:19:19 +0530	[thread overview]
Message-ID: <0c9f534d-a782-4e42-ae44-5d6ac9b51d25@amd.com> (raw)
In-Reply-To: <CABPqkBS+k4Om3-sQWGBFN-imhiU8fXYsiDR1XAyp0Ro3uknCHw@mail.gmail.com>

On 4/18/2025 10:08 AM, Stephane Eranian wrote:
> On Thu, Apr 17, 2025 at 8:44 PM Sandipan Das <sandipan.das@amd.com> wrote:
>>
>> Uncore counters do not provide mechanisms like interrupts to report
>> overflows and the accumulated user-visible count is incorrect if there
>> is more than one overflow between two successive read requests for the
>> same event because the value of prev_count goes out-of-date for
>> calculating the correct delta.
>>
>> To avoid this, start a hrtimer to periodically initiate a pmu->read() of
>> the active counters for keeping prev_count up-to-date. It should be
>> noted that the hrtimer duration should be lesser than the shortest time
>> it takes for a counter to overflow for this approach to be effective.
>>
> The problem I see is that the number of uncore PMU varies a lot based
> on the CPU model, in particular due to the L3 PMU.
> Is there a timer armed per CCX or only a global one that will generate
> IPI to all other CPUs?
> 

For L3 PMU, its on a per-CCX basis.

>> Signed-off-by: Sandipan Das <sandipan.das@amd.com>
>> ---
>>  arch/x86/events/amd/uncore.c | 63 ++++++++++++++++++++++++++++++++++++
>>  1 file changed, 63 insertions(+)
>>
>> diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c
>> index 010024f09f2c..e09bfbb4a4cd 100644
>> --- a/arch/x86/events/amd/uncore.c
>> +++ b/arch/x86/events/amd/uncore.c
>> @@ -21,6 +21,7 @@
>>  #define NUM_COUNTERS_NB                4
>>  #define NUM_COUNTERS_L2                4
>>  #define NUM_COUNTERS_L3                6
>> +#define NUM_COUNTERS_MAX       64
>>
>>  #define RDPMC_BASE_NB          6
>>  #define RDPMC_BASE_LLC         10
>> @@ -38,6 +39,10 @@ struct amd_uncore_ctx {
>>         int refcnt;
>>         int cpu;
>>         struct perf_event **events;
>> +       unsigned long active_mask[BITS_TO_LONGS(NUM_COUNTERS_MAX)];
>> +       int nr_active;
>> +       struct hrtimer hrtimer;
>> +       u64 hrtimer_duration;
>>  };
>>
>>  struct amd_uncore_pmu {
>> @@ -87,6 +92,42 @@ static struct amd_uncore_pmu *event_to_amd_uncore_pmu(struct perf_event *event)
>>         return container_of(event->pmu, struct amd_uncore_pmu, pmu);
>>  }
>>
>> +static enum hrtimer_restart amd_uncore_hrtimer(struct hrtimer *hrtimer)
>> +{
>> +       struct amd_uncore_ctx *ctx;
>> +       struct perf_event *event;
>> +       int bit;
>> +
>> +       ctx = container_of(hrtimer, struct amd_uncore_ctx, hrtimer);
>> +
>> +       if (!ctx->nr_active || ctx->cpu != smp_processor_id())
>> +               return HRTIMER_NORESTART;
>> +
>> +       for_each_set_bit(bit, ctx->active_mask, NUM_COUNTERS_MAX) {
>> +               event = ctx->events[bit];
>> +               event->pmu->read(event);
>> +       }
>> +
>> +       hrtimer_forward_now(hrtimer, ns_to_ktime(ctx->hrtimer_duration));
>> +       return HRTIMER_RESTART;
>> +}
>> +
>> +static void amd_uncore_start_hrtimer(struct amd_uncore_ctx *ctx)
>> +{
>> +       hrtimer_start(&ctx->hrtimer, ns_to_ktime(ctx->hrtimer_duration),
>> +                     HRTIMER_MODE_REL_PINNED_HARD);
>> +}
>> +
>> +static void amd_uncore_cancel_hrtimer(struct amd_uncore_ctx *ctx)
>> +{
>> +       hrtimer_cancel(&ctx->hrtimer);
>> +}
>> +
>> +static void amd_uncore_init_hrtimer(struct amd_uncore_ctx *ctx)
>> +{
>> +       hrtimer_setup(&ctx->hrtimer, amd_uncore_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
>> +}
>> +
>>  static void amd_uncore_read(struct perf_event *event)
>>  {
>>         struct hw_perf_event *hwc = &event->hw;
>> @@ -117,18 +158,26 @@ static void amd_uncore_read(struct perf_event *event)
>>
>>  static void amd_uncore_start(struct perf_event *event, int flags)
>>  {
>> +       struct amd_uncore_pmu *pmu = event_to_amd_uncore_pmu(event);
>> +       struct amd_uncore_ctx *ctx = *per_cpu_ptr(pmu->ctx, event->cpu);
>>         struct hw_perf_event *hwc = &event->hw;
>>
>> +       if (!ctx->nr_active++)
>> +               amd_uncore_start_hrtimer(ctx);
>> +
>>         if (flags & PERF_EF_RELOAD)
>>                 wrmsrl(hwc->event_base, (u64)local64_read(&hwc->prev_count));
>>
>>         hwc->state = 0;
>> +       __set_bit(hwc->idx, ctx->active_mask);
>>         wrmsrl(hwc->config_base, (hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE));
>>         perf_event_update_userpage(event);
>>  }
>>
>>  static void amd_uncore_stop(struct perf_event *event, int flags)
>>  {
>> +       struct amd_uncore_pmu *pmu = event_to_amd_uncore_pmu(event);
>> +       struct amd_uncore_ctx *ctx = *per_cpu_ptr(pmu->ctx, event->cpu);
>>         struct hw_perf_event *hwc = &event->hw;
>>
>>         wrmsrl(hwc->config_base, hwc->config);
>> @@ -138,6 +187,11 @@ static void amd_uncore_stop(struct perf_event *event, int flags)
>>                 event->pmu->read(event);
>>                 hwc->state |= PERF_HES_UPTODATE;
>>         }
>> +
>> +       if (!--ctx->nr_active)
>> +               amd_uncore_cancel_hrtimer(ctx);
>> +
>> +       __clear_bit(hwc->idx, ctx->active_mask);
>>  }
>>
>>  static int amd_uncore_add(struct perf_event *event, int flags)
>> @@ -490,6 +544,9 @@ static int amd_uncore_ctx_init(struct amd_uncore *uncore, unsigned int cpu)
>>                                 goto fail;
>>                         }
>>
>> +                       amd_uncore_init_hrtimer(curr);
>> +                       curr->hrtimer_duration = 60LL * NSEC_PER_SEC;
>> +
>>                         cpumask_set_cpu(cpu, &pmu->active_mask);
>>                 }
>>
>> @@ -879,12 +936,18 @@ static int amd_uncore_umc_event_init(struct perf_event *event)
>>
>>  static void amd_uncore_umc_start(struct perf_event *event, int flags)
>>  {
>> +       struct amd_uncore_pmu *pmu = event_to_amd_uncore_pmu(event);
>> +       struct amd_uncore_ctx *ctx = *per_cpu_ptr(pmu->ctx, event->cpu);
>>         struct hw_perf_event *hwc = &event->hw;
>>
>> +       if (!ctx->nr_active++)
>> +               amd_uncore_start_hrtimer(ctx);
>> +
>>         if (flags & PERF_EF_RELOAD)
>>                 wrmsrl(hwc->event_base, (u64)local64_read(&hwc->prev_count));
>>
>>         hwc->state = 0;
>> +       __set_bit(hwc->idx, ctx->active_mask);
>>         wrmsrl(hwc->config_base, (hwc->config | AMD64_PERFMON_V2_ENABLE_UMC));
>>         perf_event_update_userpage(event);
>>  }
>> --
>> 2.43.0
>>


  reply	other threads:[~2025-04-18  4:49 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-18  3:42 [PATCH v2 0/5] perf/x86/uncore: Overflow handling enhancements Sandipan Das
2025-04-18  3:42 ` [PATCH v2 1/5] perf/x86/amd/uncore: Remove unused member from amd_uncore_ctx Sandipan Das
2025-04-18  3:43 ` [PATCH v2 2/5] perf/x86/intel/uncore: Use HRTIMER_MODE_HARD for detecting overflows Sandipan Das
2025-04-18  3:43 ` [PATCH v2 3/5] perf/x86/amd/uncore: Use hrtimer for handling overflows Sandipan Das
2025-04-18  4:38   ` Stephane Eranian
2025-04-18  4:49     ` Sandipan Das [this message]
2025-04-18  3:43 ` [PATCH v2 4/5] perf/x86/amd/uncore: Add parameter to configure hrtimer Sandipan Das
2025-04-18  3:43 ` [PATCH v2 5/5] perf/x86/amd/uncore: Prevent UMC counters from saturating Sandipan Das
2025-04-18  8:32 ` [PATCH v2 0/5] perf/x86/uncore: Overflow handling enhancements Ingo Molnar
2025-04-18  9:27   ` Sandipan Das

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0c9f534d-a782-4e42-ae44-5d6ac9b51d25@amd.com \
    --to=sandipan.das@amd.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=ananth.narayan@amd.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=eranian@google.com \
    --cc=hpa@zytor.com \
    --cc=irogers@google.com \
    --cc=jolsa@kernel.org \
    --cc=kan.liang@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    --cc=ravi.bangoria@amd.com \
    --cc=songliubraving@meta.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox