Eventtimers b0rking w/ math/atlas
Kostik Belousov
kostikbel at gmail.com
Fri Sep 10 14:40:41 UTC 2010
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 @ 1000Hz, HPET @
> >127Hz; then LAPIC @ 1000Hz, HPET @ 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
@@ -65,6 +65,7 @@ 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;
@@ -91,6 +92,22 @@ 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)
@@ -246,6 +263,8 @@ 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);
}
@@ -366,9 +385,7 @@ 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. */
@@ -376,12 +393,10 @@ 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. */
@@ -411,9 +426,11 @@ cpu_restartclocks(void)
timer2hz = round_freq(timer[1], timer2hz);
}
timer1hz = round_freq(timer[0], timer1hz);
+#ifdef notyet
printf("Starting kernel event timers: %s @ %dHz, %s @ %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);
@@ -422,7 +439,9 @@ cpu_restartclocks(void)
timerticks[1] = 0;
FREQ2BT(timer2hz, &timerperiod[1]);
configtimer(1);
+#ifdef notyet
timertest = 1;
+#endif
}
}
@@ -433,7 +452,11 @@ cpu_startprofclock(void)
ET_LOCK();
profiling_on = 1;
+ block_timer(0);
+ block_timer(1);
cpu_restartclocks();
+ unblock_timer(1);
+ unblock_timer(0);
ET_UNLOCK();
}
@@ -444,7 +467,11 @@ cpu_stopprofclock(void)
ET_LOCK();
profiling_on = 0;
+ block_timer(0);
+ block_timer(1);
cpu_restartclocks();
+ unblock_timer(1);
+ unblock_timer(0);
ET_UNLOCK();
}
@@ -461,10 +488,11 @@ 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);
}
@@ -473,12 +501,14 @@ 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);
}
@@ -501,10 +531,11 @@ 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);
}
@@ -513,6 +544,7 @@ sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
ET_UNLOCK();
return (ENOENT);
}
+ block_timer(1);
if (timer[1] != NULL) {
timer2hz = 0;
configtimer(1);
@@ -522,6 +554,7 @@ 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
@@ -38,7 +38,7 @@ 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
@@ -83,8 +83,8 @@ 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
@@ -500,9 +500,11 @@ 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 =
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-current/attachments/20100910/8be6be30/attachment.pgp
More information about the freebsd-current
mailing list