Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Apr 2012 06:29:02 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r234167 - in stable/9: share/man/man4 sys/kern
Message-ID:  <201204120629.q3C6T3rX014095@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Thu Apr 12 06:29:02 2012
New Revision: 234167
URL: http://svn.freebsd.org/changeset/base/234167

Log:
  MFC 232919:
  Add kern.eventtimer.activetick tunable/sysctl, specifying whether each
  hardclock() tick should be run on every active CPU, or on only one.
  
  On my tests, avoiding extra interrupts because of this on 8-CPU Core i7
  system with HZ=10000 saves about 2% of performance. At this moment option
  implemented only for global timers, as reprogramming per-CPU timers is
  too expensive now to be compensated by this benefit, especially since we
  still have to regularly run hardclock() on at least one active CPU to
  update system uptime. For global timer it is quite trivial: timer runs
  always, but we just skip IPIs to other CPUs when possible.
  
  Option is enabled by default now, keeping previous behavior, as periodic
  hardclock() calls are still used at least to implement setitimer(2) with
  ITIMER_VIRTUAL and ITIMER_PROF arguments. But since default schedulers don't
  depend on it since r232917, we are much more free to experiment with it.

Modified:
  stable/9/share/man/man4/eventtimers.4
  stable/9/sys/kern/kern_clocksource.c
Directory Properties:
  stable/9/share/man/man4/   (props changed)
  stable/9/sys/   (props changed)

Modified: stable/9/share/man/man4/eventtimers.4
==============================================================================
--- stable/9/share/man/man4/eventtimers.4	Thu Apr 12 06:24:47 2012	(r234166)
+++ stable/9/share/man/man4/eventtimers.4	Thu Apr 12 06:29:02 2012	(r234167)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 15, 2010
+.Dd March 13, 2012
 .Dt EVENTTIMERS 4
 .Os
 .Sh NAME
@@ -143,6 +143,12 @@ By default this options is disabled.
 If chosen timer is per-CPU
 and runs in periodic mode, this option has no effect - all interrupts are
 always generating.
+.It Va kern.eventtimer.activetick
+makes each CPU to receive all kinds of timer interrupts when they are busy.
+Disabling it allows to skip some hardclock() calls in some cases.
+By default this options is enabled.
+If chosen timer is per-CPU, this option has no effect - all interrupts are
+always generating, as timer reprogramming is too expensive for that case.
 .El
 .Sh SEE ALSO
 .Xr apic 4 ,

Modified: stable/9/sys/kern/kern_clocksource.c
==============================================================================
--- stable/9/sys/kern/kern_clocksource.c	Thu Apr 12 06:24:47 2012	(r234166)
+++ stable/9/sys/kern/kern_clocksource.c	Thu Apr 12 06:29:02 2012	(r234167)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
+ * Copyright (c) 2010-2012 Alexander Motin <mav@FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -99,6 +99,7 @@ static struct bintime	hardperiod;	/* har
 static struct bintime	statperiod;	/* statclock() events period. */
 static struct bintime	profperiod;	/* profclock() events period. */
 static struct bintime	nexttick;	/* Next global timer tick time. */
+static struct bintime	nexthard;	/* Next global hardlock() event. */
 static u_int		busy = 0;	/* Reconfiguration is in progress. */
 static int		profiling = 0;	/* Profiling events enabled. */
 
@@ -110,11 +111,16 @@ TUNABLE_INT("kern.eventtimer.singlemul",
 SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
     0, "Multiplier for periodic mode");
 
-static u_int		idletick = 0;	/* Idle mode allowed. */
+static u_int		idletick = 0;	/* Run periodic events when idle. */
 TUNABLE_INT("kern.eventtimer.idletick", &idletick);
 SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick,
     0, "Run periodic events when idle");
 
+static u_int		activetick = 1;	/* Run all periodic events when active. */
+TUNABLE_INT("kern.eventtimer.activetick", &activetick);
+SYSCTL_UINT(_kern_eventtimer, OID_AUTO, activetick, CTLFLAG_RW, &activetick,
+    0, "Run all periodic events when active");
+
 static int		periodic = 0;	/* Periodic or one-shot mode. */
 static int		want_periodic = 0; /* What mode to prefer. */
 TUNABLE_INT("kern.eventtimer.periodic", &want_periodic);
@@ -202,6 +208,9 @@ handleevents(struct bintime *now, int fa
 		bintime_add(&state->nexthard, &hardperiod);
 		runs++;
 	}
+	if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 &&
+	    bintime_cmp(&state->nexthard, &nexthard, >))
+		nexthard = state->nexthard;
 	if (runs && fake < 2) {
 		hardclock_cnt(runs, usermode);
 		done = 1;
@@ -263,9 +272,11 @@ getnextcpuevent(struct bintime *event, i
 	int skip;
 
 	state = DPCPU_PTR(timerstate);
+	/* Handle hardclock() events. */
 	*event = state->nexthard;
-	if (idle) { /* If CPU is idle - ask callouts for how long. */
-		skip = 4;
+	if (idle || (!activetick && !profiling &&
+	    (timer->et_flags & ET_FLAGS_PERCPU) == 0)) {
+		skip = idle ? 4 : (stathz / 2);
 		if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > skip)
 			skip = tc_min_ticktock_freq;
 		skip = callout_tickstofirst(hz / skip) - 1;
@@ -273,7 +284,8 @@ getnextcpuevent(struct bintime *event, i
 		tmp = hardperiod;
 		bintime_mul(&tmp, skip);
 		bintime_add(event, &tmp);
-	} else { /* If CPU is active - handle all types of events. */
+	}
+	if (!idle) { /* If CPU is active - handle other types of events. */
 		if (bintime_cmp(event, &state->nextstat, >))
 			*event = state->nextstat;
 		if (profiling && bintime_cmp(event, &state->nextprof, >))
@@ -295,24 +307,28 @@ getnextevent(struct bintime *event)
 #ifdef SMP
 	int	cpu;
 #endif
-	int	c;
+	int	c, nonidle;
 
 	state = DPCPU_PTR(timerstate);
 	*event = state->nextevent;
 	c = curcpu;
-#ifdef SMP
+	nonidle = !state->idle;
 	if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) {
+#ifdef SMP
 		CPU_FOREACH(cpu) {
 			if (curcpu == cpu)
 				continue;
 			state = DPCPU_ID_PTR(cpu, timerstate);
+			nonidle += !state->idle;
 			if (bintime_cmp(event, &state->nextevent, >)) {
 				*event = state->nextevent;
 				c = cpu;
 			}
 		}
-	}
 #endif
+		if (nonidle != 0 && bintime_cmp(event, &nexthard, >))
+			*event = nexthard;
+	}
 	CTR5(KTR_SPARE2, "next at %d:    next %d.%08x%08x by %d",
 	    curcpu, event->sec, (unsigned int)(event->frac >> 32),
 			     (unsigned int)(event->frac & 0xffffffff), c);



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