[RFC] drm/msm: Add UABI to request perfcntr usage

Akhil P Oommen quic_akhilpo at quicinc.com
Mon Dec 16 16:54:49 UTC 2024


On 12/13/2024 10:40 PM, Antonino Maniscalco wrote:
> On 12/13/24 5:50 PM, Akhil P Oommen wrote:
>> On 12/12/2024 9:44 PM, Antonino Maniscalco wrote:
>>> On 12/12/24 4:58 PM, Akhil P Oommen wrote:
>>>> On 12/5/2024 10:24 PM, Rob Clark wrote:
>>>>> From: Rob Clark <robdclark at chromium.org>
>>>>>
>>>>> Performance counter usage falls into two categories:
>>>>>
>>>>> 1. Local usage, where the counter configuration, start, and end read
>>>>>      happen within (locally to) a single SUBMIT.  In this case,
>>>>> there is
>>>>>      no dependency on counter configuration or values between submits,
>>>>> and
>>>>>      in fact counters are normally cleared on context switches,
>>>>> making it
>>>>>      impossible to rely on cross-submit state.
>>>>>
>>>>> 2. Global usage, where a single privilaged daemon/process is sampling
>>>>>      counter values across all processes for profiling.
>>>>>
>>>>> The two categories are mutually exclusive.  While you can have many
>>>>> processes making local counter usage, you cannot combine global and
>>>>> local usage without the two stepping on each others feet (by changing
>>>>> counter configuration).
>>>>>
>>>>> For global counter usage, there is already a SYSPROF param (since
>>>>> global
>>>>> counter usage requires disabling counter clearing on context switch).
>>>>> This patch adds a REQ_CNTRS param to request local counter usage.  If
>>>>> one or more processes has requested counter usage, then a SYSPROF
>>>>> request will fail with -EBUSY.  And if SYSPROF is active, then
>>>>> REQ_CNTRS
>>>>> will fail with -EBUSY, maintaining the mutual exclusivity.
>>>>>
>>>>> This is purely an advisory interface to help coordinate userspace.
>>>>> There is no real means of enforcement, but the worst that can
>>>>> happen if
>>>>> userspace ignores a REQ_CNTRS failure is that you'll get nonsense
>>>>> profiling data.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark at chromium.org>
>>>>> ---
>>>>> kgsl takes a different approach, which involves a lot more UABI for
>>>>> assigning counters to different processes.  But I think by taking
>>>>> advantage of the fact that mesa (freedreno+turnip) reconfigure the
>>>>> counters they need in each SUBMIT, for their respective gl/vk perf-
>>>>> counter extensions, we can take this simpler approach.
>>>>
>>>> KGSL's approach is preemption and ifpc safe (also whatever HW changes
>>>> that will come up in future generations). How will we ensure that here?
>>>>
>>>> I have plans to bring up IFPC support in near future. Also, I
>>>> brought up
>>>> this point during preemption series. But from the responses, I felt
>>>> that
>>>> profiling was not considered a serious usecase. Still I wonder how the
>>>> perfcounter extensions work accurately with preemption.
>>>
>>> So back then I implemented the postamble IB to clear perf counters and
>>> that gets disabled when sysprof (so global usage) is happening. The
>>> kernel is oblivious to "Local isage" of profiling but in that case
>>> really what we want to do is disable preemption which in my
>>> understanding can be done from userspace with a PKT. In my understanding
>>> this had us covered for all usecases.
>>
>> I think this wasn't mentioned at that time. Which UMD PKT in a6x+ did
>> you mean?
> 
> Ah, I thought it wasmentioned, sorry.
> The packet I was referring to is:
>     <doc> Make next dword 1 to disable preemption, 0 to re-enable it. </
> doc>
>     <value name="CP_PREEMPT_DISABLE" value="0x6c" variants="A6XX"/>

Ah! Okay. I think this packet is not used by the downstream blob. IMO,
disabling preemption is still a suboptimal solution.

> 
> BTW you mentioned wanting to look into IFPC. Since I too wanted to look
> into implementing it wonder if you could let me know when you planned on
> working on it.

I have few patches in progress. Nothing final yet and need verification
on the hw side. Also, I need to do some housekeeping here to debug gmu
issues since IFPC increases the probability of those a lot.

I will try to send out the patches very soon.

-Akhil.

