If DYNAMIC_TICKS is defined 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. Original patch from Dan Kenigsberg <[EMAIL PROTECTED]>
Signed-off-by: Luca Tettamanti <[EMAIL PROTECTED]> --- configure | 5 ++ vl.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 148 insertions(+), 6 deletions(-) Index: qemu/vl.c =================================================================== --- qemu.orig/vl.c 2007-08-17 17:45:00.000000000 +0200 +++ qemu/vl.c 2007-08-18 00:38:03.000000000 +0200 @@ -784,12 +784,42 @@ struct qemu_alarm_timer { char const *name; + unsigned int flags; int (*start)(struct qemu_alarm_timer *t); void (*stop)(struct qemu_alarm_timer *t); + void (*rearm)(struct qemu_alarm_timer *t); void *priv; }; +#define ALARM_FLAG_DYNTICKS 0x1 + +#ifdef DYNAMIC_TICKS + +static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) +{ + return t->flags & ALARM_FLAG_DYNTICKS; +} + +static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) { + if (!alarm_has_dynticks(t)) + return; + + t->rearm(t); +} + +#else /* DYNAMIC_TICKS */ + +static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) +{ + return 0; +} + +static void qemu_rearm_alarm_timer(void) { +} + +#endif /* DYNAMIC_TICKS */ + static struct qemu_alarm_timer *alarm_timer; #ifdef _WIN32 @@ -808,6 +838,14 @@ static int unix_start_timer(struct qemu_alarm_timer *t); static void unix_stop_timer(struct qemu_alarm_timer *t); +#ifdef DYNAMIC_TICKS + +static int dynticks_start_timer(struct qemu_alarm_timer *t); +static void dynticks_stop_timer(struct qemu_alarm_timer *t); +static void dynticks_rearm_timer(struct qemu_alarm_timer *t); + +#endif + #ifdef __linux__ static int hpet_start_timer(struct qemu_alarm_timer *t); @@ -821,16 +859,19 @@ #endif /* _WIN32 */ static struct qemu_alarm_timer alarm_timers[] = { +#ifndef _WIN32 +#ifdef DYNAMIC_TICKS + {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer, dynticks_stop_timer, dynticks_rearm_timer, NULL}, +#endif #ifdef __linux__ /* HPET - if available - is preferred */ - {"hpet", hpet_start_timer, hpet_stop_timer, NULL}, + {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL}, /* ...otherwise try RTC */ - {"rtc", rtc_start_timer, rtc_stop_timer, NULL}, + {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL}, #endif -#ifndef _WIN32 - {"unix", unix_start_timer, unix_stop_timer, NULL}, + {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL}, #else - {"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data}, + {"win32", 0, win32_start_timer, win32_stop_timer, NULL, &alarm_win32_data}, #endif {NULL, } }; @@ -949,6 +990,8 @@ } pt = &t->next; } + + qemu_rearm_alarm_timer(alarm_timer); } /* modify the current timer so that it will be fired when current_time @@ -1008,6 +1051,7 @@ /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } + qemu_rearm_alarm_timer(alarm_timer); } int64_t qemu_get_clock(QEMUClock *clock) @@ -1115,7 +1159,8 @@ last_clock = ti; } #endif - if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + if (alarm_has_dynticks(alarm_timer) || + 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))) { @@ -1243,6 +1288,97 @@ #endif /* !defined(__linux__) */ +#ifdef DYNAMIC_TICKS +static int dynticks_start_timer(struct qemu_alarm_timer *t) +{ + struct sigevent ev; + timer_t host_timer; + struct sigaction act; + + sigfillset(&act.sa_mask); + 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); + + 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"); + + return -1; + } + + t->priv = (void *)host_timer; + + return 0; +} + +static void dynticks_stop_timer(struct qemu_alarm_timer *t) +{ + timer_t host_timer = (timer_t)t->priv; + + timer_delete(host_timer); +} + +static void dynticks_rearm_timer(struct qemu_alarm_timer *t) +{ + timer_t host_timer = (timer_t)t->priv; + 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]) { + /* 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 */ + /* TODO: 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"); + fprintf(stderr, "Internal timer error: aborting\n"); + exit(1); + } + 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"); + fprintf(stderr, "Internal timer error: aborting\n"); + exit(1); + } + } +} + +#endif /* DYNAMIC_TICKS */ + static int unix_start_timer(struct qemu_alarm_timer *t) { struct sigaction act; @@ -6490,6 +6626,7 @@ cpu_enable_ticks(); vm_running = 1; vm_state_notify(1); + qemu_rearm_alarm_timer(alarm_timer); } } Index: qemu/configure =================================================================== --- qemu.orig/configure 2007-08-17 17:45:17.000000000 +0200 +++ qemu/configure 2007-08-17 17:45:31.000000000 +0200 @@ -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 --