[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v10] new config option vtsc_tolerance_khz to avoid TSC emulation



[ the math added to xen-tscmode.7 suggests that a domU should see a time
  drift, which ntpd corrects. But the actual correction reported in
  ntp.drift is entirely different than the one calculated in the
  example. To me it is unclear why the example is wrong, more research
  must be done. I'm sending this out just to get feedback about how
  exactly the per-host knob must be implemented. ]

Add a knob to control when vTSC emulation will be activated for a domU
with tsc_mode=default. Without such option each TSC access from domU
will be emulated, which causes a significant perfomance drop for
workloads that make use of rdtsc.

One option to avoid the TSC option is to run domUs with tsc_mode=native.
This has the drawback that migrating a domU from a "2.3GHz" class host
to a "2.4GHz" class host will change the rate at wich the TSC counter
increases, the domU may not be prepared for that.

With the new knob the host admin can decide how a domU should behave
when it is migrated across systems of the same class. Since there is
always some jitter when Xen calibrates the cpu_khz value, all hosts of
the same class will most likely have slightly different values. As a
result vTSC emulation is unavoidable. Data collected during the incident
which triggered this change showed a jitter of up to 200 KHz across
systems of the same class.

Such knob can not be on a per-domU base because this would mean an
already running domU can not be handled anymore. Instead the newly added
knob is a global, optional per-host configuration file. Since it affects
only the restore path, the used configfile is /etc/xen/sr.conf.

Signed-off-by: Olaf Hering <olaf@xxxxxxxxx>
--

v10:
 - rebase to ae01a8e315
 - remove changes for libxl and save/restore protocol, the feature has
   to be per host instead of per guest
 - add newline to tsc_set_info (Andrew)
 - add pointer to xen-tscmode(7) in xl.cfg(5)/vtsc_tolerance_khz (Andrew)
 - mention potential clock drift in the domU (Andrew)
 - reword the newly added paragraph in xen-tscmode(7) (Andrew),
   and also mention that it is about the measured/estimated TSC value
   rather than the real value. The latter is simply unknown.
 - use uint32 for internal representation of 
xen_domctl_tsc_info.vtsc_tolerance_khz
   and remove padding field
 - add math for real TSC frequency to xen-tscmode
v9:
 - extend commit msg, mention potential issues with xc_sr_rec_tsc_info._res1
v8:
 - adjust also python stream checker for added tolerance member
v7:
 - use uint16 in libxl_types.idl to match type used elsewhere in the patch
v6:
 - mention default value in xl.cfg
 - tsc_set_info: remove usage of __func__, use %d for domid
 - tsc_set_info: use ABS to calculate khz_diff
v5:
 - reduce functionality to allow setting of the tolerance value
   only at initial domU startup
v4:
 - add missing copyback in XEN_DOMCTL_set_vtsc_tolerance_khz
v3:
 - rename vtsc_khz_tolerance to vtsc_tolerance_khz
 - separate domctls to adjust values
 - more docs
 - update libxl.h
 - update python tests
 - flask check bound to tsc permissions
 - not runtime tested due to dlsym() build errors in staging
---
 docs/man/xen-tscmode.pod.7        | 61 +++++++++++++++++++++++++
 docs/man/xl.cfg.pod.5.in          | 12 +++++
 tools/libxc/include/xenctrl.h     |  2 +
 tools/libxc/xc_domain.c           |  4 ++
 tools/libxc/xc_sr_common.h        |  2 +
 tools/libxc/xc_sr_common_x86.c    |  7 ++-
 tools/libxc/xc_sr_restore.c       | 93 +++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_x86.c           |  2 +-
 tools/python/xen/lowlevel/xc/xc.c |  2 +-
 xen/arch/x86/domain.c             |  2 +-
 xen/arch/x86/domctl.c             |  2 +
 xen/arch/x86/time.c               | 31 +++++++++++--
 xen/include/asm-x86/domain.h      |  1 +
 xen/include/asm-x86/time.h        |  6 ++-
 xen/include/public/domctl.h       |  2 +-
 15 files changed, 218 insertions(+), 11 deletions(-)

diff --git a/docs/man/xen-tscmode.pod.7 b/docs/man/xen-tscmode.pod.7
index 819c61dd05..61cb69a381 100644
--- a/docs/man/xen-tscmode.pod.7
+++ b/docs/man/xen-tscmode.pod.7
@@ -103,6 +103,9 @@ whether or not the VM has been saved/restored/migrated
 
 =back
 
