All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
To: Boris Brezillon <boris.brezillon@collabora.com>
Cc: dri-devel@lists.freedesktop.org,
	Steven Price <steven.price@arm.com>,
	Liviu Dudau <liviu.dudau@arm.com>, Chia-I Wu <olvaffe@gmail.com>,
	Danilo Krummrich <dakr@kernel.org>,
	Matthew Brost <matthew.brost@intel.com>,
	Philipp Stanner <phasta@kernel.org>,
	kernel-dev@igalia.com
Subject: Re: [RFC 2/8] drm/panthor: Use separate workqueue for DRM scheduler
Date: Thu, 9 Jul 2026 15:33:01 +0100	[thread overview]
Message-ID: <ffc05a67-66ff-4e0a-98f3-a9e4e87af6b0@igalia.com> (raw)
In-Reply-To: <20260709141957.7f7664d0@fedora-2.home>


On 09/07/2026 13:19, Boris Brezillon wrote:
> On Thu, 9 Jul 2026 11:56:48 +0100
> Tvrtko Ursulin <tvrtko.ursulin@igalia.com> wrote:
> 
>> On 09/07/2026 07:45, Boris Brezillon wrote:
>>> On Wed, 8 Jul 2026 17:47:36 +0100
>>> Tvrtko Ursulin <tvrtko.ursulin@igalia.com> wrote:
>>>    
>>>> On 06/07/2026 15:18, Boris Brezillon wrote:
>>>>> On Mon, 6 Jul 2026 13:03:33 +0100
>>>>> Tvrtko Ursulin <tvrtko.ursulin@igalia.com> wrote:
>>>>>       
>>>>>> On 02/07/2026 16:31, Boris Brezillon wrote:
>>>>>>> On Thu,  2 Jul 2026 15:37:39 +0100
>>>>>>> Tvrtko Ursulin <tvrtko.ursulin@igalia.com> wrote:
>>>>>>>          
>>>>>>>> Currently an unordered workqueue is used for the DRM scheduler which means
>>>>>>>> its concurrency is externally managed, and given there is one scheduler
>>>>>>>> instance per userspace queue, that means workqueue management logic is
>>>>>>>> within its rights to spawn many kernel threads to submit their respective
>>>>>>>> jobs.
>>>>>>>>
>>>>>>>> Problem there is that all run job callbacks are serialized on the device
>>>>>>>> global mutex,
>>>>>>>
>>>>>>> I think we should address that instead, and either shorten the scope of
>>>>>>> the locked section, or make it so we don't make it a contention point
>>>>>>> for concurrent job submission from different contexts (with a rwsem
>>>>>>> instead of a lock, for instance).
>>>>>>>          
>>>>>>>> making the potential thread storm just causing lock
>>>>>>>> contention.
>>>>>>>>
>>>>>>>> If we add a separate ordered workqueue for the DRM scheduler integration
>>>>>>>> we can avoid this problem, since the ordered property directly expresses
>>>>>>>> the nature of the submission backend implementation.
>>>>>>>
>>>>>>> Yep, except that's not how it was meant to work. The goal was to allow
>>>>>>> contexts to submit their jobs concurrently to the FW. The only reason we
>>>>>>> take the lock is to:
>>>>>>>
>>>>>>> 1. make sure the context is still allowed to take jobs
>>>>>>> 2. kick the group scheduler if the context is not resident
>>>>>>>
>>>>>>> For #1, I believe we can come up with either a lockless solution, or a
>>>>>>> solution where the lock protecting the state belongs to the group
>>>>>>> instead of being externally protected by the device-wide scheduler lock.
>>>>>>>
>>>>>>> For #2, the rwsem approach, and narrowing down the locked section to
>>>>>>> just this part of the code should do the trick.
>>>>>>
>>>>>> Out of curiosity how much CPU side parallelism you think is required to
>>>>>> keep these GPUs fed? Both today (with the greater lock contention) and
>>>>>> in the future (with the reduced contention) I guess would be interesting
>>>>>> data points.
>>>>>
>>>>> The maximum is known: it's the amount of FW CSG slot we have available.
>>>>> I think the theoretical limit is 16, but IIRC, we never had more than 8
>>>>> exposed by the FW.
>>>>
>>>> Yeah but is it _really_ required to have 8 CPU threads feed these slots?
>>>
>>> 8 is indeed the number of SW slots, but there are multiple HW queues
>>> under the hood (and multiple cores to dispatch jobs to), making it so
>>> multiple GPU context can effectively be scheduled in parallel. This
>>> number is lower than the number of FW slots though (I need to check if
>>> it's exposed through some RO regs).
>>
>> Got it, thanks!
>>
>> So it is desirable to keep the FW slots filled with up to N jobs of each
>> queue type, where N is the HW parallelism of that queue type.
> 
> Jobs are one level below that. Each FW slot is attached a group
> (that's Arm's naming), which is basically backing a VkQueue. The group
> contains 1 to 8 queues (1 for fragment processing, 1 for geometry
> processing, 1 for compute, 1 for transfers, ...) which can run
> concurrently, and each of these queues has a ring buffer to push jobs
> to. The ring buffer size is customizable and determines the maximum
> number of jobs you can have queued before you have to wait for a ringbuf
> slot to become available again. I know I use the term "slot" a lot and
> it gets confusing, but FW slot (a way to make a group/VkQueue resident)
> must not be confused with a ringbuf slot (a slot where you store you job
> targeting a specific queue under this group). You can fill up your
> ringbuf slots while the group is not resident (when that happens, we
> kick the second-stage scheduler to make sure the group is going to
> become resident at some point). And equally, you can have a group that's
> resident, but has all its queue ringbufs empty (in that case, it should
> sooner or later be evicted and replaced by another group that wants to
> execute things).

Thank you for this explanation - I am marking it with my "reference 
material" tag.

> So, back to your initial statement, it is desirable to keep the queues
> under a resident group (one that's attached to a FW slot) filled with
> jobs to maximize utilization. And ideally, we want the group with the
> highest priority to be refilled faster than the other resident groups.
> 
>>
>> At least assuming that the MCU is not significantly slower than the main
>> CPU in dequeing the FW slots into HW queues.
> 
> So, FW is scheduling queues under the resident groups, but the ring
> buffers are consumed by a HW component (CSHWIF in Arm's naming), which I
> expect to run faster than the MCU itself, even though, the MCU being
> dedicated to just that scheduling task with very little to no OS
> overhead, I'd expect the turnaround time to be quite fast compared to
> the APU, even if the MCU is clocked at a way lower freq.

Makes sense.

>> What would that number be in practice? I am going back to what Tejun
>> mentioned, that if we can provide some bound number of how many RT
>> workers we may need, then he may be able to provide the RT facility.
> 
> As I say below, I think we can start with just a single-worker
> wq per priority, and take it from there if we see the resident queues
> are not filled fast enough compared to the non-resident ones. What's
> really important for us is for jobs targeting high-prio queues to hit
> their ringbuf before those targeting lower prio queues.
> 
>>
>>>> GPU will still take one at a time and preemption is not that fast, no?
>>>
>>> Preemption on the FW side is pretty simple: each slot gets a unique
>>> prio, and lower prio slots only get HW queues and GPU resources if
>>> higher prio ones are idle and accept to give up their resources for a
>>> bit. We then have a 10ms tick in panthor to rotate the FW slot
>>> priorities. So yes, preemption is not very granular, but that's not
>>> really the problem I'm worried about. What I'm worried about is having
>>> just one thread for everything, with the first-queued/first-served
>>> model that the kthread_worker infrastructure provides. If we're talking
>>> about one thread per-priority level, that's already better, and then I
>>> agree that the contention on GPU contexts with the same priority is less
>>> of an issue, especially since the run_job work has to run before being
>>> rescheduled, which gives you this natural FIFO behavior, thus leaving
>>> other contexts a chance to queue their run_job in the meantime.
>>>
>>> But this WQ_UNBOUND -> WQ_SINGLE_THREAD transition, where the wq is
>>> shared among the entire device is not that. It's actually serializing
>>> work submission for all GPU contexts regardless of their priority.
>>>
>>> TLDR; I'd be happy if we start with just one kthread per-prio + the
>>> narrowing of the locked section in the run_job() implementation, so
>>> that context submission actually happens concurrently, and low prio
>>> context don't starve high-prio/RT ones in the submission path.
>>
>> I don't think this is actually priority starvation but plain FIFO
>> starvation.
> 
> The FIFO is per group-queue, not global to the device though (we have
> one sched_entity and one scheduler per group-queue, not one for the
> entire system). The starvation, if any, would come from the
> serialization in the run_job() implementation, as we try to acquire the
> device-wide panthor_scheduler::lock. And that's not by design, but
> rather a flaw in the original implementation.
> 
>> It can happen even today with WQ_UNBOUND, which does nothing
>> about breaking the FIFO order based on priorities, just that some
>> parallelism alleviates it.
> 
> Well, it's indeed not providing a guarantee that things will be
> pushed in the proper prio order, but the fact threads can be
> spawned makes it less likely for low-prio queues to block high-prio
> ones, at least.
> 
>>
>> But in principle I am fine with going with N workers. It's just a matter
>> of what is N derived from and how big it is. It could be even be passed
>> to alloc_workqueue in the today's code base but I accept there is not
>> much value to that since I don't think there are SoC's with a Mali GPU
>> and server level number of CPU cores.
> 
> I think we can start with one ordered-wq per prio level. So basically
> what you intended to do in this patch, but instead of having a single
> ordered-wq, we have four of them (one per prio). It doesn't address the
> fact run_job() on non-resident groups might hit their ringbuf before
> resident ones, but that's probably good enough as a first step, and as
> you pointed out, the current locking forces this serialization with no
> more guarantee regarding who's going to be served first anyway, so it
> can't be worse than it already is.

Lets for a moment assume the kthread_worker idea will not fly due to xe, 
or any other reason really. Also since the option for RT workqueues is 
unexpectedly on the table. In that case, and assuming RT workqueues will 
happen, could a feasible plan for panthor be to create three workqueues:

  1. One unbound with max_active = 2 for low and medium group priority.
  2. Another unbound + WQ_HIGHPRI, also with max_active = 2 for high.
  3. And one unbound + WQ_REALTIME, again max_active = 2 for realtime.

For high and realtime max_active either 2 or 1 on dual core, if there 
are such SoCs. Two threads ensure same priority clients are able to keep 
the GPU fed.

One issue is that you mentioned you would like dynamic priority changes 
and with this it may be tricky. But ignoring that for the moment, and 
the discussion on how to handle other panthor workers which take part in 
the execution flow post submit, this should pretty much address the 
submit latency from userspace to ->run_job(). What do you think, is it 
worth entertaining this alternative?

Regards,

Tvrtko

> Note that this is probably not enough to make a difference, we also
> need panthor-specific work items to go to the per-prio wqs based on
> where the event comes from (we have per-FW-slot interrupts), and the
> priority of the group attached to the FW slot. Or we just consider any
> event from the FW as high-prio regardless of the slot its pointing to,
> dunno.


  reply	other threads:[~2026-07-09 14:33 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-02 14:37 [RFC 0/8] DRM scheduler kthread_worker for submission latency improvements Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 1/8] drm/panthor: Remove redundant drm_sched_job_cleanup() from the .free_job callback Tvrtko Ursulin
2026-07-03 15:00   ` Steven Price
2026-07-09 10:05     ` Tvrtko Ursulin
2026-07-09 10:15       ` Boris Brezillon
2026-07-09 12:16         ` Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 2/8] drm/panthor: Use separate workqueue for DRM scheduler Tvrtko Ursulin
2026-07-02 15:31   ` Boris Brezillon
2026-07-06 12:03     ` Tvrtko Ursulin
2026-07-06 14:18       ` Boris Brezillon
2026-07-08 16:47         ` Tvrtko Ursulin
2026-07-09  6:45           ` Boris Brezillon
2026-07-09 10:56             ` Tvrtko Ursulin
2026-07-09 12:19               ` Boris Brezillon
2026-07-09 14:33                 ` Tvrtko Ursulin [this message]
2026-07-02 14:37 ` [RFC 3/8] drm/sched: Use generic naming for workqueue helpers Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 4/8] drm/xe: Convert to per gt scheduler workers Tvrtko Ursulin
2026-07-03  9:06   ` Matthew Brost
2026-07-06 12:27     ` Tvrtko Ursulin
2026-07-06 23:14       ` Matthew Brost
2026-07-08 16:35         ` Tvrtko Ursulin
2026-07-08 19:32           ` Matthew Brost
2026-07-09 11:35             ` Tvrtko Ursulin
2026-07-09 11:45               ` Matthew Brost
2026-07-09 12:05                 ` Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 5/8] drm: Wrap DRM scheduler worker in own abstraction Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 6/8] drm/sched: Convert the scheduler job submission to kthread_worker Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 7/8] drm/sched: Add ability to change drm_sched_worker priority Tvrtko Ursulin
2026-07-02 14:37 ` [RFC 8/8] drm/sched: Notify worker of the entity submission priority Tvrtko Ursulin
2026-07-03  8:52 ` [RFC 0/8] DRM scheduler kthread_worker for submission latency improvements Philipp Stanner
2026-07-06 12:20   ` Tvrtko Ursulin
2026-07-06 19:36     ` Tejun Heo
2026-07-08 16:24       ` Tvrtko Ursulin
2026-07-09  8:28         ` Tvrtko Ursulin
2026-07-03  9:22 ` Matthew Brost
2026-07-06 12:41   ` Tvrtko Ursulin
2026-07-06 22:54     ` Matthew Brost
2026-07-07  7:12       ` Matthew Brost
2026-07-08 17:01         ` Tvrtko Ursulin
2026-07-08 20:46           ` Matthew Brost
2026-07-08 22:39             ` Matthew Brost
2026-07-09  6:52             ` Boris Brezillon
2026-07-09  7:25             ` Boris Brezillon
2026-07-09  7:55               ` Matthew Brost
2026-07-09 10:08                 ` Boris Brezillon

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=ffc05a67-66ff-4e0a-98f3-a9e4e87af6b0@igalia.com \
    --to=tvrtko.ursulin@igalia.com \
    --cc=boris.brezillon@collabora.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=kernel-dev@igalia.com \
    --cc=liviu.dudau@arm.com \
    --cc=matthew.brost@intel.com \
    --cc=olvaffe@gmail.com \
    --cc=phasta@kernel.org \
    --cc=steven.price@arm.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.