Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


More timing cleanup with a fix to 8254.c for running cores slower than
Patrick G. Bridges [Fri, 25 Feb 2011 19:50:23 +0000 (12:50 -0700)]
host speed; multiple guest CPUs on a single host CPU seems broken, still
but more testing/debugging is needed.

Kconfig
palacios/include/palacios/vmm_time.h
palacios/src/devices/8254.c
palacios/src/palacios/vmm_time.c

diff --git a/Kconfig b/Kconfig
index 0eb9692..45a0568 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -233,24 +233,7 @@ config TIME_HIDE_VM_COST
            Offset guest time from host time sufficiently to hide the cost of
            running in the virtual machine. This can aid the consistency of
            time between multiple timers, but can cause the guest to run 
-           slightly slower than the host.
-
-config TIME_HIDE_EXIT_COST
-        bool "Hide VMM Exit Cost"
-       default n
-       depends on TIME_HIDE_VM_COST
-       help
-           Add additional TSC offset to hide VMM exit costs from the guest.
-
-config TIME_EXIT_COST_ADJUST
-       int "Exit cost adjustment for hiding VM exits"
-       default 2000
-       depends on TIME_HIDE_EXIT_COST
-       help
-           Amount to adjust the time to hide the exit cost of fully virtualizing
-          the timestamp counter. Used to hide the cost of fully virtualizing 
-          the TSC for OSes that assume that reading the TSC is inexpensive 
-          (e.g. Linux TSC-based timer calibration).
+           a good bit slower than the host in VM-intensive parts of the code.
 
 config TIME_VIRTUALIZE_TSC
        bool "Fully virtualize guest TSC"