+If the tsc_mode is set to "default" the decision to emulate TSC can be
+tweaked further with the "vtsc_tolerance_khz" option in /etc/xen/sr.conf.
+
 To understand this in more detail, the rest of this document must
 be read.
 
@@ -215,6 +218,64 @@ is emulated.  Note that, though emulated, the "apparent" 
TSC frequency
 will be the TSC frequency of the initial physical machine, even after
 migration.
 
+Since the calibration of the TSC frequency isn't 100% accurate, the
+value measured by Xen will vary across reboots. This means also several
+otherwise identical systems can have a slightly different _measured_ TSC
+frequency. As a result TSC access will be emulated if a domU is migrated
+from one host to another, identical host. To avoid the performance
+impact of TSC emulation a certain tolerance of the measured host TSC
+frequency can be specified with "vtsc_tolerance_khz". If the measured
+"cpu_khz" value is within the tolerance range, TSC access remains
+native. Otherwise it will be emulated. This allows to migrate domUs
+between identical hardware. If the domU will be migrated to a different
+kind of hardware, say from a "2.3GHz" to a "2.5GHz" system, TSC will be
+emualted to maintain the TSC frequency expected by the domU.
+
+Some math to demonstrate the expected time drift in a domU with
+tsc_mode==2: on a 2.0GHz host, The dom0 and domU kernels may measure the
+TSC frequency as 2000.082 MHz during boot. This means, the amount of
+2000082*1000=2000082000 Hz ticks represent "a second".
+If ntpd runs in that dom0, it will estimate the drift and stores it in a
+ntp.drift file. The unit of the number is "PPM", in this example let it
+be 23.296. This means the time would run 23.296 microsends faster per
+second, the TSC frequency is in fact lower, ntpd has to delay system time.
+
+Xen:    ((1*1000*1000*1000)*2000084000) / ((1*1000*1000*1000) + 23296) = 
2000037407 Hz = 2000.037 MHz
+
+Native: ((1*1000*1000*1000)*2000070000) / ((1*1000*1000*1000) + 16393) = 
2000037213 Hz = 2000.037 MHz
+
+The other, supposedly identical, system reports 2000.086 MHz and 6.157 ppm
+drift:
+
+Xen:    ((1*1000*1000*1000)*2000086000) / ((1*1000*1000*1000) +  6157) = 
2000073685 Hz = 2000.073 MHz
+
+Native: ((1*1000*1000*1000)*2000070000) / ((1*1000*1000*1000) + -1876) = 
2000073752 Hz = 2000.073 MHz
+
+If a domU is started on the first system, it will use the reported
+frequency of 2000.084 MHz. The ntpd within that domU will calculate the
+effective drift and keep the actual time close to the reference system.
+Once that domU is migrated to the second system, the kernel does not
+recalculate the TSC frequency. It continues to use the value it found
+during startup. Now the TSC ticks faster. ntpd will notice this and
+increases the drift. It can correct a drift up to 500 PPM. The time
+drift on the second system will be:
+
+( ((2000074370 * ((1*1000*1000*1000) + 23296)) / 2000037407) - 
(1*1000*1000*1000) ) / 1000 =  41.777
+
+To see how much the actual TSC could change to stay within the +/- 500 PPM 
limit: 
+
+(2000037407 * ((1*1000*1000*1000) + 500000)) / ((1*1000*1000*1000) + 23296) = 
2000990810 Hz = 2000.990 MHz
+
+(2000037407 * ((1*1000*1000*1000) - 500000)) / ((1*1000*1000*1000) + 23296) = 
1998990819 Hz = 1998.990 MHz
+
+This means a domU can not be migrated from a 2.0GHz host to a 2.1GHz
+or 1.9GHz host, the drift would be too large.
+
+The exact value of the vtsc_tolerance_khz config option must be
+calculated by the host admin based on the ntp.drift and estimated TSC
+frequency for each host. Based on the example numbers above,  a possible
+value would be between 898 and 1102 (2000082-2000980=-898, 
2000082-1998980=1102).
+
 For environments where both TSC-safeness AND highest performance
 even across migration is a requirement, application code can be specially
 modified to use an algorithm explicitly designed into Xen for this purpose.
diff --git a/docs/man/xl.cfg.pod.5.in b/docs/man/xl.cfg.pod.5.in
index b1c0be14cd..bd211fb31b 100644
--- a/docs/man/xl.cfg.pod.5.in
+++ b/docs/man/xl.cfg.pod.5.in
@@ -2084,6 +2084,18 @@ constant host TSC and supports Intel VMX TSC scaling/AMD 
SVM TSC
 ratio, its guest TSC frequency will be the same before and after
 migration, and guest rdtsc/p will be executed natively after migration as well
 
