Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 Sep 2012 16:24:05 +0800
From:      David Xu <davidxu@freebsd.org>
To:        Andriy Gapon <avg@freebsd.org>
Cc:        freebsd-hackers <freebsd-hackers@freebsd.org>, Jeff Roberson <jeff@freebsd.org>
Subject:   Re: ule+smp: small optimization for turnstile priority lending
Message-ID:  <505AD2A5.6060008@freebsd.org>
In-Reply-To: <50587F8D.9060102@FreeBSD.org>
References:  <50587F8D.9060102@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2012/09/18 22:05, Andriy Gapon wrote:
>
> Here is a snippet that demonstrates the issue on a supposedly fully loaded
> 2-processor system:
>
> 136794   0 3670427870244462 KTRGRAPH group:"thread", id:"Xorg tid 102818",
> state:"running", attributes: prio:122
>
> 136793   0 3670427870241000 KTRGRAPH group:"thread", id:"cc1plus tid 111916",
> state:"yielding", attributes: prio:183, wmesg:"(null)", lockname:"(null)"
>
> 136792   1 3670427870240829 KTRGRAPH group:"thread", id:"idle: cpu1 tid 100004",
> state:"running", attributes: prio:255
>
> 136791   1 3670427870239520 KTRGRAPH group:"load", id:"CPU 1 load", counter:0,
> attributes: none
>
> 136790   1 3670427870239248 KTRGRAPH group:"thread", id:"firefox tid 113473",
> state:"blocked", attributes: prio:122, wmesg:"(null)", lockname:"unp_mtx"
>
> 136789   1 3670427870237697 KTRGRAPH group:"load", id:"CPU 0 load", counter:2,
> attributes: none
>
> 136788   1 3670427870236394 KTRGRAPH group:"thread", id:"firefox tid 113473",
> point:"wokeup", attributes: linkedto:"Xorg tid 102818"
>
> 136787   1 3670427870236145 KTRGRAPH group:"thread", id:"Xorg tid 102818",
> state:"runq add", attributes: prio:122, linkedto:"firefox tid 113473"
>
> 136786   1 3670427870235981 KTRGRAPH group:"load", id:"CPU 1 load", counter:1,
> attributes: none
>
> 136785   1 3670427870235707 KTRGRAPH group:"thread", id:"Xorg tid 102818",
> state:"runq rem", attributes: prio:176
>
> 136784   1 3670427870235423 KTRGRAPH group:"thread", id:"Xorg tid 102818",
> point:"prio", attributes: prio:176, new prio:122, linkedto:"firefox tid 113473"
>
> 136783   1 3670427870202392 KTRGRAPH group:"thread", id:"firefox tid 113473",
> state:"running", attributes: prio:104
>
> See how how the Xorg thread was forced from CPU 1 to CPU 0 where it preempted
> cc1plus thread (I do have preemption enabled) only to leave CPU 1 with zero load.
>
> Here is a proposed solution:
>
>      turnstile_wait: optimize priority lending to a thread on a runqueue
>
>      As the current thread is definitely going into mi_switch, it now removes
>      its load before doing priority propagation which can potentially result
>      in sched_add.  In the SMP && ULE case the latter searches for the
>      least loaded CPU to place a boosted thread, which is supposedly about
>      to run.
>
> diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c
> index 8e466cd..3299cae 100644
> --- a/sys/kern/sched_ule.c
> +++ b/sys/kern/sched_ule.c
> @@ -1878,7 +1878,10 @@ sched_switch(struct thread *td, struct thread *newtd, int
> flags)
>   		/* This thread must be going to sleep. */
>   		TDQ_LOCK(tdq);
>   		mtx = thread_lock_block(td);
> -		tdq_load_rem(tdq, td);
> +#if defined(SMP)
> +		if ((flags & SW_TYPE_MASK) != SWT_TURNSTILE)
> +#endif
> +			tdq_load_rem(tdq, td);
>   	}
>   	/*
>   	 * We enter here with the thread blocked and assigned to the
> @@ -2412,6 +2415,21 @@ sched_rem(struct thread *td)
>   		tdq_setlowpri(tdq, NULL);
>   }
>
> +void
> +sched_load_rem(struct thread *td)
> +{
> +	struct tdq *tdq;
> +
> +	KASSERT(td == curthread,
> +	    ("sched_rem_load: only curthread is supported"));
> +	KASSERT(td->td_oncpu == td->td_sched->ts_cpu,
> +	    ("thread running on cpu different from ts_cpu"));
> +	tdq = TDQ_CPU(td->td_sched->ts_cpu);
> +	TDQ_LOCK_ASSERT(tdq, MA_OWNED);
> +	MPASS(td->td_lock == TDQ_LOCKPTR(tdq));
> +	tdq_load_rem(tdq, td);
> +}
> +
>   /*
>    * Fetch cpu utilization information.  Updates on demand.
>    */
> diff --git a/sys/kern/subr_turnstile.c b/sys/kern/subr_turnstile.c
> index 31d16fe..d1d68e9 100644
> --- a/sys/kern/subr_turnstile.c
> +++ b/sys/kern/subr_turnstile.c
> @@ -731,6 +731,13 @@ turnstile_wait(struct turnstile *ts, struct thread *owner,
> int queue)
>   		LIST_INSERT_HEAD(&ts->ts_free, td->td_turnstile, ts_hash);
>   	}
>   	thread_lock(td);
> +#if defined(SCHED_ULE) && defined(SMP)
> +	/*
> +	 * Remove load earlier so that it does not affect cpu selection
> +	 * for a thread waken up due to priority lending, if any.
> +	 */
> +	sched_load_rem(td);
> +#endif
>   	thread_lock_set(td, &ts->ts_lock);
>   	td->td_turnstile = NULL;
>
> diff --git a/sys/sys/sched.h b/sys/sys/sched.h
> index 4b8387c..b1ead1b 100644
> --- a/sys/sys/sched.h
> +++ b/sys/sys/sched.h
> @@ -110,6 +110,9 @@ void	sched_preempt(struct thread *td);
>   void	sched_add(struct thread *td, int flags);
>   void	sched_clock(struct thread *td);
>   void	sched_rem(struct thread *td);
> +#if defined(SCHED_ULE) && defined(SMP)
> +void	sched_load_rem(struct thread *td);
> +#endif
>   void	sched_tick(int cnt);
>   void	sched_relinquish(struct thread *td);
>   struct thread *sched_choose(void);
>

I found another scenario in taskqueue, in the function
taskqueue_terminate, current thread tries to wake
another thread up and sleep immediately, the tq_mutex sometimes
is a spinlock. So if you remove one thread load from current cpu
before wakeup, the resumed thread may be put on same cpu,
so it will optimize the cpu scheduling too.

/*
  * Signal a taskqueue thread to terminate.
  */
static void
taskqueue_terminate(struct thread **pp, struct taskqueue *tq)
{

         while (tq->tq_tcount > 0 || tq->tq_callouts > 0) {
                 wakeup(tq);
                 TQ_SLEEP(tq, pp, &tq->tq_mutex, PWAIT, 
"taskqueue_destroy", 0);
         }
}




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?505AD2A5.6060008>