index 3255aca..c9248b8 100644 (file)
@@ -93,11 +93,8 @@ static inline uint64_t v3_get_host_time(struct vm_time *t) {
 // Returns *monotonic* guest time.
 static inline uint64_t v3_get_guest_time(struct vm_time *t) {
 #ifdef CONFIG_TIME_HIDE_VM_COST
-    if (t->exit_time) {
-        return t->exit_time + t->guest_host_offset;
-    } else {
-        return v3_get_host_time(t) + t->guest_host_offset;
-    }
+    V3_ASSERT(t->exit_time);
+    return t->exit_time + t->guest_host_offset;
 #else
     return v3_get_host_time(t) + t->guest_host_offset;
 #endif
index ffae665..4c3a8af 100644 (file)
@@ -679,7 +679,7 @@ static int pit_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     // just hardcode the core context
     struct guest_info * info = &(vm->cores[0]);
 
-    uint_t cpu_khz = V3_CPU_KHZ();
+    uint_t cpu_khz = info->time_state.guest_cpu_freq;
     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
 
     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
index 06bb27c..dea7cdb 100644 (file)
@@ -18,8 +18,8 @@
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#include <palacios/vmm_time.h>
 #include <palacios/vmm.h>
+#include <palacios/vmm_time.h>
 #include <palacios/vm_guest.h>
 
 #ifndef CONFIG_DEBUG_TIME
@@ -94,41 +94,62 @@ int v3_start_time(struct guest_info * info) {
     return 0;
 }
 
-// If the guest is supposed to run slower than the host, yield out until
-// the host time is appropriately far along;
+// Control guest time in relation to host time so that the two stay 
+// appropriately synchronized to the extent possible. 
 int v3_adjust_time(struct guest_info * info) {
     struct vm_time * time_state = &(info->time_state);
+    uint64_t host_time, target_host_time;
+    uint64_t guest_time, target_guest_time, old_guest_time;
+    uint64_t guest_elapsed, host_elapsed, desired_elapsed;
 
-    if (time_state->host_cpu_freq != time_state->guest_cpu_freq) {
-       uint64_t guest_time, host_time, target_host_time;
-       sint64_t guest_elapsed, desired_elapsed;
-
-       guest_time = v3_get_guest_time(time_state);
-
-       /* Compute what host time this guest time should correspond to. */
-       guest_elapsed = (guest_time - time_state->initial_time);
-       desired_elapsed = (guest_elapsed * time_state->host_cpu_freq) / time_state->guest_cpu_freq;
-       target_host_time = time_state->initial_time + desired_elapsed;
-
-       /* Yield until that host time is reached */
+    /* Compute the target host time given how much time has *already*
+     * passed in the guest */
+    guest_time = v3_get_guest_time(time_state);
+    guest_elapsed = (guest_time - time_state->initial_time);
+    desired_elapsed = (guest_elapsed * time_state->host_cpu_freq) / time_state->guest_cpu_freq;
+    target_host_time = time_state->initial_time + desired_elapsed;
+
+    /* Now, let the host run while the guest is stopped to make the two
+     * sync up. */
+    host_time = v3_get_host_time(time_state);
+    old_guest_time = v3_get_guest_time(time_state);
+    while (target_host_time > host_time) {
+       v3_yield(info);
        host_time = v3_get_host_time(time_state);
-
-       if (host_time < target_host_time) {
-           PrintDebug("Yielding until host time (%llu) greater than target (%llu).\n", host_time, target_host_time);
-       }
-
-       while (host_time < target_host_time) {
-           v3_yield(info);
-           host_time = v3_get_host_time(time_state);
+    }
+    guest_time = v3_get_guest_time(time_state);
+    // We do *not* assume the guest timer was paused in the VM. If it was
+    // this offseting is 0. If it wasn't we need this.
+    v3_offset_time(info, (sint64_t)old_guest_time - (sint64_t)guest_time);
+
+    /* Now the host may have gotten ahead of the guest because
+     * yielding is a coarse grained thing. Figure out what guest time
+     * we want to be at, and use the use the offsetting mechanism in 
+     * the VMM to make the guest run forward. We limit *how* much we skew 
+     * it forward to prevent the guest time making large jumps, 
+     * however. */
+    host_elapsed = host_time - time_state->initial_time;
+    desired_elapsed = (host_elapsed * time_state->guest_cpu_freq) / time_state->host_cpu_freq;
+    target_guest_time = time_state->initial_time + desired_elapsed;
+
+    if (guest_time < target_guest_time) {
+       uint64_t max_skew, desired_skew, skew;
+
+       if (time_state->enter_time) {
+           max_skew = (time_state->exit_time - time_state->enter_time)/10;
+       } else {
+           max_skew = 0;
        }
-
-#ifndef CONFIG_TIME_HIDE_VM_COST
-        // XXX This should turn into a target offset we want to move towards XXX
-       time_state->guest_host_offset = 
-               (sint64_t)guest_time - (sint64_t)host_time;
-#endif
+       desired_skew = target_guest_time - guest_time;
+       skew = desired_skew > max_skew ? max_skew : desired_skew;
+/*     PrintDebug("Guest %llu cycles behind where it should be.\n",
+                  desired_skew);
+       PrintDebug("Limit on forward skew is %llu. Skewing forward %llu.\n",
+                  max_skew, skew); */
+       
+       v3_offset_time(info, skew);
     }
-
+    
     return 0;
 }
 
@@ -140,11 +161,6 @@ v3_time_exit_vm( struct guest_info * info )
     
     time_state->exit_time = v3_get_host_time(time_state);
 
-#ifdef CONFIG_TIME_HIDE_EXIT_COST
-    // XXX should make the cost adjustment a runtime parameter
-    // so it can be set by the config file and/or tuned dynamically
-    v3_offset_time(info, -CONFIG_TIME_EXIT_COST_ADJUST);
-#endif
     return 0;
 }
 
@@ -153,17 +169,17 @@ int
 v3_time_enter_vm( struct guest_info * info )
 {
     struct vm_time * time_state = &(info->time_state);
+    uint64_t guest_time, host_time;
 
-    time_state->enter_time = v3_get_host_time(time_state);
-#ifdef CONFIG_TIME_HIDE_VM_COST
-    if (time_state->exit_time) {
-        sint64_t pause_diff = time_state->enter_time - time_state->exit_time;
-        time_state->guest_host_offset -= pause_diff;
-    } else {
-        PrintError( "Time at which guest exited to VM not recorded!\n" );
-    }
-#endif
-    time_state->exit_time = 0;
+    guest_time = v3_get_guest_time(time_state);
+    host_time = v3_get_host_time(time_state);
+    time_state->enter_time = host_time;
+    time_state->guest_host_offset = guest_time - host_time;
+
+    // Because we just modified the offset - shouldn't matter as this should be 
+    // the last time-related call prior to entering the VMM, but worth it 
+    // just in case.
+    time_state->exit_time = host_time; 
 
     return 0;
 }