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

Re: [Xen-devel] [PATCH] Add a timer mode that disables pending missed ticks



I'm going to apply Haitao's no_missed_ticks_fix.patch. If you think fixes
are needed apart from that, please provide a unified diff.

 -- Keir

On 30/10/07 21:16, "Dave Winchell" <dwinchell@xxxxxxxxxxxxxxx> wrote:

> Keir,
> 
> Here are my comments on your change.
> I've attached an updated vpt.c with the changes.
> 
> 1. For the no_missed_tick_accounting method, we still need the update
>     to pt->scheduled taking into account the time that has elapsed when
>     missed ticks are calculated. missed_ticks (pt_process_missed_ticks)
>     is called from pt_restore_timer() and pt_timer_fn() and, thus, its
>     easiest to put the check for no_missed_tick_accounting method in
>     missed_ticks() itself.
> 
> 2. In pt_timer_fn you don't want to increment pending_intr_nr beyond 1
>     for no_missed_tick_accounting option.
> 
> thanks,
> Dave
> 
> 
> Keir Fraser wrote:
> 
>> 
>> Applied as c/s 16274. Please take a look and make sure the mode works
>> as you expect.
>> 
>>  -- Keir
>> 
>> On 30/10/07 14:28, "Shan, Haitao" <haitao.shan@xxxxxxxxx> wrote:
>> 
>>     Hi, Keir,
>> 
>>     This patch adds a new timer mode, in which no missed ticks is
>>     calculated. This can be used with latest x86_64 linux guest, since
>>     it can pick up missed ticks themselves.
>> 
>>      <<no_missed_ticks.patch>>
>> 
>>     Best Regards
>>     Haitao Shan
>> 
>>     ------------------------------------------------------------------------
>>     _______________________________________________
>>     Xen-devel mailing list
>>     Xen-devel@xxxxxxxxxxxxxxxxxxx
>>     http://lists.xensource.com/xen-devel
>> 
>> 
> 
> *** vpt.c.new.c 2007-10-30 16:45:26.000000000 -0400
> --- vpt.c 2007-10-30 15:30:57.000000000 -0400
> ***************
> *** 57,73 ****
>           return;
>   
>       missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
> ! 
> !     if( !mode_is(pt->vcpu->domain, no_missed_tick_accounting) ) {
> !  if ( missed_ticks > 1000 )
> !      {
> !   /* TODO: Adjust guest time together */
> !   pt->pending_intr_nr++;
> !      }
> !  else
> !      {
> !   pt->pending_intr_nr += missed_ticks;
> !      }
>       }
>   
>       pt->scheduled += missed_ticks * pt->period;
> --- 57,70 ----
>           return;
>   
>       missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
> !     if ( missed_ticks > 1000 )
> !     {
> !         /* TODO: Adjust guest time together */
> !         pt->pending_intr_nr++;
> !     }
> !     else
> !     {
> !         pt->pending_intr_nr += missed_ticks;
>       }
>   
>       pt->scheduled += missed_ticks * pt->period;
> ***************
> *** 120,126 ****
>   
>       list_for_each_entry ( pt, head, list )
>       {
> !  pt_process_missed_ticks(pt);
>           set_timer(&pt->timer, pt->scheduled);
>       }
>   
> --- 117,124 ----
>   
>       list_for_each_entry ( pt, head, list )
>       {
> !         if ( !mode_is(v->domain, no_missed_tick_accounting) )
> !             pt_process_missed_ticks(pt);
>           set_timer(&pt->timer, pt->scheduled);
>       }
>   
> ***************
> *** 135,151 ****
>   
>       pt_lock(pt);
>   
> !     if (mode_is(pt->vcpu->domain, no_missed_tick_accounting)) {
> !  if(!pt->pending_intr_nr)
> !      pt->pending_intr_nr++;
> !     }
> !     else
> !  pt->pending_intr_nr++;
>   
>       if ( !pt->one_shot )
>       {
>           pt->scheduled += pt->period;
> !  pt_process_missed_ticks(pt);
>           set_timer(&pt->timer, pt->scheduled);
>       }
>   
> --- 133,152 ----
>   
>       pt_lock(pt);
>   
> !     pt->pending_intr_nr++;
>   
>       if ( !pt->one_shot )
>       {
>           pt->scheduled += pt->period;
> !         if ( !mode_is(pt->vcpu->domain, no_missed_tick_accounting) )
> !         {
> !             pt_process_missed_ticks(pt);
> !         }
> !         else if ( (NOW() - pt->scheduled) >= 0 )
> !         {
> !             pt->pending_intr_nr++;
> !             pt->scheduled = NOW() + pt->period;
> !         }
>           set_timer(&pt->timer, pt->scheduled);
>       }
>   
> /*
>  * vpt.c: Virtual Platform Timer
>  *
>  * Copyright (c) 2006, Xiaowei Yang, Intel Corporation.
>  *
>  * This program is free software; you can redistribute it and/or modify it
>  * under the terms and conditions of the GNU General Public License,
>  * version 2, as published by the Free Software Foundation.
>  *
>  * This program is distributed in the hope it will be useful, but WITHOUT
>  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>  * more details.
>  *
>  * You should have received a copy of the GNU General Public License along
> with
>  * this program; if not, write to the Free Software Foundation, Inc., 59
> Temple
>  * Place - Suite 330, Boston, MA 02111-1307 USA.
>  *
>  */
> 
> #include <xen/time.h>
> #include <asm/hvm/support.h>
> #include <asm/hvm/vpt.h>
> #include <asm/event.h>
> 
> #define mode_is(d, name) \
>     ((d)->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] == HVMPTM_##name)
> 
> static void pt_lock(struct periodic_time *pt)
> {
>     struct vcpu *v;
> 
>     for ( ; ; )
>     {
>         v = pt->vcpu;
>         spin_lock(&v->arch.hvm_vcpu.tm_lock);
>         if ( likely(pt->vcpu == v) )
>             break;
>         spin_unlock(&v->arch.hvm_vcpu.tm_lock);
>     }
> }
> 
> static void pt_unlock(struct periodic_time *pt)
> {
>     spin_unlock(&pt->vcpu->arch.hvm_vcpu.tm_lock);
> }
> 
> static void pt_process_missed_ticks(struct periodic_time *pt)
> {
>     s_time_t missed_ticks;
> 
>     if ( pt->one_shot )
>         return;
> 
>     missed_ticks = NOW() - pt->scheduled;
>     if ( missed_ticks <= 0 )
>         return;
> 
>     missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
> 
>     if( !mode_is(pt->vcpu->domain, no_missed_tick_accounting) ) {
> if ( missed_ticks > 1000 )
>    {
> /* TODO: Adjust guest time together */
> pt->pending_intr_nr++;
>    }
> else
>    {
> pt->pending_intr_nr += missed_ticks;
>    }
>     }
> 
>     pt->scheduled += missed_ticks * pt->period;
> }
> 
> static void pt_freeze_time(struct vcpu *v)
> {
>     if ( !mode_is(v->domain, delay_for_missed_ticks) )
>         return;
> 
>     v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
> }
> 
> static void pt_thaw_time(struct vcpu *v)
> {
>     if ( !mode_is(v->domain, delay_for_missed_ticks) )
>         return;
> 
>     if ( v->arch.hvm_vcpu.guest_time == 0 )
>         return;
> 
>     hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
>     v->arch.hvm_vcpu.guest_time = 0;
> }
> 
> void pt_save_timer(struct vcpu *v)
> {
>     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
>     struct periodic_time *pt;
> 
>     if ( test_bit(_VPF_blocked, &v->pause_flags) )
>         return;
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     list_for_each_entry ( pt, head, list )
>         stop_timer(&pt->timer);
> 
>     pt_freeze_time(v);
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> }
> 
> void pt_restore_timer(struct vcpu *v)
> {
>     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
>     struct periodic_time *pt;
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     list_for_each_entry ( pt, head, list )
>     {
> pt_process_missed_ticks(pt);
>         set_timer(&pt->timer, pt->scheduled);
>     }
> 
>     pt_thaw_time(v);
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> }
> 
> static void pt_timer_fn(void *data)
> {
>     struct periodic_time *pt = data;
> 
>     pt_lock(pt);
> 
>     if (mode_is(pt->vcpu->domain, no_missed_tick_accounting)) {
> if(!pt->pending_intr_nr)
>    pt->pending_intr_nr++;
>     }
>     else
> pt->pending_intr_nr++;
> 
>     if ( !pt->one_shot )
>     {
>         pt->scheduled += pt->period;
> pt_process_missed_ticks(pt);
>         set_timer(&pt->timer, pt->scheduled);
>     }
> 
>     vcpu_kick(pt->vcpu);
> 
>     pt_unlock(pt);
> }
> 
> void pt_update_irq(struct vcpu *v)
> {
>     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
>     struct periodic_time *pt;
>     uint64_t max_lag = -1ULL;
>     int irq = -1;
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     list_for_each_entry ( pt, head, list )
>     {
>         if ( !is_isa_irq_masked(v, pt->irq) && pt->pending_intr_nr &&
>              ((pt->last_plt_gtime + pt->period_cycles) < max_lag) )
>         {
>             max_lag = pt->last_plt_gtime + pt->period_cycles;
>             irq = pt->irq;
>         }
>     }
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> 
>     if ( is_lvtt(v, irq) )
>     {
>         vlapic_set_irq(vcpu_vlapic(v), irq, 0);
>     }
>     else if ( irq >= 0 )
>     {
>         hvm_isa_irq_deassert(v->domain, irq);
>         hvm_isa_irq_assert(v->domain, irq);
>     }
> }
> 
> static struct periodic_time *is_pt_irq(
>     struct vcpu *v, struct hvm_intack intack)
> {
>     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
>     struct periodic_time *pt;
>     struct RTCState *rtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
>     int vector;
> 
>     list_for_each_entry ( pt, head, list )
>     {
>         if ( !pt->pending_intr_nr )
>             continue;
> 
>         if ( is_lvtt(v, pt->irq) )
>         {
>             if ( pt->irq != intack.vector )
>                 continue;
>             return pt;
>         }
> 
>         vector = get_isa_irq_vector(v, pt->irq, intack.source);
> 
>         /* RTC irq need special care */
>         if ( (intack.vector != vector) ||
>              ((pt->irq == 8) && !is_rtc_periodic_irq(rtc)) )
>             continue;
> 
>         return pt;
>     }
> 
>     return NULL;
> }
> 
> void pt_intr_post(struct vcpu *v, struct hvm_intack intack)
> {
>     struct periodic_time *pt;
>     time_cb *cb;
>     void *cb_priv;
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     pt = is_pt_irq(v, intack);
>     if ( pt == NULL )
>     {
>         spin_unlock(&v->arch.hvm_vcpu.tm_lock);
>         return;
>     }
> 
>     if ( pt->one_shot )
>     {
>         pt->enabled = 0;
>         list_del(&pt->list);
>     }
>     else
>     {
>         pt->pending_intr_nr--;
>         if ( mode_is(v->domain, no_missed_tick_accounting) )
>             pt->last_plt_gtime = hvm_get_guest_time(v);
>         else
>             pt->last_plt_gtime += pt->period_cycles;
>     }
> 
>     if ( mode_is(v->domain, delay_for_missed_ticks) &&
>          (hvm_get_guest_time(v) < pt->last_plt_gtime) )
>         hvm_set_guest_time(v, pt->last_plt_gtime);
> 
>     cb = pt->cb;
>     cb_priv = pt->priv;
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> 
>     if ( cb != NULL )
>         cb(v, cb_priv);
> }
> 
> void pt_reset(struct vcpu *v)
> {
>     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
>     struct periodic_time *pt;
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     list_for_each_entry ( pt, head, list )
>     {
>         pt->pending_intr_nr = 0;
>         pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
>         pt->scheduled = NOW() + pt->period;
>         set_timer(&pt->timer, pt->scheduled);
>     }
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> }
> 
> void pt_migrate(struct vcpu *v)
> {
>     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
>     struct periodic_time *pt;
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     list_for_each_entry ( pt, head, list )
>         migrate_timer(&pt->timer, v->processor);
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> }
> 
> void create_periodic_time(
>     struct vcpu *v, struct periodic_time *pt, uint64_t period,
>     uint8_t irq, char one_shot, time_cb *cb, void *data)
> {
>     destroy_periodic_time(pt);
> 
>     spin_lock(&v->arch.hvm_vcpu.tm_lock);
> 
>     pt->enabled = 1;
>     pt->pending_intr_nr = 0;
> 
>     /* Periodic timer must be at least 0.9ms. */
>     if ( (period < 900000) && !one_shot )
>     {
>         gdprintk(XENLOG_WARNING,
>                  "HVM_PlatformTime: program too small period %"PRIu64"\n",
>                  period);
>         period = 900000;
>     }
> 
>     pt->period = period;
>     pt->vcpu = v;
>     pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
>     pt->irq = irq;
>     pt->period_cycles = (u64)period * cpu_khz / 1000000L;
>     pt->one_shot = one_shot;
>     pt->scheduled = NOW() + period;
>     /*
>      * Offset LAPIC ticks from other timer ticks. Otherwise guests which use
>      * LAPIC ticks for process accounting can see long sequences of process
>      * ticks incorrectly accounted to interrupt processing.
>      */
>     if ( is_lvtt(v, irq) )
>         pt->scheduled += period >> 1;
>     pt->cb = cb;
>     pt->priv = data;
> 
>     list_add(&pt->list, &v->arch.hvm_vcpu.tm_list);
> 
>     init_timer(&pt->timer, pt_timer_fn, pt, v->processor);
>     set_timer(&pt->timer, pt->scheduled);
> 
>     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
> }
> 
> void destroy_periodic_time(struct periodic_time *pt)
> {
>     if ( !pt->enabled )
>         return;
> 
>     pt_lock(pt);
>     pt->enabled = 0;
>     list_del(&pt->list);
>     pt_unlock(pt);
> 
>     /*
>      * pt_timer_fn() can run until this kill_timer() returns. We must do this
>      * outside pt_lock() otherwise we can deadlock with pt_timer_fn().
>      */
>     kill_timer(&pt->timer);
> }



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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