Re: Eventtimers b0rking w/ math/atlas

From: Kostik Belousov <kostikbel_at_gmail.com>
Date: Fri, 10 Sep 2010 17:40:25 +0300
On Fri, Sep 10, 2010 at 04:31:40PM +0200, Dimitry Andric wrote:
> On 2010-09-10 15:50, Thomas E. Spanjaard wrote:
> >While trying to build math/atlas on a FreeBSD/amd64 9.0-CURRENT r212411,
> >the kernel hangs at some point when math/atlas tries to run some tests
> >(presumably the ones to profile the code and optimise). The kernel
> >spouts messages about Starting event timers: LAPIC _at_ 1000Hz, HPET _at_
> >127Hz; then LAPIC _at_ 1000Hz, HPET _at_ 8128Hz (iirc), back, then back again.
> 
> It's probably running profiled executables (e.g. compiled with -pg)?
> This can lead to the above messages, and apparently also to deadlocks.
> 
> I am not sure what to do about it though, except confirm that this is
> very likely your problem...

Try this.

diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c
index 6b005de..7f0c781 100644
--- a/sys/kern/kern_clocksource.c
+++ b/sys/kern/kern_clocksource.c
_at__at_ -65,6 +65,7 _at__at_ inline static int	doconfigtimer(int i);
 static void		configtimer(int i);
 
 static struct eventtimer *timer[2] = { NULL, NULL };
+static int		blocked_timer[2];
 static int		timertest = 0;
 static int		timerticks[2] = { 0, 0 };
 static int		profiling_on = 0;
_at__at_ -91,6 +92,22 _at__at_ static DPCPU_DEFINE(tc, configtimer);
 	(((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) /		\
 	    ((bt)->frac >> 1))
 
+static void
+block_timer(int i)
+{
+
+	critical_enter();
+	atomic_add_acq_int(&blocked_timer[i], 1);
+}
+
+static void
+unblock_timer(int i)
+{
+
+	atomic_add_rel_int(&blocked_timer[i], -1);
+	critical_exit();
+}
+
 /* Per-CPU timer1 handler. */
 static int
 hardclockhandler(struct trapframe *frame)
_at__at_ -246,6 +263,8 _at__at_ doconfigtimer(int i)
 		atomic_store_rel_int(*conf + i, 0);
 		return (1);
 	}
+	if (atomic_load_acq_int(&blocked_timer[i]) > 0)
+		return (1);
 	return (0);
 }
 
_at__at_ -366,9 +385,7 _at__at_ cpu_initclocks_bsp(void)
 		profhz = round_freq(timer[1], stathz * 64);
 	}
 	tick = 1000000 / hz;
-	ET_LOCK();
 	cpu_restartclocks();
-	ET_UNLOCK();
 }
 
 /* Start per-CPU event timers on APs. */
_at__at_ -376,12 +393,10 _at__at_ void
 cpu_initclocks_ap(void)
 {
 
-	ET_LOCK();
 	if (timer[0]->et_flags & ET_FLAGS_PERCPU)
 		et_start(timer[0], NULL, &timerperiod[0]);
 	if (timer[1] && timer[1]->et_flags & ET_FLAGS_PERCPU)
 		et_start(timer[1], NULL, &timerperiod[1]);
-	ET_UNLOCK();
 }
 
 /* Reconfigure and restart event timers after configuration changes. */
_at__at_ -411,9 +426,11 _at__at_ cpu_restartclocks(void)
 		timer2hz = round_freq(timer[1], timer2hz);
 	}
 	timer1hz = round_freq(timer[0], timer1hz);
+#ifdef notyet
 	printf("Starting kernel event timers: %s _at_ %dHz, %s _at_ %dHz\n",
 	    timer[0]->et_name, timer1hz,
 	    timer[1] ? timer[1]->et_name : "NONE", timer2hz);
+#endif
 	/* Restart event timers. */
 	FREQ2BT(timer1hz, &timerperiod[0]);
 	configtimer(0);
_at__at_ -422,7 +439,9 _at__at_ cpu_restartclocks(void)
 		timerticks[1] = 0;
 		FREQ2BT(timer2hz, &timerperiod[1]);
 		configtimer(1);
+#ifdef notyet
 		timertest = 1;
+#endif
 	}
 }
 
_at__at_ -433,7 +452,11 _at__at_ cpu_startprofclock(void)
 
 	ET_LOCK();
 	profiling_on = 1;
+	block_timer(0);
+	block_timer(1);
 	cpu_restartclocks();
+	unblock_timer(1);
+	unblock_timer(0);
 	ET_UNLOCK();
 }
 
_at__at_ -444,7 +467,11 _at__at_ cpu_stopprofclock(void)
 
 	ET_LOCK();
 	profiling_on = 0;
+	block_timer(0);
+	block_timer(1);
 	cpu_restartclocks();
+	unblock_timer(1);
+	unblock_timer(0);
 	ET_UNLOCK();
 }
 
_at__at_ -461,10 +488,11 _at__at_ sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS)
 	snprintf(buf, sizeof(buf), "%s", et->et_name);
 	ET_UNLOCK();
 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+	if (error != 0 || req->newptr == NULL)
+		return (error);
 	ET_LOCK();
 	et = timer[0];
-	if (error != 0 || req->newptr == NULL ||
-	    strcmp(buf, et->et_name) == 0) {
+	if (strcmp(buf, et->et_name) == 0) {
 		ET_UNLOCK();
 		return (error);
 	}
_at__at_ -473,12 +501,14 _at__at_ sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS)
 		ET_UNLOCK();
 		return (ENOENT);
 	}
+	block_timer(0);
 	timer1hz = 0;
 	configtimer(0);
 	et_free(timer[0]);
 	timer[0] = et;
 	et_init(timer[0], timer1cb, NULL, NULL);
 	cpu_restartclocks();
+	unblock_timer(0);
 	ET_UNLOCK();
 	return (error);
 }
_at__at_ -501,10 +531,11 _at__at_ sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
 		snprintf(buf, sizeof(buf), "%s", et->et_name);
 	ET_UNLOCK();
 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+	if (error != 0 || req->newptr == NULL)
+		return (error);
 	ET_LOCK();
 	et = timer[1];
-	if (error != 0 || req->newptr == NULL ||
-	    strcmp(buf, et ? et->et_name : "NONE") == 0) {
+	if (strcmp(buf, et ? et->et_name : "NONE") == 0) {
 		ET_UNLOCK();
 		return (error);
 	}
_at__at_ -513,6 +544,7 _at__at_ sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
 		ET_UNLOCK();
 		return (ENOENT);
 	}
+	block_timer(1);
 	if (timer[1] != NULL) {
 		timer2hz = 0;
 		configtimer(1);
_at__at_ -522,6 +554,7 _at__at_ sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
 	if (timer[1] != NULL)
 		et_init(timer[1], timer2cb, NULL, NULL);
 	cpu_restartclocks();
+	unblock_timer(1);
 	ET_UNLOCK();
 	return (error);
 }
diff --git a/sys/kern/kern_et.c b/sys/kern/kern_et.c
index 6a56b1d..94e1466 100644
--- a/sys/kern/kern_et.c
+++ b/sys/kern/kern_et.c
_at__at_ -38,7 +38,7 _at__at_ SLIST_HEAD(et_eventtimers_list, eventtimer);
 static struct et_eventtimers_list eventtimers = SLIST_HEAD_INITIALIZER(et_eventtimers);
 
 struct mtx	et_eventtimers_mtx;
-MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_SPIN);
+MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_DEF);
 
 SYSCTL_NODE(_kern, OID_AUTO, eventtimer, CTLFLAG_RW, 0, "Event timers");
 SYSCTL_NODE(_kern_eventtimer, OID_AUTO, et, CTLFLAG_RW, 0, "");
diff --git a/sys/sys/timeet.h b/sys/sys/timeet.h
index bc713d6..87392a2 100644
--- a/sys/sys/timeet.h
+++ b/sys/sys/timeet.h
_at__at_ -83,8 +83,8 _at__at_ struct eventtimer {
 };
 
 extern struct mtx	et_eventtimers_mtx;
-#define	ET_LOCK()	mtx_lock_spin(&et_eventtimers_mtx)
-#define	ET_UNLOCK()	mtx_unlock_spin(&et_eventtimers_mtx)
+#define	ET_LOCK()	mtx_lock(&et_eventtimers_mtx)
+#define	ET_UNLOCK()	mtx_unlock(&et_eventtimers_mtx)
 
 /* Driver API */
 int	et_register(struct eventtimer *et);
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index f479bbe..7811441 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
_at__at_ -500,9 +500,11 _at__at_ lapic_et_start(struct eventtimer *et,
 		} while (lapic_timer_divisor <= 128);
 		if (lapic_timer_divisor > 128)
 			panic("lapic: Divisor too big");
+#ifdef notyet
 		if (bootverbose)
 			printf("lapic: Divisor %lu, Frequency %lu Hz\n",
 			    lapic_timer_divisor, value);
+#endif
 		et->et_frequency = value;
 		et->et_min_period.sec = 0;
 		et->et_min_period.frac =

Received on Fri Sep 10 2010 - 12:40:41 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:07 UTC