Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Dec 2012 20:36:57 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r244364 - in projects/calloutng/sys: kern sys
Message-ID:  <201212172036.qBHKavP2064975@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Dec 17 20:36:56 2012
New Revision: 244364
URL: http://svnweb.freebsd.org/changeset/base/244364

Log:
  Experiments with dummynet exposed number of problems in code supporting
  legacy tick-based callouts. "callou_reset(... , 1, ...)", used by dummynet,
  effectively means "call me on the next hardclock tick after now".  But our
  new world order had no concept of the "next tick", and concept of "now" was
  also complicated by using imprecise getbinuptime().  Different attempts to
  handle that gave either low resolution, or lack of event aggregation.  In
  all cases resolution was limited by 1ms of getbinuptime(), that made at
  least useless setting hz above 1000.
  
  To fix that, new callout code was made to get the time of the hardclock()
  call directly from the kern_eventtimer.c, where it is already present with
  full precision.  That fixed all above problems at the same time: all legacy
  callouts are now sychronized and so will aggregate with hardclock events,
  and because of having precise time values hz above 1000 are again usable.
  
  In addition to that, create and use new global variable tc_tick_bt,
  representing duration of the timecounter tick, that is bigger then
  duration of hz tick (tick_bt), when hz is set above 1000;
  
  Reviewed by:	davide

Modified:
  projects/calloutng/sys/kern/kern_clocksource.c
  projects/calloutng/sys/kern/kern_tc.c
  projects/calloutng/sys/kern/kern_time.c
  projects/calloutng/sys/kern/kern_timeout.c
  projects/calloutng/sys/kern/subr_param.c
  projects/calloutng/sys/kern/sys_generic.c
  projects/calloutng/sys/sys/time.h

Modified: projects/calloutng/sys/kern/kern_clocksource.c
==============================================================================
--- projects/calloutng/sys/kern/kern_clocksource.c	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/kern/kern_clocksource.c	Mon Dec 17 20:36:56 2012	(r244364)
@@ -96,7 +96,6 @@ static struct mtx	et_hw_mtx;
 
 static struct eventtimer *timer = NULL;
 static struct bintime	timerperiod;	/* Timer period for periodic mode. */
-static struct bintime	hardperiod;	/* hardclock() events period. */
 static struct bintime	statperiod;	/* statclock() events period. */
 static struct bintime	profperiod;	/* profclock() events period. */
 static struct bintime	nexttick;	/* Next global timer tick time. */
@@ -146,6 +145,7 @@ struct pcpu_state {
 };
 
 static DPCPU_DEFINE(struct pcpu_state, timerstate);
