Patchwork [[PATCH,v2] ] Add option to slow qemu down

login
register
mail settings
Submitter Wolfgang Mauerer
Date May 7, 2013, 11:30 a.m.
Message ID <5188E5CB.1060008@siemens.com>
Download mbox | patch
Permalink /patch/242180/
State New
Headers show

Comments

Wolfgang Mauerer - May 7, 2013, 11:30 a.m.
On 07/05/13 12:56, Markus Armbruster wrote:
(...)  
>> +    if (slowdown_option && (kvm_enabled() || xen_enabled())) {
>> +        fprintf(stderr, "-slowdown is not allowed with kvm or xen\n");
>> +        exit(1);
> 
> Suggest to mention this in the commit message, and perhaps the manual
> (STEXI..ETEXI section in qemu-options.hx).

sure, updated patch is attached (I've also updated the github repository).

Thanks, Wolfgang

---
From 6c85a1d11ca0f8ceaf4fbf7c97a0aaa1b145acd2 Mon Sep 17 00:00:00 2001
From: Wolfgang Mauerer <wolfgang.mauerer@siemens.com>
Date: Tue, 7 May 2013 13:20:28 +0200
Subject: [PATCH] Add option to slow qemu down

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.

The option is not available when KVM or XEN acceleration is
enabled since it would defeat the purpose.

Signed-off-by: Wolfgang Mauerer <wolfgang.mauerer@siemens.com>
---
 cpus.c                |   30 ++++++++++++++++++++++++++++++
 include/qemu-common.h |    2 ++
 qemu-options.hx       |   15 +++++++++++++++
 vl.c                  |   10 ++++++++++
 4 files changed, 57 insertions(+)

Patch

diff --git a/cpus.c b/cpus.c
index c232265..f59c935 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, ...)
 {
@@ -1121,6 +1139,8 @@  void vm_stop_force_state(RunState state)
 static int tcg_cpu_exec(CPUArchState *env)
 {
     int ret;
+    int64_t ss = 0; /* Initialise to avoid bogus maybe-uninitialized error */
+    uint64_t slowdown_sleep;
 #ifdef CONFIG_PROFILER
     int64_t ti;
 #endif
@@ -1141,7 +1161,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 b399d85..219993f 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -108,6 +108,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);
+
 #include "qemu/osdep.h"
 #include "qemu/bswap.h"
 
diff --git a/qemu-options.hx b/qemu-options.hx
index fb62b75..fd16cb3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2801,6 +2801,21 @@  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     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.
+
+Note that this option cannot be used when KVM or XEN support is active.
+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 6e6225f..27acf8b 100644
--- a/vl.c
+++ b/vl.c
@@ -2839,6 +2839,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] = "";
@@ -3751,6 +3752,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);
@@ -4169,6 +4173,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);
     }