[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] Dynamic ticks
From: |
Dan Kenigsberg |
Subject: |
[Qemu-devel] [PATCH] Dynamic ticks |
Date: |
Sun, 12 Aug 2007 20:06:59 +0300 |
User-agent: |
Mutt/1.5.14 (2007-02-12) |
"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).
Note that I raise a flag called dont_rearm_host_timer when I want to
inhibit redundant arming of the POSIX timer (see comment in sourcecode).
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 12 Aug 2007 16:24:32 -0000
@@ -793,6 +793,16 @@
/* 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 dont_rearm_host_timer = 0;
+static int use_dynamic_ticks = 1;
+#endif
QEMUClock *qemu_new_clock(int type)
{
@@ -838,6 +848,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
@@ -846,6 +860,10 @@
{
QEMUTimer **pt, *t;
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks)
+ dont_rearm_host_timer++;
+#endif
qemu_del_timer(ts);
/* add the timer in the sorted list */
@@ -863,6 +881,13 @@
ts->expire_time = expire_time;
ts->next = *pt;
*pt = ts;
+
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks) {
+ dont_rearm_host_timer--;
+ rearm_host_timer();
+ }
+#endif
}
int qemu_timer_pending(QEMUTimer *ts)
@@ -886,6 +911,14 @@
{
QEMUTimer *ts;
+#ifdef DYNAMIC_TICKS
+ /* callback functions that are run here may each try to rearm the timer. In
+ * oreder to avoid this, we raise the dont_rearm_host_timer flag.
+ * Alternatively, it is possible to go over all callback functions and make
+ * sure they do not call functions that rearm the system timer. */
+ if (use_dynamic_ticks)
+ dont_rearm_host_timer++;
+#endif
for(;;) {
ts = *ptimer_head;
if (!ts || ts->expire_time > current_time)
@@ -897,6 +930,12 @@
/* run the callback (the timer list can be modified) */
ts->cb(ts->opaque);
}
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks) {
+ dont_rearm_host_timer--;
+ rearm_host_timer();
+ }
+#endif
}
int64_t qemu_get_clock(QEMUClock *clock)
@@ -1004,7 +1043,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))) {
@@ -1102,28 +1146,44 @@
/* timer signal */
sigfillset(&act.sa_mask);
- act.sa_flags = 0;
+ act.sa_flags = 0;
#if defined (TARGET_I386) && defined(USE_CODE_COPY)
act.sa_flags |= SA_ONSTACK;
#endif
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 +6347,10 @@
cpu_enable_ticks();
vm_running = 1;
vm_state_notify(1);
+#ifdef DYNAMIC_TICKS
+ if (use_dynamic_ticks)
+ rearm_host_timer();
+#endif
}
}
@@ -6708,6 +6772,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 +6872,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 +6979,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 +7210,55 @@
#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 (dont_rearm_host_timer) 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]) {
+ 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 +7809,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
}
}
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 12 Aug 2007 16:24:33 -0000
@@ -294,6 +294,8 @@
*) echo "undefined SPARC architecture. Exiting";exit 1;;
esac
;;
+ --disable-dynamic-ticks) dynamic_ticks="no"
+ ;;
esac
done
@@ -859,6 +861,10 @@
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
+ echo "DYNAMIC_TICKS=yes" >> $config_mak
+fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
- [Qemu-devel] [PATCH] Dynamic ticks,
Dan Kenigsberg <=