+B<(x86 only, relevant only for tsc_mode=default)>
+When a domU is started, the CPU frequency of the host is used by the domU for
+TSC related time measurement. Once the domU is either migrated or
+saved/restored on another host that CPU frequency has to be emulated to avoid
+timedrift. To avoid the performance penalty of the TSC emulation, allow a
+certain amount of jitter of the measured CPU frequency on the hosts the domU
+is supposed to run on. Default value is 0, i.e. no tolerance.
+
+Please see B<xen-tscmode(7)> for more information about the impact of this
+option, specifically about potential clock drive in the domU when
+vtsc_tolerance_khz="KHZ" is used.
+
 =item B<always_emulate>
 
 Guest rdtsc/p is always emulated and the virtual TSC will appear to increment
diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 97ae965be7..ad723bf962 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1343,6 +1343,7 @@ int xc_domain_set_tsc_info(xc_interface *xch,
                            uint32_t tsc_mode,
                            uint64_t elapsed_nsec,
                            uint32_t gtsc_khz,
+                           uint32_t vtsc_tolerance_khz,
                            uint32_t incarnation);
 
 int xc_domain_get_tsc_info(xc_interface *xch,
@@ -1350,6 +1351,7 @@ int xc_domain_get_tsc_info(xc_interface *xch,
                            uint32_t *tsc_mode,
                            uint64_t *elapsed_nsec,
                            uint32_t *gtsc_khz,
+                           uint32_t *vtsc_tolerance_khz,
                            uint32_t *incarnation);
 
 int xc_domain_disable_migrate(xc_interface *xch, uint32_t domid);
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 05d771f2ce..be9f8a9fec 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -830,6 +830,7 @@ int xc_domain_set_tsc_info(xc_interface *xch,
                            uint32_t tsc_mode,
                            uint64_t elapsed_nsec,
                            uint32_t gtsc_khz,
+                           uint32_t vtsc_tolerance_khz,
                            uint32_t incarnation)
 {
     DECLARE_DOMCTL;
@@ -838,6 +839,7 @@ int xc_domain_set_tsc_info(xc_interface *xch,
     domctl.u.tsc_info.tsc_mode = tsc_mode;
     domctl.u.tsc_info.elapsed_nsec = elapsed_nsec;
     domctl.u.tsc_info.gtsc_khz = gtsc_khz;
+    domctl.u.tsc_info.vtsc_tolerance_khz = vtsc_tolerance_khz;
     domctl.u.tsc_info.incarnation = incarnation;
     return do_domctl(xch, &domctl);
 }
@@ -847,6 +849,7 @@ int xc_domain_get_tsc_info(xc_interface *xch,
                            uint32_t *tsc_mode,
                            uint64_t *elapsed_nsec,
                            uint32_t *gtsc_khz,
+                           uint32_t *vtsc_tolerance_khz,
                            uint32_t *incarnation)
 {
     int rc;
@@ -860,6 +863,7 @@ int xc_domain_get_tsc_info(xc_interface *xch,
         *tsc_mode = domctl.u.tsc_info.tsc_mode;
         *elapsed_nsec = domctl.u.tsc_info.elapsed_nsec;
         *gtsc_khz = domctl.u.tsc_info.gtsc_khz;
+        *vtsc_tolerance_khz = domctl.u.tsc_info.vtsc_tolerance_khz;
         *incarnation = domctl.u.tsc_info.incarnation;
     }
     return rc;
diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
index a145a15301..a72934edf6 100644
--- a/tools/libxc/xc_sr_common.h
+++ b/tools/libxc/xc_sr_common.h
@@ -231,6 +231,8 @@ struct xc_sr_context
             /* Currently buffering records between a checkpoint */
             bool buffer_all_records;
 
+            uint32_t vtsc_tolerance_khz;
+
 /*
  * With Remus/COLO, we buffer the records sent by the primary at checkpoint,
  * in case the primary will fail, we can recover from the last
diff --git a/tools/libxc/xc_sr_common_x86.c b/tools/libxc/xc_sr_common_x86.c
index 98f1cef30f..cab0ae1a38 100644
--- a/tools/libxc/xc_sr_common_x86.c
+++ b/tools/libxc/xc_sr_common_x86.c
@@ -10,9 +10,11 @@ int write_tsc_info(struct xc_sr_context *ctx)
         .length = sizeof(tsc),
         .data = &tsc
     };
+    uint32_t vtsc_tolerance_khz;
 
     if ( xc_domain_get_tsc_info(xch, ctx->domid, &tsc.mode,
-                                &tsc.nsec, &tsc.khz, &tsc.incarnation) < 0 )
+                                &tsc.nsec, &tsc.khz, &vtsc_tolerance_khz,
+                                &tsc.incarnation) < 0 )
     {
         PERROR("Unable to obtain TSC information");
         return -1;
@@ -34,7 +36,8 @@ int handle_tsc_info(struct xc_sr_context *ctx, struct 
xc_sr_record *rec)
     }
 
     if ( xc_domain_set_tsc_info(xch, ctx->domid, tsc->mode,
-                                tsc->nsec, tsc->khz, tsc->incarnation) )
+                                tsc->nsec, tsc->khz, 
ctx->restore.vtsc_tolerance_khz,
+                                tsc->incarnation) )
     {
         PERROR("Unable to set TSC information");
         return -1;
diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c
index ea7b0339ef..0baaafa6ba 100644
--- a/tools/libxc/xc_sr_restore.c
+++ b/tools/libxc/xc_sr_restore.c
@@ -4,6 +4,96 @@
 
 #include "xc_sr_common.h"
 
+static const char config_file[] = XEN_CONFIG_DIR "/sr.conf";
+static void parse_config(struct xc_sr_context *ctx, FILE *f, size_t len)
+{
+    xc_interface *xch = ctx->xch;
+    long long v;
+    char *buf, *s;
+    int i, num;
+
+    /* fgets needs a terminating null byte */
+    len++;
+    buf = malloc(len);
+    if ( !buf )
+        return;
+    do
+    {
+        s = fgets(buf, len, f);
+        if ( !s )
+            break;
+
+        /* trim trailing whitespace */
+        i = strlen(s);
+        while ( --i > 0 )
+        {
+            if ( s[i] == '\n' || s[i] == ' ' || s[i] == '\t' || s[i] == '\r' )
+            {
+                s[i] = '\0';
+                continue;
+            }
+            break;
+        }
+
+        i = sscanf(s, "vtsc_tolerance_khz=%lld%n", &v, &num);
+        if ( i == 1 )
+        {
+            if ( strlen(&s[num]) > 1 )
+            {
+                ERROR("garbage after vtsc_tolerance_khz=: '%s'", &s[num]);
+                continue;
+            }
+            if ( v > INT_MAX )
+                v = INT_MAX;
+            else if ( v < 0 )
+                v = 0;
+            IPRINTF("domid %u got vtsc_tolerance_khz %lld from %s",
+                    ctx->domid, v, config_file);
+            ctx->restore.vtsc_tolerance_khz = v;
+        }
+    } while ( s && !feof(f) && !ferror(f) );
+    free(buf);
+}
+
+static int read_config(struct xc_sr_context *ctx)
+{
+    xc_interface *xch = ctx->xch;
+    FILE *f;
+    struct stat stab;
+    int rc = -1;
+
+    errno = 0;
+    f = fopen(config_file, "r");
+    if ( !f )
+    {
+        if ( errno != ENOENT )
+            PERROR("failed to open %s", config_file);
+        return 0;
+    }
+    if ( fstat(fileno(f), &stab) )
+    {
+        PERROR("failed to fstat %s", config_file);
+        goto done;
+    }
+    if ( !S_ISREG(stab.st_mode) )
+    {
+        ERROR("%s is not a plain file", config_file);
+        goto done;
+    }
+    if ( stab.st_size > SHRT_MAX )
+    {
+        ERROR("file %s is far too large", config_file);
+        goto done;
+    }
+    if ( stab.st_size )
+        parse_config(ctx, f, stab.st_size);
+
+    rc = 0;
+done:
+    fclose(f);
+    return rc;
+}
+
 /*
  * Read and validate the Image and Domain headers.
  */
@@ -877,6 +967,9 @@ int xc_domain_restore(xc_interface *xch, int io_fd, 
uint32_t dom,
 
     ctx.domid = dom;
 
+    if ( read_config(&ctx) )
+        return -1;
+
     if ( read_headers(&ctx) )
         return -1;
 
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index c04fd75a64..7460b7f420 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -314,7 +314,7 @@ int libxl__arch_domain_create(libxl__gc *gc, 
libxl_domain_config *d_config,
     default:
         abort();
     }
-    xc_domain_set_tsc_info(ctx->xch, domid, tsc_mode, 0, 0, 0);
+    xc_domain_set_tsc_info(ctx->xch, domid, tsc_mode, 0, 0, 0, 0);
     if (libxl_defbool_val(d_config->b_info.disable_migrate))
         xc_domain_disable_migrate(ctx->xch, domid);
     rtc_timeoffset = d_config->b_info.rtc_timeoffset;
diff --git a/tools/python/xen/lowlevel/xc/xc.c 
b/tools/python/xen/lowlevel/xc/xc.c
index 484b790c75..8bb22cf65e 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -1540,7 +1540,7 @@ static PyObject *pyxc_domain_set_tsc_info(XcObject *self, 
PyObject *args)
     if (!PyArg_ParseTuple(args, "ii", &dom, &tsc_mode))
         return NULL;
 
-    if (xc_domain_set_tsc_info(self->xc_handle, dom, tsc_mode, 0, 0, 0) != 0)
+    if (xc_domain_set_tsc_info(self->xc_handle, dom, tsc_mode, 0, 0, 0, 0) != 
0)
         return pyxc_error_to_exception(self->xc_handle);
 
     Py_INCREF(zero);
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index b4d59487ad..b3acb836fc 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -600,7 +600,7 @@ int arch_domain_create(struct domain *d,
         ASSERT_UNREACHABLE(); /* Not HVM and not PV? */
 
     /* initialize default tsc behavior in case tools don't */
-    tsc_set_info(d, TSC_MODE_DEFAULT, 0UL, 0, 0);
+    tsc_set_info(d, TSC_MODE_DEFAULT, 0UL, 0, 0, 0);
 
     /* PV/PVH guests get an emulated PIT too for video BIOSes to use. */
     pit_init(d, cpu_khz);
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index aa8ad19479..ef5720051f 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -963,6 +963,7 @@ long arch_do_domctl(
             tsc_get_info(d, &domctl->u.tsc_info.tsc_mode,
                          &domctl->u.tsc_info.elapsed_nsec,
                          &domctl->u.tsc_info.gtsc_khz,
+                         &domctl->u.tsc_info.vtsc_tolerance_khz,
                          &domctl->u.tsc_info.incarnation);
             domain_unpause(d);
             copyback = true;
@@ -978,6 +979,7 @@ long arch_do_domctl(
             tsc_set_info(d, domctl->u.tsc_info.tsc_mode,
                          domctl->u.tsc_info.elapsed_nsec,
                          domctl->u.tsc_info.gtsc_khz,
+                         domctl->u.tsc_info.vtsc_tolerance_khz,
                          domctl->u.tsc_info.incarnation);
             domain_unpause(d);
         }
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 24d4c2794b..42b27b22cc 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -2138,7 +2138,7 @@ int host_tsc_is_safe(void)
  */
 void tsc_get_info(struct domain *d, uint32_t *tsc_mode,
                   uint64_t *elapsed_nsec, uint32_t *gtsc_khz,
-                  uint32_t *incarnation)
+                  uint32_t *vtsc_tolerance_khz, uint32_t *incarnation)
 {
     bool enable_tsc_scaling = is_hvm_domain(d) &&
                               hvm_tsc_scaling_supported && !d->arch.vtsc;
@@ -2154,6 +2154,7 @@ void tsc_get_info(struct domain *d, uint32_t *tsc_mode,
         *elapsed_nsec = *gtsc_khz = 0;
         break;
     case TSC_MODE_DEFAULT:
+        *vtsc_tolerance_khz = d->arch.vtsc_tolerance_khz;
         if ( d->arch.vtsc )
         {
     case TSC_MODE_ALWAYS_EMULATE:
@@ -2196,7 +2197,8 @@ void tsc_get_info(struct domain *d, uint32_t *tsc_mode,
  */
 void tsc_set_info(struct domain *d,
                   uint32_t tsc_mode, uint64_t elapsed_nsec,
-                  uint32_t gtsc_khz, uint32_t incarnation)
+                  uint32_t gtsc_khz, uint32_t vtsc_tolerance_khz,
+                  uint32_t incarnation)
 {
     ASSERT(!is_system_domain(d));
 
@@ -2208,9 +2210,12 @@ void tsc_set_info(struct domain *d,
 
     switch ( d->arch.tsc_mode = tsc_mode )
     {
+        bool disable_vtsc;
         bool enable_tsc_scaling;
 
     case TSC_MODE_DEFAULT:
+        d->arch.vtsc_tolerance_khz = vtsc_tolerance_khz;
+        /* Fallthrough. */
     case TSC_MODE_ALWAYS_EMULATE:
         d->arch.vtsc_offset = get_s_time() - elapsed_nsec;
         d->arch.tsc_khz = gtsc_khz ?: cpu_khz;
@@ -2223,8 +2228,26 @@ void tsc_set_info(struct domain *d,
          * When a guest is created, gtsc_khz is passed in as zero, making
          * d->arch.tsc_khz == cpu_khz. Thus no need to check incarnation.
          */
+        disable_vtsc = d->arch.tsc_khz == cpu_khz;
+
+        if ( tsc_mode == TSC_MODE_DEFAULT && gtsc_khz &&
+             d->arch.vtsc_tolerance_khz )
+        {
+            long khz_diff;
+
+            khz_diff = ABS((long)(cpu_khz - gtsc_khz));
+            disable_vtsc = khz_diff <= d->arch.vtsc_tolerance_khz;
+
+            printk(XENLOG_G_INFO "d%d: host has %lu kHz,"
+                   " domU expects %u kHz,"
+                   " difference of %ld is %s tolerance of %u\n",
+                   d->domain_id, cpu_khz, gtsc_khz, khz_diff,
+                   disable_vtsc ? "within" : "outside",
+                   d->arch.vtsc_tolerance_khz);
+        }
+
         if ( tsc_mode == TSC_MODE_DEFAULT && host_tsc_is_safe() &&
-             (d->arch.tsc_khz == cpu_khz ||
+             (disable_vtsc ||
               (is_hvm_domain(d) &&
                hvm_get_tsc_scaling_ratio(d->arch.tsc_khz))) )
         {
@@ -2313,6 +2336,8 @@ static void dump_softtsc(unsigned char key)
             printk(",ofs=%#"PRIx64, d->arch.vtsc_offset);
         if ( d->arch.tsc_khz )
             printk(",khz=%"PRIu32, d->arch.tsc_khz);
+        if ( d->arch.vtsc_tolerance_khz )
+            printk(",tol=%"PRIu16, d->arch.vtsc_tolerance_khz);
         if ( d->arch.incarnation )
             printk(",inc=%"PRIu32, d->arch.incarnation);
 #if !defined(NDEBUG) || defined(CONFIG_PERF_COUNTERS)
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 277f99f633..bc64d8f8fe 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -386,6 +386,7 @@ struct arch_domain
     uint64_t vtsc_offset;    /* adjustment for save/restore/migrate */
     uint32_t tsc_khz;        /* cached guest khz for certain emulated or
                                 hardware TSC scaling cases */
+    uint32_t vtsc_tolerance_khz; /* domU handles that much jitter in cpu_khz */
     struct time_scale vtsc_to_ns; /* scaling for certain emulated or
                                      hardware TSC scaling cases */
     struct time_scale ns_to_vtsc; /* scaling for certain emulated or
diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h
index ce96ec9778..8c52b4e693 100644
--- a/xen/include/asm-x86/time.h
+++ b/xen/include/asm-x86/time.h
@@ -61,10 +61,12 @@ u64 gtime_to_gtsc(struct domain *d, u64 time);
 u64 gtsc_to_gtime(struct domain *d, u64 tsc);
 
 void tsc_set_info(struct domain *d, uint32_t tsc_mode, uint64_t elapsed_nsec,
-                  uint32_t gtsc_khz, uint32_t incarnation);
+                  uint32_t gtsc_khz, uint32_t vtsc_tolerance_khz,
+                  uint32_t incarnation);
    
 void tsc_get_info(struct domain *d, uint32_t *tsc_mode, uint64_t *elapsed_nsec,
-                  uint32_t *gtsc_khz, uint32_t *incarnation);
+                  uint32_t *gtsc_khz, uint32_t *vtsc_tolerance_khz,
+                  uint32_t *incarnation);
    
 
 void force_update_vcpu_system_time(struct vcpu *v);
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 7e1cf21075..6979baff58 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -735,7 +735,7 @@ struct xen_domctl_tsc_info {
     uint32_t tsc_mode;
     uint32_t gtsc_khz;
     uint32_t incarnation;
-    uint32_t pad;
+    uint32_t vtsc_tolerance_khz;
     uint64_aligned_t elapsed_nsec;
 };
 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.