* [Qemu-devel] [PATCH] Dynamic ticks
@ 2007-08-13 14:42 Dan Kenigsberg
2007-08-13 20:37 ` [Qemu-devel] Re: [kvm-devel] " Luca Tettamanti
0 siblings, 1 reply; 7+ messages in thread
From: Dan Kenigsberg @ 2007-08-13 14:42 UTC (permalink / raw)
To: qemu-devel, kvm-devel
"Dynamic ticks" in Qemu: have a SIGALRM generated only when it is
needed, instead of every 1 millisecond. This patch requires that the
host supports high resolution timers, since it arms a POSIX timer to the
nearest Qemu timer's expiry time (which might be rather near).
I tried to send a previous version of this patch yesterday, but luckily
it seems to have been eaten by qemu-devel list. I'd be happy to hear
your comments about it.
Index: configure
===================================================================
RCS file: /sources/qemu/qemu/configure,v
retrieving revision 1.152
diff -u -r1.152 configure
--- configure 1 Aug 2007 00:09:31 -0000 1.152
+++ configure 13 Aug 2007 14:18:18 -0000
@@ -294,6 +294,8 @@
*) echo "undefined SPARC architecture. Exiting";exit 1;;
esac
;;
+ --disable-dynamic-ticks) dynamic_ticks="no"
+ ;;
esac
done
@@ -859,6 +861,9 @@
if [ "$build_docs" = "yes" ] ; then
echo "BUILD_DOCS=yes" >> $config_mak
fi
+if test "$dynamic_ticks" != "no" ; then
+ echo "#define DYNAMIC_TICKS 1" >> $config_h
+fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.323
diff -u -r1.323 vl.c
--- vl.c 29 Jul 2007 17:57:25 -0000 1.323
+++ vl.c 13 Aug 2007 14:18:19 -0000
@@ -793,6 +793,15 @@
/* frequency of the times() clock tick */
static int timer_freq;
#endif
+#ifdef DYNAMIC_TICKS
+/* If DYNAMIC_TICKS is defined (and use_dynamic_ticks selected) qemu does not
+ * attepmt to generate SIGALRM at a constant rate. Rather, the system timer is
+ * set to generate SIGALRM only when it is needed. DYNAMIC_TICKS reduces the
+ * number of SIGALRMs sent to idle dynamic-ticked guests. */
+static timer_t host_timer;
+static void rearm_host_timer(void);
+static int use_dynamic_ticks = 1;
+#endif
QEMUClock *qemu_new_clock(int type)
{
@@ -838,6 +847,10 @@
}
pt = &t->next;
}
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks)
+ rearm_host_timer();
+#endif
}
/* modify the current timer so that it will be fired when current_time
@@ -897,6 +910,7 @@
/* run the callback (the timer list can be modified) */
ts->cb(ts->opaque);
}
+ rearm_host_timer();
}
int64_t qemu_get_clock(QEMUClock *clock)
@@ -1004,7 +1018,12 @@
last_clock = ti;
}
#endif
- if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+
+ if (
+#ifdef DYNAMIC_TICKS
+ use_dynamic_ticks ||
+#endif
+ qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
qemu_get_clock(vm_clock)) ||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
@@ -1109,21 +1128,37 @@
act.sa_handler = host_alarm_handler;
sigaction(SIGALRM, &act, NULL);
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 10 * 1000;
- setitimer(ITIMER_REAL, &itv, NULL);
- /* we probe the tick duration of the kernel to inform the user if
- the emulated kernel requested a too high timer frequency */
- getitimer(ITIMER_REAL, &itv);
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks) {
+ struct sigevent ev;
+ ev.sigev_value.sival_int = 0;
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = SIGALRM;
+ if (timer_create(CLOCK_REALTIME, &ev, &host_timer))
+ perror("timer_create");
+ } else
+#endif /* DYNAMIC_TICKS */
+ {
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 10 * 1000;
+ setitimer(ITIMER_REAL, &itv, NULL);
+ /* we probe the tick duration of the kernel to inform the user if
+ the emulated kernel requested a too high timer frequency */
+ getitimer(ITIMER_REAL, &itv);
+ }
#if defined(__linux__)
/* XXX: force /dev/rtc usage because even 2.6 kernels may not
have timers with 1 ms resolution. The correct solution will
be to use the POSIX real time timers available in recent
2.6 kernels */
- if (itv.it_interval.tv_usec > 1000 || 1) {
+ if (
+#ifdef DYNAMIC_TICKS
+ !use_dynamic_ticks &&
+#endif
+ (itv.it_interval.tv_usec > 1000 || 1)) {
/* try to use /dev/rtc to have a faster timer */
if (start_rtc_timer() < 0)
goto use_itimer;
@@ -6287,6 +6322,10 @@
cpu_enable_ticks();
vm_running = 1;
vm_state_notify(1);
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks)
+ rearm_host_timer();
+#endif
}
}
@@ -6708,6 +6747,9 @@
#ifdef TARGET_SPARC
"-prom-env variable=value set OpenBIOS nvram variables\n"
#endif
+#if defined(DYNAMIC_TICKS)
+ "-no-dyntick don't use dynamic ticks\n"
+#endif
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -6805,6 +6847,9 @@
QEMU_OPTION_name,
QEMU_OPTION_prom_env,
QEMU_OPTION_old_param,
+#ifdef DYNAMIC_TICKS
+ QEMU_OPTION_no_dyntick,
+#endif
};
typedef struct QEMUOption {
@@ -6909,6 +6954,9 @@
#if defined(TARGET_ARM)
{ "old-param", 0, QEMU_OPTION_old_param },
#endif
+#if defined(DYNAMIC_TICKS)
+ { "no-dyntick", 0, QEMU_OPTION_no_dyntick },
+#endif
{ NULL },
};
@@ -7137,6 +7185,53 @@
#define MAX_NET_CLIENTS 32
+
+#ifdef DYNAMIC_TICKS
+/* call host_alarm_handler just when the nearest QEMUTimer expires */
+/* expire_time is measured in nanosec for vm_clock
+ * but in millisec for rt_clock */
+static void rearm_host_timer(void)
+{
+ struct itimerspec timeout;
+ int64_t nearest_delta_us = INT64_MAX;
+
+ if (active_timers[QEMU_TIMER_REALTIME] ||
+ active_timers[QEMU_TIMER_VIRTUAL]) {
+ int64_t vmdelta_us, current_us;
+ if (active_timers[QEMU_TIMER_REALTIME]) {
+ nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000;
+ }
+
+ if (active_timers[QEMU_TIMER_VIRTUAL]) {
+ vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - qemu_get_clock(vm_clock)+999)/1000; /* round up */
+ if (vmdelta_us < nearest_delta_us) {
+ nearest_delta_us = vmdelta_us;
+ }
+ }
+ /* Avoid arming the timer to negative, zero, or too low values */
+ /* MIN_TIMER_REARM_US should be optimized */
+#define MIN_TIMER_REARM_US 250
+ if (nearest_delta_us <= MIN_TIMER_REARM_US) {
+ nearest_delta_us = MIN_TIMER_REARM_US;
+ }
+
+ /* check whether a timer is already running */
+ if (timer_gettime(host_timer, &timeout))
+ perror("gettime");
+ current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
+ if (current_us && current_us <= nearest_delta_us)
+ return;
+
+ timeout.it_interval.tv_sec = 0;
+ timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+ timeout.it_value.tv_sec = nearest_delta_us / 1000000;
+ timeout.it_value.tv_nsec = nearest_delta_us % 1000000 * 1000;
+ if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL))
+ perror("settime");
+ }
+}
+#endif /* DYNAMIC_TICKS */
+
int main(int argc, char **argv)
{
#ifdef CONFIG_GDBSTUB
@@ -7687,6 +7782,12 @@
#ifdef TARGET_ARM
case QEMU_OPTION_old_param:
old_param = 1;
+ break;
+#endif
+#if defined(DYNAMIC_TICKS)
+ case QEMU_OPTION_no_dyntick:
+ use_dynamic_ticks = 0;
+ break;
#endif
}
}
^ permalink raw reply [flat|nested] 7+ messages in thread* [Qemu-devel] Re: [kvm-devel] [PATCH] Dynamic ticks 2007-08-13 14:42 [Qemu-devel] [PATCH] Dynamic ticks Dan Kenigsberg @ 2007-08-13 20:37 ` Luca Tettamanti 2007-08-13 23:06 ` Thiemo Seufer ` (2 more replies) 0 siblings, 3 replies; 7+ messages in thread From: Luca Tettamanti @ 2007-08-13 20:37 UTC (permalink / raw) To: Dan Kenigsberg; +Cc: kvm-devel, qemu-devel Il Mon, Aug 13, 2007 at 05:42:55PM +0300, Dan Kenigsberg ha scritto: > "Dynamic ticks" in Qemu: have a SIGALRM generated only when it is > needed, instead of every 1 millisecond. This patch requires that the > host supports high resolution timers, since it arms a POSIX timer to the > nearest Qemu timer's expiry time (which might be rather near). > > I tried to send a previous version of this patch yesterday, but luckily > it seems to have been eaten by qemu-devel list. I'd be happy to hear > your comments about it. I like it ;) I have some comments (and a reworked patch at the end): > Index: vl.c > =================================================================== > RCS file: /sources/qemu/qemu/vl.c,v > retrieving revision 1.323 > diff -u -r1.323 vl.c > --- vl.c 29 Jul 2007 17:57:25 -0000 1.323 > +++ vl.c 13 Aug 2007 14:18:19 -0000 > @@ -793,6 +793,15 @@ > /* frequency of the times() clock tick */ > static int timer_freq; > #endif > +#ifdef DYNAMIC_TICKS > +/* If DYNAMIC_TICKS is defined (and use_dynamic_ticks selected) qemu does not > + * attepmt to generate SIGALRM at a constant rate. Rather, the system timer is > + * set to generate SIGALRM only when it is needed. DYNAMIC_TICKS reduces the > + * number of SIGALRMs sent to idle dynamic-ticked guests. */ > +static timer_t host_timer; > +static void rearm_host_timer(void); > +static int use_dynamic_ticks = 1; > +#endif I'd make use_dynamic_ticks a static inline helper, in this way gcc will still optimize it away when not need and you can remove a lot of #ifdefs from the code. > > QEMUClock *qemu_new_clock(int type) > { > @@ -838,6 +847,10 @@ > } > pt = &t->next; > } > +#ifdef DYNAMIC_TICKS > + if (use_dynamic_ticks) > + rearm_host_timer(); > +#endif Like here > } > > /* modify the current timer so that it will be fired when current_time > @@ -897,6 +910,7 @@ > /* run the callback (the timer list can be modified) */ > ts->cb(ts->opaque); > } > + rearm_host_timer(); > } > > int64_t qemu_get_clock(QEMUClock *clock) > @@ -1004,7 +1018,12 @@ > last_clock = ti; > } > #endif > - if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], > + > + if ( > +#ifdef DYNAMIC_TICKS > + use_dynamic_ticks || > +#endif > + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], > qemu_get_clock(vm_clock)) || > qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], > qemu_get_clock(rt_clock))) { and here (this one is pretty ugly btw) > @@ -1109,21 +1128,37 @@ > act.sa_handler = host_alarm_handler; > sigaction(SIGALRM, &act, NULL); > > - itv.it_interval.tv_sec = 0; > - itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ > - itv.it_value.tv_sec = 0; > - itv.it_value.tv_usec = 10 * 1000; > - setitimer(ITIMER_REAL, &itv, NULL); > - /* we probe the tick duration of the kernel to inform the user if > - the emulated kernel requested a too high timer frequency */ > - getitimer(ITIMER_REAL, &itv); > +#ifdef DYNAMIC_TICKS > + if (use_dynamic_ticks) { > + struct sigevent ev; > + ev.sigev_value.sival_int = 0; > + ev.sigev_notify = SIGEV_SIGNAL; > + ev.sigev_signo = SIGALRM; > + if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) > + perror("timer_create"); Should this fail you end up with a non-working QEMU. It's pretty easy to recover though, running this code: > + } else > +#endif /* DYNAMIC_TICKS */ > + { > + itv.it_interval.tv_sec = 0; > + itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ > + itv.it_value.tv_sec = 0; > + itv.it_value.tv_usec = 10 * 1000; > + setitimer(ITIMER_REAL, &itv, NULL); > + /* we probe the tick duration of the kernel to inform the user if > + the emulated kernel requested a too high timer frequency */ > + getitimer(ITIMER_REAL, &itv); > + } > > #if defined(__linux__) > /* XXX: force /dev/rtc usage because even 2.6 kernels may not > have timers with 1 ms resolution. The correct solution will > be to use the POSIX real time timers available in recent > 2.6 kernels */ > - if (itv.it_interval.tv_usec > 1000 || 1) { > + if ( > +#ifdef DYNAMIC_TICKS > + !use_dynamic_ticks && helper ;) > +#endif > + (itv.it_interval.tv_usec > 1000 || 1)) { Plus, in this way you change the behaviour from "always try RTC under Linux" to "don't use RTC is dynticks is enabled". Is this what you really want? Furthermore: I'm not sure about the cost of reprogramming the CMOS RTC, but with HPET should be feasible to program the timer in one-shot mode. > /* try to use /dev/rtc to have a faster timer */ > if (start_rtc_timer() < 0) > goto use_itimer; > @@ -6287,6 +6322,10 @@ > cpu_enable_ticks(); > vm_running = 1; > vm_state_notify(1); > +#ifdef DYNAMIC_TICKS > + if (use_dynamic_ticks) > + rearm_host_timer(); > +#endif > } > } > > @@ -6708,6 +6747,9 @@ > #ifdef TARGET_SPARC > "-prom-env variable=value set OpenBIOS nvram variables\n" > #endif > +#if defined(DYNAMIC_TICKS) > + "-no-dyntick don't use dynamic ticks\n" > +#endif > "\n" > "During emulation, the following keys are useful:\n" > "ctrl-alt-f toggle full screen\n" > @@ -6805,6 +6847,9 @@ > QEMU_OPTION_name, > QEMU_OPTION_prom_env, > QEMU_OPTION_old_param, > +#ifdef DYNAMIC_TICKS > + QEMU_OPTION_no_dyntick, > +#endif > }; > > typedef struct QEMUOption { > @@ -6909,6 +6954,9 @@ > #if defined(TARGET_ARM) > { "old-param", 0, QEMU_OPTION_old_param }, > #endif > +#if defined(DYNAMIC_TICKS) > + { "no-dyntick", 0, QEMU_OPTION_no_dyntick }, > +#endif > { NULL }, > }; > > @@ -7137,6 +7185,53 @@ > > #define MAX_NET_CLIENTS 32 > > + > +#ifdef DYNAMIC_TICKS > +/* call host_alarm_handler just when the nearest QEMUTimer expires */ > +/* expire_time is measured in nanosec for vm_clock > + * but in millisec for rt_clock */ > +static void rearm_host_timer(void) > +{ > + struct itimerspec timeout; > + int64_t nearest_delta_us = INT64_MAX; > + > + if (active_timers[QEMU_TIMER_REALTIME] || > + active_timers[QEMU_TIMER_VIRTUAL]) { > + int64_t vmdelta_us, current_us; > + if (active_timers[QEMU_TIMER_REALTIME]) { > + nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; > + } > + > + if (active_timers[QEMU_TIMER_VIRTUAL]) { > + vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - qemu_get_clock(vm_clock)+999)/1000; /* round up */ > + if (vmdelta_us < nearest_delta_us) { > + nearest_delta_us = vmdelta_us; > + } > + } > + /* Avoid arming the timer to negative, zero, or too low values */ > + /* MIN_TIMER_REARM_US should be optimized */ > +#define MIN_TIMER_REARM_US 250 > + if (nearest_delta_us <= MIN_TIMER_REARM_US) { > + nearest_delta_us = MIN_TIMER_REARM_US; > + } > + > + /* check whether a timer is already running */ > + if (timer_gettime(host_timer, &timeout)) > + perror("gettime"); Hum. > + current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; > + if (current_us && current_us <= nearest_delta_us) > + return; > + > + timeout.it_interval.tv_sec = 0; > + timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ > + timeout.it_value.tv_sec = nearest_delta_us / 1000000; > + timeout.it_value.tv_nsec = nearest_delta_us % 1000000 * 1000; > + if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) > + perror("settime"); Hum. Hopefully those 2 functions won't fail after timer_create() succeeded; still error handling should be improved. I can't see an easy way to recover, maybe the right thing to do is printing the error and closing the VM (instead of leaving it half-dead). > + } > +} > +#endif /* DYNAMIC_TICKS */ > + > int main(int argc, char **argv) > { > #ifdef CONFIG_GDBSTUB > @@ -7687,6 +7782,12 @@ > #ifdef TARGET_ARM > case QEMU_OPTION_old_param: > old_param = 1; > + break; > +#endif > +#if defined(DYNAMIC_TICKS) > + case QEMU_OPTION_no_dyntick: > + use_dynamic_ticks = 0; > + break; > #endif > } > } I've implemented some of my suggestions in the following patch - rebased to kvm-userspace current git since it's easier to test (...ok, I'm lazy - but you get the idea): diff --git a/qemu/configure b/qemu/configure index 365b7fb..38373db 100755 --- a/qemu/configure +++ b/qemu/configure @@ -262,6 +262,8 @@ for opt do ;; --enable-uname-release=*) uname_release="$optarg" ;; + --disable-dynamic-ticks) dynamic_ticks="no" + ;; esac done @@ -788,6 +790,9 @@ echo "TARGET_DIRS=$target_list" >> $config_mak if [ "$build_docs" = "yes" ] ; then echo "BUILD_DOCS=yes" >> $config_mak fi +if test "$dynamic_ticks" != "no" ; then + echo "#define DYNAMIC_TICKS 1" >> $config_h +fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then diff --git a/qemu/vl.c b/qemu/vl.c index 4b73f77..05639d7 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -759,6 +759,35 @@ static unsigned int period = 1; static int timer_freq; #endif +#ifdef DYNAMIC_TICKS +/* If DYNAMIC_TICKS is defined (and use_dynamic_ticks selected) qemu does not + * attepmt to generate SIGALRM at a constant rate. Rather, the system timer is + * set to generate SIGALRM only when it is needed. DYNAMIC_TICKS reduces the + * number of SIGALRMs sent to idle dynamic-ticked guests. */ + +static void rearm_host_timer(void); +static int dynticks_create_timer(void); + +static int use_dynticks = 1; + +static int use_dynamic_ticks() { + return use_dynticks; +} + +#else + +static void rearm_host_timer(void) {} + +static int dynticks_create_timer(void) { + return 0; +} + +static int use_dynamic_ticks() { + return 0; +} + +#endif + QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; @@ -803,6 +832,7 @@ void qemu_del_timer(QEMUTimer *ts) } pt = &t->next; } + rearm_host_timer(); } /* modify the current timer so that it will be fired when current_time @@ -862,6 +892,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } + rearm_host_timer(); } int64_t qemu_get_clock(QEMUClock *clock) @@ -969,7 +1000,8 @@ static void host_alarm_handler(int host_signum) last_clock = ti; } #endif - if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + if (use_dynamic_ticks() || + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { @@ -1126,21 +1158,26 @@ static void init_timer_alarm(void) act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - setitimer(ITIMER_REAL, &itv, NULL); - /* we probe the tick duration of the kernel to inform the user if - the emulated kernel requested a too high timer frequency */ - getitimer(ITIMER_REAL, &itv); + if (use_dynamic_ticks() && dynticks_create_timer()) { + /* dynticks disabled or failed to create a timer, fallback + * to old code. + */ + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + setitimer(ITIMER_REAL, &itv, NULL); + /* we probe the tick duration of the kernel to inform the user if + the emulated kernel requested a too high timer frequency */ + getitimer(ITIMER_REAL, &itv); + } #if defined(__linux__) /* XXX: force /dev/rtc usage because even 2.6 kernels may not have timers with 1 ms resolution. The correct solution will be to use the POSIX real time timers available in recent 2.6 kernels */ - if (itv.it_interval.tv_usec > 1000 || 1) { + if (!use_dynamic_ticks() && (itv.it_interval.tv_usec > 1000 || 1)) { /* try to use /dev/rtc to have a faster timer */ if ((!use_rtc && !use_hpet) || (start_rtc_timer() < 0)) goto use_itimer; @@ -6110,6 +6147,7 @@ void vm_start(void) cpu_enable_ticks(); vm_running = 1; vm_state_notify(1); + rearm_host_timer(); } } @@ -6536,6 +6574,9 @@ void help(void) "-no-rtc don't use /dev/rtc for timer alarm (do use gettimeofday)\n" "-use-hpet use /dev/hpet (HPET) instead of RTC for timer alarm\n" #endif +#ifdef DYNAMIC_TICKS + "-no-dyntick don't use dynamic ticks\n" +#endif "-option-rom rom load a file, rom, into the option ROM space\n" "\n" "During emulation, the following keys are useful:\n" @@ -6630,6 +6671,9 @@ enum { QEMU_OPTION_use_hpet, #endif QEMU_OPTION_cpu_vendor, +#ifdef DYNAMIC_TICKS + QEMU_OPTION_no_dyntick, +#endif }; typedef struct QEMUOption { @@ -6728,6 +6772,9 @@ const QEMUOption qemu_options[] = { { "use-hpet", 0, QEMU_OPTION_use_hpet }, #endif { "cpu-vendor", HAS_ARG, QEMU_OPTION_cpu_vendor }, +#if defined(DYNAMIC_TICKS) + { "no-dyntick", 0, QEMU_OPTION_no_dyntick }, +#endif { NULL }, }; @@ -6932,6 +6979,78 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) #define MAX_NET_CLIENTS 32 +#ifdef DYNAMIC_TICKS + +static timer_t host_timer; + +static int dynticks_create_timer() { + struct sigevent ev; + + ev.sigev_value.sival_int = 0; + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGALRM; + + if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { + perror("timer_create"); + + /* disable dynticks */ + fprintf(stderr, "Dynamic Ticks disabled\n"); + use_dynticks = 0; + + return -1; + } + + return 0; +} + +/* call host_alarm_handler just when the nearest QEMUTimer expires */ +/* expire_time is measured in nanosec for vm_clock but in millisec + * for rt_clock + */ +static void rearm_host_timer(void) { + struct itimerspec timeout; + int64_t nearest_delta_us = INT64_MAX; + + if (!use_dynamic_ticks()) + return; + + if (active_timers[QEMU_TIMER_REALTIME] || + active_timers[QEMU_TIMER_VIRTUAL]) { + int64_t vmdelta_us, current_us; + + if (active_timers[QEMU_TIMER_REALTIME]) + nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; + + if (active_timers[QEMU_TIMER_VIRTUAL]) { + /* round up */ + vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - qemu_get_clock(vm_clock)+999)/1000; + if (vmdelta_us < nearest_delta_us) + nearest_delta_us = vmdelta_us; + } + + /* Avoid arming the timer to negative, zero, or too low values */ + /* MIN_TIMER_REARM_US should be optimized */ +#define MIN_TIMER_REARM_US 250 + if (nearest_delta_us <= MIN_TIMER_REARM_US) + nearest_delta_us = MIN_TIMER_REARM_US; + + /* check whether a timer is already running */ + if (timer_gettime(host_timer, &timeout)) + perror("gettime"); + current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; + if (current_us && current_us <= nearest_delta_us) + return; + + timeout.it_interval.tv_sec = 0; + timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ + timeout.it_value.tv_sec = nearest_delta_us / 1000000; + timeout.it_value.tv_nsec = nearest_delta_us % 1000000 * 1000; + if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) + perror("settime"); + } +} +#endif /* DYNAMIC_TICKS */ + static int saved_argc; static char **saved_argv; @@ -7457,6 +7576,11 @@ int main(int argc, char **argv) case QEMU_OPTION_cpu_vendor: cpu_vendor_string = optarg; break; +#ifdef DYNAMIC_TICKS + case QEMU_OPTION_no_dyntick: + use_dynticks = 0; + break; +#endif } } } Luca -- Se non puoi convincerli, confondili. ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] Re: [kvm-devel] [PATCH] Dynamic ticks 2007-08-13 20:37 ` [Qemu-devel] Re: [kvm-devel] " Luca Tettamanti @ 2007-08-13 23:06 ` Thiemo Seufer 2007-08-15 17:05 ` [Qemu-devel] " Dan Kenigsberg 2007-08-15 17:13 ` Dan Kenigsberg 2007-08-16 9:36 ` [Qemu-devel] " Dan Kenigsberg 2 siblings, 1 reply; 7+ messages in thread From: Thiemo Seufer @ 2007-08-13 23:06 UTC (permalink / raw) To: Luca Tettamanti; +Cc: kvm-devel, Dan Kenigsberg, qemu-devel Luca Tettamanti wrote: [snip] > I've implemented some of my suggestions in the following patch - rebased > to kvm-userspace current git since it's easier to test (...ok, I'm lazy - > but you get the idea): > > > diff --git a/qemu/configure b/qemu/configure > index 365b7fb..38373db 100755 > --- a/qemu/configure > +++ b/qemu/configure > @@ -262,6 +262,8 @@ for opt do > ;; > --enable-uname-release=*) uname_release="$optarg" > ;; > + --disable-dynamic-ticks) dynamic_ticks="no" > + ;; Is there a situation where the attempt to use dynticks is harmful? > esac > done > > @@ -788,6 +790,9 @@ echo "TARGET_DIRS=$target_list" >> $config_mak > if [ "$build_docs" = "yes" ] ; then > echo "BUILD_DOCS=yes" >> $config_mak > fi > +if test "$dynamic_ticks" != "no" ; then > + echo "#define DYNAMIC_TICKS 1" >> $config_h > +fi > > # XXX: suppress that > if [ "$bsd" = "yes" ] ; then > diff --git a/qemu/vl.c b/qemu/vl.c > index 4b73f77..05639d7 100644 > --- a/qemu/vl.c > +++ b/qemu/vl.c > @@ -759,6 +759,35 @@ static unsigned int period = 1; > static int timer_freq; > #endif > > +#ifdef DYNAMIC_TICKS > +/* If DYNAMIC_TICKS is defined (and use_dynamic_ticks selected) qemu does not > + * attepmt to generate SIGALRM at a constant rate. Rather, the system timer is > + * set to generate SIGALRM only when it is needed. DYNAMIC_TICKS reduces the > + * number of SIGALRMs sent to idle dynamic-ticked guests. */ > + > +static void rearm_host_timer(void); > +static int dynticks_create_timer(void); > + > +static int use_dynticks = 1; > + > +static int use_dynamic_ticks() { > + return use_dynticks; > +} > + > +#else > + > +static void rearm_host_timer(void) {} > + > +static int dynticks_create_timer(void) { > + return 0; > +} > + > +static int use_dynamic_ticks() { > + return 0; > +} > + > +#endif This optimization is probably not worth an #ifdef. > + > QEMUClock *qemu_new_clock(int type) > { > QEMUClock *clock; > @@ -803,6 +832,7 @@ void qemu_del_timer(QEMUTimer *ts) > } > pt = &t->next; > } > + rearm_host_timer(); > } > > /* modify the current timer so that it will be fired when current_time > @@ -862,6 +892,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) > /* run the callback (the timer list can be modified) */ > ts->cb(ts->opaque); > } > + rearm_host_timer(); > } > > int64_t qemu_get_clock(QEMUClock *clock) > @@ -969,7 +1000,8 @@ static void host_alarm_handler(int host_signum) > last_clock = ti; > } > #endif > - if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], > + if (use_dynamic_ticks() || > + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], > qemu_get_clock(vm_clock)) || > qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], > qemu_get_clock(rt_clock))) { > @@ -1126,21 +1158,26 @@ static void init_timer_alarm(void) > act.sa_handler = host_alarm_handler; > sigaction(SIGALRM, &act, NULL); > > - itv.it_interval.tv_sec = 0; > - itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ > - itv.it_value.tv_sec = 0; > - itv.it_value.tv_usec = 10 * 1000; > - setitimer(ITIMER_REAL, &itv, NULL); > - /* we probe the tick duration of the kernel to inform the user if > - the emulated kernel requested a too high timer frequency */ > - getitimer(ITIMER_REAL, &itv); > + if (use_dynamic_ticks() && dynticks_create_timer()) { Maybe dynticks_create_timer(); if (!use_dynamic_ticks()) { ... is a bit clearer. Or maybe put both alternatives in a create_timer() function. > + /* dynticks disabled or failed to create a timer, fallback > + * to old code. > + */ > + itv.it_interval.tv_sec = 0; > + itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ > + itv.it_value.tv_sec = 0; > + itv.it_value.tv_usec = 10 * 1000; > + setitimer(ITIMER_REAL, &itv, NULL); > + /* we probe the tick duration of the kernel to inform the user if > + the emulated kernel requested a too high timer frequency */ > + getitimer(ITIMER_REAL, &itv); > + } > > #if defined(__linux__) > /* XXX: force /dev/rtc usage because even 2.6 kernels may not > have timers with 1 ms resolution. The correct solution will > be to use the POSIX real time timers available in recent > 2.6 kernels */ > - if (itv.it_interval.tv_usec > 1000 || 1) { > + if (!use_dynamic_ticks() && (itv.it_interval.tv_usec > 1000 || 1)) { > /* try to use /dev/rtc to have a faster timer */ > if ((!use_rtc && !use_hpet) || (start_rtc_timer() < 0)) > goto use_itimer; > @@ -6110,6 +6147,7 @@ void vm_start(void) > cpu_enable_ticks(); > vm_running = 1; > vm_state_notify(1); > + rearm_host_timer(); > } > } > > @@ -6536,6 +6574,9 @@ void help(void) > "-no-rtc don't use /dev/rtc for timer alarm (do use gettimeofday)\n" > "-use-hpet use /dev/hpet (HPET) instead of RTC for timer alarm\n" > #endif > +#ifdef DYNAMIC_TICKS > + "-no-dyntick don't use dynamic ticks\n" > +#endif > "-option-rom rom load a file, rom, into the option ROM space\n" > "\n" > "During emulation, the following keys are useful:\n" > @@ -6630,6 +6671,9 @@ enum { > QEMU_OPTION_use_hpet, > #endif > QEMU_OPTION_cpu_vendor, > +#ifdef DYNAMIC_TICKS > + QEMU_OPTION_no_dyntick, > +#endif > }; > > typedef struct QEMUOption { > @@ -6728,6 +6772,9 @@ const QEMUOption qemu_options[] = { > { "use-hpet", 0, QEMU_OPTION_use_hpet }, > #endif > { "cpu-vendor", HAS_ARG, QEMU_OPTION_cpu_vendor }, > +#if defined(DYNAMIC_TICKS) > + { "no-dyntick", 0, QEMU_OPTION_no_dyntick }, > +#endif > { NULL }, > }; > > @@ -6932,6 +6979,78 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) > > #define MAX_NET_CLIENTS 32 > > +#ifdef DYNAMIC_TICKS > + > +static timer_t host_timer; > + > +static int dynticks_create_timer() { > + struct sigevent ev; > + > + ev.sigev_value.sival_int = 0; > + ev.sigev_notify = SIGEV_SIGNAL; > + ev.sigev_signo = SIGALRM; > + > + if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { > + perror("timer_create"); > + > + /* disable dynticks */ > + fprintf(stderr, "Dynamic Ticks disabled\n"); > + use_dynticks = 0; > + > + return -1; > + } > + > + return 0; > +} > + > +/* call host_alarm_handler just when the nearest QEMUTimer expires */ > +/* expire_time is measured in nanosec for vm_clock but in millisec > + * for rt_clock > + */ > +static void rearm_host_timer(void) { > + struct itimerspec timeout; > + int64_t nearest_delta_us = INT64_MAX; > + > + if (!use_dynamic_ticks()) > + return; > + > + if (active_timers[QEMU_TIMER_REALTIME] || > + active_timers[QEMU_TIMER_VIRTUAL]) { > + int64_t vmdelta_us, current_us; > + > + if (active_timers[QEMU_TIMER_REALTIME]) > + nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; > + > + if (active_timers[QEMU_TIMER_VIRTUAL]) { > + /* round up */ > + vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - qemu_get_clock(vm_clock)+999)/1000; > + if (vmdelta_us < nearest_delta_us) > + nearest_delta_us = vmdelta_us; > + } > + > + /* Avoid arming the timer to negative, zero, or too low values */ > + /* MIN_TIMER_REARM_US should be optimized */ > +#define MIN_TIMER_REARM_US 250 > + if (nearest_delta_us <= MIN_TIMER_REARM_US) > + nearest_delta_us = MIN_TIMER_REARM_US; > + > + /* check whether a timer is already running */ > + if (timer_gettime(host_timer, &timeout)) > + perror("gettime"); ... and exit() ? > + current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; > + if (current_us && current_us <= nearest_delta_us) > + return; > + > + timeout.it_interval.tv_sec = 0; > + timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ > + timeout.it_value.tv_sec = nearest_delta_us / 1000000; > + timeout.it_value.tv_nsec = nearest_delta_us % 1000000 * 1000; > + if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) > + perror("settime"); Likewise here. > + } > +} > +#endif /* DYNAMIC_TICKS */ > + > static int saved_argc; > static char **saved_argv; > > @@ -7457,6 +7576,11 @@ int main(int argc, char **argv) > case QEMU_OPTION_cpu_vendor: > cpu_vendor_string = optarg; > break; > +#ifdef DYNAMIC_TICKS > + case QEMU_OPTION_no_dyntick: > + use_dynticks = 0; > + break; > +#endif > } > } > } > > Luca > -- > Se non puoi convincerli, confondili. > > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] Re: [PATCH] Dynamic ticks 2007-08-13 23:06 ` Thiemo Seufer @ 2007-08-15 17:05 ` Dan Kenigsberg 0 siblings, 0 replies; 7+ messages in thread From: Dan Kenigsberg @ 2007-08-15 17:05 UTC (permalink / raw) To: Thiemo Seufer; +Cc: kvm-devel, Luca Tettamanti, qemu-devel Thank you (Luca and Thiemo) for your prompt review and comments! On Tue, Aug 14, 2007 at 12:06:20AM +0100, Thiemo Seufer wrote: > Luca Tettamanti wrote: > [snip] > > I've implemented some of my suggestions in the following patch - rebased > > to kvm-userspace current git since it's easier to test (...ok, I'm lazy - > > but you get the idea): > > > > > > diff --git a/qemu/configure b/qemu/configure > > index 365b7fb..38373db 100755 > > --- a/qemu/configure > > +++ b/qemu/configure > > @@ -262,6 +262,8 @@ for opt do > > ;; > > --enable-uname-release=*) uname_release="$optarg" > > ;; > > + --disable-dynamic-ticks) dynamic_ticks="no" > > + ;; > > Is there a situation where the attempt to use dynticks is harmful? > Well, I cannot really say when and how much, but rearming the timer every shot has its price (especially when the guest is not idling). I thought that even just uselessly checking use_dynamic_ticks in every signal handler call would be frowned upon. Maybe you are right, and for the sake of code and build simplisity I should drop that ifdef altogether. Thanks, Dan. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] Re: [PATCH] Dynamic ticks 2007-08-13 20:37 ` [Qemu-devel] Re: [kvm-devel] " Luca Tettamanti 2007-08-13 23:06 ` Thiemo Seufer @ 2007-08-15 17:13 ` Dan Kenigsberg 2007-08-15 19:48 ` [Qemu-devel] RE: [kvm-devel] " Dor Laor 2007-08-16 9:36 ` [Qemu-devel] " Dan Kenigsberg 2 siblings, 1 reply; 7+ messages in thread From: Dan Kenigsberg @ 2007-08-15 17:13 UTC (permalink / raw) To: Luca Tettamanti; +Cc: kvm-devel, qemu-devel On Mon, Aug 13, 2007 at 10:37:41PM +0200, Luca Tettamanti wrote: > > I like it ;) I have some comments (and a reworked patch at the end): > And thanks a lot for that. > > Plus, in this way you change the behaviour from "always try RTC under > Linux" to "don't use RTC is dynticks is enabled". > Is this what you really want? I don't know whether this is what should be done, but it's what I wanted. I was not looking for a dynamic-ticks solution for every available time source, and considered the system's POSIX timer as a good enough source. Am I wrong here? ^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] RE: [kvm-devel] [PATCH] Dynamic ticks 2007-08-15 17:13 ` Dan Kenigsberg @ 2007-08-15 19:48 ` Dor Laor 0 siblings, 0 replies; 7+ messages in thread From: Dor Laor @ 2007-08-15 19:48 UTC (permalink / raw) To: Dan Kenigsberg, Luca Tettamanti; +Cc: kvm-devel, qemu-devel >> I like it ;) I have some comments (and a reworked patch at the end): >> > >And thanks a lot for that. > >> >> Plus, in this way you change the behaviour from "always try RTC under >> Linux" to "don't use RTC is dynticks is enabled". >> Is this what you really want? > >I don't know whether this is what should be done, but it's what I >wanted. >I was not looking for a dynamic-ticks solution for every available time >source, and considered the system's POSIX timer as a good enough source. >Am I wrong here? Using dyn-tick should be the default option. Not only it saves ticks for guests with HZ < 1000, it improves the accurency and responsiveness of the system. There are also issues with RTC@1024 because of HPET inteference. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] Re: [kvm-devel] [PATCH] Dynamic ticks 2007-08-13 20:37 ` [Qemu-devel] Re: [kvm-devel] " Luca Tettamanti 2007-08-13 23:06 ` Thiemo Seufer 2007-08-15 17:13 ` Dan Kenigsberg @ 2007-08-16 9:36 ` Dan Kenigsberg 2 siblings, 0 replies; 7+ messages in thread From: Dan Kenigsberg @ 2007-08-16 9:36 UTC (permalink / raw) To: Luca Tettamanti; +Cc: kvm-devel, qemu-devel Luca, One more comment on your patch: the logic in the following condition does not fit the comment bellow it. On Mon, Aug 13, 2007 at 10:37:41PM +0200, Luca Tettamanti wrote: > + if (use_dynamic_ticks() && dynticks_create_timer()) { > + /* dynticks disabled or failed to create a timer, fallback > + * to old code. > + */ > + [old code follows] One should have if (!use_dynamic_ticks() || dynticks_create_timer()) { Instead. Regards, Dan. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-08-16 9:36 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-08-13 14:42 [Qemu-devel] [PATCH] Dynamic ticks Dan Kenigsberg 2007-08-13 20:37 ` [Qemu-devel] Re: [kvm-devel] " Luca Tettamanti 2007-08-13 23:06 ` Thiemo Seufer 2007-08-15 17:05 ` [Qemu-devel] " Dan Kenigsberg 2007-08-15 17:13 ` Dan Kenigsberg 2007-08-15 19:48 ` [Qemu-devel] RE: [kvm-devel] " Dor Laor 2007-08-16 9:36 ` [Qemu-devel] " Dan Kenigsberg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).