aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2008-12-21 20:24:48 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-27 05:53:07 -0500
commit1cc4fff0b360aeffeedb7d6db5089d88dd861700 (patch)
tree8c71507911722595731853f8b67add46abb78b5e /kernel
parent32e8d18683adb322c994d1a0fe02d66380991f45 (diff)
hrtimers: increase clock min delta threshold while interrupt hanging
Impact: avoid timer IRQ hanging slow systems While using the function graph tracer on a virtualized system, the hrtimer_interrupt can hang the system on an infinite loop. This can be caused in several situations: - the hardware is very slow and HZ is set too high - something intrusive is slowing the system down (tracing under emulation) ... and the next clock events to program are always before the current time. This patch implements a reasonable compromise: if such a situation is detected, we share the CPUs time in 1/4 to process the hrtimer interrupts. This is enough to let the system running without serious starvation. It has been successfully tested under VirtualBox with 1000 HZ and 100 HZ with function graph tracer launched. On both cases, the clock events were increased until about 25 ms periodic ticks, which means 40 HZ. So we change a hard to debug hang into a warning message and a system that still manages to limp along. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/hrtimer.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index bda9cb924276..c2a69b89ac61 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1171,6 +1171,29 @@ static void __run_hrtimer(struct hrtimer *timer)
1171 1171
1172#ifdef CONFIG_HIGH_RES_TIMERS 1172#ifdef CONFIG_HIGH_RES_TIMERS
1173 1173
1174static int force_clock_reprogram;
1175
1176/*
1177 * After 5 iteration's attempts, we consider that hrtimer_interrupt()
1178 * is hanging, which could happen with something that slows the interrupt
1179 * such as the tracing. Then we force the clock reprogramming for each future
1180 * hrtimer interrupts to avoid infinite loops and use the min_delta_ns
1181 * threshold that we will overwrite.
1182 * The next tick event will be scheduled to 3 times we currently spend on
1183 * hrtimer_interrupt(). This gives a good compromise, the cpus will spend
1184 * 1/4 of their time to process the hrtimer interrupts. This is enough to
1185 * let it running without serious starvation.
1186 */
1187
1188static inline void
1189hrtimer_interrupt_hanging(struct clock_event_device *dev,
1190 ktime_t try_time)
1191{
1192 force_clock_reprogram = 1;
1193 dev->min_delta_ns = (unsigned long)try_time.tv64 * 3;
1194 printk(KERN_WARNING "hrtimer: interrupt too slow, "
1195 "forcing clock min delta to %lu ns\n", dev->min_delta_ns);
1196}
1174/* 1197/*
1175 * High resolution timer interrupt 1198 * High resolution timer interrupt
1176 * Called with interrupts disabled 1199 * Called with interrupts disabled
@@ -1180,6 +1203,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
1180 struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); 1203 struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
1181 struct hrtimer_clock_base *base; 1204 struct hrtimer_clock_base *base;
1182 ktime_t expires_next, now; 1205 ktime_t expires_next, now;
1206 int nr_retries = 0;
1183 int i; 1207 int i;
1184 1208
1185 BUG_ON(!cpu_base->hres_active); 1209 BUG_ON(!cpu_base->hres_active);
@@ -1187,6 +1211,10 @@ void hrtimer_interrupt(struct clock_event_device *dev)
1187 dev->next_event.tv64 = KTIME_MAX; 1211 dev->next_event.tv64 = KTIME_MAX;
1188 1212
1189 retry: 1213 retry:
1214 /* 5 retries is enough to notice a hang */
1215 if (!(++nr_retries % 5))
1216 hrtimer_interrupt_hanging(dev, ktime_sub(ktime_get(), now));
1217
1190 now = ktime_get(); 1218 now = ktime_get();
1191 1219
1192 expires_next.tv64 = KTIME_MAX; 1220 expires_next.tv64 = KTIME_MAX;
@@ -1239,7 +1267,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
1239 1267
1240 /* Reprogramming necessary ? */ 1268 /* Reprogramming necessary ? */
1241 if (expires_next.tv64 != KTIME_MAX) { 1269 if (expires_next.tv64 != KTIME_MAX) {
1242 if (tick_program_event(expires_next, 0)) 1270 if (tick_program_event(expires_next, force_clock_reprogram))
1243 goto retry; 1271 goto retry;
1244 } 1272 }
1245} 1273}