qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [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).