Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Jun 2012 22:27:17 +0000 (UTC)
From:      Davide Italiano <davide@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r236530 - in projects/calloutng/sys: kern sys
Message-ID:  <201206032227.q53MRHN8087724@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: davide
Date: Sun Jun  3 22:27:17 2012
New Revision: 236530
URL: http://svn.freebsd.org/changeset/base/236530

Log:
  - Everytime callout_tick() is called it looks for the nearest future
  event and communicate it to eventtimers subsystem via
  via callout_new_inserted(). So, we don't need anymore to call
  callout_tickstofirst() when we're in getnextcpuevent(), and we can get
  rid of it.
  
  - Completely refactor the cpu_new_callout() function (many thanks to
  Alexander Motin that helped me there with this code).
  
  - Switch back from getbinuptime() to binuptime() to measure present time in
  callout_tick().
  
  Pointed out by:		mav, bde

Modified:
  projects/calloutng/sys/kern/kern_clocksource.c
  projects/calloutng/sys/kern/kern_timeout.c
  projects/calloutng/sys/sys/callout.h

Modified: projects/calloutng/sys/kern/kern_clocksource.c
==============================================================================
--- projects/calloutng/sys/kern/kern_clocksource.c	Sun Jun  3 21:03:16 2012	(r236529)
+++ projects/calloutng/sys/kern/kern_clocksource.c	Sun Jun  3 22:27:17 2012	(r236530)
@@ -72,9 +72,7 @@ static int		round_freq(struct eventtimer
 static void		getnextcpuevent(struct bintime *event, int idle);
 static void		getnextevent(struct bintime *event);
 static int		handleevents(struct bintime *now, int fake);
-#ifdef SMP
 static void		cpu_new_callout(int cpu, struct bintime bt);
-#endif
 
 static struct mtx	et_hw_mtx;
 
@@ -274,24 +272,28 @@ handleevents(struct bintime *now, int fa
 static void
 getnextcpuevent(struct bintime *event, int idle)
 {
-	struct bintime tmp;
 	struct pcpu_state *state;
-
+	struct bintime tmp;
+	int hardfreq;
+	
 	state = DPCPU_PTR(timerstate);
-	/* Handle hardclock() events. */
+	/* Handle hardclock() events, skipping some is CPU is idle. */
 	*event = state->nexthard;
+	if (idle || (!activetick && !profiling &&
+	    (timer->et_flags & ET_FLAGS_PERCPU) == 0)) {
+		hardfreq = idle ? 4 : (stathz / 2);
+		if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > hardfreq)
+			hardfreq = tc_min_ticktock_freq;
+		if (hz > hardfreq) {
+			tmp = hardperiod;
+			bintime_mul(&tmp, hz / hardfreq - 1);
+			bintime_add(event, &tmp);
+		}
+	}
 	/* Handle callout events. */
-	tmp = callout_tickstofirst();
-	if (state->nextcall.sec == -1)
-		state->nextcall = tmp;
-	if (bintime_cmp(&tmp, &state->nextcall, <) && 	
-	    (tmp.sec != -1)) {
-		state->nextcall = tmp;
-	}	
-	if (bintime_cmp(event, &state->nextcall, >) && 
-	    (state->nextcall.sec != -1)) {
+	if (state->nextcall.sec != -1 &&
+	    bintime_cmp(event, &state->nextcall, >))
 		*event = state->nextcall;
-	}
 	if (!idle) { /* If CPU is active - handle other types of events. */
 		if (bintime_cmp(event, &state->nextstat, >))
 			*event = state->nextstat;
@@ -634,9 +636,7 @@ cpu_initclocks_bsp(void)
 #endif
 		state->nextcall.sec = -1;
 	}
-#ifdef SMP
 	callout_new_inserted = cpu_new_callout;
-#endif
 	periodic = want_periodic;
 	/* Grab requested timer or the best of present. */
 	if (timername[0])
@@ -864,74 +864,48 @@ clocksource_cyc_set(const struct bintime
 }
 #endif
 
-#ifdef SMP
 static void
 cpu_new_callout(int cpu, struct bintime bt)
 {
 	struct bintime now;
 	struct pcpu_state *state;
 
-	CTR3(KTR_SPARE2, "new co at %d:    on %d in %d",
-	    curcpu, cpu, ticks);
+	CTR4(KTR_SPARE2, "new co at %d:    on %d at %d.%08x%08x",
+	    curcpu, cpu, (unsigned int)(bt.frac >> 32),
+			 (unsigned int)(bt.frac & 0xffffffff));
 	state = DPCPU_ID_PTR(cpu, timerstate);
 	ET_HW_LOCK(state);
-	if (state->idle == 0 || busy) {
+
+	/* If there is callout time already set earlier -- do nothing. */
+	if (state->nextcall.sec != -1 &&
+	    bintime_cmp(&bt, &state->nextcall, >=)) {
 		ET_HW_UNLOCK(state);
 		return;
 	}
-	/*
-	 * If timer is periodic - just update next event time for target CPU.
-	 * If timer is global - there is chance it is already programmed.
-	 */
-	if (periodic || (timer->et_flags & ET_FLAGS_PERCPU) == 0) {
-		/* 
-		 * Update next callout time. We can do this only if 
-		 * this one on which we're running is the target CPU.
-		 */
-		if (!periodic) {
-			if (bintime_cmp(&bt, &state->nextcall, ==)) {
-				ET_HW_UNLOCK(state);
-				return;
-			}
-			if (state->nextcall.sec == -1 ||
-			    bintime_cmp(&bt, &state->nextcall, <))
-				state->nextcall = bt;
-			if (bintime_cmp(&state->nextcall, &state->nextevent, >=)) {
-				ET_HW_UNLOCK(state);
-				return;
-			}	
-			state->nextevent = state->nextcall;
-			if (cpu == curcpu) {
-				loadtimer(&now, 0);
-				ET_HW_UNLOCK(state);
-			}
-			else
-				goto out;
-		}
-		if (bintime_cmp(&state->nexthard, &state->nextevent, <))
-			state->nextevent = state->nexthard;
-		if (periodic ||
-		    bintime_cmp(&state->nextevent, &nexttick, >=)) {
-			ET_HW_UNLOCK(state);
-			return;
-		}
+	state->nextcall = bt;
+	/* If there is some some other event set earlier -- do nothing. */
+	if (bintime_cmp(&state->nextcall, &state->nextevent, >=)) {
+		ET_HW_UNLOCK(state);
+		return;
 	}
-out:
-	/*
-	 * Otherwise we have to wake that CPU up, as we can't get present
-	 * bintime to reprogram global timer from here. If timer is per-CPU,
-	 * we by definition can't do it from here.
-	 */
-	ET_HW_UNLOCK(state);
-	if (timer->et_flags & ET_FLAGS_PERCPU) {
-		state->handle = 1;
-		ipi_cpu(cpu, IPI_HARDCLOCK);
-	} else {
-		if (!cpu_idle_wakeup(cpu))
-			ipi_cpu(cpu, IPI_AST);
+	state->nextevent = state->nextcall;
+	/* If timer is periodic -- there is nothing to reprogram. */
+	if (periodic) {
+		ET_HW_UNLOCK(state);
+		return;
 	}
+	/* If timer is global or of the current CPU -- reprogram it. */
+	if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) {
+		binuptime(&now);
+		loadtimer(&now, 0);
+		ET_HW_UNLOCK(state);
+		return;
+	}
+	/* Otherwise make other CPU to reprogram it. */
+	state->handle = 1;
+	ET_HW_UNLOCK(state);
+	ipi_cpu(cpu, IPI_HARDCLOCK);
 }
-#endif
 
 /*
  * Report or change the active event timers hardware.

Modified: projects/calloutng/sys/kern/kern_timeout.c
==============================================================================
--- projects/calloutng/sys/kern/kern_timeout.c	Sun Jun  3 21:03:16 2012	(r236529)
+++ projects/calloutng/sys/kern/kern_timeout.c	Sun Jun  3 22:27:17 2012	(r236530)
@@ -364,7 +364,9 @@ callout_tick(void)
 	struct callout_tailq *sc;
 	struct bintime now;
 	struct bintime bt;
-	int need_softclock, first, last;
+	struct bintime limit;
+	struct bintime next;
+	int cpu, first, flag, future, last, need_softclock; 
 
 	/*
 	 * Process callouts at a very low cpu priority, so we don't keep the
@@ -373,7 +375,7 @@ callout_tick(void)
 	need_softclock = 0;
 	cc = CC_SELF();
 	mtx_lock_spin_flags(&cc->cc_lock, MTX_QUIET);
-	getbinuptime(&now);
+	binuptime(&now);
 	/* 
 	 * getbinuptime() may be inaccurate and return time up to 1/HZ in the past. 
 	 * In order to avoid the possible loss of one or more events look back 1/HZ
@@ -395,20 +397,46 @@ callout_tick(void)
 		first &= callwheelmask;
 		last &= callwheelmask;
 	}
+	cpu = curcpu;
+	next.sec = -1;
+	next .frac = -1;
+	limit.sec = 0;
+	limit.frac = 4611686018427250000; /* 1/4 sec */
+	bintime_add(&limit,&now);
+	future = get_bucket(&limit);
+	flag = 0;
 	for (;;) {	
 		sc = &cc->cc_callwheel[first];
 		TAILQ_FOREACH(tmp, sc, c_links.tqe) {
-			if (bintime_cmp(&tmp->c_time,&now, <=)) {
+			if ((!flag || flag == 1) && 
+			    bintime_cmp(&tmp->c_time, &now, <=)) {
 				TAILQ_INSERT_TAIL(cc->cc_localexp,tmp,c_staiter);
 				TAILQ_REMOVE(sc, tmp, c_links.tqe);
 				tmp->c_flags |= CALLOUT_PROCESSED;
 				need_softclock = 1;
 			}	
+			if ((flag == 1 || flag == 2)  && 
+			    bintime_cmp(&tmp->c_time, &now, >)) {
+				if (next.sec == -1 ||
+				    bintime_cmp(&tmp->c_time, &next, <)) {
+					next = tmp->c_time;
+					cpu = tmp->c_cpu;
+				}
+			}
 		}
+		if (first == ((last - 1) & callwheelmask)) 
+			flag = 1;
 		if (first == last)
+			flag = 2;
+		if (first == future || next.sec != -1)
 			break;
 		first = (first + 1) & callwheelmask;
 	}
+	if (next.sec == -1)  
+		next = limit;
+	if (callout_new_inserted != NULL) 
+	(*callout_new_inserted)(cpu,
+	    next);
 	cc->cc_softticks = now;
 	mtx_unlock_spin_flags(&cc->cc_lock, MTX_QUIET);
 	/*
@@ -420,43 +448,6 @@ callout_tick(void)
 	}
 }
 
-struct bintime
-callout_tickstofirst(void)
-{
-	struct callout_cpu *cc;
-	struct callout *c;
-	struct callout_tailq *sc;
-	struct bintime tmp;
-	struct bintime now;
-	int bucket;
-
-	tmp.sec = 0;
-	tmp.frac = 0;
-	cc = CC_SELF();
-	mtx_lock_spin_flags(&cc->cc_lock, MTX_QUIET);
-	binuptime(&now);
-	for (bucket = 0; bucket < callwheelsize; ++bucket) {
-		sc = &cc->cc_callwheel[bucket];
-		TAILQ_FOREACH( c, sc, c_links.tqe ) {
-			if (tmp.sec == 0 && tmp.frac == 0) 
-				tmp = c->c_time;
-			if (bintime_cmp(&c->c_time, &now, <)) 
-				tmp = now;
-			if (bintime_cmp(&c->c_time, &tmp, <=)) 
-				tmp = c->c_time;
-			
-		}
-	}
-	if (tmp.sec == 0 && tmp.frac == 0) {
-		cc->cc_firsttick.sec = -1;
-		cc->cc_firsttick.frac = -1;
-	}
-	else
-		cc->cc_firsttick = tmp;
-	mtx_unlock_spin_flags(&cc->cc_lock, MTX_QUIET);
-	return (cc->cc_firsttick);
-}
-
 static struct callout_cpu *
 callout_lock(struct callout *c)
 {
@@ -854,7 +845,7 @@ callout_reset_on(struct callout *c, int 
 	 */
 
 	FREQ2BT(hz,&bt);
-	binuptime(&now);
+	getbinuptime(&now);
 	bintime_mul(&bt,to_ticks);
 	bintime_add(&bt,&now);
 	/*

Modified: projects/calloutng/sys/sys/callout.h
==============================================================================
--- projects/calloutng/sys/sys/callout.h	Sun Jun  3 21:03:16 2012	(r236529)
+++ projects/calloutng/sys/sys/callout.h	Sun Jun  3 22:27:17 2012	(r236530)
@@ -80,7 +80,6 @@ int	callout_schedule_on(struct callout *
 #define	callout_stop(c)		_callout_stop_safe(c, 0)
 int	_callout_stop_safe(struct callout *, int);
 void	callout_tick(void);
-struct bintime callout_tickstofirst(void);
 extern void (*callout_new_inserted)(int cpu, struct bintime bt);
 
 #endif



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