From: Rob Clark <hidden> Date: 2021-08-07 18:33:58
From: Rob Clark <redacted>
Based on discussion from a previous series[1] to add a "boost" mechanism
when, for example, vblank deadlines are missed. Instead of a boost
callback, this approach adds a way to set a deadline on the fence, by
which the waiter would like to see the fence signalled.
I've not yet had a chance to re-work the drm/msm part of this, but
wanted to send this out as an RFC in case I don't have a chance to
finish the drm/msm part this week.
Original description:
In some cases, like double-buffered rendering, missing vblanks can
trick the GPU into running at a lower frequence, when really we
want to be running at a higher frequency to not miss the vblanks
in the first place.
This is partially inspired by a trick i915 does, but implemented
via dma-fence for a couple of reasons:
1) To continue to be able to use the atomic helpers
2) To support cases where display and gpu are different drivers
[1] https://patchwork.freedesktop.org/series/90331/
v1: https://patchwork.freedesktop.org/series/93035/
v2: Move filtering out of later deadlines to fence implementation
to avoid increasing the size of dma_fence
Rob Clark (5):
dma-fence: Add deadline awareness
drm/vblank: Add helper to get next vblank time
drm/atomic-helper: Set fence deadline for vblank
drm/scheduler: Add fence deadline support
drm/msm: Add deadline based boost support
drivers/dma-buf/dma-fence.c | 20 +++++++
drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++
drivers/gpu/drm/drm_vblank.c | 31 ++++++++++
drivers/gpu/drm/msm/msm_fence.c | 76 +++++++++++++++++++++++++
drivers/gpu/drm/msm/msm_fence.h | 20 +++++++
drivers/gpu/drm/msm/msm_gpu.h | 1 +
drivers/gpu/drm/msm/msm_gpu_devfreq.c | 20 +++++++
drivers/gpu/drm/scheduler/sched_fence.c | 25 ++++++++
drivers/gpu/drm/scheduler/sched_main.c | 3 +
include/drm/drm_vblank.h | 1 +
include/drm/gpu_scheduler.h | 6 ++
include/linux/dma-fence.h | 16 ++++++
12 files changed, 255 insertions(+)
--
2.31.1
From: Rob Clark <hidden> Date: 2021-08-07 18:34:01
From: Rob Clark <redacted>
Add a way to hint to the fence signaler of an upcoming deadline, such as
vblank, which the fence waiter would prefer not to miss. This is to aid
the fence signaler in making power management decisions, like boosting
frequency as the deadline approaches and awareness of missing deadlines
so that can be factored in to the frequency scaling.
v2: Drop dma_fence::deadline and related logic to filter duplicate
deadlines, to avoid increasing dma_fence size. The fence-context
implementation will need similar logic to track deadlines of all
the fences on the same timeline. [ckoenig]
Signed-off-by: Rob Clark <redacted>
---
drivers/dma-buf/dma-fence.c | 20 ++++++++++++++++++++
include/linux/dma-fence.h | 16 ++++++++++++++++
2 files changed, 36 insertions(+)
@@ -99,6 +99,7 @@ enum dma_fence_flag_bits {DMA_FENCE_FLAG_SIGNALED_BIT,DMA_FENCE_FLAG_TIMESTAMP_BIT,DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,+DMA_FENCE_FLAG_HAS_DEADLINE_BIT,DMA_FENCE_FLAG_USER_BITS,/* must always be last member */};
From: Rob Clark <hidden> Date: 2021-08-07 18:34:14
From: Rob Clark <redacted>
As the finished fence is the one that is exposed to userspace, and
therefore the one that other operations, like atomic update, would
block on, we need to propagate the deadline from from the finished
fence to the actual hw fence.
Signed-off-by: Rob Clark <redacted>
---
drivers/gpu/drm/scheduler/sched_fence.c | 25 +++++++++++++++++++++++++
drivers/gpu/drm/scheduler/sched_main.c | 3 +++
include/drm/gpu_scheduler.h | 6 ++++++
3 files changed, 34 insertions(+)
@@ -128,6 +128,30 @@ static void drm_sched_fence_release_finished(struct dma_fence *f)dma_fence_put(&fence->scheduled);}+staticvoiddrm_sched_fence_set_deadline_finished(structdma_fence*f,+ktime_tdeadline)+{+structdrm_sched_fence*fence=to_drm_sched_fence(f);+unsignedlongflags;++spin_lock_irqsave(&fence->lock,flags);++/* If we already have an earlier deadline, keep it: */+if(test_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags)&&+ktime_before(fence->deadline,deadline)){+spin_unlock_irqrestore(&fence->lock,flags);+return;+}++fence->deadline=deadline;+set_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags);++spin_unlock_irqrestore(&fence->lock,flags);++if(fence->parent)+dma_fence_set_deadline(fence->parent,deadline);+}+staticconststructdma_fence_opsdrm_sched_fence_ops_scheduled={.get_driver_name=drm_sched_fence_get_driver_name,.get_timeline_name=drm_sched_fence_get_timeline_name,
@@ -8,6 +8,37 @@#include"msm_drv.h"#include"msm_fence.h"+#include"msm_gpu.h"++staticinlineboolfence_completed(structmsm_fence_context*fctx,uint32_tfence);++staticstructmsm_gpu*fctx2gpu(structmsm_fence_context*fctx)+{+structmsm_drm_private*priv=fctx->dev->dev_private;+returnpriv->gpu;+}++staticenumhrtimer_restartdeadline_timer(structhrtimer*t)+{+structmsm_fence_context*fctx=container_of(t,+structmsm_fence_context,deadline_timer);++kthread_queue_work(fctx2gpu(fctx)->worker,&fctx->deadline_work);++returnHRTIMER_NORESTART;+}++staticvoiddeadline_work(structkthread_work*work)+{+structmsm_fence_context*fctx=container_of(work,+structmsm_fence_context,deadline_work);++/* If deadline fence has already passed, nothing to do: */+if(fence_completed(fctx,fctx->next_deadline_fence))+return;++msm_devfreq_boost(fctx2gpu(fctx),2);+}structmsm_fence_context*
@@ -50,6 +50,26 @@ struct msm_fence_context {volatileuint32_t*fenceptr;spinlock_tspinlock;++/*+*TODOthisdoesn'treallydealwithmultipledeadlines,like+*ifuserspacegotmultipleframesahead..OTOHatomicupdates+*don'tqueue,somaybethatisok+*/++/** next_deadline: Time of next deadline */+ktime_tnext_deadline;++/**+*next_deadline_fence:+*+*Fencevaluefornextpendingdeadline.Thedeadlinetimeris+*canceledwhenthisfenceissignaled.+*/+uint32_tnext_deadline_fence;++structhrtimerdeadline_timer;+structkthread_workdeadline_work;};structmsm_fence_context*msm_fence_context_alloc(structdrm_device*dev,
From: Christian König <ckoenig.leichtzumerken@gmail.com> Date: 2021-08-16 10:14:41
Am 07.08.21 um 20:37 schrieb Rob Clark:
quoted hunk
From: Rob Clark <redacted>
As the finished fence is the one that is exposed to userspace, and
therefore the one that other operations, like atomic update, would
block on, we need to propagate the deadline from from the finished
fence to the actual hw fence.
Signed-off-by: Rob Clark <redacted>
---
drivers/gpu/drm/scheduler/sched_fence.c | 25 +++++++++++++++++++++++++
drivers/gpu/drm/scheduler/sched_main.c | 3 +++
include/drm/gpu_scheduler.h | 6 ++++++
3 files changed, 34 insertions(+)
@@ -128,6 +128,30 @@ static void drm_sched_fence_release_finished(struct dma_fence *f)dma_fence_put(&fence->scheduled);}+staticvoiddrm_sched_fence_set_deadline_finished(structdma_fence*f,+ktime_tdeadline)+{+structdrm_sched_fence*fence=to_drm_sched_fence(f);+unsignedlongflags;++spin_lock_irqsave(&fence->lock,flags);++/* If we already have an earlier deadline, keep it: */+if(test_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags)&&+ktime_before(fence->deadline,deadline)){+spin_unlock_irqrestore(&fence->lock,flags);+return;+}++fence->deadline=deadline;+set_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags);++spin_unlock_irqrestore(&fence->lock,flags);++if(fence->parent)+dma_fence_set_deadline(fence->parent,deadline);+}+staticconststructdma_fence_opsdrm_sched_fence_ops_scheduled={.get_driver_name=drm_sched_fence_get_driver_name,.get_timeline_name=drm_sched_fence_get_timeline_name,
From: Christian König <ckoenig.leichtzumerken@gmail.com> Date: 2021-08-16 10:15:43
Am 07.08.21 um 20:37 schrieb Rob Clark:
From: Rob Clark <redacted>
Add a way to hint to the fence signaler of an upcoming deadline, such as
vblank, which the fence waiter would prefer not to miss. This is to aid
the fence signaler in making power management decisions, like boosting
frequency as the deadline approaches and awareness of missing deadlines
so that can be factored in to the frequency scaling.
v2: Drop dma_fence::deadline and related logic to filter duplicate
deadlines, to avoid increasing dma_fence size. The fence-context
implementation will need similar logic to track deadlines of all
the fences on the same timeline. [ckoenig]
Signed-off-by: Rob Clark <redacted>
Reviewed-by: Christian König <christian.koenig@amd.com>
@@ -99,6 +99,7 @@ enum dma_fence_flag_bits {DMA_FENCE_FLAG_SIGNALED_BIT,DMA_FENCE_FLAG_TIMESTAMP_BIT,DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,+DMA_FENCE_FLAG_HAS_DEADLINE_BIT,DMA_FENCE_FLAG_USER_BITS,/* must always be last member */};
From: Christian König <christian.koenig@amd.com> Date: 2021-08-16 10:17:19
The general approach seems to make sense now I think.
One minor thing which I'm missing is adding support for this to the
dma_fence_array and dma_fence_chain containers.
Regards,
Christian.
Am 07.08.21 um 20:37 schrieb Rob Clark:
From: Rob Clark <redacted>
Based on discussion from a previous series[1] to add a "boost" mechanism
when, for example, vblank deadlines are missed. Instead of a boost
callback, this approach adds a way to set a deadline on the fence, by
which the waiter would like to see the fence signalled.
I've not yet had a chance to re-work the drm/msm part of this, but
wanted to send this out as an RFC in case I don't have a chance to
finish the drm/msm part this week.
Original description:
In some cases, like double-buffered rendering, missing vblanks can
trick the GPU into running at a lower frequence, when really we
want to be running at a higher frequency to not miss the vblanks
in the first place.
This is partially inspired by a trick i915 does, but implemented
via dma-fence for a couple of reasons:
1) To continue to be able to use the atomic helpers
2) To support cases where display and gpu are different drivers
[1] https://patchwork.freedesktop.org/series/90331/
v1: https://patchwork.freedesktop.org/series/93035/
v2: Move filtering out of later deadlines to fence implementation
to avoid increasing the size of dma_fence
Rob Clark (5):
dma-fence: Add deadline awareness
drm/vblank: Add helper to get next vblank time
drm/atomic-helper: Set fence deadline for vblank
drm/scheduler: Add fence deadline support
drm/msm: Add deadline based boost support
drivers/dma-buf/dma-fence.c | 20 +++++++
drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++
drivers/gpu/drm/drm_vblank.c | 31 ++++++++++
drivers/gpu/drm/msm/msm_fence.c | 76 +++++++++++++++++++++++++
drivers/gpu/drm/msm/msm_fence.h | 20 +++++++
drivers/gpu/drm/msm/msm_gpu.h | 1 +
drivers/gpu/drm/msm/msm_gpu_devfreq.c | 20 +++++++
drivers/gpu/drm/scheduler/sched_fence.c | 25 ++++++++
drivers/gpu/drm/scheduler/sched_main.c | 3 +
include/drm/drm_vblank.h | 1 +
include/drm/gpu_scheduler.h | 6 ++
include/linux/dma-fence.h | 16 ++++++
12 files changed, 255 insertions(+)
From: Daniel Vetter <hidden> Date: 2021-08-16 15:38:43
On Mon, Aug 16, 2021 at 12:14:35PM +0200, Christian König wrote:
Am 07.08.21 um 20:37 schrieb Rob Clark:
quoted
From: Rob Clark <redacted>
As the finished fence is the one that is exposed to userspace, and
therefore the one that other operations, like atomic update, would
block on, we need to propagate the deadline from from the finished
fence to the actual hw fence.
Signed-off-by: Rob Clark <redacted>
I guess you're already letting the compositor run at a higher gpu priority
so that your deadline'd drm_sched_job isn't stuck behind the app rendering
the next frame?
I'm not sure whether you wire that one up as part of the conversion to
drm/sched. Without that I think we might need to ponder how we can do a
prio-boost for these, e.g. within a scheduling class we pick the jobs with
the nearest deadline first, before we pick others.
-Daniel
@@ -128,6 +128,30 @@ static void drm_sched_fence_release_finished(struct dma_fence *f)dma_fence_put(&fence->scheduled);}+staticvoiddrm_sched_fence_set_deadline_finished(structdma_fence*f,+ktime_tdeadline)+{+structdrm_sched_fence*fence=to_drm_sched_fence(f);+unsignedlongflags;++spin_lock_irqsave(&fence->lock,flags);++/* If we already have an earlier deadline, keep it: */+if(test_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags)&&+ktime_before(fence->deadline,deadline)){+spin_unlock_irqrestore(&fence->lock,flags);+return;+}++fence->deadline=deadline;+set_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags);++spin_unlock_irqrestore(&fence->lock,flags);++if(fence->parent)+dma_fence_set_deadline(fence->parent,deadline);+}+staticconststructdma_fence_opsdrm_sched_fence_ops_scheduled={.get_driver_name=drm_sched_fence_get_driver_name,.get_timeline_name=drm_sched_fence_get_timeline_name,
From: Rob Clark <hidden> Date: 2021-08-16 22:21:14
On Mon, Aug 16, 2021 at 8:38 AM Daniel Vetter [off-list ref] wrote:
On Mon, Aug 16, 2021 at 12:14:35PM +0200, Christian König wrote:
quoted
Am 07.08.21 um 20:37 schrieb Rob Clark:
quoted
From: Rob Clark <redacted>
As the finished fence is the one that is exposed to userspace, and
therefore the one that other operations, like atomic update, would
block on, we need to propagate the deadline from from the finished
fence to the actual hw fence.
Signed-off-by: Rob Clark <redacted>
I guess you're already letting the compositor run at a higher gpu priority
so that your deadline'd drm_sched_job isn't stuck behind the app rendering
the next frame?
With the scheduler conversion we do have multiple priorities (provided
by scheduler) for all generations.. but not yet preemption for all
generations.
But the most common use-case where we need this ends up being display
composition (either fullscreen app/game or foreground app/game
composited via overlay) so I haven't thought too much about the next
step of boosting job priority. I might leave that to someone who
already has preemption wired up ;-)
BR,
-R
I'm not sure whether you wire that one up as part of the conversion to
drm/sched. Without that I think we might need to ponder how we can do a
prio-boost for these, e.g. within a scheduling class we pick the jobs with
the nearest deadline first, before we pick others.
-Daniel
@@ -128,6 +128,30 @@ static void drm_sched_fence_release_finished(struct dma_fence *f)dma_fence_put(&fence->scheduled);}+staticvoiddrm_sched_fence_set_deadline_finished(structdma_fence*f,+ktime_tdeadline)+{+structdrm_sched_fence*fence=to_drm_sched_fence(f);+unsignedlongflags;++spin_lock_irqsave(&fence->lock,flags);++/* If we already have an earlier deadline, keep it: */+if(test_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags)&&+ktime_before(fence->deadline,deadline)){+spin_unlock_irqrestore(&fence->lock,flags);+return;+}++fence->deadline=deadline;+set_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags);++spin_unlock_irqrestore(&fence->lock,flags);++if(fence->parent)+dma_fence_set_deadline(fence->parent,deadline);+}+staticconststructdma_fence_opsdrm_sched_fence_ops_scheduled={.get_driver_name=drm_sched_fence_get_driver_name,.get_timeline_name=drm_sched_fence_get_timeline_name,
From: Rob Clark <hidden> Date: 2021-08-16 22:25:35
dma_fence_array looks simple enough, just propagate the deadline to
all children.
I guess dma_fence_chain is similar (ie. fence is signalled when all
children are signalled), the difference being simply that children are
added dynamically?
BR,
-R
On Mon, Aug 16, 2021 at 3:17 AM Christian König
[off-list ref] wrote:
The general approach seems to make sense now I think.
One minor thing which I'm missing is adding support for this to the
dma_fence_array and dma_fence_chain containers.
Regards,
Christian.
Am 07.08.21 um 20:37 schrieb Rob Clark:
quoted
From: Rob Clark <redacted>
Based on discussion from a previous series[1] to add a "boost" mechanism
when, for example, vblank deadlines are missed. Instead of a boost
callback, this approach adds a way to set a deadline on the fence, by
which the waiter would like to see the fence signalled.
I've not yet had a chance to re-work the drm/msm part of this, but
wanted to send this out as an RFC in case I don't have a chance to
finish the drm/msm part this week.
Original description:
In some cases, like double-buffered rendering, missing vblanks can
trick the GPU into running at a lower frequence, when really we
want to be running at a higher frequency to not miss the vblanks
in the first place.
This is partially inspired by a trick i915 does, but implemented
via dma-fence for a couple of reasons:
1) To continue to be able to use the atomic helpers
2) To support cases where display and gpu are different drivers
[1] https://patchwork.freedesktop.org/series/90331/
v1: https://patchwork.freedesktop.org/series/93035/
v2: Move filtering out of later deadlines to fence implementation
to avoid increasing the size of dma_fence
Rob Clark (5):
dma-fence: Add deadline awareness
drm/vblank: Add helper to get next vblank time
drm/atomic-helper: Set fence deadline for vblank
drm/scheduler: Add fence deadline support
drm/msm: Add deadline based boost support
drivers/dma-buf/dma-fence.c | 20 +++++++
drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++
drivers/gpu/drm/drm_vblank.c | 31 ++++++++++
drivers/gpu/drm/msm/msm_fence.c | 76 +++++++++++++++++++++++++
drivers/gpu/drm/msm/msm_fence.h | 20 +++++++
drivers/gpu/drm/msm/msm_gpu.h | 1 +
drivers/gpu/drm/msm/msm_gpu_devfreq.c | 20 +++++++
drivers/gpu/drm/scheduler/sched_fence.c | 25 ++++++++
drivers/gpu/drm/scheduler/sched_main.c | 3 +
include/drm/drm_vblank.h | 1 +
include/drm/gpu_scheduler.h | 6 ++
include/linux/dma-fence.h | 16 ++++++
12 files changed, 255 insertions(+)
From: Christian König <christian.koenig@amd.com> Date: 2021-08-17 09:01:29
Am 17.08.21 um 00:29 schrieb Rob Clark:
dma_fence_array looks simple enough, just propagate the deadline to
all children.
I guess dma_fence_chain is similar (ie. fence is signalled when all
children are signalled), the difference being simply that children are
added dynamically?
No, new chain nodes are always added at the top.
So when you have a dma_fence_chain as a starting point the linked nodes
after it will stay the same (except for garbage collection).
The tricky part is you can't use recursion, cause that would easily
exceed the kernels stack depth. So you need something similar to
dma_fence_chain_signaled().
Something like this should do it:
static bool dma_fence_chain_set_deadline(struct dma_fence *fence,
ktime_t deadline)
{
dma_fence_chain_for_each(fence, fence) {
struct dma_fence_chain *chain = to_dma_fence_chain(fence);
struct dma_fence *f = chain ? chain->fence : fence;
dma_fence_set_deadline(f, deadline);
}
}
Regards,
Christian.
BR,
-R
On Mon, Aug 16, 2021 at 3:17 AM Christian König
[off-list ref] wrote:
quoted
The general approach seems to make sense now I think.
One minor thing which I'm missing is adding support for this to the
dma_fence_array and dma_fence_chain containers.
Regards,
Christian.
Am 07.08.21 um 20:37 schrieb Rob Clark:
From: Daniel Vetter <hidden> Date: 2021-08-17 09:04:39
On Mon, Aug 16, 2021 at 03:25:20PM -0700, Rob Clark wrote:
On Mon, Aug 16, 2021 at 8:38 AM Daniel Vetter [off-list ref] wrote:
quoted
On Mon, Aug 16, 2021 at 12:14:35PM +0200, Christian König wrote:
quoted
Am 07.08.21 um 20:37 schrieb Rob Clark:
quoted
From: Rob Clark <redacted>
As the finished fence is the one that is exposed to userspace, and
therefore the one that other operations, like atomic update, would
block on, we need to propagate the deadline from from the finished
fence to the actual hw fence.
Signed-off-by: Rob Clark <redacted>
I guess you're already letting the compositor run at a higher gpu priority
so that your deadline'd drm_sched_job isn't stuck behind the app rendering
the next frame?
With the scheduler conversion we do have multiple priorities (provided
by scheduler) for all generations.. but not yet preemption for all
generations.
But the most common use-case where we need this ends up being display
composition (either fullscreen app/game or foreground app/game
composited via overlay) so I haven't thought too much about the next
step of boosting job priority. I might leave that to someone who
already has preemption wired up ;-)
Atm no-one, drm/sched isn't really aware that's a concept. I was more
thinking of just boosting that request as a first step. Maybe within the
same priority class we pick jobs with deadlines first, or something like
that.
Preempting is an entire can of worms on top.
-Daniel
BR,
-R
quoted
I'm not sure whether you wire that one up as part of the conversion to
drm/sched. Without that I think we might need to ponder how we can do a
prio-boost for these, e.g. within a scheduling class we pick the jobs with
the nearest deadline first, before we pick others.
-Daniel
@@ -128,6 +128,30 @@ static void drm_sched_fence_release_finished(struct dma_fence *f)dma_fence_put(&fence->scheduled);}+staticvoiddrm_sched_fence_set_deadline_finished(structdma_fence*f,+ktime_tdeadline)+{+structdrm_sched_fence*fence=to_drm_sched_fence(f);+unsignedlongflags;++spin_lock_irqsave(&fence->lock,flags);++/* If we already have an earlier deadline, keep it: */+if(test_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags)&&+ktime_before(fence->deadline,deadline)){+spin_unlock_irqrestore(&fence->lock,flags);+return;+}++fence->deadline=deadline;+set_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT,&f->flags);++spin_unlock_irqrestore(&fence->lock,flags);++if(fence->parent)+dma_fence_set_deadline(fence->parent,deadline);+}+staticconststructdma_fence_opsdrm_sched_fence_ops_scheduled={.get_driver_name=drm_sched_fence_get_driver_name,.get_timeline_name=drm_sched_fence_get_timeline_name,