xref: /openbmc/linux/arch/powerpc/kvm/timing.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d94d71cbSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
273e75b41SHollis Blanchard /*
373e75b41SHollis Blanchard  *
47b701591SHollis Blanchard  * Copyright IBM Corp. 2008
573e75b41SHollis Blanchard  *
673e75b41SHollis Blanchard  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
773e75b41SHollis Blanchard  *          Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
873e75b41SHollis Blanchard  */
973e75b41SHollis Blanchard 
1073e75b41SHollis Blanchard #include <linux/kvm_host.h>
1173e75b41SHollis Blanchard #include <linux/fs.h>
1273e75b41SHollis Blanchard #include <linux/seq_file.h>
1373e75b41SHollis Blanchard #include <linux/debugfs.h>
1473e75b41SHollis Blanchard #include <linux/uaccess.h>
15e0ea8b2cSBenjamin Herrenschmidt #include <linux/module.h>
1673e75b41SHollis Blanchard 
1773e75b41SHollis Blanchard #include <asm/time.h>
1873e75b41SHollis Blanchard #include <asm-generic/div64.h>
1973e75b41SHollis Blanchard 
207b701591SHollis Blanchard #include "timing.h"
217b701591SHollis Blanchard 
kvmppc_init_timing_stats(struct kvm_vcpu * vcpu)2273e75b41SHollis Blanchard void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
2373e75b41SHollis Blanchard {
2473e75b41SHollis Blanchard 	int i;
2573e75b41SHollis Blanchard 
2609000adbSBharat Bhushan 	/* Take a lock to avoid concurrent updates */
2709000adbSBharat Bhushan 	mutex_lock(&vcpu->arch.exit_timing_lock);
2873e75b41SHollis Blanchard 
2973e75b41SHollis Blanchard 	vcpu->arch.last_exit_type = 0xDEAD;
3073e75b41SHollis Blanchard 	for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
3173e75b41SHollis Blanchard 		vcpu->arch.timing_count_type[i] = 0;
3273e75b41SHollis Blanchard 		vcpu->arch.timing_max_duration[i] = 0;
3373e75b41SHollis Blanchard 		vcpu->arch.timing_min_duration[i] = 0xFFFFFFFF;
3473e75b41SHollis Blanchard 		vcpu->arch.timing_sum_duration[i] = 0;
3573e75b41SHollis Blanchard 		vcpu->arch.timing_sum_quad_duration[i] = 0;
3673e75b41SHollis Blanchard 	}
3773e75b41SHollis Blanchard 	vcpu->arch.timing_last_exit = 0;
3873e75b41SHollis Blanchard 	vcpu->arch.timing_exit.tv64 = 0;
3973e75b41SHollis Blanchard 	vcpu->arch.timing_last_enter.tv64 = 0;
4073e75b41SHollis Blanchard 
4109000adbSBharat Bhushan 	mutex_unlock(&vcpu->arch.exit_timing_lock);
4273e75b41SHollis Blanchard }
4373e75b41SHollis Blanchard 
add_exit_timing(struct kvm_vcpu * vcpu,u64 duration,int type)447b701591SHollis Blanchard static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
4573e75b41SHollis Blanchard {
4673e75b41SHollis Blanchard 	u64 old;
4773e75b41SHollis Blanchard 
4809000adbSBharat Bhushan 	mutex_lock(&vcpu->arch.exit_timing_lock);
4909000adbSBharat Bhushan 
5073e75b41SHollis Blanchard 	vcpu->arch.timing_count_type[type]++;
5173e75b41SHollis Blanchard 
5273e75b41SHollis Blanchard 	/* sum */
5373e75b41SHollis Blanchard 	old = vcpu->arch.timing_sum_duration[type];
5473e75b41SHollis Blanchard 	vcpu->arch.timing_sum_duration[type] += duration;
5573e75b41SHollis Blanchard 	if (unlikely(old > vcpu->arch.timing_sum_duration[type])) {
5673e75b41SHollis Blanchard 		printk(KERN_ERR"%s - wrap adding sum of durations"
5773e75b41SHollis Blanchard 			" old %lld new %lld type %d exit # of type %d\n",
5873e75b41SHollis Blanchard 			__func__, old, vcpu->arch.timing_sum_duration[type],
5973e75b41SHollis Blanchard 			type, vcpu->arch.timing_count_type[type]);
6073e75b41SHollis Blanchard 	}
6173e75b41SHollis Blanchard 
6273e75b41SHollis Blanchard 	/* square sum */
6373e75b41SHollis Blanchard 	old = vcpu->arch.timing_sum_quad_duration[type];
6473e75b41SHollis Blanchard 	vcpu->arch.timing_sum_quad_duration[type] += (duration*duration);
6573e75b41SHollis Blanchard 	if (unlikely(old > vcpu->arch.timing_sum_quad_duration[type])) {
6673e75b41SHollis Blanchard 		printk(KERN_ERR"%s - wrap adding sum of squared durations"
6773e75b41SHollis Blanchard 			" old %lld new %lld type %d exit # of type %d\n",
6873e75b41SHollis Blanchard 			__func__, old,
6973e75b41SHollis Blanchard 			vcpu->arch.timing_sum_quad_duration[type],
7073e75b41SHollis Blanchard 			type, vcpu->arch.timing_count_type[type]);
7173e75b41SHollis Blanchard 	}
7273e75b41SHollis Blanchard 
7373e75b41SHollis Blanchard 	/* set min/max */
7473e75b41SHollis Blanchard 	if (unlikely(duration < vcpu->arch.timing_min_duration[type]))
7573e75b41SHollis Blanchard 		vcpu->arch.timing_min_duration[type] = duration;
7673e75b41SHollis Blanchard 	if (unlikely(duration > vcpu->arch.timing_max_duration[type]))
7773e75b41SHollis Blanchard 		vcpu->arch.timing_max_duration[type] = duration;
7809000adbSBharat Bhushan 
7909000adbSBharat Bhushan 	mutex_unlock(&vcpu->arch.exit_timing_lock);
8073e75b41SHollis Blanchard }
8173e75b41SHollis Blanchard 
kvmppc_update_timing_stats(struct kvm_vcpu * vcpu)8273e75b41SHollis Blanchard void kvmppc_update_timing_stats(struct kvm_vcpu *vcpu)
8373e75b41SHollis Blanchard {
8473e75b41SHollis Blanchard 	u64 exit = vcpu->arch.timing_last_exit;
8573e75b41SHollis Blanchard 	u64 enter = vcpu->arch.timing_last_enter.tv64;
8673e75b41SHollis Blanchard 
8773e75b41SHollis Blanchard 	/* save exit time, used next exit when the reenter time is known */
8873e75b41SHollis Blanchard 	vcpu->arch.timing_last_exit = vcpu->arch.timing_exit.tv64;
8973e75b41SHollis Blanchard 
9073e75b41SHollis Blanchard 	if (unlikely(vcpu->arch.last_exit_type == 0xDEAD || exit == 0))
9173e75b41SHollis Blanchard 		return; /* skip incomplete cycle (e.g. after reset) */
9273e75b41SHollis Blanchard 
9373e75b41SHollis Blanchard 	/* update statistics for average and standard deviation */
9473e75b41SHollis Blanchard 	add_exit_timing(vcpu, (enter - exit), vcpu->arch.last_exit_type);
9573e75b41SHollis Blanchard 	/* enter -> timing_last_exit is time spent in guest - log this too */
9673e75b41SHollis Blanchard 	add_exit_timing(vcpu, (vcpu->arch.timing_last_exit - enter),
9773e75b41SHollis Blanchard 			TIMEINGUEST);
9873e75b41SHollis Blanchard }
9973e75b41SHollis Blanchard 
10073e75b41SHollis Blanchard static const char *kvm_exit_names[__NUMBER_OF_KVM_EXIT_TYPES] = {
10173e75b41SHollis Blanchard 	[MMIO_EXITS] =              "MMIO",
10273e75b41SHollis Blanchard 	[SIGNAL_EXITS] =            "SIGNAL",
10373e75b41SHollis Blanchard 	[ITLB_REAL_MISS_EXITS] =    "ITLBREAL",
10473e75b41SHollis Blanchard 	[ITLB_VIRT_MISS_EXITS] =    "ITLBVIRT",
10573e75b41SHollis Blanchard 	[DTLB_REAL_MISS_EXITS] =    "DTLBREAL",
10673e75b41SHollis Blanchard 	[DTLB_VIRT_MISS_EXITS] =    "DTLBVIRT",
10773e75b41SHollis Blanchard 	[SYSCALL_EXITS] =           "SYSCALL",
10873e75b41SHollis Blanchard 	[ISI_EXITS] =               "ISI",
10973e75b41SHollis Blanchard 	[DSI_EXITS] =               "DSI",
11073e75b41SHollis Blanchard 	[EMULATED_INST_EXITS] =     "EMULINST",
11173e75b41SHollis Blanchard 	[EMULATED_MTMSRWE_EXITS] =  "EMUL_WAIT",
11273e75b41SHollis Blanchard 	[EMULATED_WRTEE_EXITS] =    "EMUL_WRTEE",
11373e75b41SHollis Blanchard 	[EMULATED_MTSPR_EXITS] =    "EMUL_MTSPR",
11473e75b41SHollis Blanchard 	[EMULATED_MFSPR_EXITS] =    "EMUL_MFSPR",
11573e75b41SHollis Blanchard 	[EMULATED_MTMSR_EXITS] =    "EMUL_MTMSR",
11673e75b41SHollis Blanchard 	[EMULATED_MFMSR_EXITS] =    "EMUL_MFMSR",
11773e75b41SHollis Blanchard 	[EMULATED_TLBSX_EXITS] =    "EMUL_TLBSX",
11873e75b41SHollis Blanchard 	[EMULATED_TLBWE_EXITS] =    "EMUL_TLBWE",
11973e75b41SHollis Blanchard 	[EMULATED_RFI_EXITS] =      "EMUL_RFI",
12073e75b41SHollis Blanchard 	[DEC_EXITS] =               "DEC",
12173e75b41SHollis Blanchard 	[EXT_INTR_EXITS] =          "EXTINT",
12273e75b41SHollis Blanchard 	[HALT_WAKEUP] =             "HALT",
12373e75b41SHollis Blanchard 	[USR_PR_INST] =             "USR_PR_INST",
12473e75b41SHollis Blanchard 	[FP_UNAVAIL] =              "FP_UNAVAIL",
12573e75b41SHollis Blanchard 	[DEBUG_EXITS] =             "DEBUG",
12673e75b41SHollis Blanchard 	[TIMEINGUEST] =             "TIMEINGUEST"
12773e75b41SHollis Blanchard };
12873e75b41SHollis Blanchard 
kvmppc_exit_timing_show(struct seq_file * m,void * private)12973e75b41SHollis Blanchard static int kvmppc_exit_timing_show(struct seq_file *m, void *private)
13073e75b41SHollis Blanchard {
13173e75b41SHollis Blanchard 	struct kvm_vcpu *vcpu = m->private;
13273e75b41SHollis Blanchard 	int i;
1331a040b26SStuart Yoder 	u64 min, max, sum, sum_quad;
1347b701591SHollis Blanchard 
13516273010SMarkus Elfring 	seq_puts(m, "type	count	min	max	sum	sum_squared\n");
1361a040b26SStuart Yoder 
13773e75b41SHollis Blanchard 	for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
1381a040b26SStuart Yoder 
1391a040b26SStuart Yoder 		min = vcpu->arch.timing_min_duration[i];
1401a040b26SStuart Yoder 		do_div(min, tb_ticks_per_usec);
1411a040b26SStuart Yoder 		max = vcpu->arch.timing_max_duration[i];
1421a040b26SStuart Yoder 		do_div(max, tb_ticks_per_usec);
1431a040b26SStuart Yoder 		sum = vcpu->arch.timing_sum_duration[i];
1441a040b26SStuart Yoder 		do_div(sum, tb_ticks_per_usec);
1451a040b26SStuart Yoder 		sum_quad = vcpu->arch.timing_sum_quad_duration[i];
1461a040b26SStuart Yoder 		do_div(sum_quad, tb_ticks_per_usec);
1471a040b26SStuart Yoder 
1487b701591SHollis Blanchard 		seq_printf(m, "%12s	%10d	%10lld	%10lld	%20lld	%20lld\n",
1497b701591SHollis Blanchard 			kvm_exit_names[i],
1507b701591SHollis Blanchard 			vcpu->arch.timing_count_type[i],
1511a040b26SStuart Yoder 			min,
1521a040b26SStuart Yoder 			max,
1531a040b26SStuart Yoder 			sum,
1541a040b26SStuart Yoder 			sum_quad);
1551a040b26SStuart Yoder 
15673e75b41SHollis Blanchard 	}
15773e75b41SHollis Blanchard 	return 0;
15873e75b41SHollis Blanchard }
15973e75b41SHollis Blanchard 
1607b701591SHollis Blanchard /* Write 'c' to clear the timing statistics. */
kvmppc_exit_timing_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)16173e75b41SHollis Blanchard static ssize_t kvmppc_exit_timing_write(struct file *file,
16273e75b41SHollis Blanchard 				       const char __user *user_buf,
16373e75b41SHollis Blanchard 				       size_t count, loff_t *ppos)
16473e75b41SHollis Blanchard {
1657b701591SHollis Blanchard 	int err = -EINVAL;
16673e75b41SHollis Blanchard 	char c;
16773e75b41SHollis Blanchard 
1687b701591SHollis Blanchard 	if (count > 1) {
16973e75b41SHollis Blanchard 		goto done;
17073e75b41SHollis Blanchard 	}
17173e75b41SHollis Blanchard 
1727b701591SHollis Blanchard 	if (get_user(c, user_buf)) {
17373e75b41SHollis Blanchard 		err = -EFAULT;
17473e75b41SHollis Blanchard 		goto done;
17573e75b41SHollis Blanchard 	}
17673e75b41SHollis Blanchard 
17773e75b41SHollis Blanchard 	if (c == 'c') {
178ea01c6b4SJoe Perches 		struct seq_file *seqf = file->private_data;
17973e75b41SHollis Blanchard 		struct kvm_vcpu *vcpu = seqf->private;
1807b701591SHollis Blanchard 		/* Write does not affect our buffers previously generated with
1817b701591SHollis Blanchard 		 * show. seq_file is locked here to prevent races of init with
18273e75b41SHollis Blanchard 		 * a show call */
18373e75b41SHollis Blanchard 		mutex_lock(&seqf->lock);
18473e75b41SHollis Blanchard 		kvmppc_init_timing_stats(vcpu);
18573e75b41SHollis Blanchard 		mutex_unlock(&seqf->lock);
18673e75b41SHollis Blanchard 		err = count;
18773e75b41SHollis Blanchard 	}
18873e75b41SHollis Blanchard 
18973e75b41SHollis Blanchard done:
19073e75b41SHollis Blanchard 	return err;
19173e75b41SHollis Blanchard }
19273e75b41SHollis Blanchard 
kvmppc_exit_timing_open(struct inode * inode,struct file * file)19373e75b41SHollis Blanchard static int kvmppc_exit_timing_open(struct inode *inode, struct file *file)
19473e75b41SHollis Blanchard {
19573e75b41SHollis Blanchard 	return single_open(file, kvmppc_exit_timing_show, inode->i_private);
19673e75b41SHollis Blanchard }
19773e75b41SHollis Blanchard 
198828c0950SAlexey Dobriyan static const struct file_operations kvmppc_exit_timing_fops = {
19973e75b41SHollis Blanchard 	.owner   = THIS_MODULE,
20073e75b41SHollis Blanchard 	.open    = kvmppc_exit_timing_open,
20173e75b41SHollis Blanchard 	.read    = seq_read,
20273e75b41SHollis Blanchard 	.write   = kvmppc_exit_timing_write,
20373e75b41SHollis Blanchard 	.llseek  = seq_lseek,
20473e75b41SHollis Blanchard 	.release = single_release,
20573e75b41SHollis Blanchard };
20673e75b41SHollis Blanchard 
kvmppc_create_vcpu_debugfs_e500(struct kvm_vcpu * vcpu,struct dentry * debugfs_dentry)207*faf01aefSAlexey Kardashevskiy int kvmppc_create_vcpu_debugfs_e500(struct kvm_vcpu *vcpu,
208*faf01aefSAlexey Kardashevskiy 				    struct dentry *debugfs_dentry)
20973e75b41SHollis Blanchard {
210*faf01aefSAlexey Kardashevskiy 	debugfs_create_file("timing", 0666, debugfs_dentry,
211c4fd527fSGreg Kroah-Hartman 			    vcpu, &kvmppc_exit_timing_fops);
212*faf01aefSAlexey Kardashevskiy 	return 0;
21373e75b41SHollis Blanchard }
214