[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH/RFC 4/4] Add support for dynamic ticks.
From: |
Luca Tettamanti |
Subject: |
[Qemu-devel] [PATCH/RFC 4/4] Add support for dynamic ticks. |
Date: |
Thu, 16 Aug 2007 22:41:17 +0200 |
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 <address@hidden>
Signed-off-by: Luca Tettamanti <address@hidden>
---
qemu/configure | 5 ++
qemu/vl.c | 149 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 148 insertions(+), 6 deletions(-)
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 0373beb..096729d 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -748,12 +748,42 @@ struct QEMUTimer {
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
@@ -772,6 +802,14 @@ static void win32_stop_timer(struct qemu_alarm_timer *t);
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);
@@ -785,16 +823,19 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t);
#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, }
};
@@ -913,6 +954,8 @@ void qemu_del_timer(QEMUTimer *ts)
}
pt = &t->next;
}
+
+ qemu_rearm_alarm_timer(alarm_timer);
}
/* modify the current timer so that it will be fired when current_time
@@ -972,6 +1015,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);
}
+ qemu_rearm_alarm_timer(alarm_timer);
}
int64_t qemu_get_clock(QEMUClock *clock)
@@ -1079,7 +1123,8 @@ static void host_alarm_handler(int host_signum)
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))) {
@@ -1207,6 +1252,97 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t)
#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;
@@ -6259,6 +6395,7 @@ void vm_start(void)
cpu_enable_ticks();
vm_running = 1;
vm_state_notify(1);
+ qemu_rearm_alarm_timer(alarm_timer);
}
}
--
1.5.2.4
[Qemu-devel] Re: [kvm-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure., Avi Kivity, 2007/08/17