* [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 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
* [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
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).