[libvirt PATCH] qemu: Do not require TSC frequency to strictly match host

Jiri Denemark posted 1 patch 3 years, 5 months ago
Test syntax-check failed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/6d84af8e8e4d4f9fcfd3d37fce5b1373c161ba22.1605096553.git.jdenemar@redhat.com
src/qemu/qemu_process.c | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)
[libvirt PATCH] qemu: Do not require TSC frequency to strictly match host
Posted by Jiri Denemark 3 years, 5 months ago
Some CPUs provide a way to read exact TSC frequency, while measuring it
is required on other CPUs. However, measuring is never exact and the
result may slightly differ across reboots. For this reason both Linux
kernel and QEMU recently started allowing for guests TSC frequency to
fall into +/- 250 ppm tolerance interval around the host TSC frequency.

Let's do the same to avoid unnecessary failures (esp. during migration)
in case the host frequency does not exactly match the frequency
configured in a domain XML.

https://bugzilla.redhat.com/show_bug.cgi?id=1839095

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_process.c | 35 ++++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 0a36b49c85..7f56ddf114 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -5358,12 +5358,18 @@ qemuProcessStartValidateDisks(virDomainObjPtr vm,
 }
 
 
+/* 250 parts per million (ppm) is a half of NTP threshold */
+#define TSC_TOLERANCE 250
+
 static int
 qemuProcessStartValidateTSC(virQEMUDriverPtr driver,
                             virDomainObjPtr vm)
 {
     size_t i;
     unsigned long long freq = 0;
+    unsigned long long tolerance;
+    unsigned long long minFreq;
+    unsigned long long maxFreq;
     virHostCPUTscInfoPtr tsc;
     g_autoptr(virCPUDef) cpu = NULL;
 
@@ -5389,23 +5395,34 @@ qemuProcessStartValidateTSC(virQEMUDriverPtr driver,
     }
 
     tsc = cpu->tsc;
-    VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s",
-              tsc->frequency, virTristateBoolTypeToString(tsc->scaling));
+    tolerance = tsc->frequency * TSC_TOLERANCE / 1000000;
+    minFreq = tsc->frequency - tolerance;
+    maxFreq = tsc->frequency + tolerance;
+
+    VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s, tolerance +/- %llu Hz",
+              tsc->frequency, virTristateBoolTypeToString(tsc->scaling),
+              tolerance);
+
+    if (freq > minFreq && freq < maxFreq) {
+        VIR_DEBUG("Requested TSC frequency is within tolerance interval");
+        return 0;
+    }
 
-    if (freq == tsc->frequency || tsc->scaling == VIR_TRISTATE_BOOL_YES)
+    if (tsc->scaling == VIR_TRISTATE_BOOL_YES)
         return 0;
 
     if (tsc->scaling == VIR_TRISTATE_BOOL_ABSENT) {
-        VIR_DEBUG("TSC frequencies do not match and scaling support is "
-                  "unknown, QEMU will try and possibly fail later");
+        VIR_DEBUG("Requested TSC frequency falls outside tolerance range and "
+                  "scaling support is unknown, QEMU will try and possibly "
+                  "fail later");
         return 0;
     }
 
     virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                   _("Requested TSC frequency %llu Hz does not match "
-                     "host (%llu Hz) and TSC scaling is not supported "
-                     "by the host CPU"),
-                   freq, tsc->frequency);
+                   _("Requested TSC frequency %llu Hz is outside tolerance "
+                     "range ([%llu, %llu] Hz) around host frequency %llu Hz "
+                     "and TSC scaling is not supported by the host CPU"),
+                   freq, minFreq, maxFreq, tsc->frequency);
     return -1;
 }
 
-- 
2.29.2

Re: [libvirt PATCH] qemu: Do not require TSC frequency to strictly match host
Posted by Daniel Henrique Barboza 3 years, 5 months ago

On 11/11/20 9:09 AM, Jiri Denemark wrote:
> Some CPUs provide a way to read exact TSC frequency, while measuring it
> is required on other CPUs. However, measuring is never exact and the
> result may slightly differ across reboots. For this reason both Linux
> kernel and QEMU recently started allowing for guests TSC frequency to
> fall into +/- 250 ppm tolerance interval around the host TSC frequency.
> 
> Let's do the same to avoid unnecessary failures (esp. during migration)
> in case the host frequency does not exactly match the frequency
> configured in a domain XML.
> 
> https://bugzilla.redhat.com/show_bug.cgi?id=1839095
> 
> Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
> ---


Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>



>   src/qemu/qemu_process.c | 35 ++++++++++++++++++++++++++---------
>   1 file changed, 26 insertions(+), 9 deletions(-)
> 
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 0a36b49c85..7f56ddf114 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -5358,12 +5358,18 @@ qemuProcessStartValidateDisks(virDomainObjPtr vm,
>   }
>   
>   
> +/* 250 parts per million (ppm) is a half of NTP threshold */
> +#define TSC_TOLERANCE 250
> +
>   static int
>   qemuProcessStartValidateTSC(virQEMUDriverPtr driver,
>                               virDomainObjPtr vm)
>   {
>       size_t i;
>       unsigned long long freq = 0;
> +    unsigned long long tolerance;
> +    unsigned long long minFreq;
> +    unsigned long long maxFreq;
>       virHostCPUTscInfoPtr tsc;
>       g_autoptr(virCPUDef) cpu = NULL;
>   
> @@ -5389,23 +5395,34 @@ qemuProcessStartValidateTSC(virQEMUDriverPtr driver,
>       }
>   
>       tsc = cpu->tsc;
> -    VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s",
> -              tsc->frequency, virTristateBoolTypeToString(tsc->scaling));
> +    tolerance = tsc->frequency * TSC_TOLERANCE / 1000000;
> +    minFreq = tsc->frequency - tolerance;
> +    maxFreq = tsc->frequency + tolerance;
> +
> +    VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s, tolerance +/- %llu Hz",
> +              tsc->frequency, virTristateBoolTypeToString(tsc->scaling),
> +              tolerance);
> +
> +    if (freq > minFreq && freq < maxFreq) {
> +        VIR_DEBUG("Requested TSC frequency is within tolerance interval");
> +        return 0;
> +    }
>   
> -    if (freq == tsc->frequency || tsc->scaling == VIR_TRISTATE_BOOL_YES)
> +    if (tsc->scaling == VIR_TRISTATE_BOOL_YES)
>           return 0;
>   
>       if (tsc->scaling == VIR_TRISTATE_BOOL_ABSENT) {
> -        VIR_DEBUG("TSC frequencies do not match and scaling support is "
> -                  "unknown, QEMU will try and possibly fail later");
> +        VIR_DEBUG("Requested TSC frequency falls outside tolerance range and "
> +                  "scaling support is unknown, QEMU will try and possibly "
> +                  "fail later");
>           return 0;
>       }
>   
>       virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> -                   _("Requested TSC frequency %llu Hz does not match "
> -                     "host (%llu Hz) and TSC scaling is not supported "
> -                     "by the host CPU"),
> -                   freq, tsc->frequency);
> +                   _("Requested TSC frequency %llu Hz is outside tolerance "
> +                     "range ([%llu, %llu] Hz) around host frequency %llu Hz "
> +                     "and TSC scaling is not supported by the host CPU"),
> +                   freq, minFreq, maxFreq, tsc->frequency);
>       return -1;
>   }
>   
>