root/arch/powerpc/kvm/timing.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kvmppc_init_timing_stats
  2. add_exit_timing
  3. kvmppc_update_timing_stats
  4. kvmppc_exit_timing_show
  5. kvmppc_exit_timing_write
  6. kvmppc_exit_timing_open
  7. kvmppc_create_vcpu_debugfs
  8. kvmppc_remove_vcpu_debugfs

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *
   4  * Copyright IBM Corp. 2008
   5  *
   6  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
   7  *          Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
   8  */
   9 
  10 #include <linux/kvm_host.h>
  11 #include <linux/fs.h>
  12 #include <linux/seq_file.h>
  13 #include <linux/debugfs.h>
  14 #include <linux/uaccess.h>
  15 #include <linux/module.h>
  16 
  17 #include <asm/time.h>
  18 #include <asm-generic/div64.h>
  19 
  20 #include "timing.h"
  21 
  22 void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
  23 {
  24         int i;
  25 
  26         /* Take a lock to avoid concurrent updates */
  27         mutex_lock(&vcpu->arch.exit_timing_lock);
  28 
  29         vcpu->arch.last_exit_type = 0xDEAD;
  30         for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
  31                 vcpu->arch.timing_count_type[i] = 0;
  32                 vcpu->arch.timing_max_duration[i] = 0;
  33                 vcpu->arch.timing_min_duration[i] = 0xFFFFFFFF;
  34                 vcpu->arch.timing_sum_duration[i] = 0;
  35                 vcpu->arch.timing_sum_quad_duration[i] = 0;
  36         }
  37         vcpu->arch.timing_last_exit = 0;
  38         vcpu->arch.timing_exit.tv64 = 0;
  39         vcpu->arch.timing_last_enter.tv64 = 0;
  40 
  41         mutex_unlock(&vcpu->arch.exit_timing_lock);
  42 }
  43 
  44 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
  45 {
  46         u64 old;
  47 
  48         mutex_lock(&vcpu->arch.exit_timing_lock);
  49 
  50         vcpu->arch.timing_count_type[type]++;
  51 
  52         /* sum */
  53         old = vcpu->arch.timing_sum_duration[type];
  54         vcpu->arch.timing_sum_duration[type] += duration;
  55         if (unlikely(old > vcpu->arch.timing_sum_duration[type])) {
  56                 printk(KERN_ERR"%s - wrap adding sum of durations"
  57                         " old %lld new %lld type %d exit # of type %d\n",
  58                         __func__, old, vcpu->arch.timing_sum_duration[type],
  59                         type, vcpu->arch.timing_count_type[type]);
  60         }
  61 
  62         /* square sum */
  63         old = vcpu->arch.timing_sum_quad_duration[type];
  64         vcpu->arch.timing_sum_quad_duration[type] += (duration*duration);
  65         if (unlikely(old > vcpu->arch.timing_sum_quad_duration[type])) {
  66                 printk(KERN_ERR"%s - wrap adding sum of squared durations"
  67                         " old %lld new %lld type %d exit # of type %d\n",
  68                         __func__, old,
  69                         vcpu->arch.timing_sum_quad_duration[type],
  70                         type, vcpu->arch.timing_count_type[type]);
  71         }
  72 
  73         /* set min/max */
  74         if (unlikely(duration < vcpu->arch.timing_min_duration[type]))
  75                 vcpu->arch.timing_min_duration[type] = duration;
  76         if (unlikely(duration > vcpu->arch.timing_max_duration[type]))
  77                 vcpu->arch.timing_max_duration[type] = duration;
  78 
  79         mutex_unlock(&vcpu->arch.exit_timing_lock);
  80 }
  81 
  82 void kvmppc_update_timing_stats(struct kvm_vcpu *vcpu)
  83 {
  84         u64 exit = vcpu->arch.timing_last_exit;
  85         u64 enter = vcpu->arch.timing_last_enter.tv64;
  86 
  87         /* save exit time, used next exit when the reenter time is known */
  88         vcpu->arch.timing_last_exit = vcpu->arch.timing_exit.tv64;
  89 
  90         if (unlikely(vcpu->arch.last_exit_type == 0xDEAD || exit == 0))
  91                 return; /* skip incomplete cycle (e.g. after reset) */
  92 
  93         /* update statistics for average and standard deviation */
  94         add_exit_timing(vcpu, (enter - exit), vcpu->arch.last_exit_type);
  95         /* enter -> timing_last_exit is time spent in guest - log this too */
  96         add_exit_timing(vcpu, (vcpu->arch.timing_last_exit - enter),
  97                         TIMEINGUEST);
  98 }
  99 
 100 static const char *kvm_exit_names[__NUMBER_OF_KVM_EXIT_TYPES] = {
 101         [MMIO_EXITS] =              "MMIO",
 102         [SIGNAL_EXITS] =            "SIGNAL",
 103         [ITLB_REAL_MISS_EXITS] =    "ITLBREAL",
 104         [ITLB_VIRT_MISS_EXITS] =    "ITLBVIRT",
 105         [DTLB_REAL_MISS_EXITS] =    "DTLBREAL",
 106         [DTLB_VIRT_MISS_EXITS] =    "DTLBVIRT",
 107         [SYSCALL_EXITS] =           "SYSCALL",
 108         [ISI_EXITS] =               "ISI",
 109         [DSI_EXITS] =               "DSI",
 110         [EMULATED_INST_EXITS] =     "EMULINST",
 111         [EMULATED_MTMSRWE_EXITS] =  "EMUL_WAIT",
 112         [EMULATED_WRTEE_EXITS] =    "EMUL_WRTEE",
 113         [EMULATED_MTSPR_EXITS] =    "EMUL_MTSPR",
 114         [EMULATED_MFSPR_EXITS] =    "EMUL_MFSPR",
 115         [EMULATED_MTMSR_EXITS] =    "EMUL_MTMSR",
 116         [EMULATED_MFMSR_EXITS] =    "EMUL_MFMSR",
 117         [EMULATED_TLBSX_EXITS] =    "EMUL_TLBSX",
 118         [EMULATED_TLBWE_EXITS] =    "EMUL_TLBWE",
 119         [EMULATED_RFI_EXITS] =      "EMUL_RFI",
 120         [DEC_EXITS] =               "DEC",
 121         [EXT_INTR_EXITS] =          "EXTINT",
 122         [HALT_WAKEUP] =             "HALT",
 123         [USR_PR_INST] =             "USR_PR_INST",
 124         [FP_UNAVAIL] =              "FP_UNAVAIL",
 125         [DEBUG_EXITS] =             "DEBUG",
 126         [TIMEINGUEST] =             "TIMEINGUEST"
 127 };
 128 
 129 static int kvmppc_exit_timing_show(struct seq_file *m, void *private)
 130 {
 131         struct kvm_vcpu *vcpu = m->private;
 132         int i;
 133         u64 min, max, sum, sum_quad;
 134 
 135         seq_puts(m, "type       count   min     max     sum     sum_squared\n");
 136 
 137         for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
 138 
 139                 min = vcpu->arch.timing_min_duration[i];
 140                 do_div(min, tb_ticks_per_usec);
 141                 max = vcpu->arch.timing_max_duration[i];
 142                 do_div(max, tb_ticks_per_usec);
 143                 sum = vcpu->arch.timing_sum_duration[i];
 144                 do_div(sum, tb_ticks_per_usec);
 145                 sum_quad = vcpu->arch.timing_sum_quad_duration[i];
 146                 do_div(sum_quad, tb_ticks_per_usec);
 147 
 148                 seq_printf(m, "%12s     %10d    %10lld  %10lld  %20lld  %20lld\n",
 149                         kvm_exit_names[i],
 150                         vcpu->arch.timing_count_type[i],
 151                         min,
 152                         max,
 153                         sum,
 154                         sum_quad);
 155 
 156         }
 157         return 0;
 158 }
 159 
 160 /* Write 'c' to clear the timing statistics. */
 161 static ssize_t kvmppc_exit_timing_write(struct file *file,
 162                                        const char __user *user_buf,
 163                                        size_t count, loff_t *ppos)
 164 {
 165         int err = -EINVAL;
 166         char c;
 167 
 168         if (count > 1) {
 169                 goto done;
 170         }
 171 
 172         if (get_user(c, user_buf)) {
 173                 err = -EFAULT;
 174                 goto done;
 175         }
 176 
 177         if (c == 'c') {
 178                 struct seq_file *seqf = file->private_data;
 179                 struct kvm_vcpu *vcpu = seqf->private;
 180                 /* Write does not affect our buffers previously generated with
 181                  * show. seq_file is locked here to prevent races of init with
 182                  * a show call */
 183                 mutex_lock(&seqf->lock);
 184                 kvmppc_init_timing_stats(vcpu);
 185                 mutex_unlock(&seqf->lock);
 186                 err = count;
 187         }
 188 
 189 done:
 190         return err;
 191 }
 192 
 193 static int kvmppc_exit_timing_open(struct inode *inode, struct file *file)
 194 {
 195         return single_open(file, kvmppc_exit_timing_show, inode->i_private);
 196 }
 197 
 198 static const struct file_operations kvmppc_exit_timing_fops = {
 199         .owner   = THIS_MODULE,
 200         .open    = kvmppc_exit_timing_open,
 201         .read    = seq_read,
 202         .write   = kvmppc_exit_timing_write,
 203         .llseek  = seq_lseek,
 204         .release = single_release,
 205 };
 206 
 207 void kvmppc_create_vcpu_debugfs(struct kvm_vcpu *vcpu, unsigned int id)
 208 {
 209         static char dbg_fname[50];
 210         struct dentry *debugfs_file;
 211 
 212         snprintf(dbg_fname, sizeof(dbg_fname), "vm%u_vcpu%u_timing",
 213                  current->pid, id);
 214         debugfs_file = debugfs_create_file(dbg_fname, 0666,
 215                                         kvm_debugfs_dir, vcpu,
 216                                         &kvmppc_exit_timing_fops);
 217 
 218         if (!debugfs_file) {
 219                 printk(KERN_ERR"%s: error creating debugfs file %s\n",
 220                         __func__, dbg_fname);
 221                 return;
 222         }
 223 
 224         vcpu->arch.debugfs_exit_timing = debugfs_file;
 225 }
 226 
 227 void kvmppc_remove_vcpu_debugfs(struct kvm_vcpu *vcpu)
 228 {
 229         if (vcpu->arch.debugfs_exit_timing) {
 230                 debugfs_remove(vcpu->arch.debugfs_exit_timing);
 231                 vcpu->arch.debugfs_exit_timing = NULL;
 232         }
 233 }

/* [<][>][^][v][top][bottom][index][help] */