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

Re: [Xen-devel] [PATCH v2] viridian: unify time sources



Ping?

> -----Original Message-----
> From: Paul Durrant <paul.durrant@xxxxxxxxxx>
> Sent: 17 June 2019 09:24
> To: xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Paul Durrant <Paul.Durrant@xxxxxxxxxx>; Jan Beulich <jbeulich@xxxxxxxx>; 
> Andrew Cooper
> <Andrew.Cooper3@xxxxxxxxxx>; Wei Liu <wl@xxxxxxx>; Roger Pau Monne 
> <roger.pau@xxxxxxxxxx>
> Subject: [PATCH v2] viridian: unify time sources
> 
> Currently, the time_ref_count enlightened time source maintains an offset
> such that time is frozen when the domain paused, but the reference_tsc
> enlightened time source does not. After migrate, the reference_tsc source
> may become invalidated (e.g. because of host cpu frequency mismatch) which
> will cause Windows to fall back to time_ref_count. Thus, the guest will
> observe a jump in time equivalent to the offset.
> 
> This patch unifies the two enlightened time sources such that the same
> offset applies to both of them. Also, it's not really necessary to have
> two different functions to calculating a 10MHz counter value, time_now() and
> raw_trc_val(), so this patch removes the latter implementation. The
> unification also allows removal of the reference_tsc_valid flag.
> 
> Whilst in the area, this patch also takes the opportunity to constify a few
> pointers which were missed in earlier patches.
> 
> Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
> ---
> Cc: Jan Beulich <jbeulich@xxxxxxxx>
> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> Cc: Wei Liu <wl@xxxxxxx>
> Cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx>
> 
> v2:
>  - Expand comments above newly added TscOffset setting
> ---
>  xen/arch/x86/hvm/viridian/time.c   | 105 +++++++++++++----------------
>  xen/include/asm-x86/hvm/viridian.h |   1 -
>  2 files changed, 45 insertions(+), 61 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/viridian/time.c 
> b/xen/arch/x86/hvm/viridian/time.c
> index 2a3c9697d7..28e3d88ca9 100644
> --- a/xen/arch/x86/hvm/viridian/time.c
> +++ b/xen/arch/x86/hvm/viridian/time.c
> @@ -26,9 +26,10 @@ typedef struct _HV_REFERENCE_TSC_PAGE
>      uint64_t Reserved2[509];
>  } HV_REFERENCE_TSC_PAGE, *PHV_REFERENCE_TSC_PAGE;
> 
> -static void update_reference_tsc(struct domain *d, bool initialize)
> +static void update_reference_tsc(const struct domain *d, bool initialize)
>  {
>      struct viridian_domain *vd = d->arch.hvm.viridian;
> +    const struct viridian_time_ref_count *trc = &vd->time_ref_count;
>      const struct viridian_page *rt = &vd->reference_tsc;
>      HV_REFERENCE_TSC_PAGE *p = rt->ptr;
>      uint32_t seq;
> @@ -44,7 +45,9 @@ static void update_reference_tsc(struct domain *d, bool 
> initialize)
>       * with this, allowing vtsc to be turned off, but support for this is
>       * not yet present in the hypervisor. Thus is it is possible that
>       * migrating a Windows VM between hosts of differing TSC frequencies
> -     * may result in large differences in guest performance.
> +     * may result in large differences in guest performance. Any jump in
> +     * TSC due to migration down-time can, however, be compensated for by
> +     * setting the TscOffset value (see below).
>       */
>      if ( !host_tsc_is_safe() || d->arch.vtsc )
>      {
> @@ -62,8 +65,6 @@ static void update_reference_tsc(struct domain *d, bool 
> initialize)
> 
>          printk(XENLOG_G_INFO "d%d: VIRIDIAN REFERENCE_TSC: invalidated\n",
>                 d->domain_id);
> -
> -        vd->reference_tsc_valid = false;
>          return;
>      }
> 
> @@ -75,8 +76,11 @@ static void update_reference_tsc(struct domain *d, bool 
> initialize)
>       *
>       * Windows uses a 100ns tick, so we need a scale which is cpu
>       * ticks per 100ns shifted left by 64.
> +     * The offset value is calculated on restore after migration and
> +     * ensures that Windows will not see a large jump in ReferenceTime.
>       */
>      p->TscScale = ((10000ul << 32) / d->arch.tsc_khz) << 32;
> +    p->TscOffset = trc->off;
>      smp_wmb();
> 
>      seq = p->TscSequence + 1;
> @@ -84,46 +88,6 @@ static void update_reference_tsc(struct domain *d, bool 
> initialize)
>          seq = 1;
> 
>      p->TscSequence = seq;
> -    vd->reference_tsc_valid = true;
> -}
> -
> -static int64_t raw_trc_val(const struct domain *d)
> -{
> -    uint64_t tsc;
> -    struct time_scale tsc_to_ns;
> -
> -    tsc = hvm_get_guest_tsc(pt_global_vcpu_target(d));
> -
> -    /* convert tsc to count of 100ns periods */
> -    set_time_scale(&tsc_to_ns, d->arch.tsc_khz * 1000ul);
> -    return scale_delta(tsc, &tsc_to_ns) / 100ul;
> -}
> -
> -static void time_ref_count_freeze(const struct domain *d)
> -{
> -    struct viridian_time_ref_count *trc =
> -        &d->arch.hvm.viridian->time_ref_count;
> -
> -    if ( test_and_clear_bit(_TRC_running, &trc->flags) )
> -        trc->val = raw_trc_val(d) + trc->off;
> -}
> -
> -static void time_ref_count_thaw(const struct domain *d)
> -{
> -    struct viridian_time_ref_count *trc =
> -        &d->arch.hvm.viridian->time_ref_count;
> -
> -    if ( !d->is_shutting_down &&
> -         !test_and_set_bit(_TRC_running, &trc->flags) )
> -        trc->off = (int64_t)trc->val - raw_trc_val(d);
> -}
> -
> -static int64_t time_ref_count(const struct domain *d)
> -{
> -    struct viridian_time_ref_count *trc =
> -        &d->arch.hvm.viridian->time_ref_count;
> -
> -    return raw_trc_val(d) + trc->off;
>  }
> 
>  /*
> @@ -136,7 +100,7 @@ static int64_t time_ref_count(const struct domain *d)
>   * 128 bit number which is then shifted 64 times to the right to obtain
>   * the high 64 bits."
>   */
> -static uint64_t scale_tsc(uint64_t tsc, uint64_t scale, uint64_t offset)
> +static uint64_t scale_tsc(uint64_t tsc, uint64_t scale, int64_t offset)
>  {
>      uint64_t result;
> 
> @@ -153,22 +117,46 @@ static uint64_t scale_tsc(uint64_t tsc, uint64_t scale, 
> uint64_t offset)
>      return result + offset;
>  }
> 
> -static uint64_t time_now(struct domain *d)
> +static uint64_t trc_val(const struct domain *d, int64_t offset)
>  {
>      uint64_t tsc, scale;
> 
> -    /*
> -     * If the reference TSC page is not enabled, or has been invalidated
> -     * fall back to the partition reference counter.
> -     */
> -    if ( !d->arch.hvm.viridian->reference_tsc_valid )
> -        return time_ref_count(d);
> -
> -    /* Otherwise compute reference time in the same way the guest would */
>      tsc = hvm_get_guest_tsc(pt_global_vcpu_target(d));
>      scale = ((10000ul << 32) / d->arch.tsc_khz) << 32;
> 
> -    return scale_tsc(tsc, scale, 0);
> +    return scale_tsc(tsc, scale, offset);
> +}
> +
> +static void time_ref_count_freeze(const struct domain *d)
> +{
> +    struct viridian_time_ref_count *trc =
> +        &d->arch.hvm.viridian->time_ref_count;
> +
> +    if ( test_and_clear_bit(_TRC_running, &trc->flags) )
> +        trc->val = trc_val(d, trc->off);
> +}
> +
> +static void time_ref_count_thaw(const struct domain *d)
> +{
> +    struct viridian_domain *vd = d->arch.hvm.viridian;
> +    struct viridian_time_ref_count *trc = &vd->time_ref_count;
> +
> +    if ( d->is_shutting_down ||
> +         test_and_set_bit(_TRC_running, &trc->flags) )
> +        return;
> +
> +    trc->off = (int64_t)trc->val - trc_val(d, 0);
> +
> +    if ( vd->reference_tsc.msr.enabled )
> +        update_reference_tsc(d, false);
> +}
> +
> +static int64_t time_ref_count(const struct domain *d)
> +{
> +    const struct viridian_time_ref_count *trc =
> +        &d->arch.hvm.viridian->time_ref_count;
> +
> +    return trc_val(d, trc->off);
>  }
> 
>  static void stop_stimer(struct viridian_stimer *vs)
> @@ -196,7 +184,7 @@ static void start_stimer(struct viridian_stimer *vs)
>      const struct vcpu *v = vs->v;
>      struct viridian_vcpu *vv = v->arch.hvm.viridian;
>      unsigned int stimerx = vs - &vv->stimer[0];
> -    int64_t now = time_now(v->domain);
> +    int64_t now = time_ref_count(v->domain);
>      int64_t expiration;
>      s_time_t timeout;
> 
> @@ -285,7 +273,7 @@ static void poll_stimer(struct vcpu *v, unsigned int 
> stimerx)
> 
>      if ( !viridian_synic_deliver_timer_msg(v, vs->config.sintx,
>                                             stimerx, vs->expiration,
> -                                           time_now(v->domain)) )
> +                                           time_ref_count(v->domain)) )
>          return;
> 
>      clear_bit(stimerx, &vv->stimer_pending);
> @@ -641,10 +629,7 @@ void viridian_time_load_domain_ctxt(
>      vd->reference_tsc.msr.raw = ctxt->reference_tsc;
> 
>      if ( vd->reference_tsc.msr.enabled )
> -    {
>          viridian_map_guest_page(d, &vd->reference_tsc);
> -        update_reference_tsc(d, false);
> -    }
>  }
> 
>  /*
> diff --git a/xen/include/asm-x86/hvm/viridian.h 
> b/xen/include/asm-x86/hvm/viridian.h
> index 54e46cc4c4..010c8b58d4 100644
> --- a/xen/include/asm-x86/hvm/viridian.h
> +++ b/xen/include/asm-x86/hvm/viridian.h
> @@ -116,7 +116,6 @@ struct viridian_domain
>      union viridian_page_msr hypercall_gpa;
>      struct viridian_time_ref_count time_ref_count;
>      struct viridian_page reference_tsc;
> -    bool reference_tsc_valid;
>  };
> 
>  void cpuid_viridian_leaves(const struct vcpu *v, uint32_t leaf,
> --
> 2.20.1.2.gb21ebb671

_______________________________________________
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®.