ia64/xen-unstable

changeset 655:3c7d3bff01da

bitkeeper revision 1.370 (3f1bf42fuDsd9ULrhDoxWR8V_vV2zQ)

time.c, hypervisor-if.h, domain.c:
Fixed more time code in Xen and Xenolinux. Reduced the chance of guest OS time going backwards. Better fixed-point arithmetic when calculating current system time.
author kaf24@scramble.cl.cam.ac.uk
date Mon Jul 21 14:09:51 2003 +0000 (2003-07-21)
parents 4d7f44227ecf
children fb6f05624b37
files xen/arch/i386/time.c xen/common/domain.c xen/include/hypervisor-ifs/hypervisor-if.h xenolinux-2.4.21-sparse/arch/xeno/kernel/time.c
line diff
     1.1 --- a/xen/arch/i386/time.c	Mon Jul 21 10:50:15 2003 +0000
     1.2 +++ b/xen/arch/i386/time.c	Mon Jul 21 14:09:51 2003 +0000
     1.3 @@ -20,19 +20,6 @@
     1.4   */
     1.5  
     1.6  /*
     1.7 - * Note from KAF: We should probably be more careful about overflow
     1.8 - * of our timestamp cycle counter value, as we only use 31 bits of
     1.9 - * precision. This will overflow on a 3GHz processor in less than a second,
    1.10 - * and the situation is only going to get worse. 
    1.11 - * 
    1.12 - * Probably we should use bits N-N+31 of the TSC rather than 0-31, and
    1.13 - * adjust scale_f and scale_i accordingly. If we're really smart we'd
    1.14 - * calculate N dynamically, according to the measured CPU speed!
    1.15 - * 
    1.16 - * I think the current code limps along okay for now though.
    1.17 - */
    1.18 -
    1.19 -/*
    1.20   *  linux/arch/i386/kernel/time.c
    1.21   *
    1.22   *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
    1.23 @@ -65,6 +52,9 @@
    1.24  unsigned long cpu_khz;  /* Detected as we calibrate the TSC */
    1.25  unsigned long ticks_per_usec; /* TSC ticks per microsecond. */
    1.26  
    1.27 +/* We use this to prevent overflow of 31-bit RDTSC "diffs". */
    1.28 +static unsigned int rdtsc_bitshift;
    1.29 +
    1.30  spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
    1.31  
    1.32  int timer_ack=0;
    1.33 @@ -288,26 +278,18 @@ s_time_t    stime_now;   /* time in ns a
    1.34  static inline s_time_t __get_s_time(void)
    1.35  {
    1.36      s32      delta_tsc;
    1.37 -    u32      low, pcc;
    1.38 -    u64      delta;
    1.39 -    s_time_t now;
    1.40 -
    1.41 -    pcc = stime_pcc;        
    1.42 -    now = stime_now;
    1.43 -
    1.44 -    /*
    1.45 -     * We only use the bottom 32 bits of the TSC. This should be sufficient,
    1.46 -     * although we take care that TSC on this CPU may be lagging the master TSC
    1.47 -     * slightly. In this case we clamp the TSC difference to a minimum of zero.
    1.48 -     */
    1.49 -    rdtscl(low);
    1.50 -    delta_tsc = low - pcc;
    1.51 +    u32      low;
    1.52 +    u64      delta, tsc;
    1.53 +    
    1.54 +    rdtscll(tsc);
    1.55 +    low = (u32)(tsc >> rdtsc_bitshift);
    1.56 +    delta_tsc = (s32)(low - stime_pcc);
    1.57      if ( unlikely(delta_tsc < 0) ) delta_tsc = 0;
    1.58      delta = ((u64)delta_tsc * st_scale_f);
    1.59      delta >>= 32;
    1.60      delta += ((u64)delta_tsc * st_scale_i);
    1.61  
    1.62 -    return now + delta;
    1.63 +    return stime_now + delta;
    1.64  }
    1.65  
    1.66  s_time_t get_s_time(void)
    1.67 @@ -359,11 +341,13 @@ void update_dom_time(shared_info_t *si)
    1.68      unsigned long flags;
    1.69  
    1.70      spin_lock_irqsave(&stime_lock, flags);
    1.71 -    si->system_time  = stime_now;
    1.72 -    si->st_timestamp = stime_pcc;
    1.73 -    si->tv_sec       = wall_clock_time.tv_sec;
    1.74 -    si->tv_usec      = wall_clock_time.tv_usec;
    1.75 -    si->wc_timestamp = wctime_st;
    1.76 +    si->cpu_freq       = cpu_freq;
    1.77 +    si->rdtsc_bitshift = rdtsc_bitshift;
    1.78 +    si->system_time    = stime_now;
    1.79 +    si->st_timestamp   = stime_pcc;
    1.80 +    si->tv_sec         = wall_clock_time.tv_sec;
    1.81 +    si->tv_usec        = wall_clock_time.tv_usec;
    1.82 +    si->wc_timestamp   = wctime_st;
    1.83      si->wc_version++;
    1.84      spin_unlock_irqrestore(&stime_lock, flags);
    1.85  
    1.86 @@ -420,7 +404,7 @@ static void update_scale(void)
    1.87      cpu_freq = cpu_freqs[freq_index];
    1.88  
    1.89      /* adjust scaling factor */
    1.90 -    scale = 1000000000LL << 32;
    1.91 +    scale = 1000000000LL << (32 + rdtsc_bitshift);
    1.92      scale /= cpu_freq;
    1.93      st_scale_f = scale & 0xffffffff;
    1.94      st_scale_i = scale >> 32;
    1.95 @@ -438,21 +422,15 @@ static void update_time(unsigned long fo
    1.96      unsigned long  flags;
    1.97      s_time_t       new_st;
    1.98      unsigned long  usec;
    1.99 -    static int calls_since_scale_update = 0;
   1.100 +    u64            full_pcc;
   1.101 +    static int     calls_since_scale_update = 0;
   1.102  
   1.103      spin_lock_irqsave(&stime_lock, flags);
   1.104  
   1.105      /* Update system time. */
   1.106      stime_now = new_st = __get_s_time();
   1.107 -    rdtscl(stime_pcc);
   1.108 -
   1.109 -    /* Maybe update our rate to be in sync with the RTC. */
   1.110 -    if ( ++calls_since_scale_update >= 
   1.111 -         (SCALE_UPDATE_PERIOD/TIME_UPDATE_PERIOD) )
   1.112 -    {
   1.113 -        update_scale();
   1.114 -        calls_since_scale_update = 0;
   1.115 -    }
   1.116 +    rdtscll(full_pcc);
   1.117 +    stime_pcc = (u32)(full_pcc >> rdtsc_bitshift);
   1.118  
   1.119      /* Update wall clock time. */
   1.120      usec = ((unsigned long)(new_st - wctime_st))/1000;
   1.121 @@ -464,6 +442,14 @@ static void update_time(unsigned long fo
   1.122      wall_clock_time.tv_usec = usec;
   1.123      wctime_st = new_st;
   1.124  
   1.125 +    /* Maybe update our rate to be in sync with the RTC. */
   1.126 +    if ( ++calls_since_scale_update >= 
   1.127 +         (SCALE_UPDATE_PERIOD/TIME_UPDATE_PERIOD) )
   1.128 +    {
   1.129 +        update_scale();
   1.130 +        calls_since_scale_update = 0;
   1.131 +    }
   1.132 +
   1.133      spin_unlock_irqrestore(&stime_lock, flags);
   1.134  
   1.135      TRC(printk("TIME[%02d] update time: stime_now=%lld now=%lld,wct=%ld:%ld\n",
   1.136 @@ -486,25 +472,31 @@ int __init init_xeno_time()
   1.137      u32      cpu_cycle;  /* time of one cpu cyle in pico-seconds */
   1.138      u64      scale;      /* scale factor */
   1.139      s64      freq_off;
   1.140 +    u64      full_pcc;
   1.141 +    unsigned int cpu_ghz;
   1.142  
   1.143      spin_lock_init(&stime_lock);
   1.144  
   1.145 -    printk("Init Time[%02d]:\n", cpu);
   1.146 +    cpu_ghz = (unsigned int)(cpu_freq / 1000000000ULL);
   1.147 +    for ( rdtsc_bitshift = 0; cpu_ghz != 0; rdtsc_bitshift++, cpu_ghz >>= 1 )
   1.148 +        continue;
   1.149 +
   1.150 +    printk("Init Time[%02d]: %u\n", cpu, rdtsc_bitshift);
   1.151  
   1.152      /* System Time */
   1.153      cpu_cycle   = (u32) (1000000000LL/cpu_khz); /* in pico seconds */
   1.154  
   1.155 -    scale = 1000000000LL << 32;
   1.156 -    scale /= cpu_freq;
   1.157 -    st_scale_f = scale & 0xffffffff;
   1.158 -    st_scale_i = scale >> 32;
   1.159 -
   1.160      /* calculate adjusted frequencies */
   1.161      freq_off  = cpu_freq/1000; /* .1%  */
   1.162      cpu_freqs[0] = cpu_freq + freq_off;
   1.163      cpu_freqs[1] = cpu_freq;
   1.164      cpu_freqs[2] = cpu_freq - freq_off;
   1.165  
   1.166 +    scale = 1000000000LL << (32 + rdtsc_bitshift);
   1.167 +    scale /= cpu_freq;
   1.168 +    st_scale_f = scale & 0xffffffff;
   1.169 +    st_scale_i = scale >> 32;
   1.170 +
   1.171      /* Wall Clock time */
   1.172      wall_clock_time.tv_sec  = get_cmos_time();
   1.173      wall_clock_time.tv_usec = 0;
   1.174 @@ -514,7 +506,8 @@ int __init init_xeno_time()
   1.175  
   1.176      /* set starting times */
   1.177      stime_now = (s_time_t)0;
   1.178 -    rdtscl(stime_pcc);
   1.179 +    rdtscll(full_pcc);
   1.180 +    stime_pcc = (u32)(full_pcc >> rdtsc_bitshift);
   1.181      wctime_st = NOW();
   1.182  
   1.183      /* start timer to update time periodically */
     2.1 --- a/xen/common/domain.c	Mon Jul 21 10:50:15 2003 +0000
     2.2 +++ b/xen/common/domain.c	Mon Jul 21 14:09:51 2003 +0000
     2.3 @@ -382,7 +382,6 @@ int final_setup_guestos(struct task_stru
     2.4  
     2.5      /* set up the shared info structure */
     2.6      update_dom_time(p->shared_info);
     2.7 -    p->shared_info->cpu_freq     = cpu_freq;
     2.8      p->shared_info->domain_time  = 0;
     2.9  
    2.10      /* we pass start info struct to guest os as function parameter on stack */
    2.11 @@ -635,7 +634,6 @@ int setup_guestos(struct task_struct *p,
    2.12  
    2.13      /* Set up shared info area. */
    2.14      update_dom_time(p->shared_info);
    2.15 -    p->shared_info->cpu_freq     = cpu_freq;
    2.16      p->shared_info->domain_time  = 0;
    2.17  
    2.18      virt_startinfo_address = (start_info_t *)
     3.1 --- a/xen/include/hypervisor-ifs/hypervisor-if.h	Mon Jul 21 10:50:15 2003 +0000
     3.2 +++ b/xen/include/hypervisor-ifs/hypervisor-if.h	Mon Jul 21 14:09:51 2003 +0000
     3.3 @@ -193,20 +193,21 @@ typedef struct shared_info_st {
     3.4      /*
     3.5       * Time: The following abstractions are exposed: System Time, Clock Time,
     3.6       * Domain Virtual Time. Domains can access Cycle counter time directly.
     3.7 -     * XXX RN: Need something to pass NTP scaling to GuestOS.
     3.8 +     * 
     3.9 +     * The following values are updated periodically (and atomically, from the
    3.10 +     * p.o.v. of the guest OS). Th eguest OS detects this because the wc_version
    3.11 +     * is incremented.
    3.12       */
    3.13 -
    3.14 -    u64		  cpu_freq;	    /* to calculate ticks -> real time */
    3.15 -
    3.16 +    u32		       wc_version;      /* a version number for info below */
    3.17 +    unsigned int       rdtsc_bitshift;  /* use bits N:N+31 of TSC          */
    3.18 +    u64		       cpu_freq;        /* to calculate ticks -> real time */
    3.19      /* System Time */
    3.20 -    long long	       system_time;	/* in ns */
    3.21 -    unsigned long      st_timestamp;	/* cyclecounter at last update */
    3.22 -
    3.23 +    long long	       system_time;     /* in ns */
    3.24 +    unsigned long      st_timestamp;    /* cyclecounter at last update */
    3.25      /* Wall Clock Time */
    3.26 -    u32		       wc_version;	/* a version number for info below */
    3.27 -    long	       tv_sec;		/* essentially a struct timeval */
    3.28 +    long	       tv_sec;          /* essentially a struct timeval */
    3.29      long	       tv_usec;
    3.30 -    long long	       wc_timestamp;	/* system time at last update */
    3.31 +    long long	       wc_timestamp;    /* system time at last update */
    3.32      
    3.33      /* Domain Virtual Time */
    3.34      unsigned long long domain_time;
     4.1 --- a/xenolinux-2.4.21-sparse/arch/xeno/kernel/time.c	Mon Jul 21 10:50:15 2003 +0000
     4.2 +++ b/xenolinux-2.4.21-sparse/arch/xeno/kernel/time.c	Mon Jul 21 14:09:51 2003 +0000
     4.3 @@ -76,9 +76,9 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED
     4.4  extern rwlock_t xtime_lock;
     4.5  
     4.6  unsigned long cpu_khz;	/* get this from Xen, used elsewhere */
     4.7 -static spinlock_t hyp_stime_lock = SPIN_LOCK_UNLOCKED;
     4.8 -static spinlock_t hyp_wctime_lock = SPIN_LOCK_UNLOCKED;
     4.9 +static spinlock_t hyp_time_lock = SPIN_LOCK_UNLOCKED;
    4.10  
    4.11 +static unsigned int rdtsc_bitshift;
    4.12  static u32 st_scale_f;
    4.13  static u32 st_scale_i;
    4.14  static u32 shadow_st_pcc;
    4.15 @@ -92,37 +92,22 @@ static s64 shadow_st;
    4.16   * and use the cycle counter value as the "version" number. Clashes
    4.17   * should be very rare.
    4.18   */
    4.19 -static inline long long get_s_time(void)
    4.20 +static inline s64 __get_s_time(void)
    4.21  {
    4.22 -	unsigned long flags;
    4.23 -    u32           delta_tsc, low, pcc;
    4.24 -	u64           delta;
    4.25 -	s64           now;
    4.26 -
    4.27 -	spin_lock_irqsave(&hyp_stime_lock, flags);
    4.28 +    s32 delta_tsc;
    4.29 +    u32 low;
    4.30 +	u64 delta, tsc;
    4.31  
    4.32 -	while ((pcc = HYPERVISOR_shared_info->st_timestamp) != shadow_st_pcc)
    4.33 -	{
    4.34 -		barrier();
    4.35 -		shadow_st_pcc = pcc;
    4.36 -		shadow_st     = HYPERVISOR_shared_info->system_time;
    4.37 -		barrier();
    4.38 -	}
    4.39 -
    4.40 -    now = shadow_st;
    4.41 -    /* only use bottom 32bits of TSC. This should be sufficient */
    4.42 -	rdtscl(low);
    4.43 -    delta_tsc = low - pcc;
    4.44 +    rdtscll(tsc);
    4.45 +    low = (u32)(tsc >> rdtsc_bitshift);
    4.46 +    delta_tsc = (s32)(low - shadow_st_pcc);
    4.47 +    if ( unlikely(delta_tsc < 0) ) delta_tsc = 0;
    4.48  	delta = ((u64)delta_tsc * st_scale_f);
    4.49  	delta >>= 32;
    4.50  	delta += ((u64)delta_tsc * st_scale_i);
    4.51  
    4.52 -	spin_unlock_irqrestore(&hyp_time_lock, flags);
    4.53 -
    4.54 -    return now + delta; 
    4.55 -
    4.56 +    return shadow_st + delta;
    4.57  }
    4.58 -#define NOW()				((long long)get_s_time())
    4.59  
    4.60  /*
    4.61   * Wallclock time.
    4.62 @@ -139,21 +124,35 @@ void do_gettimeofday(struct timeval *tv)
    4.63  	unsigned long flags;
    4.64      long          usec, sec;
    4.65  	u32	          version;
    4.66 -	u64           now;
    4.67 +	u64           now, cpu_freq, scale;
    4.68  
    4.69 -	spin_lock_irqsave(&hyp_wctime_lock, flags);
    4.70 +	spin_lock_irqsave(&hyp_time_lock, flags);
    4.71  
    4.72 -	while ((version = HYPERVISOR_shared_info->wc_version)!= shadow_wc_version)
    4.73 +	while ( (version = HYPERVISOR_shared_info->wc_version) != 
    4.74 +            shadow_wc_version )
    4.75  	{
    4.76  		barrier();
    4.77 +
    4.78  		shadow_wc_version   = version;
    4.79  		shadow_tv_sec       = HYPERVISOR_shared_info->tv_sec;
    4.80  		shadow_tv_usec      = HYPERVISOR_shared_info->tv_usec;
    4.81  		shadow_wc_timestamp = HYPERVISOR_shared_info->wc_timestamp;
    4.82 +		shadow_st_pcc       = HYPERVISOR_shared_info->st_timestamp;
    4.83 +		shadow_st           = HYPERVISOR_shared_info->system_time;
    4.84 +
    4.85 +        rdtsc_bitshift      = HYPERVISOR_shared_info->rdtsc_bitshift;
    4.86 +        cpu_freq            = HYPERVISOR_shared_info->cpu_freq;
    4.87 +
    4.88 +        /* XXX cpu_freq as u32 limits it to 4.29 GHz. Get a better do_div! */
    4.89 +        scale = 1000000000LL << (32 + rdtsc_bitshift);
    4.90 +        do_div(scale,(u32)cpu_freq);
    4.91 +        st_scale_f = scale & 0xffffffff;
    4.92 +        st_scale_i = scale >> 32;
    4.93 +
    4.94  		barrier();
    4.95  	}
    4.96  
    4.97 -	now   = NOW();
    4.98 +	now   = __get_s_time();
    4.99  	usec  = ((unsigned long)(now-shadow_wc_timestamp))/1000;
   4.100  	sec   = shadow_tv_sec;
   4.101  	usec += shadow_tv_usec;
   4.102 @@ -242,18 +241,6 @@ static inline void do_timer_interrupt(in
   4.103  	struct timeval tv;
   4.104  	long long time, delta;
   4.105  	
   4.106 -#ifdef XENO_TIME_DEBUG
   4.107 -	static u32 foo_count = 0;
   4.108 -	foo_count++;		
   4.109 -	if (foo_count>= 1000) {
   4.110 -		s64 n = NOW();
   4.111 -		struct timeval tv;
   4.112 -		do_gettimeofday(&tv);
   4.113 -		printk("0x%08X%08X %ld:%ld\n",
   4.114 -			   (u32)(n>>32), (u32)n, tv.tv_sec, tv.tv_usec);
   4.115 -		foo_count = 0;
   4.116 -	}
   4.117 -#endif
   4.118      /*
   4.119       * The next bit really sucks:
   4.120       * Linux not only uses do_gettimeofday() to keep a notion of
   4.121 @@ -268,7 +255,7 @@ static inline void do_timer_interrupt(in
   4.122       * updates xtime accordingly. Yuck!
   4.123       */
   4.124  
   4.125 -	/* work out the number of jiffies past and update them */
   4.126 +	/* Work out the number of jiffy intervals passed and update them. */
   4.127  	do_gettimeofday(&tv);
   4.128  	time = (((long long)tv.tv_sec) * 1000000) + tv.tv_usec;
   4.129  	delta = time - last_irq;
   4.130 @@ -307,24 +294,14 @@ static struct irqaction irq_timer = {
   4.131  void __init time_init(void)
   4.132  {
   4.133      unsigned long long alarm;
   4.134 -	u64	cpu_freq = HYPERVISOR_shared_info->cpu_freq;
   4.135 -	u64 scale;
   4.136 +    u64 __cpu_khz;
   4.137  
   4.138 -	cpu_khz = (u32)cpu_freq/1000;
   4.139 +    __cpu_khz = HYPERVISOR_shared_info->cpu_freq;
   4.140 +    do_div(__cpu_khz, 1000);
   4.141 +    cpu_khz = (u32)__cpu_khz;
   4.142  	printk("Xen reported: %lu.%03lu MHz processor.\n", 
   4.143  		   cpu_khz / 1000, cpu_khz % 1000);
   4.144  
   4.145 -	/*
   4.146 -     * calculate systemtime scaling factor
   4.147 -	 * XXX RN: have to cast cpu_freq to u32 limits it to 4.29 GHz. 
   4.148 -	 *     Get a better do_div!
   4.149 -	 */
   4.150 -	scale = 1000000000LL << 32;
   4.151 -	do_div(scale,(u32)cpu_freq);
   4.152 -	st_scale_f = scale & 0xffffffff;
   4.153 -	st_scale_i = scale >> 32;
   4.154 -	printk("System Time scale: %X %X\n",st_scale_i, st_scale_f);
   4.155 -
   4.156  	do_gettimeofday(&xtime);
   4.157  	last_irq = (((long long)xtime.tv_sec) * 1000000) + xtime.tv_usec;
   4.158