Re: [PATCH v2] drm/i915/breadcrumbs: Drop request reference for the signaler thread

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Quoting Chris Wilson (2018-02-05 13:36:36)
> Quoting Tvrtko Ursulin (2018-02-05 13:23:54)
> > 
> > On 03/02/2018 10:19, Chris Wilson wrote:
> > > @@ -656,41 +705,21 @@ static int intel_breadcrumbs_signaler(void *arg)
> > >                * a new client.
> > >                */
> > >               rcu_read_lock();
> > > -             request = rcu_dereference(b->first_signal);
> > > -             if (request)
> > > -                     request = i915_gem_request_get_rcu(request);
> > > +             request = get_first_signal_rcu(b);
> > >               rcu_read_unlock();
> > >               if (signal_complete(request)) {
> > > -                     local_bh_disable();
> > > -                     dma_fence_signal(&request->fence);
> > > -                     local_bh_enable(); /* kick start the tasklets */
> > > -
> > > -                     spin_lock_irq(&b->rb_lock);
> > > -
> > > -                     /* Wake up all other completed waiters and select the
> > > -                      * next bottom-half for the next user interrupt.
> > > -                      */
> > > -                     __intel_engine_remove_wait(engine,
> > > -                                                &request->signaling.wait);
> > > -
> > > -                     /* Find the next oldest signal. Note that as we have
> > > -                      * not been holding the lock, another client may
> > > -                      * have installed an even older signal than the one
> > > -                      * we just completed - so double check we are still
> > > -                      * the oldest before picking the next one.
> > > -                      */
> > > -                     if (request == rcu_access_pointer(b->first_signal)) {
> > > -                             struct rb_node *rb =
> > > -                                     rb_next(&request->signaling.node);
> > > -                             rcu_assign_pointer(b->first_signal,
> > > -                                                rb ? to_signaler(rb) : NULL);
> > > +                     if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
> > > +                                   &request->fence.flags)) {
> > > +                             local_bh_disable();
> > > +                             dma_fence_signal(&request->fence);
> > > +                             local_bh_enable(); /* kick start the tasklets */
> > >                       }
> > > -                     rb_erase(&request->signaling.node, &b->signals);
> > > -                     RB_CLEAR_NODE(&request->signaling.node);
> > > -
> > > -                     spin_unlock_irq(&b->rb_lock);
> > >   
> > > -                     i915_gem_request_put(request);
> > > +                     if (READ_ONCE(request->signaling.wait.seqno)) {
> > > +                             spin_lock_irq(&b->rb_lock);
> > > +                             __intel_engine_remove_signal(engine, request);
> > > +                             spin_unlock_irq(&b->rb_lock);
> > > +                     }
> > 
> > How would you view taking the request->lock over this block in the 
> > signaler and then being able to call simply 
> > intel_engine_cancel_signaling - ending up with very similar code as in 
> > i915_gem_request_retire?
> 
> I am not keen on the conflation here (maybe it's just a hatred of bool
> parameters). But at first glance it's just the commonality of
> remove_signal, which is already a common routine?
> 
> > Only difference would be the tasklet kicking, but maybe still it would 
> > be possible to consolidate the two in one helper.
> > 
> > __i915_gem_request_retire_signaling(req, bool kick_tasklets)
> > {
> >         if (!DMA_FENCE_FLAG_SIGNALED_BIT) {
> >                 dma_fence_signal_locked(...);
> >                 if (kick_tasklets) {
> >                         local_bh_disable();
> >                         local_bh_enable();
> >                 }
> 
> We can't kick the tasklet inside a spinlock. Especially not a lockclass
> as nested as request.lock :(

Also bear in mind this is just an intermediate step in my plans. :)


static int intel_breadcrumbs_signaler(void *arg)
{
        struct intel_engine_cs *engine = arg;
        struct intel_breadcrumbs *b = &engine->breadcrumbs;
        struct drm_i915_gem_request *rq, *n;

        /* Install ourselves with high priority to reduce signalling latency */
        signaler_set_rtpriority();

        do {
                bool do_schedule = true;
                LIST_HEAD(list);
                u32 seqno;

                set_current_state(TASK_INTERRUPTIBLE);
                if (list_empty(&b->signals))
                        goto sleep;
                
                /*
                 * We are either woken up by the interrupt bottom-half,
                 * or by a client adding a new signaller. In both cases,
                 * the GPU seqno may have advanced beyond our oldest signal.
                 * If it has, propagate the signal, remove the waiter and
                 * check again with the next oldest signal. Otherwise we
                 * need to wait for a new interrupt from the GPU or for
                 * a new client.
                 */
                seqno = intel_engine_get_seqno(engine);

                spin_lock_irq(&b->rb_lock);
                list_for_each_entry_safe(rq, n, &b->signals, signaling.link) {
                        u32 this = rq->signaling.wait.seqno;

                        GEM_BUG_ON(!rq->signaling.wait.seqno);

                        if (!i915_seqno_passed(seqno, this))
                                break;

                        if (this == i915_gem_request_global_seqno(rq)) {
                                __intel_engine_remove_wait(engine,
                                                           &rq->signaling.wait);

                                rq->signaling.wait.seqno = 0;
                                __list_del_entry(&rq->signaling.link);

                                if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
                                              &rq->fence.flags)) {
                                        list_add_tail(&rq->signaling.link,
                                                      &list);
                                        i915_gem_request_get(rq);
                                }
                        }
                }
                spin_unlock_irq(&b->rb_lock);

                if (!list_empty(&list)) {
                        local_bh_disable();
                        list_for_each_entry_safe(rq, n, &list, signaling.link) {
                                dma_fence_signal(&rq->fence);
                                i915_gem_request_put(rq);
                        }
                        local_bh_enable(); /* kick start the tasklets */
                        
                        /*
                         * If the engine is saturated we may be continually
                         * processing completed requests. This angers the
                         * NMI watchdog if we never let anything else
                         * have access to the CPU. Let's pretend to be nice
                         * and relinquish the CPU if we burn through the
                         * entire RT timeslice!
                         */
                        do_schedule = need_resched();
                }

                if (unlikely(do_schedule)) { 
                        if (current->state & TASK_NORMAL &&
                            !list_empty(&b->signals) &&
                            engine->irq_seqno_barrier &&
                            test_and_clear_bit(ENGINE_IRQ_BREADCRUMB,
                                               &engine->irq_posted)) {
                                engine->irq_seqno_barrier(engine);
                                intel_engine_wakeup(engine);
                        }

sleep:
                        if (kthread_should_park())
                                kthread_parkme();

                        if (unlikely(kthread_should_stop()))
                                break;
                 
                        schedule();
                }
        } while (1);
        __set_current_state(TASK_RUNNING);

        return 0;
}

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux