ia64/xen-unstable

changeset 14301:9ea0c5f469c8

[IA64] PV steal time accounting

Signed-off-by: Atsushi SAKAI <sakaia@jp.fujitsu.com>
author awilliam@xenbuild2.aw
date Mon Mar 12 09:39:59 2007 -0600 (2007-03-12)
parents 800f7904d6a4
children d1853a39e063
files linux-2.6-xen-sparse/arch/ia64/kernel/time.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/time.c	Mon Mar 12 08:43:56 2007 -0600
     1.2 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/time.c	Mon Mar 12 09:39:59 2007 -0600
     1.3 @@ -29,6 +29,13 @@
     1.4  #include <asm/sections.h>
     1.5  #include <asm/system.h>
     1.6  
     1.7 +#ifdef CONFIG_XEN
     1.8 +#include <linux/kernel_stat.h>
     1.9 +#include <linux/posix-timers.h>
    1.10 +#include <xen/interface/vcpu.h>
    1.11 +#include <asm/percpu.h>
    1.12 +#endif
    1.13 +
    1.14  extern unsigned long wall_jiffies;
    1.15  
    1.16  volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
    1.17 @@ -40,16 +47,109 @@ EXPORT_SYMBOL(last_cli_ip);
    1.18  
    1.19  #endif
    1.20  
    1.21 +#ifdef CONFIG_XEN
    1.22 +DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
    1.23 +DEFINE_PER_CPU(unsigned long, processed_stolen_time);
    1.24 +DEFINE_PER_CPU(unsigned long, processed_blocked_time);
    1.25 +#define NS_PER_TICK (1000000000LL/HZ)
    1.26 +#endif
    1.27 +
    1.28  static struct time_interpolator itc_interpolator = {
    1.29  	.shift = 16,
    1.30  	.mask = 0xffffffffffffffffLL,
    1.31  	.source = TIME_SOURCE_CPU
    1.32  };
    1.33  
    1.34 +#ifdef CONFIG_XEN
    1.35 +static unsigned long 
    1.36 +consider_steal_time(unsigned long new_itm, struct pt_regs *regs)
    1.37 +{
    1.38 +	unsigned long stolen, blocked, sched_time;
    1.39 +	unsigned long delta_itm = 0, stolentick = 0;
    1.40 +	int i, cpu = smp_processor_id();
    1.41 +	struct vcpu_runstate_info *runstate;
    1.42 +	struct task_struct *p = current;
    1.43 +
    1.44 +	runstate = &per_cpu(runstate, smp_processor_id());
    1.45 +
    1.46 +	do {
    1.47 +		sched_time = runstate->state_entry_time;
    1.48 +		mb();
    1.49 +		stolen = runstate->time[RUNSTATE_runnable] + 
    1.50 +			 runstate->time[RUNSTATE_offline] -
    1.51 +			 per_cpu(processed_stolen_time, cpu);
    1.52 +		blocked = runstate->time[RUNSTATE_blocked] -
    1.53 +			  per_cpu(processed_blocked_time, cpu);
    1.54 +		mb();
    1.55 +	} while (sched_time != runstate->state_entry_time);
    1.56 +
    1.57 +	/*
    1.58 +	 * Check for vcpu migration effect
    1.59 +	 * In this case, itc value is reversed.
    1.60 +	 * This causes huge stolen value.  
    1.61 +	 * This function just checks and reject this effect.
    1.62 +	 */
    1.63 +	if (!time_after_eq(runstate->time[RUNSTATE_blocked],
    1.64 +			   per_cpu(processed_blocked_time, cpu)))
    1.65 +		blocked = 0;
    1.66 +
    1.67 +	if (!time_after_eq(runstate->time[RUNSTATE_runnable] +
    1.68 +			   runstate->time[RUNSTATE_offline],
    1.69 +			   per_cpu(processed_stolen_time, cpu)))
    1.70 +		stolen = 0;
    1.71 +
    1.72 +	if (!time_after(delta_itm + new_itm, ia64_get_itc()))
    1.73 +		stolentick = ia64_get_itc() - delta_itm - new_itm;
    1.74 +
    1.75 +	do_div(stolentick, NS_PER_TICK);
    1.76 +	stolentick++;
    1.77 +
    1.78 +	do_div(stolen, NS_PER_TICK);
    1.79 +
    1.80 +	if (stolen > stolentick)
    1.81 +		stolen = stolentick;
    1.82 +
    1.83 +	stolentick -= stolen;
    1.84 +	do_div(blocked, NS_PER_TICK);
    1.85 +
    1.86 +	if (blocked > stolentick)
    1.87 +		blocked = stolentick;
    1.88 +
    1.89 +	if (stolen > 0 || blocked > 0) {
    1.90 +		account_steal_time(NULL, jiffies_to_cputime(stolen)); 
    1.91 +		account_steal_time(idle_task(cpu), jiffies_to_cputime(blocked)); 
    1.92 +		run_local_timers();
    1.93 +
    1.94 +		if (rcu_pending(cpu))
    1.95 +			rcu_check_callbacks(cpu, user_mode(regs));
    1.96 +
    1.97 +		scheduler_tick();
    1.98 +		run_posix_cpu_timers(p);
    1.99 +		delta_itm += local_cpu_data->itm_delta * (stolen + blocked);
   1.100 +
   1.101 +		if (cpu == time_keeper_id) {
   1.102 +			write_seqlock(&xtime_lock);
   1.103 +			for(i = 0; i < stolen + blocked; i++)
   1.104 +				do_timer(regs);
   1.105 +			local_cpu_data->itm_next = delta_itm + new_itm;
   1.106 +			write_sequnlock(&xtime_lock);
   1.107 +		} else {
   1.108 +			local_cpu_data->itm_next = delta_itm + new_itm;
   1.109 +		}
   1.110 +		per_cpu(processed_stolen_time,cpu) += NS_PER_TICK * stolen;
   1.111 +		per_cpu(processed_blocked_time,cpu) += NS_PER_TICK * blocked;
   1.112 +	}
   1.113 +	return delta_itm; 
   1.114 +}
   1.115 +#else
   1.116 +#define consider_steal_time(new_itm, regs) (0)
   1.117 +#endif
   1.118 +
   1.119  static irqreturn_t
   1.120  timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
   1.121  {
   1.122  	unsigned long new_itm;
   1.123 +	unsigned long delta_itm; /* XEN */
   1.124  
   1.125  	if (unlikely(cpu_is_offline(smp_processor_id()))) {
   1.126  		return IRQ_HANDLED;
   1.127 @@ -65,6 +165,13 @@ timer_interrupt (int irq, void *dev_id, 
   1.128  
   1.129  	profile_tick(CPU_PROFILING, regs);
   1.130  
   1.131 +	if (is_running_on_xen()) {
   1.132 +		delta_itm = consider_steal_time(new_itm, regs);
   1.133 +		new_itm += delta_itm;
   1.134 +		if (time_after(new_itm, ia64_get_itc()) && delta_itm)
   1.135 +			goto skip_process_time_accounting;
   1.136 +	}
   1.137 +
   1.138  	while (1) {
   1.139  		update_process_times(user_mode(regs));
   1.140  
   1.141 @@ -88,6 +195,8 @@ timer_interrupt (int irq, void *dev_id, 
   1.142  			break;
   1.143  	}
   1.144  
   1.145 +skip_process_time_accounting:	/* XEN */
   1.146 +
   1.147  	do {
   1.148  		/*
   1.149  		 * If we're too close to the next clock tick for
   1.150 @@ -142,6 +251,25 @@ static int __init nojitter_setup(char *s
   1.151  
   1.152  __setup("nojitter", nojitter_setup);
   1.153  
   1.154 +#ifdef CONFIG_XEN
   1.155 +/* taken from i386/kernel/time-xen.c */
   1.156 +static void init_missing_ticks_accounting(int cpu)
   1.157 +{
   1.158 +	struct vcpu_register_runstate_memory_area area;
   1.159 +	struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
   1.160 +
   1.161 +	memset(runstate, 0, sizeof(*runstate));
   1.162 +
   1.163 +	area.addr.v = runstate;
   1.164 +	HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area);
   1.165 +
   1.166 +	per_cpu(processed_blocked_time, cpu) = runstate->time[RUNSTATE_blocked];
   1.167 +	per_cpu(processed_stolen_time, cpu) = runstate->time[RUNSTATE_runnable]
   1.168 +					    + runstate->time[RUNSTATE_offline];
   1.169 +}
   1.170 +#else
   1.171 +#define init_missing_ticks_accounting(cpu) do {} while (0)
   1.172 +#endif
   1.173  
   1.174  void __devinit
   1.175  ia64_init_itm (void)
   1.176 @@ -225,6 +353,9 @@ ia64_init_itm (void)
   1.177  		register_time_interpolator(&itc_interpolator);
   1.178  	}
   1.179  
   1.180 +	if (is_running_on_xen())
   1.181 +		init_missing_ticks_accounting(smp_processor_id());
   1.182 +
   1.183  	/* Setup the CPU local timer tick */
   1.184  	ia64_cpu_local_tick();
   1.185  }