* [Qemu-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure.
@ 2007-08-16 20:41 Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 1/4] " Luca Tettamanti
2007-08-17 12:44 ` [Qemu-devel] Re: [kvm-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure Avi Kivity
0 siblings, 2 replies; 8+ messages in thread
From: Luca Tettamanti @ 2007-08-16 20:41 UTC (permalink / raw)
To: kvm-devel; +Cc: Dan Kenigsberg, Luca Tettamanti, qemu-devel
Hello,
in reply to this mail I will send a serie of 4 patches that cleans up and expands
the alarm timer handling in QEMU. Patches apply to current kvm-userspace tree,
but I think I can rebase it to QEMU svn if desired.
Patch 1 is mostly a cleanup of the existing code; instead of having multiple
#ifdefs to handle different timers scattered all over the code I've created a
modular infrastructure where each timer type is self-contained and generic code
is more readable. The resulting code is functionally equivalent to the old one.
Patch 2 implements the "-clock" command line option proposed by Daniel Berrange
and Avi Kivity. By default QEMU tries RTC and then falls back to unix timer;
user can override the order of the timer through this options. Syntax is pretty
simple: -clock timer1,timer2,etc. (QEMU will pick the first one that works).
Patch 3 adds support for HPET under Linux (which is basically my old patch). As
suggested HPET takes precedence over other timers, but of course this can be
overridden.
Patch 4 introduces "dynticks" timer source; patch is mostly based on the work
Dan Kenigsberg. dynticks is now the default alarm timer.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH/RFC 1/4] Rework alarm timer infrastrucure.
2007-08-16 20:41 [Qemu-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure Luca Tettamanti
@ 2007-08-16 20:41 ` Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 2/4] Add -clock option Luca Tettamanti
2007-08-17 12:44 ` [Qemu-devel] Re: [kvm-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure Avi Kivity
1 sibling, 1 reply; 8+ messages in thread
From: Luca Tettamanti @ 2007-08-16 20:41 UTC (permalink / raw)
To: kvm-devel; +Cc: Dan Kenigsberg, Luca Tettamanti, qemu-devel
Make the alarm code modular, removing #ifdef from the generic code and
abstract a common interface for all the timer. The result is functionally
equivalent to the old code.
Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
---
qemu/vl.c | 292 +++++++++++++++++++++++++++++++++------------------
1 files changed, 189 insertions(+), 103 deletions(-)
diff --git a/qemu/vl.c b/qemu/vl.c
index 5360ed7..33443ca 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -745,18 +745,58 @@ struct QEMUTimer {
struct QEMUTimer *next;
};
-QEMUClock *rt_clock;
-QEMUClock *vm_clock;
+struct qemu_alarm_timer {
+ char const *name;
+
+ int (*start)(struct qemu_alarm_timer *t);
+ void (*stop)(struct qemu_alarm_timer *t);
+ void *priv;
+};
+
+static struct qemu_alarm_timer *alarm_timer;
-static QEMUTimer *active_timers[2];
#ifdef _WIN32
-static MMRESULT timerID;
-static HANDLE host_alarm = NULL;
-static unsigned int period = 1;
+
+struct qemu_alarm_win32 {
+ MMRESULT timerId;
+ HANDLE host_alarm;
+ unsigned int period;
+} alarm_win32_data = {0, NULL, -1};
+
+static int win32_start_timer(struct qemu_alarm_timer *t);
+static void win32_stop_timer(struct qemu_alarm_timer *t);
+
+#else
+
+static int unix_start_timer(struct qemu_alarm_timer *t);
+static void unix_stop_timer(struct qemu_alarm_timer *t);
+
+#ifdef __linux__
+
+static int rtc_start_timer(struct qemu_alarm_timer *t);
+static void rtc_stop_timer(struct qemu_alarm_timer *t);
+
+#endif
+
+#endif /* _WIN32 */
+
+static struct qemu_alarm_timer alarm_timers[] = {
+#ifdef __linux__
+ /* RTC - if available - is preferred */
+ {"rtc", rtc_start_timer, rtc_stop_timer, NULL},
+#endif
+#ifndef _WIN32
+ {"unix", unix_start_timer, unix_stop_timer, NULL},
#else
-/* frequency of the times() clock tick */
-static int timer_freq;
+ {"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data},
#endif
+ {NULL, }
+};
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+
+static QEMUTimer *active_timers[2];
QEMUClock *qemu_new_clock(int type)
{
@@ -973,7 +1013,8 @@ static void host_alarm_handler(int host_signum)
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
#ifdef _WIN32
- SetEvent(host_alarm);
+ struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
+ SetEvent(data->host_alarm);
#endif
CPUState *env = cpu_single_env;
if (env) {
@@ -995,10 +1036,31 @@ static void host_alarm_handler(int host_signum)
#define RTC_FREQ 1024
static int use_rtc = 1;
-static int rtc_fd;
-static int start_rtc_timer(void)
+static void enable_sigio_timer(int fd)
+{
+ struct sigaction act;
+
+ /* timer signal */
+ 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(SIGIO, &act, NULL);
+ fcntl(fd, F_SETFL, O_ASYNC);
+ fcntl(fd, F_SETOWN, getpid());
+}
+
+static int rtc_start_timer(struct qemu_alarm_timer *t)
{
+ int rtc_fd;
+
+ if (!use_rtc)
+ return -1;
+
rtc_fd = open("/dev/rtc", O_RDONLY);
if (rtc_fd < 0)
return -1;
@@ -1009,121 +1071,145 @@ static int start_rtc_timer(void)
goto fail;
}
if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
- fail:
+fail:
close(rtc_fd);
return -1;
}
- pit_min_timer_count = PIT_FREQ / RTC_FREQ;
+
+ enable_sigio_timer(rtc_fd);
+
+ t->priv = (void *)rtc_fd;
+
return 0;
}
-#else
-
-static int start_rtc_timer(void)
+static void rtc_stop_timer(struct qemu_alarm_timer *t)
{
- return -1;
+ int rtc_fd = (int)t->priv;
+
+ close(rtc_fd);
}
#endif /* !defined(__linux__) */
-#endif /* !defined(_WIN32) */
+static int unix_start_timer(struct qemu_alarm_timer *t)
+{
+ struct sigaction act;
+ struct itimerval itv;
+ int err;
-static void init_timer_alarm(void)
+ /* timer signal */
+ 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);
+
+ itv.it_interval.tv_sec = 0;
+ /* for i386 kernel 2.6 to get 1 ms */
+ itv.it_interval.tv_usec = 999;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 10 * 1000;
+
+ err = setitimer(ITIMER_REAL, &itv, NULL);
+ if (err)
+ return -1;
+
+ return 0;
+}
+
+static void unix_stop_timer(struct qemu_alarm_timer *t)
{
+ struct itimerval itv;
+
+ memset(&itv, 0, sizeof(itv));
+ setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+#endif /* !defined(_WIN32) */
+
#ifdef _WIN32
- {
- int count=0;
- TIMECAPS tc;
-
- ZeroMemory(&tc, sizeof(TIMECAPS));
- timeGetDevCaps(&tc, sizeof(TIMECAPS));
- if (period < tc.wPeriodMin)
- period = tc.wPeriodMin;
- timeBeginPeriod(period);
- timerID = timeSetEvent(1, // interval (ms)
- period, // resolution
- host_alarm_handler, // function
- (DWORD)&count, // user parameter
- TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
- if( !timerID ) {
- perror("failed timer alarm");
- exit(1);
- }
- host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!host_alarm) {
- perror("failed CreateEvent");
- exit(1);
- }
- qemu_add_wait_object(host_alarm, NULL, NULL);
+
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+ TIMECAPS tc;
+ struct qemu_alarm_win32 *data = t->priv;
+
+ data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!data->host_alarm) {
+ perror("Failed CreateEvent");
+ return -1;
}
- pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
-#else
- {
- struct sigaction act;
- struct itimerval itv;
-
- /* get times() syscall frequency */
- timer_freq = sysconf(_SC_CLK_TCK);
-
- /* timer signal */
- 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);
- 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);
+ memset(&tc, 0, sizeof(tc));
+ timeGetDevCaps(&tc, sizeof(tc));
-#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) {
- /* try to use /dev/rtc to have a faster timer */
- if (!use_rtc || (start_rtc_timer() < 0))
- goto use_itimer;
- /* disable itimer */
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 0;
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL, &itv, NULL);
-
- /* use the RTC */
- sigaction(SIGIO, &act, NULL);
- fcntl(rtc_fd, F_SETFL, O_ASYNC);
- fcntl(rtc_fd, F_SETOWN, getpid());
- } else
-#endif /* defined(__linux__) */
- {
- use_itimer:
- pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec *
- PIT_FREQ) / 1000000;
- }
+ if (data->period < tc.wPeriodMin)
+ data->period = tc.wPeriodMin;
+
+ timeBeginPeriod(data->period);
+
+ data->timerId = timeSetEvent(1, // interval (ms)
+ data->period, // resolution
+ host_alarm_handler, // function
+ (DWORD)t, // parameter
+ TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
+
+ if (!data->timerId) {
+ perror("Failed to initialize win32 alarm timer");
+
+ CloseHandle(data->host_alarm);
+ return -1;
}
+
+ qemu_add_wait_object(data->host_alarm, NULL, NULL);
+
+ return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+ struct qemu_alarm_win32 *data = t->priv;
+
+ timeKillEvent(data->timerId);
+ timeEndPeriod(data->period);
+
+ CloseHandle(data->host_alarm);
+}
+
#endif
+
+static void init_timer_alarm(void)
+{
+ struct qemu_alarm_timer *t;
+ int i, err = -1;
+
+ for (i = 0; alarm_timers[i].name; i++) {
+ t = &alarm_timers[i];
+
+ printf("trying %s...\n", t->name);
+
+ err = t->start(t);
+ if (!err)
+ break;
+ }
+
+ if (err) {
+ fprintf(stderr, "Unable to find any suitable alarm timer.\n");
+ fprintf(stderr, "Terminating\n");
+ exit(1);
+ }
+
+ alarm_timer = t;
}
void quit_timers(void)
{
-#ifdef _WIN32
- timeKillEvent(timerID);
- timeEndPeriod(period);
- if (host_alarm) {
- CloseHandle(host_alarm);
- host_alarm = NULL;
- }
-#endif
+ alarm_timer->stop(alarm_timer);
+ alarm_timer = NULL;
}
/***********************************************************/
--
1.5.2.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH/RFC 2/4] Add -clock option.
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 1/4] " Luca Tettamanti
@ 2007-08-16 20:41 ` Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 3/4] Add support for HPET periodic timer Luca Tettamanti
0 siblings, 1 reply; 8+ messages in thread
From: Luca Tettamanti @ 2007-08-16 20:41 UTC (permalink / raw)
To: kvm-devel; +Cc: Dan Kenigsberg, Luca Tettamanti, qemu-devel
Allow user to override the list of available alarm timers and their
priority. The format of the options is -clock clk1,clk2,...
Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
---
qemu/vl.c | 90 ++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 72 insertions(+), 18 deletions(-)
diff --git a/qemu/vl.c b/qemu/vl.c
index 33443ca..f0b4896 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -793,6 +793,71 @@ static struct qemu_alarm_timer alarm_timers[] = {
{NULL, }
};
+static void show_available_alarms()
+{
+ int i;
+
+ printf("Available alarm timers, in order of precedence:\n");
+ for (i = 0; alarm_timers[i].name; i++)
+ printf("%s\n", alarm_timers[i].name);
+}
+
+static void configure_alarms(char const *opt)
+{
+ int i;
+ int cur = 0;
+ int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
+ char *arg;
+ char *name;
+
+ if (!strcmp(opt, "help")) {
+ show_available_alarms();
+ exit(0);
+ }
+
+ arg = strdup(opt);
+
+ /* Reorder the array */
+ name = strtok(arg, ",");
+ while (name) {
+ struct qemu_alarm_timer tmp;
+
+ for (i = 0; i < count; i++) {
+ if (!strcmp(alarm_timers[i].name, name))
+ break;
+ }
+
+ if (i == count) {
+ fprintf(stderr, "Unknown clock %s\n", name);
+ goto next;
+ }
+
+ if (i < cur)
+ /* Ignore */
+ goto next;
+
+ /* Swap */
+ tmp = alarm_timers[i];
+ alarm_timers[i] = alarm_timers[cur];
+ alarm_timers[cur] = tmp;
+
+ cur++;
+next:
+ name = strtok(NULL, ",");
+ }
+
+ free(arg);
+
+ if (cur) {
+ /* Disable remaining timers */
+ for (i = cur; i < count; i++)
+ alarm_timers[i].name = NULL;
+ }
+
+ /* debug */
+ show_available_alarms();
+}
+
QEMUClock *rt_clock;
QEMUClock *vm_clock;
@@ -1035,8 +1100,6 @@ static void host_alarm_handler(int host_signum)
#define RTC_FREQ 1024
-static int use_rtc = 1;
-
static void enable_sigio_timer(int fd)
{
struct sigaction act;
@@ -1058,9 +1121,6 @@ static int rtc_start_timer(struct qemu_alarm_timer *t)
{
int rtc_fd;
- if (!use_rtc)
- return -1;
-
rtc_fd = open("/dev/rtc", O_RDONLY);
if (rtc_fd < 0)
return -1;
@@ -6566,9 +6626,8 @@ void help(void)
"-daemonize daemonize QEMU after initializing\n"
#endif
"-tdf inject timer interrupts that got lost\n"
-#if defined(__linux__)
- "-no-rtc don't use /dev/rtc for timer alarm (do use gettimeofday)\n"
-#endif
+ "-clock force the use of the given methods for timer alarm.\n"
+ " To see what timers are available use -clock help\n"
"-option-rom rom load a file, rom, into the option ROM space\n"
"\n"
"During emulation, the following keys are useful:\n"
@@ -6658,9 +6717,7 @@ enum {
QEMU_OPTION_semihosting,
QEMU_OPTION_incoming,
QEMU_OPTION_tdf,
-#if defined(__linux__)
- QEMU_OPTION_no_rtc,
-#endif
+ QEMU_OPTION_clock,
QEMU_OPTION_cpu_vendor,
};
@@ -6755,9 +6812,7 @@ const QEMUOption qemu_options[] = {
{ "semihosting", 0, QEMU_OPTION_semihosting },
#endif
{ "tdf", 0, QEMU_OPTION_tdf }, /* enable time drift fix */
-#if defined(__linux__)
- { "no-rtc", 0, QEMU_OPTION_no_rtc },
-#endif
+ { "clock", HAS_ARG, QEMU_OPTION_clock },
{ "cpu-vendor", HAS_ARG, QEMU_OPTION_cpu_vendor },
{ NULL },
};
@@ -7477,11 +7532,10 @@ int main(int argc, char **argv)
break;
case QEMU_OPTION_tdf:
time_drift_fix = 1;
-#if defined(__linux__)
- case QEMU_OPTION_no_rtc:
- use_rtc = 0;
break;
-#endif
+ case QEMU_OPTION_clock:
+ configure_alarms(optarg);
+ break;
case QEMU_OPTION_cpu_vendor:
cpu_vendor_string = optarg;
break;
--
1.5.2.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH/RFC 3/4] Add support for HPET periodic timer.
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 2/4] Add -clock option Luca Tettamanti
@ 2007-08-16 20:41 ` Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 4/4] Add support for dynamic ticks Luca Tettamanti
0 siblings, 1 reply; 8+ messages in thread
From: Luca Tettamanti @ 2007-08-16 20:41 UTC (permalink / raw)
To: kvm-devel; +Cc: Dan Kenigsberg, Luca Tettamanti, qemu-devel
Linux operates the HPET timer in legacy replacement mode, which means that
the periodic interrupt of the CMOS RTC is not delivered (qemu won't be able
to use /dev/rtc). Add support for HPET (/dev/hpet) as a replacement for the
RTC; the periodic interrupt is delivered via SIGIO and is handled in the
same way as the RTC timer.
Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
---
qemu/vl.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 56 insertions(+), 1 deletions(-)
diff --git a/qemu/vl.c b/qemu/vl.c
index f0b4896..0373beb 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -54,6 +54,7 @@
#include <pty.h>
#include <malloc.h>
#include <linux/rtc.h>
+#include <linux/hpet.h>
#include <linux/ppdev.h>
#endif
#endif
@@ -773,6 +774,9 @@ static void unix_stop_timer(struct qemu_alarm_timer *t);
#ifdef __linux__
+static int hpet_start_timer(struct qemu_alarm_timer *t);
+static void hpet_stop_timer(struct qemu_alarm_timer *t);
+
static int rtc_start_timer(struct qemu_alarm_timer *t);
static void rtc_stop_timer(struct qemu_alarm_timer *t);
@@ -782,7 +786,9 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t);
static struct qemu_alarm_timer alarm_timers[] = {
#ifdef __linux__
- /* RTC - if available - is preferred */
+ /* HPET - if available - is preferred */
+ {"hpet", hpet_start_timer, hpet_stop_timer, NULL},
+ /* ...otherwise try RTC */
{"rtc", rtc_start_timer, rtc_stop_timer, NULL},
#endif
#ifndef _WIN32
@@ -1117,6 +1123,55 @@ static void enable_sigio_timer(int fd)
fcntl(fd, F_SETOWN, getpid());
}
+static int hpet_start_timer(struct qemu_alarm_timer *t)
+{
+ struct hpet_info info;
+ int r, fd;
+
+ fd = open("/dev/hpet", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ /* Set frequency */
+ r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
+ if (r < 0) {
+ fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
+ "error, but for better emulation accuracy type:\n"
+ "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
+ goto fail;
+ }
+
+ /* Check capabilities */
+ r = ioctl(fd, HPET_INFO, &info);
+ if (r < 0)
+ goto fail;
+
+ /* Enable periodic mode */
+ r = ioctl(fd, HPET_EPI, 0);
+ if (info.hi_flags && (r < 0))
+ goto fail;
+
+ /* Enable interrupt */
+ r = ioctl(fd, HPET_IE_ON, 0);
+ if (r < 0)
+ goto fail;
+
+ enable_sigio_timer(fd);
+ t->priv = (void *)fd;
+
+ return 0;
+fail:
+ close(fd);
+ return -1;
+}
+
+static void hpet_stop_timer(struct qemu_alarm_timer *t)
+{
+ int fd = (int)t->priv;
+
+ close(fd);
+}
+
static int rtc_start_timer(struct qemu_alarm_timer *t)
{
int rtc_fd;
--
1.5.2.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH/RFC 4/4] Add support for dynamic ticks.
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 3/4] Add support for HPET periodic timer Luca Tettamanti
@ 2007-08-16 20:41 ` Luca Tettamanti
2007-08-17 7:16 ` [Qemu-devel] Re: [kvm-devel] " Matthew Kent
0 siblings, 1 reply; 8+ messages in thread
From: Luca Tettamanti @ 2007-08-16 20:41 UTC (permalink / raw)
To: kvm-devel; +Cc: Dan Kenigsberg, Luca Tettamanti, qemu-devel
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 <dank@qumranet.com>
Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
---
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
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] Re: [kvm-devel] [PATCH/RFC 4/4] Add support for dynamic ticks.
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 4/4] Add support for dynamic ticks Luca Tettamanti
@ 2007-08-17 7:16 ` Matthew Kent
2007-08-19 8:08 ` Avi Kivity
0 siblings, 1 reply; 8+ messages in thread
From: Matthew Kent @ 2007-08-17 7:16 UTC (permalink / raw)
To: Luca Tettamanti; +Cc: kvm-devel, Dan Kenigsberg, qemu-devel
> 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 <dank@qumranet.com>
>
> Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
Wow, this patch sure made a difference for some timings I've been doing
with kvm-35 and hackbench. All tests using 2.6.23-rc3+hrtimers patch for
x86_64/i386 tickless and a quad core intel:
[mkent@localhost ~]$ time ./hackbench 50
x86_64 host : real 0m10.845s
x86_64 host, bound to 1 cpu : real 0m21.884s
i386 guest+unix clock : real 0m49.206s
i386 guest+hpet clock : real 0m48.292s
i386 guest+dynticks clock : real 0m28.835s
Results are repeatable and verfied with a stopwatch because I didn't
believe them at first :)
Great stuff.
--
Matthew Kent <mkent@magoazul.com>
http://magoazul.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] Re: [kvm-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure.
2007-08-16 20:41 [Qemu-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 1/4] " Luca Tettamanti
@ 2007-08-17 12:44 ` Avi Kivity
1 sibling, 0 replies; 8+ messages in thread
From: Avi Kivity @ 2007-08-17 12:44 UTC (permalink / raw)
To: Luca Tettamanti; +Cc: kvm-devel, Dan Kenigsberg, qemu-devel
Luca Tettamanti wrote:
> Hello,
> in reply to this mail I will send a serie of 4 patches that cleans up and expands
> the alarm timer handling in QEMU. Patches apply to current kvm-userspace tree,
> but I think I can rebase it to QEMU svn if desired.
>
>
I would really like to see this go into qemu first (assuming the qemu
maintainers want it). So far kvm changes are minor additions, but this
is a fairly intrusive change. In addition, it benefits qemu as much as kvm.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] Re: [kvm-devel] [PATCH/RFC 4/4] Add support for dynamic ticks.
2007-08-17 7:16 ` [Qemu-devel] Re: [kvm-devel] " Matthew Kent
@ 2007-08-19 8:08 ` Avi Kivity
0 siblings, 0 replies; 8+ messages in thread
From: Avi Kivity @ 2007-08-19 8:08 UTC (permalink / raw)
To: Matthew Kent; +Cc: kvm-devel, Dan Kenigsberg, Luca Tettamanti, qemu-devel
Matthew Kent wrote:
>> 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 <dank@qumranet.com>
>>
>> Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
>>
>
> Wow, this patch sure made a difference for some timings I've been doing
> with kvm-35 and hackbench. All tests using 2.6.23-rc3+hrtimers patch for
> x86_64/i386 tickless and a quad core intel:
>
> [mkent@localhost ~]$ time ./hackbench 50
> x86_64 host : real 0m10.845s
> x86_64 host, bound to 1 cpu : real 0m21.884s
> i386 guest+unix clock : real 0m49.206s
> i386 guest+hpet clock : real 0m48.292s
> i386 guest+dynticks clock : real 0m28.835s
>
> Results are repeatable and verfied with a stopwatch because I didn't
> believe them at first :)
>
> Great stuff.
>
I'm not sure what these results mean...
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-08-19 8:08 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-16 20:41 [Qemu-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 1/4] " Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 2/4] Add -clock option Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 3/4] Add support for HPET periodic timer Luca Tettamanti
2007-08-16 20:41 ` [Qemu-devel] [PATCH/RFC 4/4] Add support for dynamic ticks Luca Tettamanti
2007-08-17 7:16 ` [Qemu-devel] Re: [kvm-devel] " Matthew Kent
2007-08-19 8:08 ` Avi Kivity
2007-08-17 12:44 ` [Qemu-devel] Re: [kvm-devel] [PATCH/RFC 0/4] Rework alarm timer infrastrucure Avi Kivity
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).