> 
>>
>> -Akhil.
>>
>>>
>>> So what would you expect instead we should do kernel side to make
>>> profiling preemption safe?
>>>
>>>>
>>>> -Akhil
>>>>
>>>>>
>>>>>    drivers/gpu/drm/msm/adreno/adreno_gpu.c |  2 +
>>>>>    drivers/gpu/drm/msm/msm_drv.c           |  5 ++-
>>>>>    drivers/gpu/drm/msm/msm_gpu.c           |  1 +
>>>>>    drivers/gpu/drm/msm/msm_gpu.h           | 29 +++++++++++++-
>>>>>    drivers/gpu/drm/msm/msm_submitqueue.c   | 52 +++++++++++++++++++
>>>>> +++++-
>>>>>    include/uapi/drm/msm_drm.h              |  1 +
>>>>>    6 files changed, 85 insertions(+), 5 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/
>>>>> drm/msm/adreno/adreno_gpu.c
>>>>> index 31bbf2c83de4..f688e37059b8 100644
>>>>> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
>>>>> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
>>>>> @@ -441,6 +441,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct
>>>>> msm_file_private *ctx,
>>>>>            if (!capable(CAP_SYS_ADMIN))
>>>>>                return UERR(EPERM, drm, "invalid permissions");
>>>>>            return msm_file_private_set_sysprof(ctx, gpu, value);
>>>>> +    case MSM_PARAM_REQ_CNTRS:
>>>>> +        return msm_file_private_request_counters(ctx, gpu, value);
>>>>>        default:
>>>>>            return UERR(EINVAL, drm, "%s: invalid param: %u", gpu-
>>>>>> name, param);
>>>>>        }
>>>>> diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/
>>>>> msm_drv.c
>>>>> index 6416d2cb4efc..bf8314ff4a25 100644
>>>>> --- a/drivers/gpu/drm/msm/msm_drv.c
>>>>> +++ b/drivers/gpu/drm/msm/msm_drv.c
>>>>> @@ -377,9 +377,12 @@ static void msm_postclose(struct drm_device
>>>>> *dev, struct drm_file *file)
>>>>>         * It is not possible to set sysprof param to non-zero if gpu
>>>>>         * is not initialized:
>>>>>         */
>>>>> -    if (priv->gpu)
>>>>> +    if (ctx->sysprof)
>>>>>            msm_file_private_set_sysprof(ctx, priv->gpu, 0);
>>>>>    +    if (ctx->counters_requested)
>>>>> +        msm_file_private_request_counters(ctx, priv->gpu, 0);
>>>>> +
>>>>>        context_close(ctx);
>>>>>    }
>>>>>    diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/
>>>>> msm_gpu.c
>>>>> index 82f204f3bb8f..013b59ca3bb1 100644
>>>>> --- a/drivers/gpu/drm/msm/msm_gpu.c
>>>>> +++ b/drivers/gpu/drm/msm/msm_gpu.c
>>>>> @@ -991,6 +991,7 @@ int msm_gpu_init(struct drm_device *drm, struct
>>>>> platform_device *pdev,
>>>>>        gpu->nr_rings = nr_rings;
>>>>>          refcount_set(&gpu->sysprof_active, 1);
>>>>> +    refcount_set(&gpu->local_counters_active, 1);
>>>>>          return 0;
>>>>>    diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/
>>>>> msm_gpu.h
>>>>> index e25009150579..83c61e523b1b 100644
>>>>> --- a/drivers/gpu/drm/msm/msm_gpu.h
>>>>> +++ b/drivers/gpu/drm/msm/msm_gpu.h
>>>>> @@ -195,12 +195,28 @@ struct msm_gpu {
>>>>>        int nr_rings;
>>>>>          /**
>>>>> -     * sysprof_active:
>>>>> +     * @sysprof_active:
>>>>>         *
>>>>> -     * The count of contexts that have enabled system profiling.
>>>>> +     * The count of contexts that have enabled system profiling plus
>>>>> one.
>>>>> +     *
>>>>> +     * Note: refcount_t does not like 0->1 transitions.. we want to
>>>>> keep
>>>>> +     * the under/overflow checks that refcount_t provides, but allow
>>>>> +     * multiple on/off transitions so we track the logical value
>>>>> plus one.)
>>>>>         */
>>>>>        refcount_t sysprof_active;
>>>>>    +    /**
>>>>> +     * @local_counters_active:
>>>>> +     *
>>>>> +     * The count of contexts that have requested local (intra-submit)
>>>>> +     * performance counter usage plus one.
>>>>> +     *
>>>>> +     * Note: refcount_t does not like 0->1 transitions.. we want to
>>>>> keep
>>>>> +     * the under/overflow checks that refcount_t provides, but allow
>>>>> +     * multiple on/off transitions so we track the logical value
>>>>> plus one.)
>>>>> +     */
>>>>> +    refcount_t local_counters_active;
>>>>> +
>>>>>        /**
>>>>>         * lock:
>>>>>         *
>>>>> @@ -383,6 +399,13 @@ struct msm_file_private {
>>>>>         */
>>>>>        int sysprof;
>>>>>    +    /**
>>>>> +     * @counters_requested:
>>>>> +     *
>>>>> +     * Has the context requested local perfcntr usage.
>>>>> +     */
>>>>> +    bool counters_requested;
>>>>> +
>>>>>        /**
>>>>>         * comm: Overridden task comm, see MSM_PARAM_COMM
>>>>>         *
>>>>> @@ -626,6 +649,8 @@ void msm_submitqueue_destroy(struct kref *kref);
>>>>>      int msm_file_private_set_sysprof(struct msm_file_private *ctx,
>>>>>                     struct msm_gpu *gpu, int sysprof);
>>>>> +int msm_file_private_request_counters(struct msm_file_private *ctx,
>>>>> +                      struct msm_gpu *gpu, int reqcntrs);
>>>>>    void __msm_file_private_destroy(struct kref *kref);
>>>>>      static inline void msm_file_private_put(struct msm_file_private
>>>>> *ctx)
>>>>> diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/
>>>>> msm/msm_submitqueue.c
>>>>> index 7fed1de63b5d..1e1e21e6f7ae 100644
>>>>> --- a/drivers/gpu/drm/msm/msm_submitqueue.c
>>>>> +++ b/drivers/gpu/drm/msm/msm_submitqueue.c
>>>>> @@ -10,6 +10,15 @@
>>>>>    int msm_file_private_set_sysprof(struct msm_file_private *ctx,
>>>>>                     struct msm_gpu *gpu, int sysprof)
>>>>>    {
>>>>> +    int ret = 0;
>>>>> +
>>>>> +    mutex_lock(&gpu->lock);
>>>>> +
>>>>> +    if (sysprof && (refcount_read(&gpu->local_counters_active) >
>>>>> 1)) {
>>>>> +        ret = UERR(EBUSY, gpu->dev, "Local counter usage active");
>>>>> +        goto out_unlock;
>>>>> +    }
>>>>> +
>>>>>        /*
>>>>>         * Since pm_runtime and sysprof_active are both refcounts, we
>>>>>         * call apply the new value first, and then unwind the previous
>>>>> @@ -18,7 +27,8 @@ int msm_file_private_set_sysprof(struct
>>>>> msm_file_private *ctx,
>>>>>          switch (sysprof) {
>>>>>        default:
>>>>> -        return UERR(EINVAL, gpu->dev, "Invalid sysprof: %d",
>>>>> sysprof);
>>>>> +        ret = UERR(EINVAL, gpu->dev, "Invalid sysprof: %d", sysprof);
>>>>> +        goto out_unlock;
>>>>>        case 2:
>>>>>            pm_runtime_get_sync(&gpu->pdev->dev);
>>>>>            fallthrough;
>>>>> @@ -43,7 +53,45 @@ int msm_file_private_set_sysprof(struct
>>>>> msm_file_private *ctx,
>>>>>          ctx->sysprof = sysprof;
>>>>>    -    return 0;
>>>>> +out_unlock:
>>>>> +    mutex_unlock(&gpu->lock);
>>>>> +
>>>>> +    return ret;
>>>>> +}
>>>>> +
>>>>> +int msm_file_private_request_counters(struct msm_file_private *ctx,
>>>>> +                      struct msm_gpu *gpu, int reqctrs)
>>>>> +{
>>>>> +    int ret = 0;
>>>>> +
>>>>> +    mutex_lock(&gpu->lock);
>>>>> +
>>>>> +    if (reqctrs && (refcount_read(&gpu->sysprof_active) > 1)) {
>>>>> +        ret = UERR(EBUSY, gpu->dev, "System profiling active");
>>>>> +        goto out_unlock;
>>>>> +    }
>>>>> +
>>>>> +    if (reqctrs) {
>>>>> +        if (ctx->counters_requested) {
>>>>> +            ret = UERR(EINVAL, gpu->dev, "Already requested");
>>>>> +            goto out_unlock;
>>>>> +        }
>>>>> +
>>>>> +        ctx->counters_requested = true;
>>>>> +        refcount_inc(&gpu->local_counters_active);
>>>>> +    } else {
>>>>> +        if (!ctx->counters_requested) {
>>>>> +            ret = UERR(EINVAL, gpu->dev, "Not requested");
>>>>> +            goto out_unlock;
>>>>> +        }
>>>>> +        refcount_dec(&gpu->local_counters_active);
>>>>> +        ctx->counters_requested = false;
>>>>> +    }
>>>>> +
>>>>> +out_unlock:
>>>>> +    mutex_unlock(&gpu->lock);
>>>>> +
>>>>> +    return ret;
>>>>>    }
>>>>>      void __msm_file_private_destroy(struct kref *kref)
>>>>> diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
>>>>> index 2342cb90857e..ae7fb355e4a1 100644
>>>>> --- a/include/uapi/drm/msm_drm.h
>>>>> +++ b/include/uapi/drm/msm_drm.h
>>>>> @@ -91,6 +91,7 @@ struct drm_msm_timespec {
>>>>>    #define MSM_PARAM_UBWC_SWIZZLE 0x12 /* RO */
>>>>>    #define MSM_PARAM_MACROTILE_MODE 0x13 /* RO */
>>>>>    #define MSM_PARAM_UCHE_TRAP_BASE 0x14 /* RO */
>>>>> +#define MSM_PARAM_REQ_CNTRS  0x15 /* WO: request "local" (intra-
>>>>> submit) perfcntr usage  */
>>>>>      /* For backwards compat.  The original support for preemption was
>>>>> based on
>>>>>     * a single ring per priority level so # of priority levels equals
>>>>> the #
>>>>
>>>
>>>
>>> Best regards,
>>
> 
> 
> Best regards,



More information about the Freedreno mailing list