+DPCPU_DEFINE(struct bintime, hardclocktime);
 
 /*
  * Timer broadcast IPI handler.
@@ -174,7 +174,7 @@ hardclockintr(void)
 static int
 handleevents(struct bintime *now, int fake)
 {
-	struct bintime t;
+	struct bintime t, *hct;
 	struct trapframe *frame;
 	struct pcpu_state *state;
 	uintfptr_t pc;
@@ -199,10 +199,13 @@ handleevents(struct bintime *now, int fa
 
 	runs = 0;
 	while (bintime_cmp(now, &state->nexthard, >=)) {
-		bintime_addx(&state->nexthard, hardperiod.frac);
+		bintime_addx(&state->nexthard, tick_bt.frac);
 		runs++;
 	}
 	if (runs) {
+		hct = DPCPU_PTR(hardclocktime);
+		*hct = state->nexthard;
+		bintime_sub(hct, &tick_bt);
 		if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 &&
 		    bintime_cmp(&state->nexthard, &nexthard, >))
 			nexthard = state->nexthard;
@@ -282,7 +285,7 @@ getnextcpuevent(struct bintime *event, i
 		if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > hardfreq)
 			hardfreq = tc_min_ticktock_freq;
 		if (hz > hardfreq) {
-			tmp = hardperiod;
+			tmp = tick_bt;
 			bintime_mul(&tmp, hz / hardfreq - 1);
 			bintime_add(event, &tmp);
 		}
@@ -698,7 +701,7 @@ cpu_initclocks_bsp(void)
 		profhz = round_freq(timer, stathz * 64);
 	}
 	tick = 1000000 / hz;
-	FREQ2BT(hz, &hardperiod);
+	FREQ2BT(hz, &tick_bt);
 	FREQ2BT(stathz, &statperiod);
 	FREQ2BT(profhz, &profperiod);
 	ET_LOCK();

Modified: projects/calloutng/sys/kern/kern_tc.c
==============================================================================
--- projects/calloutng/sys/kern/kern_tc.c	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/kern/kern_tc.c	Mon Dec 17 20:36:56 2012	(r244364)
@@ -121,7 +121,7 @@ SYSCTL_INT(_kern_timecounter, OID_AUTO, 
     &timestepwarnings, 0, "Log time steps");
 
 struct bintime bt_timethreshold;
-struct bintime tick_bt;
+struct bintime tc_tick_bt;
 int tc_timeexp;
 int tc_timepercentage = TC_DEFAULTPERC;
 TUNABLE_INT("kern.timecounter.alloweddeviation", &tc_timepercentage);
@@ -1772,8 +1772,9 @@ inittimecounter(void *dummy)
 	else
 		tc_tick = 1;
 	tc_adjprecision();
+	FREQ2BT(hz, &tick_bt);
 	tick_rate = hz / tc_tick;
-	FREQ2BT(tick_rate, &tick_bt);
+	FREQ2BT(tick_rate, &tc_tick_bt);
 	p = (tc_tick * 1000000) / hz;
 	printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
 

Modified: projects/calloutng/sys/kern/kern_time.c
==============================================================================
--- projects/calloutng/sys/kern/kern_time.c	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/kern/kern_time.c	Mon Dec 17 20:36:56 2012	(r244364)
@@ -494,7 +494,7 @@ kern_nanosleep(struct thread *td, struct
 	bt_prec = tmp;
 	bintime_divpow2(&bt_prec, tc_timeexp);
 	if (TIMESEL(&bt, &tmp))
-		bintime_add(&bt, &tick_bt);
+		bintime_add(&bt, &tc_tick_bt);
 	bintime_add(&bt, &tmp);
 	error = tsleep_bt(&nanowait, PWAIT | PCATCH, "nanslp", &bt, &bt_prec);
 	TIMESEL(&btt, &tmp);

Modified: projects/calloutng/sys/kern/kern_timeout.c
==============================================================================
--- projects/calloutng/sys/kern/kern_timeout.c	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/kern/kern_timeout.c	Mon Dec 17 20:36:56 2012	(r244364)
@@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_callout_profiling.h"
 #include "opt_kdtrace.h"
+#if defined(__arm__)
+#include "opt_timer.h"
+#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -872,6 +875,10 @@ callout_handle_init(struct callout_handl
 	handle->callout = NULL;
 }
 
+#ifndef NO_EVENTTIMERS
+DPCPU_DECLARE(struct bintime, hardclocktime);
+#endif
+
 /*
  * New interface; clients allocate their own callout structures.
  *
@@ -893,26 +900,34 @@ _callout_reset_on(struct callout *c, str
     struct bintime *precision, int to_ticks, void (*ftn)(void *),
     void *arg, int cpu, int flags)
 {
-	struct bintime now, to_bt, pr;
+	struct bintime to_bt, pr;
 	struct callout_cpu *cc;
 	int bucket, cancelled, direct;
 
 	cancelled = 0;
 	if (bt == NULL) {
-		pr = to_bt = tick_bt;
-		getbinuptime(&now);
+#ifdef NO_EVENTTIMERS
+		getbinuptime(&to_bt);
+		/* Add safety belt for the case of hz > 1000. */
+		bintime_addx(&to_bt, tc_tick_bt.frac - tick_bt.frac);
+#else
+		/*
+		 * Obtain the time of the last hardclock() call on this CPU
+		 * directly from the kern_clocksource.c.  This value is
+		 * per-CPU, but it is equal for all active ones.
+		 */
+		spinlock_enter();
+		to_bt = DPCPU_GET(hardclocktime);
+		spinlock_exit();
+#endif
+		pr = tick_bt;
 		if (to_ticks > 1)
