Patchwork Add option to slow qemu down

login
register
mail settings
Submitter Wolfgang Mauerer
Date Jan. 18, 2013, 12:05 p.m.
Message ID <1358510708-2857-1-git-send-email-wolfgang.mauerer@siemens.com>
Download mbox | patch
Permalink /patch/213600/
State New
Headers show

Comments

Wolfgang Mauerer - Jan. 18, 2013, 12:05 p.m.
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                |   30 ++++++++++++++++++++++++++++++
 include/qemu-common.h |    2 ++
 qemu-options.hx       |   14 ++++++++++++++
 vl.c                  |   10 ++++++++++
 4 files changed, 56 insertions(+)

Patch

diff --git a/cpus.c b/cpus.c
index a4390c3..b7838fd 100644
--- a/cpus.c
+++ b/cpus.c
@@ -61,6 +61,7 @@ 
 #endif /* CONFIG_LINUX */
 
 static CPUArchState *next_cpu;
+static bool use_slowdown;
 
 static bool cpu_thread_is_idle(CPUArchState *env)
 {
@@ -106,6 +107,8 @@  static QEMUTimer *icount_warp_timer;
 static int64_t vm_clock_warp_start;
 static int64_t qemu_icount;
 
+static double slowdown_factor;
+
 typedef struct TimersState {
     int64_t cpu_ticks_prev;
     int64_t cpu_ticks_offset;
@@ -385,6 +388,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;
+    }
+
+    use_slowdown = true;
+}
+
 /***********************************************************/
 void hw_error(const char *fmt, ...)
 {
@@ -1094,6 +1112,8 @@  void vm_stop_force_state(RunState state)
 static int tcg_cpu_exec(CPUArchState *env)
 {
     int ret;
+    int64_t ss;
+    uint64_t slowdown_sleep;
 #ifdef CONFIG_PROFILER
     int64_t ti;
 #endif
@@ -1114,7 +1134,17 @@  static int tcg_cpu_exec(CPUArchState *env)
         env->icount_decr.u16.low = decr;
         env->icount_extra = count;
     }
+    if (use_slowdown) {
+        ss = qemu_get_clock_ns(rt_clock);
+    }
+
     ret = cpu_exec(env);
+
+    if (use_slowdown) {
+        slowdown_sleep = qemu_get_clock_ns(rt_clock) - ss;
+        slowdown_sleep *= slowdown_factor;
+        g_usleep(slowdown_sleep / 1024);
+    }
 #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 40cd683..2bab5aa 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2667,6 +2667,20 @@  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 (i.e., for c time
+units of execution time, sleep for c*s/100 time units). 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 8ce2b10..9aa44e0 100644
--- a/vl.c
+++ b/vl.c
@@ -2713,6 +2713,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] = "";
@@ -3607,6 +3608,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);
@@ -3970,6 +3974,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);
     }