ia64/xen-unstable

changeset 6306:0cf2430f520f

Mini-os updated to use the new time interface.
Signed-off-by: Grzegorz Milos <gm281@cam.ac.uk>
author kaf24@firebug.cl.cam.ac.uk
date Sat Aug 20 09:35:38 2005 +0000 (2005-08-20)
parents 46e43646cd16
children 68e13a9a9b1c
files extras/mini-os/include/time.h extras/mini-os/kernel.c extras/mini-os/time.c
line diff
     1.1 --- a/extras/mini-os/include/time.h	Fri Aug 19 20:02:01 2005 +0000
     1.2 +++ b/extras/mini-os/include/time.h	Sat Aug 20 09:35:38 2005 +0000
     1.3 @@ -28,7 +28,7 @@
     1.4   * of real time into system time 
     1.5   */
     1.6  typedef s64 s_time_t;
     1.7 -#define NOW()                   ((s_time_t)get_s_time())
     1.8 +#define NOW()                   ((s_time_t)monotonic_clock())
     1.9  #define SECONDS(_s)             (((s_time_t)(_s))  * 1000000000UL )
    1.10  #define TENTHS(_ts)             (((s_time_t)(_ts)) * 100000000UL )
    1.11  #define HUNDREDTHS(_hs)         (((s_time_t)(_hs)) * 10000000UL )
    1.12 @@ -36,7 +36,8 @@ typedef s64 s_time_t;
    1.13  #define MICROSECS(_us)          (((s_time_t)(_us)) * 1000UL )
    1.14  #define Time_Max                ((s_time_t) 0x7fffffffffffffffLL)
    1.15  #define FOREVER                 Time_Max
    1.16 -
    1.17 +#define NSEC_TO_USEC(_nsec)     (_nsec / 1000UL)
    1.18 +#define NSEC_TO_SEC(_nsec)      (_nsec / 1000000000ULL)
    1.19  
    1.20  /* wall clock time  */
    1.21  typedef long time_t;
    1.22 @@ -46,6 +47,11 @@ struct timeval {
    1.23  	suseconds_t	tv_usec;	/* microseconds */
    1.24  };
    1.25  
    1.26 +struct timespec {
    1.27 +    time_t      ts_sec;
    1.28 +    long        ts_nsec;
    1.29 +};
    1.30 +
    1.31  
    1.32  /* prototypes */
    1.33  void     init_time(void);
     2.1 --- a/extras/mini-os/kernel.c	Fri Aug 19 20:02:01 2005 +0000
     2.2 +++ b/extras/mini-os/kernel.c	Sat Aug 20 09:35:38 2005 +0000
     2.3 @@ -132,20 +132,6 @@ void start_kernel(start_info_t *si)
     2.4      i = 0;
     2.5      for ( ; ; ) 
     2.6      {      
     2.7 -        if(i >= 1000)         
     2.8 -        {
     2.9 -            {
    2.10 -                unsigned long saved;
    2.11 -                __asm__ ("movl %%esp, %0"
    2.12 -                         :"=r"(saved)  /* y is output operand */
    2.13 -                            /* x is input operand */);
    2.14 -//                        :"a"); /* %eax is clobbered register */
    2.15 -                printk("ESP=0x%lx\n", saved);
    2.16 -            }
    2.17 -            
    2.18 -            printk("1000 bloks\n");
    2.19 -            i=0;            
    2.20 -        }
    2.21  //        HYPERVISOR_yield();
    2.22          block(1);
    2.23          i++;
     3.1 --- a/extras/mini-os/time.c	Fri Aug 19 20:02:01 2005 +0000
     3.2 +++ b/extras/mini-os/time.c	Sat Aug 20 09:35:38 2005 +0000
     3.3 @@ -43,19 +43,20 @@
     3.4   * Time functions
     3.5   *************************************************************************/
     3.6  
     3.7 -/* Cached *multiplier* to convert TSC counts to microseconds.
     3.8 - * (see the equation below).
     3.9 - * Equal to 2^32 * (1 / (clocks per usec) ).
    3.10 - * Initialized in time_init.
    3.11 - */
    3.12 -static unsigned long fast_gettimeoffset_quotient;
    3.13 +/* These are peridically updated in shared_info, and then copied here. */
    3.14 +struct shadow_time_info {
    3.15 +	u64 tsc_timestamp;     /* TSC at last update of time vals.  */
    3.16 +	u64 system_timestamp;  /* Time, in nanosecs, since boot.    */
    3.17 +	u32 tsc_to_nsec_mul;
    3.18 +	u32 tsc_to_usec_mul;
    3.19 +	int tsc_shift;
    3.20 +	u32 version;
    3.21 +};
    3.22 +static struct timespec shadow_ts;
    3.23 +static u32 shadow_ts_version;
    3.24  
    3.25 +static struct shadow_time_info shadow;
    3.26  
    3.27 -/* These are peridically updated in shared_info, and then copied here. */
    3.28 -static u32 shadow_tsc_stamp;
    3.29 -static s64 shadow_system_time;
    3.30 -static u32 shadow_time_version;
    3.31 -static struct timeval shadow_tv;
    3.32  
    3.33  #ifndef rmb
    3.34  #define rmb()  __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
    3.35 @@ -63,116 +64,150 @@ static struct timeval shadow_tv;
    3.36  
    3.37  #define HANDLE_USEC_OVERFLOW(_tv)          \
    3.38      do {                                   \
    3.39 -        while ( (_tv).tv_usec >= 1000000 ) \
    3.40 +        while ( (_tv)->tv_usec >= 1000000 ) \
    3.41          {                                  \
    3.42 -            (_tv).tv_usec -= 1000000;      \
    3.43 -            (_tv).tv_sec++;                \
    3.44 +            (_tv)->tv_usec -= 1000000;      \
    3.45 +            (_tv)->tv_sec++;                \
    3.46          }                                  \
    3.47      } while ( 0 )
    3.48  
    3.49 -static void get_time_values_from_xen(void)
    3.50 +static inline int time_values_up_to_date(void)
    3.51 +{
    3.52 +	struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_time[0]; 
    3.53 +
    3.54 +	return (shadow.version == src->version);
    3.55 +}
    3.56 +
    3.57 +
    3.58 +/*
    3.59 + * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
    3.60 + * yielding a 64-bit result.
    3.61 + */
    3.62 +static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
    3.63  {
    3.64 -    do {
    3.65 -        shadow_time_version = HYPERVISOR_shared_info->time_version2;
    3.66 -        rmb();
    3.67 -        shadow_tv.tv_sec    = HYPERVISOR_shared_info->wc_sec;
    3.68 -        shadow_tv.tv_usec   = HYPERVISOR_shared_info->wc_usec;
    3.69 -        shadow_tsc_stamp    = (u32)HYPERVISOR_shared_info->tsc_timestamp;
    3.70 -        shadow_system_time  = HYPERVISOR_shared_info->system_time;
    3.71 -        rmb();
    3.72 -    }
    3.73 -    while ( shadow_time_version != HYPERVISOR_shared_info->time_version1 );
    3.74 +	u64 product;
    3.75 +#ifdef __i386__
    3.76 +	u32 tmp1, tmp2;
    3.77 +#endif
    3.78 +
    3.79 +	if ( shift < 0 )
    3.80 +		delta >>= -shift;
    3.81 +	else
    3.82 +		delta <<= shift;
    3.83 +
    3.84 +#ifdef __i386__
    3.85 +	__asm__ (
    3.86 +		"mul  %5       ; "
    3.87 +		"mov  %4,%%eax ; "
    3.88 +		"mov  %%edx,%4 ; "
    3.89 +		"mul  %5       ; "
    3.90 +		"add  %4,%%eax ; "
    3.91 +		"xor  %5,%5    ; "
    3.92 +		"adc  %5,%%edx ; "
    3.93 +		: "=A" (product), "=r" (tmp1), "=r" (tmp2)
    3.94 +		: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
    3.95 +#else
    3.96 +	__asm__ (
    3.97 +		"mul %%rdx ; shrd $32,%%rdx,%%rax"
    3.98 +		: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
    3.99 +#endif
   3.100 +
   3.101 +	return product;
   3.102 +}
   3.103 +
   3.104 +
   3.105 +static unsigned long get_nsec_offset(void)
   3.106 +{
   3.107 +	u64 now, delta;
   3.108 +	rdtscll(now);
   3.109 +	delta = now - shadow.tsc_timestamp;
   3.110 +	return scale_delta(delta, shadow.tsc_to_nsec_mul, shadow.tsc_shift);
   3.111  }
   3.112  
   3.113  
   3.114 -#define TIME_VALUES_UP_TO_DATE \
   3.115 -    (shadow_time_version == HYPERVISOR_shared_info->time_version2)
   3.116 -
   3.117 -static u32  get_time_delta_usecs(void)
   3.118 +static void get_time_values_from_xen(void)
   3.119  {
   3.120 -	register unsigned long eax, edx;
   3.121 -
   3.122 -	/* Read the Time Stamp Counter */
   3.123 -
   3.124 -	rdtsc(eax,edx);
   3.125 -
   3.126 -	/* .. relative to previous jiffy (32 bits is enough) */
   3.127 -	eax -= shadow_tsc_stamp;
   3.128 +	struct vcpu_time_info    *src = &HYPERVISOR_shared_info->vcpu_time[0];
   3.129  
   3.130 -	/*
   3.131 -	 * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
   3.132 -	 *             = (tsc_low delta) * (usecs_per_clock)
   3.133 -	 *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
   3.134 -	 *
   3.135 -	 * Using a mull instead of a divl saves up to 31 clock cycles
   3.136 -	 * in the critical path.
   3.137 -	 */
   3.138 + 	do {
   3.139 +		shadow.version = src->version;
   3.140 +		rmb();
   3.141 +		shadow.tsc_timestamp     = src->tsc_timestamp;
   3.142 +		shadow.system_timestamp  = src->system_time;
   3.143 +		shadow.tsc_to_nsec_mul   = src->tsc_to_system_mul;
   3.144 +		shadow.tsc_shift         = src->tsc_shift;
   3.145 +		rmb();
   3.146 +	}
   3.147 +	while ((src->version & 1) | (shadow.version ^ src->version));
   3.148  
   3.149 -	__asm__("mull %2"
   3.150 -		:"=a" (eax), "=d" (edx)
   3.151 -		:"rm" (fast_gettimeoffset_quotient),
   3.152 -		 "0" (eax));
   3.153 -
   3.154 -	/* our adjusted time offset in microseconds */
   3.155 -	return edx;
   3.156 +	shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
   3.157  }
   3.158  
   3.159 -s64 get_s_time (void)
   3.160 -{
   3.161 -    u64 u_delta;
   3.162 -    s64 ret;
   3.163 +
   3.164 +
   3.165  
   3.166 - again:
   3.167 -
   3.168 -    u_delta = get_time_delta_usecs();
   3.169 -    ret = shadow_system_time + (1000 * u_delta);
   3.170 +/* monotonic_clock(): returns # of nanoseconds passed since time_init()
   3.171 + *		Note: This function is required to return accurate
   3.172 + *		time even in the absence of multiple timer ticks.
   3.173 + */
   3.174 +u64 monotonic_clock(void)
   3.175 +{
   3.176 +	u64 time;
   3.177 +	u32 local_time_version;
   3.178  
   3.179 -    if ( unlikely(!TIME_VALUES_UP_TO_DATE) )
   3.180 -    {
   3.181 -        /*
   3.182 -         * We may have blocked for a long time, rendering our calculations
   3.183 -         * invalid (e.g. the time delta may have overflowed). Detect that
   3.184 -         * and recalculate with fresh values.
   3.185 -         */
   3.186 -        get_time_values_from_xen();
   3.187 -        goto again;
   3.188 -    }
   3.189 +	do {
   3.190 +		local_time_version = shadow.version;
   3.191 +		rmb();
   3.192 +		time = shadow.system_timestamp + get_nsec_offset();
   3.193 +        if (!time_values_up_to_date())
   3.194 +			get_time_values_from_xen();
   3.195 +		rmb();
   3.196 +	} while (local_time_version != shadow.version);
   3.197 +
   3.198 +	return time;
   3.199 +}
   3.200  
   3.201 -    return ret;
   3.202 +static void update_wallclock(void)
   3.203 +{
   3.204 +	shared_info_t *s = HYPERVISOR_shared_info;
   3.205 +
   3.206 +	do {
   3.207 +		shadow_ts_version = s->wc_version;
   3.208 +		rmb();
   3.209 +		shadow_ts.ts_sec  = s->wc_sec;
   3.210 +		shadow_ts.ts_nsec = s->wc_nsec;
   3.211 +		rmb();
   3.212 +	}
   3.213 +	while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
   3.214  }
   3.215  
   3.216 +
   3.217  void gettimeofday(struct timeval *tv)
   3.218  {
   3.219 -    struct timeval _tv;
   3.220 +    u64 nsec = monotonic_clock();
   3.221 +    nsec += shadow_ts.ts_nsec;
   3.222 +    
   3.223 +    
   3.224 +    tv->tv_sec = shadow_ts.ts_sec;
   3.225 +    tv->tv_sec += NSEC_TO_SEC(nsec);
   3.226 +    tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
   3.227 +}
   3.228  
   3.229 -    do {
   3.230 -        get_time_values_from_xen();
   3.231 -        _tv.tv_usec = get_time_delta_usecs();
   3.232 -        _tv.tv_sec   = shadow_tv.tv_sec;
   3.233 -        _tv.tv_usec += shadow_tv.tv_usec;
   3.234 -    }
   3.235 -    while ( unlikely(!TIME_VALUES_UP_TO_DATE) );
   3.236 -
   3.237 -    HANDLE_USEC_OVERFLOW(_tv);
   3.238 -    *tv = _tv;
   3.239 -}
   3.240  
   3.241  static void print_current_time(void)
   3.242  {
   3.243 -    struct timeval tv;
   3.244 -
   3.245 -    get_time_values_from_xen();
   3.246 +    struct timeval tv;    
   3.247  
   3.248      gettimeofday(&tv);
   3.249      printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
   3.250  }
   3.251  
   3.252 +
   3.253  void block(u32 millisecs)
   3.254  {
   3.255      struct timeval tv;
   3.256      gettimeofday(&tv);
   3.257 -    //printk("tv.tv_sec=%ld, tv.tv_usec=%ld, shadow_system_time=%lld\n", tv.tv_sec, tv.tv_usec, shadow_system_time );
   3.258 -    HYPERVISOR_set_timer_op(get_s_time() + 1000000LL * (s64) millisecs);
   3.259 +    HYPERVISOR_set_timer_op(monotonic_clock() + 1000000LL * (s64) millisecs);
   3.260      HYPERVISOR_block();
   3.261  }
   3.262  
   3.263 @@ -185,7 +220,7 @@ static void timer_handler(int ev, struct
   3.264      static int i;
   3.265  
   3.266      get_time_values_from_xen();
   3.267 -
   3.268 +    update_wallclock();
   3.269      i++;
   3.270      if (i >= 1000) {
   3.271          print_current_time();
   3.272 @@ -197,24 +232,5 @@ static void timer_handler(int ev, struct
   3.273  
   3.274  void init_time(void)
   3.275  {
   3.276 -    u64         __cpu_khz;
   3.277 -    unsigned long cpu_khz;
   3.278 -
   3.279 -    __cpu_khz = HYPERVISOR_shared_info->cpu_freq;
   3.280 -
   3.281 -    cpu_khz = (u32) (__cpu_khz/1000);
   3.282 -
   3.283 -    printk("Xen reported: %lu.%03lu MHz processor.\n", 
   3.284 -           cpu_khz / 1000, cpu_khz % 1000);
   3.285 -	/* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
   3.286 -	   (2^32 * 1 / (clocks/us)) */
   3.287 -	{	
   3.288 -		unsigned long eax=0, edx=1000;
   3.289 -		__asm__("divl %2"
   3.290 -		    :"=a" (fast_gettimeoffset_quotient), "=d" (edx)
   3.291 -		    :"r" (cpu_khz),
   3.292 -		    "0" (eax), "1" (edx));
   3.293 -	}
   3.294 -
   3.295      bind_virq(VIRQ_TIMER, &timer_handler);
   3.296  }