-			bintime_mul(&to_bt, to_ticks);
-		bintime_add(&to_bt, &now);
-		if (C_PRELGET(flags) < 0) {
-			pr = tick_bt;
-		} else {
-			to_ticks >>= C_PRELGET(flags);
-			if (to_ticks == 0)
-				pr = tick_bt;
-			else
-				bintime_mul(&pr, to_ticks);
-		}
+			bintime_mul(&pr, to_ticks);
+		bintime_add(&to_bt, &pr);
+		if (C_PRELGET(flags) < 0)
+			bintime_clear(&pr);
+		else
+			bintime_divpow2(&pr, C_PRELGET(flags));
 	} else {
 		to_bt = *bt;
 		if (precision != NULL)

Modified: projects/calloutng/sys/kern/subr_param.c
==============================================================================
--- projects/calloutng/sys/kern/subr_param.c	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/kern/subr_param.c	Mon Dec 17 20:36:56 2012	(r244364)
@@ -81,8 +81,9 @@ __FBSDID("$FreeBSD$");
 
 static int sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS);
 
-int	hz;
-int	tick;
+int	hz;				/* system clock's frequency */
+int	tick;				/* usec per tick (1000000 / hz) */
+struct bintime tick_bt;			/* bintime per tick (1s / hz) */
 int	maxusers;			/* base tunable */
 int	maxproc;			/* maximum # of processes */
 int	maxprocperuid;			/* max # of procs per user */
@@ -219,6 +220,7 @@ init_param1(void)
 	if (hz == -1)
 		hz = vm_guest > VM_GUEST_NO ? HZ_VM : HZ;
 	tick = 1000000 / hz;
+	FREQ2BT(hz, &tick_bt);
 
 #ifdef VM_SWZONE_SIZE_MAX
 	maxswzone = VM_SWZONE_SIZE_MAX;

Modified: projects/calloutng/sys/kern/sys_generic.c
==============================================================================
--- projects/calloutng/sys/kern/sys_generic.c	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/kern/sys_generic.c	Mon Dec 17 20:36:56 2012	(r244364)
@@ -1008,7 +1008,7 @@ kern_select(struct thread *td, int nd, f
 		precision = abt;
 		bintime_divpow2(&precision, tc_timeexp);
 		if (TIMESEL(&rbt, &abt))
-			bintime_add(&abt, &tick_bt);
+			bintime_add(&abt, &tc_tick_bt);
 		bintime_add(&abt, &rbt);
 	} else {
 		abt.sec = 0;
@@ -1290,7 +1290,7 @@ sys_poll(td, uap)
 		precision = abt;
 		bintime_divpow2(&precision, tc_timeexp);
 		if (TIMESEL(&rbt, &abt))
-			bintime_add(&abt, &tick_bt);
+			bintime_add(&abt, &tc_tick_bt);
 		bintime_add(&abt, &rbt);
 	} else {
 		abt.sec = 0;

Modified: projects/calloutng/sys/sys/time.h
==============================================================================
--- projects/calloutng/sys/sys/time.h	Mon Dec 17 19:34:27 2012	(r244363)
+++ projects/calloutng/sys/sys/time.h	Mon Dec 17 20:36:56 2012	(r244364)
@@ -300,6 +300,7 @@ extern time_t	time_second;
 extern time_t	time_uptime;
 extern struct bintime boottimebin;
 extern struct bintime tick_bt;
+extern struct bintime tc_tick_bt;
 extern struct timeval boottime;
 extern int tc_timeexp;
 extern int tc_timepercentage;



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