Message ID | 1357911633-12602-1-git-send-email-wolfgang.mauerer@siemens.com |
---|---|
State | New |
Headers | show |
Am 11.01.2013 14:40, schrieb Wolfgang Mauerer: > For slow targets and fast hosts, the emulation may be faster > than the actual hardware, which can be undesirable for various > reasons. Add a run-time option to slow down the emulation > by sleeping in the CPU emulation. > > Signed-off-by: Wolfgang Mauerer<wolfgang.mauerer@siemens.com> > --- > cpus.c | 34 ++++++++++++++++++++++++++++++++++ > include/qemu-common.h | 2 ++ > qemu-options.hx | 13 +++++++++++++ > vl.c | 10 ++++++++++ > 4 files changed, 59 insertions(+), 0 deletions(-) > > diff --git a/cpus.c b/cpus.c > index 4a7782a..41a9e0c 100644 > --- a/cpus.c > +++ b/cpus.c > @@ -106,6 +106,11 @@ static QEMUTimer *icount_warp_timer; > static int64_t vm_clock_warp_start; > static int64_t qemu_icount; > > +static double slowdown_factor = 0.0; > +#ifndef _WIN32 > +static struct timespec slowdown_delay; > +#endif > + > Hi, slowdown_delay is used in configure_slowdown unconditionally, so I don't expect that the _WIN32 case will compile. What about using g_usleep? It avoids the conditional compilation. Is the comparison of double value "slowdown_factor" with 0.0 time critical, or do all QEMU platforms have a fast FPU? Setting a boolean value once and testing that value would be much faster of course. Cheers, Stefan W. > typedef struct TimersState { > int64_t cpu_ticks_prev; > int64_t cpu_ticks_offset; > @@ -385,6 +390,21 @@ void configure_icount(const char *option) > qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); > } > > +void configure_slowdown(const char *option) > +{ > + if (!option) { > + return; > + } > + > + slowdown_factor = strtod(option, NULL)/100.0; > + /* We cannot provide speedups, obviously */ > + if (slowdown_factor< 0) { > + slowdown_factor *= -1.0; > + } > + > + slowdown_delay.tv_sec = 0; > +} > + > /***********************************************************/ > void hw_error(const char *fmt, ...) > { > @@ -1092,6 +1112,7 @@ void vm_stop_force_state(RunState state) > static int tcg_cpu_exec(CPUArchState *env) > { > int ret; > + int64_t ss, delta; > #ifdef CONFIG_PROFILER > int64_t ti; > #endif > @@ -1112,7 +1133,20 @@ static int tcg_cpu_exec(CPUArchState *env) > env->icount_decr.u16.low = decr; > env->icount_extra = count; > } > + ss = qemu_get_clock_ns(rt_clock); > + > ret = cpu_exec(env); > + > + if (slowdown_factor> 0) { > + delta = qemu_get_clock_ns(rt_clock) - ss; > + delta *= slowdown_factor; > +#ifdef _WIN32 > + Sleep(delta/1000000l); > +#else > + slowdown_delay.tv_nsec = delta; > + nanosleep(&slowdown_delay, NULL); > +#endif > + } > #ifdef CONFIG_PROFILER > qemu_time += profile_getclock() - ti; > #endif > diff --git a/include/qemu-common.h b/include/qemu-common.h > index ca464bb..652abb9 100644 > --- a/include/qemu-common.h > +++ b/include/qemu-common.h > @@ -119,6 +119,8 @@ static inline char *realpath(const char *path, char *resolved_path) > void configure_icount(const char *option); > extern int use_icount; > > +void configure_slowdown(const char *option); > + > /* FIXME: Remove NEED_CPU_H. */ > #ifndef NEED_CPU_H > > diff --git a/qemu-options.hx b/qemu-options.hx > index 9df0cde..2f6580f 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -2665,6 +2665,19 @@ order cores with complex cache hierarchies. The number of instructions > executed often has little or no correlation with actual performance. > ETEXI > > +DEF("slowdown", HAS_ARG, QEMU_OPTION_slowdown, \ > + "-slowdown s \n" \ > + " Slow down the CPU emulation by (approximately) s" > + " percent\n", QEMU_ARCH_ALL) > +STEXI > +@item -slowdown [@var{s}] > +@findex -slowdown > +Slow down the virtual CPU by approximately s percent. This makes it > +possible to align the emulated machine's performance roughly with > +the performance of physical entities, but does not provide identical > +performance profiles since the emulation is not cycle accurate. > +ETEXI > + > DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \ > "-watchdog i6300esb|ib700\n" \ > " enable virtual hardware watchdog [default=none]\n", > diff --git a/vl.c b/vl.c > index 79e5122..624551f 100644 > --- a/vl.c > +++ b/vl.c > @@ -2524,6 +2524,7 @@ int main(int argc, char **argv, char **envp) > int i; > int snapshot, linux_boot; > const char *icount_option = NULL; > + const char *slowdown_option = NULL; > const char *initrd_filename; > const char *kernel_filename, *kernel_cmdline; > char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */ > @@ -3402,6 +3403,9 @@ int main(int argc, char **argv, char **envp) > case QEMU_OPTION_icount: > icount_option = optarg; > break; > + case QEMU_OPTION_slowdown: > + slowdown_option = optarg; > + break; > case QEMU_OPTION_incoming: > incoming = optarg; > runstate_set(RUN_STATE_INMIGRATE); > @@ -3765,6 +3769,12 @@ int main(int argc, char **argv, char **envp) > /* clean up network at qemu process termination */ > atexit(&net_cleanup); > > + if (slowdown_option&& (kvm_enabled() || xen_enabled())) { > + fprintf(stderr, "-slowdown is not allowed with kvm or xen\n"); > + exit(1); > + } > + configure_slowdown(slowdown_option); > + > if (net_init_clients()< 0) { > exit(1); > } >
On 11/01/13 20:58, Stefan Weil wrote: > Am 11.01.2013 14:40, schrieb Wolfgang Mauerer: >> > For slow targets and fast hosts, the emulation may be faster >> > than the actual hardware, which can be undesirable for various >> > reasons. Add a run-time option to slow down the emulation >> > by sleeping in the CPU emulation. >> > >> > Signed-off-by: Wolfgang Mauerer<wolfgang.mauerer@siemens.com> >> > --- >> > cpus.c | 34 ++++++++++++++++++++++++++++++++++ >> > include/qemu-common.h | 2 ++ >> > qemu-options.hx | 13 +++++++++++++ >> > vl.c | 10 ++++++++++ >> > 4 files changed, 59 insertions(+), 0 deletions(-) >> > >> > diff --git a/cpus.c b/cpus.c >> > index 4a7782a..41a9e0c 100644 >> > --- a/cpus.c >> > +++ b/cpus.c >> > @@ -106,6 +106,11 @@ static QEMUTimer *icount_warp_timer; >> > static int64_t vm_clock_warp_start; >> > static int64_t qemu_icount; >> > >> > +static double slowdown_factor = 0.0; >> > +#ifndef _WIN32 >> > +static struct timespec slowdown_delay; >> > +#endif >> > + >> > > Hi, > > slowdown_delay is used in configure_slowdown unconditionally, > so I don't expect that the _WIN32 case will compile. > > What about using g_usleep? It avoids the conditional compilation. > > Is the comparison of double value "slowdown_factor" with 0.0 > time critical, or do all QEMU platforms have a fast FPU? > > Setting a boolean value once and testing that value would > be much faster of course. I'm not sure if the floating point comparison has a significant impact on any important platform, but using a boolean variable makes the code more similar to the icount mechanism, so I've changed it accordingly. Using g_usleep is a good idea to let the conditional _WIN32 parts go away. Revised patch follows. Cheers, Wolfgang
diff --git a/cpus.c b/cpus.c index 4a7782a..41a9e0c 100644 --- a/cpus.c +++ b/cpus.c @@ -106,6 +106,11 @@ static QEMUTimer *icount_warp_timer; static int64_t vm_clock_warp_start; static int64_t qemu_icount; +static double slowdown_factor = 0.0; +#ifndef _WIN32 +static struct timespec slowdown_delay; +#endif + typedef struct TimersState { int64_t cpu_ticks_prev; int64_t cpu_ticks_offset; @@ -385,6 +390,21 @@ void configure_icount(const char *option) qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10); } +void configure_slowdown(const char *option) +{ + if (!option) { + return; + } + + slowdown_factor = strtod(option, NULL)/100.0; + /* We cannot provide speedups, obviously */ + if (slowdown_factor < 0) { + slowdown_factor *= -1.0; + } + + slowdown_delay.tv_sec = 0; +} + /***********************************************************/ void hw_error(const char *fmt, ...) { @@ -1092,6 +1112,7 @@ void vm_stop_force_state(RunState state) static int tcg_cpu_exec(CPUArchState *env) { int ret; + int64_t ss, delta; #ifdef CONFIG_PROFILER int64_t ti; #endif @@ -1112,7 +1133,20 @@ static int tcg_cpu_exec(CPUArchState *env) env->icount_decr.u16.low = decr; env->icount_extra = count; } + ss = qemu_get_clock_ns(rt_clock); + ret = cpu_exec(env); + + if (slowdown_factor > 0) { + delta = qemu_get_clock_ns(rt_clock) - ss; + delta *= slowdown_factor; +#ifdef _WIN32 + Sleep(delta/1000000l); +#else + slowdown_delay.tv_nsec = delta; + nanosleep(&slowdown_delay, NULL); +#endif + } #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif diff --git a/include/qemu-common.h b/include/qemu-common.h index ca464bb..652abb9 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -119,6 +119,8 @@ static inline char *realpath(const char *path, char *resolved_path) void configure_icount(const char *option); extern int use_icount; +void configure_slowdown(const char *option); + /* FIXME: Remove NEED_CPU_H. */ #ifndef NEED_CPU_H diff --git a/qemu-options.hx b/qemu-options.hx index 9df0cde..2f6580f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2665,6 +2665,19 @@ order cores with complex cache hierarchies. The number of instructions executed often has little or no correlation with actual performance. ETEXI +DEF("slowdown", HAS_ARG, QEMU_OPTION_slowdown, \ + "-slowdown s \n" \ + " Slow down the CPU emulation by (approximately) s" + " percent\n", QEMU_ARCH_ALL) +STEXI +@item -slowdown [@var{s}] +@findex -slowdown +Slow down the virtual CPU by approximately s percent. This makes it +possible to align the emulated machine's performance roughly with +the performance of physical entities, but does not provide identical +performance profiles since the emulation is not cycle accurate. +ETEXI + DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \ "-watchdog i6300esb|ib700\n" \ " enable virtual hardware watchdog [default=none]\n", diff --git a/vl.c b/vl.c index 79e5122..624551f 100644 --- a/vl.c +++ b/vl.c @@ -2524,6 +2524,7 @@ int main(int argc, char **argv, char **envp) int i; int snapshot, linux_boot; const char *icount_option = NULL; + const char *slowdown_option = NULL; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */ @@ -3402,6 +3403,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_icount: icount_option = optarg; break; + case QEMU_OPTION_slowdown: + slowdown_option = optarg; + break; case QEMU_OPTION_incoming: incoming = optarg; runstate_set(RUN_STATE_INMIGRATE); @@ -3765,6 +3769,12 @@ int main(int argc, char **argv, char **envp) /* clean up network at qemu process termination */ atexit(&net_cleanup); + if (slowdown_option && (kvm_enabled() || xen_enabled())) { + fprintf(stderr, "-slowdown is not allowed with kvm or xen\n"); + exit(1); + } + configure_slowdown(slowdown_option); + if (net_init_clients() < 0) { exit(1); }
For slow targets and fast hosts, the emulation may be faster than the actual hardware, which can be undesirable for various reasons. Add a run-time option to slow down the emulation by sleeping in the CPU emulation. Signed-off-by: Wolfgang Mauerer <wolfgang.mauerer@siemens.com> --- cpus.c | 34 ++++++++++++++++++++++++++++++++++ include/qemu-common.h | 2 ++ qemu-options.hx | 13 +++++++++++++ vl.c | 10 ++++++++++ 4 files changed, 59 insertions(+), 0 deletions(-)