[Intel-gfx] [PATCH] drm/i915/pmu: Deprecate I915_PMU_LAST and optimize state tracking

Chris Wilson chris at chris-wilson.co.uk
Fri Dec 4 11:06:17 UTC 2020


Quoting Tvrtko Ursulin (2020-12-04 10:57:52)
> 
> On 03/12/2020 22:33, Chris Wilson wrote:
> > Quoting Tvrtko Ursulin (2020-11-26 16:47:03)
> >> From: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> >>
> >> Adding any kinds of "last" abi markers is usually a mistake which I
> >> repeated when implementing the PMU because it felt convenient at the time.
> >>
> >> This patch marks I915_PMU_LAST as deprecated and stops the internal
> >> implementation using it for sizing the event status bitmask and array.
> >>
> >> New way of sizing the fields is a bit less elegant, but it omits reserving
> >> slots for tracking events we are not interested in, and as such saves some
> >> runtime space. Adding sampling events is likely to be a special event and
> >> the new plumbing needed will be easily detected in testing. Existing
> >> asserts against the bitfield and array sizes are keeping the code safe.
> >>
> >> First event which gets the new treatment in this new scheme are the
> >> interrupts - which neither needs any tracking in i915 pmu nor needs
> >> waking up the GPU to read it.
> >>
> >> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> >> ---
> >>   drivers/gpu/drm/i915/i915_pmu.c | 64 +++++++++++++++++++++++++++------
> >>   drivers/gpu/drm/i915/i915_pmu.h | 35 ++++++++++++------
> >>   include/uapi/drm/i915_drm.h     |  2 +-
> >>   3 files changed, 78 insertions(+), 23 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
> >> index cd786ad12be7..cd564c709115 100644
> >> --- a/drivers/gpu/drm/i915/i915_pmu.c
> >> +++ b/drivers/gpu/drm/i915/i915_pmu.c
> >> @@ -27,8 +27,6 @@
> >>           BIT(I915_SAMPLE_WAIT) | \
> >>           BIT(I915_SAMPLE_SEMA))
> >>   
> >> -#define ENGINE_SAMPLE_BITS (1 << I915_PMU_SAMPLE_BITS)
> >> -
> >>   static cpumask_t i915_pmu_cpumask;
> >>   static unsigned int i915_pmu_target_cpu = -1;
> >>   
> >> @@ -57,12 +55,39 @@ static bool is_engine_config(u64 config)
> >>          return config < __I915_PMU_OTHER(0);
> >>   }
> >>   
> >> -static unsigned int config_enabled_bit(u64 config)
> >> +static unsigned int is_tracked_config(const u64 config)
> >>   {
> >> -       if (is_engine_config(config))
> >> +       unsigned int val;
> >> +
> >> +       switch (config) {
> >> +       case I915_PMU_ACTUAL_FREQUENCY:
> >> +               val =  __I915_PMU_ACTUAL_FREQUENCY_ENABLED;
> >> +               break;
> >> +       case I915_PMU_REQUESTED_FREQUENCY:
> >> +               val = __I915_PMU_REQUESTED_FREQUENCY_ENABLED;
> >> +               break;
> >> +       case I915_PMU_RC6_RESIDENCY:
> >> +               val = __I915_PMU_RC6_RESIDENCY_ENABLED;
> >> +               break;
> >> +       default:
> >> +               return 0;
> >> +       }
> >> +
> >> +       return val + 1;
> >> +}
> >> +
> >> +static unsigned int config_enabled_bit(const u64 config)
> >> +{
> >> +       if (is_engine_config(config)) {
> >>                  return engine_config_sample(config);
> >> -       else
> >> -               return ENGINE_SAMPLE_BITS + (config - __I915_PMU_OTHER(0));
> >> +       } else {
> >> +               unsigned int bit = is_tracked_config(config);
> >> +
> >> +               if (bit)
> >> +                       return I915_ENGINE_SAMPLE_COUNT + bit - 1;
> >> +               else
> >> +                       return -1;
> >> +       }
> >>   }
> >>   
> >>   static u64 config_enabled_mask(u64 config)
> >> @@ -80,10 +105,15 @@ static unsigned int event_enabled_bit(struct perf_event *event)
> >>          return config_enabled_bit(event->attr.config);
> >>   }
> >>   
> >> +static bool event_read_needs_wakeref(const struct perf_event *event)
> >> +{
> >> +       return event->attr.config == I915_PMU_RC6_RESIDENCY;
> >> +}
> >> +
> >>   static bool pmu_needs_timer(struct i915_pmu *pmu, bool gpu_active)
> >>   {
> >>          struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu);
> >> -       u64 enable;
> >> +       u32 enable;
> >>   
> >>          /*
> >>           * Only some counters need the sampling timer.
> >> @@ -627,12 +657,19 @@ static void i915_pmu_enable(struct perf_event *event)
> >>   {
> >>          struct drm_i915_private *i915 =
> >>                  container_of(event->pmu, typeof(*i915), pmu.base);
> >> -       unsigned int bit = event_enabled_bit(event);
> >> +       bool need_wakeref = event_read_needs_wakeref(event);
> >>          struct i915_pmu *pmu = &i915->pmu;
> >> -       intel_wakeref_t wakeref;
> >> +       intel_wakeref_t wakeref = 0;
> >>          unsigned long flags;
> >> +       unsigned int bit;
> >> +
> >> +       if (need_wakeref)
> >> +               wakeref = intel_runtime_pm_get(&i915->runtime_pm);
> >> +
> >> +       bit = event_enabled_bit(event);
> >> +       if (bit == -1)
> >> +               goto update;
> >>   
> >> -       wakeref = intel_runtime_pm_get(&i915->runtime_pm);
> >>          spin_lock_irqsave(&pmu->lock, flags);
> > 
> > What are we taking a wakeref here for?
> > 
> > Looks just to be __get_rc6. Do we need to update the sample at all?
> 
> Yes, so __get_rc6 can record the start state. But if you have seen it 
> called from irq context then obviously it is not safe.. Just no idea why 
> we haven't hit it so far. Does perf_pmu need a more evil subtest?

I haven't figured out why CI hasn't picked it up yet, but dg1 does

<3> [134.304493] BUG: sleeping function called from invalid context at drivers/base/power/runtime.c:1074
<3> [134.304638] in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 1117, name: dmesg
<4> [134.304656] 4 locks held by dmesg/1117:
<4> [134.304664]  #0: ffff88847cf375b0 (&f->f_pos_lock){+.+.}-{3:3}, at: __fdget_pos+0x45/0x50
<4> [134.304691]  #1: ffff8884a58c9430 (sb_writers#3){.+.+}-{0:0}, at: vfs_write+0x16a/0x230
<4> [134.304715]  #2: ffff8884a5573358 (&sb->s_type->i_mutex_key#14){+.+.}-{3:3}, at: ext4_buffered_write_iter+0x2e/0x140
<4> [134.304736]  #3: ffffe8ffffa353d0 (&cpuctx_lock){-...}-{2:2}, at: __perf_install_in_context+0x41/0x2c0
<4> [134.304758] irq event stamp: 18348534
<4> [134.304771] hardirqs last  enabled at (18348533): [<ffffffff812b76d7>] __slab_alloc.isra.84.constprop.93+0x87/0x90
<4> [134.304785] hardirqs last disabled at (18348534): [<ffffffff81b5bd6d>] irqentry_enter+0x1d/0x50
<4> [134.304796] softirqs last  enabled at (18343298): [<ffffffff81e0037f>] __do_softirq+0x37f/0x4cb
<4> [134.304806] softirqs last disabled at (18343291): [<ffffffff81c00f72>] asm_call_irq_on_stack+0x12/0x20
<3> [134.304813] Preemption disabled at:
<3> [134.304821] [<ffffffff81113e97>] irq_enter_rcu+0x27/0x80
<4> [134.304847] CPU: 0 PID: 1117 Comm: dmesg Not tainted 5.9.0-gbd5b876be63e-DII_3243_dg1+ #1
<4> [134.304856] Hardware name: Gigabyte Technology Co., Ltd. GB-Z390 Garuda/GB-Z390 Garuda-CF, BIOS IG1c 11/19/2019
<4> [134.304863] Call Trace:
<4> [134.304872]  <IRQ>
<4> [134.304888]  dump_stack+0x77/0xa0
<4> [134.304907]  ___might_sleep.cold.107+0xf2/0x106
<4> [134.304930]  __pm_runtime_resume+0x75/0x80
<4> [134.305073]  __intel_runtime_pm_get+0x19/0x80 [i915]
<4> [134.305227]  i915_pmu_enable+0x1b7/0x280 [i915]
<4> [134.305385]  i915_pmu_event_add+0x21/0x40 [i915]
<4> [134.305402]  event_sched_in.isra.145+0xe0/0x270
<4> [134.305427]  merge_sched_in+0x192/0x3e0
<4> [134.305458]  visit_groups_merge.constprop.150+0x140/0x4d0
<4> [134.305471]  ? sched_clock+0x5/0x10
<4> [134.305498]  ctx_sched_in+0xf9/0x250
<4> [134.305526]  ctx_resched+0x58/0x90
<4> [134.305546]  __perf_install_in_context+0x21d/0x2c0
<4> [134.305570]  remote_function+0x44/0x50
<4> [134.305589]  flush_smp_call_function_queue+0x135/0x1c0
<4> [134.305608]  __sysvec_call_function_single+0x3f/0x1e0
<4> [134.305620]  asm_call_irq_on_stack+0x12/0x20
<4> [134.305631]  </IRQ>
<4> [134.305645]  sysvec_call_function_single+0xc1/0xe0
<4> [134.305661]  asm_sysvec_call_function_single+0x12/0x20
-Chris


More information about the Intel-gfx mailing list