ia64/xen-unstable

changeset 16630:57eec263d48b

[IA64] xenoprof: various fix on linux-xen/perfmon.c

Various fixes on xen/arch/ia64/linux-xen/perfmon.c
- Fix starting/stopping sampling.
So far IPI is used. but psr.pp isn't preserved when nested interrupt case
with VTi domain. Instead timer is used.
- Redefines ia64_set_pmc() to enable sampling of all xen VMM/guest
kernel/guest user process. It supports only generic pmc/pmd.
- Twist xenpfm_write_pmcs()
It is also used when turning on pmcs. So bailing out when error is not
appropriate. Even when error occures, it should continue to update next
cpu's pmcs.
- Add gdprintk(XENLOG_DEUBG) and BUG_ON()s.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Mon Dec 17 09:45:53 2007 -0700 (2007-12-17)
parents 9a545d45b192
children 213a7029fdbc
files xen/arch/ia64/linux-xen/perfmon.c
line diff
     1.1 --- a/xen/arch/ia64/linux-xen/perfmon.c	Mon Dec 17 09:38:54 2007 -0700
     1.2 +++ b/xen/arch/ia64/linux-xen/perfmon.c	Mon Dec 17 09:45:53 2007 -0700
     1.3 @@ -69,6 +69,35 @@
     1.4  #define pid		vcpu_id
     1.5  #define thread		arch._thread
     1.6  #define task_pt_regs	vcpu_regs
     1.7 +
     1.8 +#define PMC_USER		(1UL << 3)
     1.9 +#define PMC_KERNEL		(1UL << 0)
    1.10 +#define PMC_XEN_AND_GUEST	((1UL << 0) | (1UL << 1) | (1UL << 2))
    1.11 +#define PMC_PRIV_MONITOR	(1UL << 6)
    1.12 +
    1.13 +#undef ia64_set_pmc
    1.14 +#define ia64_set_pmc(index, val)					\
    1.15 +do {									\
    1.16 +	u64 __index = (index);						\
    1.17 +	u64 __val = (val);						\
    1.18 +	/* bad hack!							\
    1.19 +	 * At this moment Linux perfmon knows only kernel and user	\
    1.20 +	 * so that it sets only pmc.plm[0] and pmc.plm[3].		\
    1.21 +	 * On the other hand what we want is to sample on the whole	\
    1.22 +	 * system. i.e. user, guest kernel and xen VMM.			\
    1.23 +	 * Thus here we enable pmc.plm[2:1] too for generic pmc/pmd.	\
    1.24 +	 *								\
    1.25 +	 * But we can not do it genericly for the implementation	\
    1.26 +	 * dependent pmc/pmd.						\
    1.27 +	 * Probably such knowlege should be taught to the oprofiled or	\
    1.28 +	 * the xenified perfmon.					\
    1.29 +	 */								\
    1.30 +	if (pmu_conf != NULL && PMC_IS_COUNTING(__index) &&		\
    1.31 +	    (__val & PMC_KERNEL))					\
    1.32 +		__val |= PMC_XEN_AND_GUEST | PMC_PRIV_MONITOR;		\
    1.33 +	asm volatile ("mov pmc[%0]=%1" ::				\
    1.34 +		      "r"(__index), "r"(__val) : "memory");		\
    1.35 +} while (0)
    1.36  #endif
    1.37  
    1.38  #ifdef CONFIG_PERFMON
    1.39 @@ -1214,7 +1243,7 @@ xenpfm_restore_pmcs(pfm_context_t* ctx)
    1.40  {
    1.41  	int i;
    1.42  	unsigned long mask = ctx->ctx_all_pmcs[0];
    1.43 -	
    1.44 +
    1.45  	for (i = 0; mask; i++, mask >>= 1) {
    1.46  		if ((mask & 0x1) == 0)
    1.47  			continue;
    1.48 @@ -3073,6 +3102,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void 
    1.49  #else
    1.50  	/* XXX FIXME */
    1.51  	if (state != PFM_CTX_UNLOADED) {
    1.52 +		gdprintk(XENLOG_DEBUG, "%s state %d\n", __func__, state);
    1.53  		return -EBUSY;
    1.54  	}
    1.55  #endif
    1.56 @@ -3334,6 +3364,7 @@ pfm_write_pmds(pfm_context_t *ctx, void 
    1.57  #else
    1.58  	/* XXX FIXME */
    1.59  	if (state != PFM_CTX_UNLOADED) {
    1.60 +		gdprintk(XENLOG_DEBUG, "%s state %d\n", __func__, state);
    1.61  		return -EBUSY;
    1.62  	}
    1.63  #endif
    1.64 @@ -7387,13 +7418,12 @@ xenpfm_write_pmcs(XEN_GUEST_HANDLE(pfarg
    1.65  		spin_lock_irqsave(&xenpfm_context_lock, flags);
    1.66  		for_each_online_cpu(cpu) {
    1.67  			pfm_context_t* ctx = per_cpu(xenpfm_context, cpu);
    1.68 +			BUG_ON(ctx == NULL);
    1.69  			PROTECT_CTX_NOIRQ(ctx);
    1.70  			error |= pfm_write_pmcs(ctx, (void *)&kreq, 1, NULL);
    1.71  			UNPROTECT_CTX_NOIRQ(ctx);
    1.72  		}
    1.73  		spin_unlock_irqrestore(&xenpfm_context_lock, flags);
    1.74 -		if (error)
    1.75 -			break;
    1.76  	}
    1.77  	
    1.78  	/* XXX if is loaded, change all physical cpus pmcs. */
    1.79 @@ -7420,6 +7450,7 @@ xenpfm_write_pmds(XEN_GUEST_HANDLE(pfarg
    1.80  		spin_lock_irqsave(&xenpfm_context_lock, flags);
    1.81  		for_each_online_cpu(cpu) {
    1.82  			pfm_context_t* ctx = per_cpu(xenpfm_context, cpu);
    1.83 +			BUG_ON(ctx == NULL);
    1.84  			PROTECT_CTX_NOIRQ(ctx);
    1.85  			error |= pfm_write_pmds(ctx, &kreq, 1, NULL);
    1.86  			UNPROTECT_CTX_NOIRQ(ctx);
    1.87 @@ -7444,6 +7475,8 @@ xenpfm_context_load_cpu(void* info)
    1.88  	unsigned long flags;
    1.89  	struct xenpfm_context_load_arg* arg = (struct xenpfm_context_load_arg*)info;
    1.90  	pfm_context_t* ctx = __get_cpu_var(xenpfm_context);
    1.91 +
    1.92 +	BUG_ON(ctx == NULL);
    1.93  	PROTECT_CTX(ctx, flags);
    1.94  	arg->error[smp_processor_id()] = pfm_context_load(ctx, arg->req, 0, NULL);
    1.95  	UNPROTECT_CTX(ctx, flags);
    1.96 @@ -7490,6 +7523,7 @@ xenpfm_context_unload_cpu(void* info)
    1.97  	unsigned long flags;
    1.98  	struct xenpfm_context_unload_arg* arg = (struct xenpfm_context_unload_arg*)info;
    1.99  	pfm_context_t* ctx = __get_cpu_var(xenpfm_context);
   1.100 +	BUG_ON(ctx == NULL);
   1.101  	PROTECT_CTX(ctx, flags);
   1.102  	arg->error[smp_processor_id()] = pfm_context_unload(ctx, NULL, 0, NULL);
   1.103  	UNPROTECT_CTX(ctx, flags);
   1.104 @@ -7500,19 +7534,25 @@ xenpfm_context_unload(void)
   1.105  {
   1.106  	int cpu;
   1.107  	struct xenpfm_context_unload_arg arg;
   1.108 +	unsigned long flags;
   1.109  	int error = 0;
   1.110  
   1.111  	for_each_online_cpu(cpu)
   1.112  		arg.error[cpu] = 0;
   1.113  
   1.114  	BUG_ON(in_irq());
   1.115 -	spin_lock(&xenpfm_context_lock);
   1.116 +	local_irq_save(flags);
   1.117 +	if (!spin_trylock(&xenpfm_context_lock)) {
   1.118 +		local_irq_restore(flags);
   1.119 +		return -EAGAIN;
   1.120 +	}
   1.121  	error = xenpfm_start_stop_locked(0);
   1.122 +	local_irq_restore(flags);
   1.123  	if (error) {
   1.124  		spin_unlock(&xenpfm_context_lock);
   1.125  		return error;
   1.126  	}
   1.127 -	
   1.128 +
   1.129  	smp_call_function(&xenpfm_context_unload_cpu, &arg, 1, 1);
   1.130  	xenpfm_context_unload_cpu(&arg);
   1.131  	spin_unlock(&xenpfm_context_lock);
   1.132 @@ -7533,10 +7573,12 @@ static int
   1.133  	int state;
   1.134  	int error = 0;
   1.135  
   1.136 +	BUG_ON(ctx == NULL);
   1.137  	BUG_ON(local_irq_is_enabled());
   1.138  	PROTECT_CTX_NOIRQ(ctx);	
   1.139  	state = ctx->ctx_state;
   1.140  	if (state != PFM_CTX_LOADED) {
   1.141 +		gdprintk(XENLOG_DEBUG, "%s state %d\n", __func__, state);
   1.142  		error = -EINVAL;
   1.143  		goto out;
   1.144  	}
   1.145 @@ -7566,9 +7608,18 @@ static int
   1.146  	int error = 0;
   1.147  
   1.148  	BUG_ON(local_irq_is_enabled());
   1.149 +	if (ctx == NULL) {
   1.150 +		gdprintk(XENLOG_DEBUG, "%s ctx=NULL p:%2d v:%2d\n",
   1.151 +			 __func__, smp_processor_id(), current->vcpu_id);
   1.152 +		return 0;
   1.153 +	}
   1.154 +	
   1.155  	PROTECT_CTX_NOIRQ(ctx);	
   1.156  	state = ctx->ctx_state;
   1.157  	if (state != PFM_CTX_LOADED) {
   1.158 +		gdprintk(XENLOG_DEBUG, "%s state %d p:%2d v:%2d\n",
   1.159 +			 __func__, state,
   1.160 +			 smp_processor_id(), current->vcpu_id);
   1.161  		error = -EINVAL;
   1.162  		goto out;
   1.163  	}
   1.164 @@ -7640,7 +7691,7 @@ xenpfm_start_stop_vcpu(struct vcpu* v, i
   1.165  		ia64_psr(regs)->up = 1;
   1.166  
   1.167  		/* don't allow user level control */
   1.168 -		ia64_psr(regs)->sp = 0;
   1.169 +		ia64_psr(regs)->sp = 1;
   1.170  	} else {
   1.171  		/*
   1.172  		 * stop monitoring in the caller
   1.173 @@ -7656,18 +7707,32 @@ xenpfm_start_stop_vcpu(struct vcpu* v, i
   1.174  		/*
   1.175  		 * cancel user level control
   1.176  		 */
   1.177 -		ia64_psr(regs)->sp = 1;
   1.178 +		ia64_psr(regs)->sp = 0;
   1.179  #endif
   1.180  	}
   1.181  }
   1.182  
   1.183 +/*
   1.184 + * This is the trickiest part.
   1.185 + * Here we want to enable/disable wide performance monitor including
   1.186 + * all xen context and all guest.
   1.187 + * For interrupt context and running vcpu, set dcr.pp = 1
   1.188 + * For blocked vcpu and idle vcpu, set psr.pp = 1 using timer via softirq.
   1.189 + * (Here IPI doesn't work because psr doesn't preserved over interruption
   1.190 + *  when VTi domain.
   1.191 + *  If IPI is used, we need to unwind the stack to the interrupt frame
   1.192 + *  and set cr_ipsr.pp = 1. but using timer via do_softirq() is easier.)
   1.193 + * For guest set all vcpu_regs(v)->cr_ipsr.pp = 1.
   1.194 + */
   1.195  static int
   1.196  xenpfm_start_stop_locked(int is_start)
   1.197  {
   1.198 +	/* avoid stack over flow. protected by xenpfm_context_lock */
   1.199 +	static struct timer xenpfm_timer[NR_CPUS];
   1.200 +
   1.201  	struct xenpfm_start_arg arg;
   1.202  	int cpus = num_online_cpus();
   1.203  	int cpu;
   1.204 -	unsigned long flags;
   1.205  	struct domain* d;
   1.206  	struct vcpu* v;
   1.207  	int error = 0;
   1.208 @@ -7679,8 +7744,14 @@ xenpfm_start_stop_locked(int is_start)
   1.209  		arg.error[cpu] = 0;
   1.210  
   1.211  	BUG_ON(!spin_is_locked(&xenpfm_context_lock));
   1.212 -	smp_call_function(&xenpfm_start_stop_cpu, &arg, 1, 0);
   1.213 -	local_irq_save(flags);
   1.214 +	for_each_online_cpu(cpu) {
   1.215 +		struct timer* start_stop_timer = &xenpfm_timer[cpu];
   1.216 +		if (cpu == smp_processor_id())
   1.217 +			continue;
   1.218 +		init_timer(start_stop_timer, &xenpfm_start_stop_cpu,
   1.219 +			   &arg, cpu);
   1.220 +		set_timer(start_stop_timer, 0);/* fire it ASAP */
   1.221 +	}
   1.222  
   1.223  	while (atomic_read(&arg.started) != cpus)
   1.224  		cpu_relax();
   1.225 @@ -7696,9 +7767,13 @@ xenpfm_start_stop_locked(int is_start)
   1.226  
   1.227  	while (atomic_read(&arg.finished) != cpus)
   1.228  		cpu_relax();
   1.229 -	local_irq_restore(flags);
   1.230  
   1.231  	for_each_online_cpu(cpu) {
   1.232 +		if (cpu == smp_processor_id())
   1.233 +			continue;
   1.234 +		/* xenpfm_timer[] is global so that we have to wait
   1.235 +		 * for xen timer subsystem to finish them. */
   1.236 +		kill_timer(&xenpfm_timer[cpu]);
   1.237  		if (arg.error[cpu]) {
   1.238  			gdprintk(XENLOG_INFO, "%s: cpu %d error %d\n", 
   1.239  				__func__, cpu, arg.error[cpu]);
   1.240 @@ -7711,12 +7786,22 @@ xenpfm_start_stop_locked(int is_start)
   1.241  static int
   1.242  xenpfm_start_stop(int is_start)
   1.243  {
   1.244 +	unsigned long flags;
   1.245  	int error;
   1.246  	
   1.247  	BUG_ON(in_irq());
   1.248 -	spin_lock(&xenpfm_context_lock);
   1.249 +	local_irq_save(flags);
   1.250 +	/*
   1.251 +	 * Avoid dead lock. At this moment xen has only spin locks and
   1.252 +	 * doesn't have blocking mutex.
   1.253 +	 */
   1.254 +	if (!spin_trylock(&xenpfm_context_lock)) {
   1.255 +		local_irq_restore(flags);
   1.256 +		gdprintk(XENLOG_DEBUG, "%s EAGAIN\n", __func__);
   1.257 +		return -EAGAIN;
   1.258 +	}
   1.259  	error = xenpfm_start_stop_locked(is_start);
   1.260 -	spin_unlock(&xenpfm_context_lock);
   1.261 +	spin_unlock_irqrestore(&xenpfm_context_lock, flags);
   1.262  
   1.263  	return error;
   1.264  }