0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kvm_host.h>
0011 #include <linux/fs.h>
0012 #include <linux/seq_file.h>
0013 #include <linux/debugfs.h>
0014 #include <linux/uaccess.h>
0015 #include <linux/module.h>
0016
0017 #include <asm/time.h>
0018 #include <asm-generic/div64.h>
0019
0020 #include "timing.h"
0021
0022 void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
0023 {
0024 int i;
0025
0026
0027 mutex_lock(&vcpu->arch.exit_timing_lock);
0028
0029 vcpu->arch.last_exit_type = 0xDEAD;
0030 for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
0031 vcpu->arch.timing_count_type[i] = 0;
0032 vcpu->arch.timing_max_duration[i] = 0;
0033 vcpu->arch.timing_min_duration[i] = 0xFFFFFFFF;
0034 vcpu->arch.timing_sum_duration[i] = 0;
0035 vcpu->arch.timing_sum_quad_duration[i] = 0;
0036 }
0037 vcpu->arch.timing_last_exit = 0;
0038 vcpu->arch.timing_exit.tv64 = 0;
0039 vcpu->arch.timing_last_enter.tv64 = 0;
0040
0041 mutex_unlock(&vcpu->arch.exit_timing_lock);
0042 }
0043
0044 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
0045 {
0046 u64 old;
0047
0048 mutex_lock(&vcpu->arch.exit_timing_lock);
0049
0050 vcpu->arch.timing_count_type[type]++;
0051
0052
0053 old = vcpu->arch.timing_sum_duration[type];
0054 vcpu->arch.timing_sum_duration[type] += duration;
0055 if (unlikely(old > vcpu->arch.timing_sum_duration[type])) {
0056 printk(KERN_ERR"%s - wrap adding sum of durations"
0057 " old %lld new %lld type %d exit # of type %d\n",
0058 __func__, old, vcpu->arch.timing_sum_duration[type],
0059 type, vcpu->arch.timing_count_type[type]);
0060 }
0061
0062
0063 old = vcpu->arch.timing_sum_quad_duration[type];
0064 vcpu->arch.timing_sum_quad_duration[type] += (duration*duration);
0065 if (unlikely(old > vcpu->arch.timing_sum_quad_duration[type])) {
0066 printk(KERN_ERR"%s - wrap adding sum of squared durations"
0067 " old %lld new %lld type %d exit # of type %d\n",
0068 __func__, old,
0069 vcpu->arch.timing_sum_quad_duration[type],
0070 type, vcpu->arch.timing_count_type[type]);
0071 }
0072
0073
0074 if (unlikely(duration < vcpu->arch.timing_min_duration[type]))
0075 vcpu->arch.timing_min_duration[type] = duration;
0076 if (unlikely(duration > vcpu->arch.timing_max_duration[type]))
0077 vcpu->arch.timing_max_duration[type] = duration;
0078
0079 mutex_unlock(&vcpu->arch.exit_timing_lock);
0080 }
0081
0082 void kvmppc_update_timing_stats(struct kvm_vcpu *vcpu)
0083 {
0084 u64 exit = vcpu->arch.timing_last_exit;
0085 u64 enter = vcpu->arch.timing_last_enter.tv64;
0086
0087
0088 vcpu->arch.timing_last_exit = vcpu->arch.timing_exit.tv64;
0089
0090 if (unlikely(vcpu->arch.last_exit_type == 0xDEAD || exit == 0))
0091 return;
0092
0093
0094 add_exit_timing(vcpu, (enter - exit), vcpu->arch.last_exit_type);
0095
0096 add_exit_timing(vcpu, (vcpu->arch.timing_last_exit - enter),
0097 TIMEINGUEST);
0098 }
0099
0100 static const char *kvm_exit_names[__NUMBER_OF_KVM_EXIT_TYPES] = {
0101 [MMIO_EXITS] = "MMIO",
0102 [SIGNAL_EXITS] = "SIGNAL",
0103 [ITLB_REAL_MISS_EXITS] = "ITLBREAL",
0104 [ITLB_VIRT_MISS_EXITS] = "ITLBVIRT",
0105 [DTLB_REAL_MISS_EXITS] = "DTLBREAL",
0106 [DTLB_VIRT_MISS_EXITS] = "DTLBVIRT",
0107 [SYSCALL_EXITS] = "SYSCALL",
0108 [ISI_EXITS] = "ISI",
0109 [DSI_EXITS] = "DSI",
0110 [EMULATED_INST_EXITS] = "EMULINST",
0111 [EMULATED_MTMSRWE_EXITS] = "EMUL_WAIT",
0112 [EMULATED_WRTEE_EXITS] = "EMUL_WRTEE",
0113 [EMULATED_MTSPR_EXITS] = "EMUL_MTSPR",
0114 [EMULATED_MFSPR_EXITS] = "EMUL_MFSPR",
0115 [EMULATED_MTMSR_EXITS] = "EMUL_MTMSR",
0116 [EMULATED_MFMSR_EXITS] = "EMUL_MFMSR",
0117 [EMULATED_TLBSX_EXITS] = "EMUL_TLBSX",
0118 [EMULATED_TLBWE_EXITS] = "EMUL_TLBWE",
0119 [EMULATED_RFI_EXITS] = "EMUL_RFI",
0120 [DEC_EXITS] = "DEC",
0121 [EXT_INTR_EXITS] = "EXTINT",
0122 [HALT_WAKEUP] = "HALT",
0123 [USR_PR_INST] = "USR_PR_INST",
0124 [FP_UNAVAIL] = "FP_UNAVAIL",
0125 [DEBUG_EXITS] = "DEBUG",
0126 [TIMEINGUEST] = "TIMEINGUEST"
0127 };
0128
0129 static int kvmppc_exit_timing_show(struct seq_file *m, void *private)
0130 {
0131 struct kvm_vcpu *vcpu = m->private;
0132 int i;
0133 u64 min, max, sum, sum_quad;
0134
0135 seq_puts(m, "type count min max sum sum_squared\n");
0136
0137 for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
0138
0139 min = vcpu->arch.timing_min_duration[i];
0140 do_div(min, tb_ticks_per_usec);
0141 max = vcpu->arch.timing_max_duration[i];
0142 do_div(max, tb_ticks_per_usec);
0143 sum = vcpu->arch.timing_sum_duration[i];
0144 do_div(sum, tb_ticks_per_usec);
0145 sum_quad = vcpu->arch.timing_sum_quad_duration[i];
0146 do_div(sum_quad, tb_ticks_per_usec);
0147
0148 seq_printf(m, "%12s %10d %10lld %10lld %20lld %20lld\n",
0149 kvm_exit_names[i],
0150 vcpu->arch.timing_count_type[i],
0151 min,
0152 max,
0153 sum,
0154 sum_quad);
0155
0156 }
0157 return 0;
0158 }
0159
0160
0161 static ssize_t kvmppc_exit_timing_write(struct file *file,
0162 const char __user *user_buf,
0163 size_t count, loff_t *ppos)
0164 {
0165 int err = -EINVAL;
0166 char c;
0167
0168 if (count > 1) {
0169 goto done;
0170 }
0171
0172 if (get_user(c, user_buf)) {
0173 err = -EFAULT;
0174 goto done;
0175 }
0176
0177 if (c == 'c') {
0178 struct seq_file *seqf = file->private_data;
0179 struct kvm_vcpu *vcpu = seqf->private;
0180
0181
0182
0183 mutex_lock(&seqf->lock);
0184 kvmppc_init_timing_stats(vcpu);
0185 mutex_unlock(&seqf->lock);
0186 err = count;
0187 }
0188
0189 done:
0190 return err;
0191 }
0192
0193 static int kvmppc_exit_timing_open(struct inode *inode, struct file *file)
0194 {
0195 return single_open(file, kvmppc_exit_timing_show, inode->i_private);
0196 }
0197
0198 static const struct file_operations kvmppc_exit_timing_fops = {
0199 .owner = THIS_MODULE,
0200 .open = kvmppc_exit_timing_open,
0201 .read = seq_read,
0202 .write = kvmppc_exit_timing_write,
0203 .llseek = seq_lseek,
0204 .release = single_release,
0205 };
0206
0207 int kvmppc_create_vcpu_debugfs_e500(struct kvm_vcpu *vcpu,
0208 struct dentry *debugfs_dentry)
0209 {
0210 debugfs_create_file("timing", 0666, debugfs_dentry,
0211 vcpu, &kvmppc_exit_timing_fops);
0212 return 0;
0213 }