aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-04-19 10:27:43 -0400
committerAvi Kivity <avi@qumranet.com>2007-05-03 03:52:30 -0400
commit1165f5fec18c077bdba88e7125fd41f8e3617cb4 (patch)
treea1931bfddfabaa909f4ebd14a5c00a549d1e37ec /drivers/kvm
parent3fca03653010b8c5fa63b99fc94c78cbfb433d00 (diff)
KVM: Per-vcpu statistics
Make the exit statistics per-vcpu instead of global. This gives a 3.5% boost when running one virtual machine per core on my two socket dual core (4 cores total) machine. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
-rw-r--r--drivers/kvm/kvm.h35
-rw-r--r--drivers/kvm/kvm_main.c61
-rw-r--r--drivers/kvm/mmu.c2
-rw-r--r--drivers/kvm/paging_tmpl.h2
-rw-r--r--drivers/kvm/svm.c14
-rw-r--r--drivers/kvm/vmx.c18
6 files changed, 79 insertions, 53 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index b9c318a9e334..d1a90c5d76ce 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -236,6 +236,22 @@ struct kvm_pio_request {
236 int rep; 236 int rep;
237}; 237};
238 238
239struct kvm_stat {
240 u32 pf_fixed;
241 u32 pf_guest;
242 u32 tlb_flush;
243 u32 invlpg;
244
245 u32 exits;
246 u32 io_exits;
247 u32 mmio_exits;
248 u32 signal_exits;
249 u32 irq_window_exits;
250 u32 halt_exits;
251 u32 request_irq_exits;
252 u32 irq_exits;
253};
254
239struct kvm_vcpu { 255struct kvm_vcpu {
240 struct kvm *kvm; 256 struct kvm *kvm;
241 union { 257 union {
@@ -298,6 +314,8 @@ struct kvm_vcpu {
298 int sigset_active; 314 int sigset_active;
299 sigset_t sigset; 315 sigset_t sigset;
300 316
317 struct kvm_stat stat;
318
301 struct { 319 struct {
302 int active; 320 int active;
303 u8 save_iopl; 321 u8 save_iopl;
@@ -347,22 +365,6 @@ struct kvm {
347 struct file *filp; 365 struct file *filp;
348}; 366};
349 367
350struct kvm_stat {
351 u32 pf_fixed;
352 u32 pf_guest;
353 u32 tlb_flush;
354 u32 invlpg;
355
356 u32 exits;
357 u32 io_exits;
358 u32 mmio_exits;
359 u32 signal_exits;
360 u32 irq_window_exits;
361 u32 halt_exits;
362 u32 request_irq_exits;
363 u32 irq_exits;
364};
365
366struct descriptor_table { 368struct descriptor_table {
367 u16 limit; 369 u16 limit;
368 unsigned long base; 370 unsigned long base;
@@ -424,7 +426,6 @@ struct kvm_arch_ops {
424 unsigned char *hypercall_addr); 426 unsigned char *hypercall_addr);
425}; 427};
426 428
427extern struct kvm_stat kvm_stat;
428extern struct kvm_arch_ops *kvm_arch_ops; 429extern struct kvm_arch_ops *kvm_arch_ops;
429 430
430#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) 431#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index f5356358acff..911c8175cc08 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -51,27 +51,27 @@ static DEFINE_SPINLOCK(kvm_lock);
51static LIST_HEAD(vm_list); 51static LIST_HEAD(vm_list);
52 52
53struct kvm_arch_ops *kvm_arch_ops; 53struct kvm_arch_ops *kvm_arch_ops;
54struct kvm_stat kvm_stat; 54
55EXPORT_SYMBOL_GPL(kvm_stat); 55#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
56 56
57static struct kvm_stats_debugfs_item { 57static struct kvm_stats_debugfs_item {
58 const char *name; 58 const char *name;
59 u32 *data; 59 int offset;
60 struct dentry *dentry; 60 struct dentry *dentry;
61} debugfs_entries[] = { 61} debugfs_entries[] = {
62 { "pf_fixed", &kvm_stat.pf_fixed }, 62 { "pf_fixed", STAT_OFFSET(pf_fixed) },
63 { "pf_guest", &kvm_stat.pf_guest }, 63 { "pf_guest", STAT_OFFSET(pf_guest) },
64 { "tlb_flush", &kvm_stat.tlb_flush }, 64 { "tlb_flush", STAT_OFFSET(tlb_flush) },
65 { "invlpg", &kvm_stat.invlpg }, 65 { "invlpg", STAT_OFFSET(invlpg) },
66 { "exits", &kvm_stat.exits }, 66 { "exits", STAT_OFFSET(exits) },
67 { "io_exits", &kvm_stat.io_exits }, 67 { "io_exits", STAT_OFFSET(io_exits) },
68 { "mmio_exits", &kvm_stat.mmio_exits }, 68 { "mmio_exits", STAT_OFFSET(mmio_exits) },
69 { "signal_exits", &kvm_stat.signal_exits }, 69 { "signal_exits", STAT_OFFSET(signal_exits) },
70 { "irq_window", &kvm_stat.irq_window_exits }, 70 { "irq_window", STAT_OFFSET(irq_window_exits) },
71 { "halt_exits", &kvm_stat.halt_exits }, 71 { "halt_exits", STAT_OFFSET(halt_exits) },
72 { "request_irq", &kvm_stat.request_irq_exits }, 72 { "request_irq", STAT_OFFSET(request_irq_exits) },
73 { "irq_exits", &kvm_stat.irq_exits }, 73 { "irq_exits", STAT_OFFSET(irq_exits) },
74 { NULL, NULL } 74 { NULL }
75}; 75};
76 76
77static struct dentry *debugfs_dir; 77static struct dentry *debugfs_dir;
@@ -2930,14 +2930,39 @@ static struct notifier_block kvm_cpu_notifier = {
2930 .priority = 20, /* must be > scheduler priority */ 2930 .priority = 20, /* must be > scheduler priority */
2931}; 2931};
2932 2932
2933static u64 stat_get(void *_offset)
2934{
2935 unsigned offset = (long)_offset;
2936 u64 total = 0;
2937 struct kvm *kvm;
2938 struct kvm_vcpu *vcpu;
2939 int i;
2940
2941 spin_lock(&kvm_lock);
2942 list_for_each_entry(kvm, &vm_list, vm_list)
2943 for (i = 0; i < KVM_MAX_VCPUS; ++i) {
2944 vcpu = &kvm->vcpus[i];
2945 total += *(u32 *)((void *)vcpu + offset);
2946 }
2947 spin_unlock(&kvm_lock);
2948 return total;
2949}
2950
2951static void stat_set(void *offset, u64 val)
2952{
2953}
2954
2955DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n");
2956
2933static __init void kvm_init_debug(void) 2957static __init void kvm_init_debug(void)
2934{ 2958{
2935 struct kvm_stats_debugfs_item *p; 2959 struct kvm_stats_debugfs_item *p;
2936 2960
2937 debugfs_dir = debugfs_create_dir("kvm", NULL); 2961 debugfs_dir = debugfs_create_dir("kvm", NULL);
2938 for (p = debugfs_entries; p->name; ++p) 2962 for (p = debugfs_entries; p->name; ++p)
2939 p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir, 2963 p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir,
2940 p->data); 2964 (void *)(long)p->offset,
2965 &stat_fops);
2941} 2966}
2942 2967
2943static void kvm_exit_debug(void) 2968static void kvm_exit_debug(void)
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 8ccf84e3fda8..32c64f682081 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -936,7 +936,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
936 936
937static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) 937static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
938{ 938{
939 ++kvm_stat.tlb_flush; 939 ++vcpu->stat.tlb_flush;
940 kvm_arch_ops->tlb_flush(vcpu); 940 kvm_arch_ops->tlb_flush(vcpu);
941} 941}
942 942
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index b94010dad809..73ffbffb1097 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -448,7 +448,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
448 if (is_io_pte(*shadow_pte)) 448 if (is_io_pte(*shadow_pte))
449 return 1; 449 return 1;
450 450
451 ++kvm_stat.pf_fixed; 451 ++vcpu->stat.pf_fixed;
452 kvm_mmu_audit(vcpu, "post page fault (fixed)"); 452 kvm_mmu_audit(vcpu, "post page fault (fixed)");
453 453
454 return write_pt; 454 return write_pt;
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 61ed7352e506..644efc5381ad 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -914,7 +914,7 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
914 case EMULATE_DONE: 914 case EMULATE_DONE:
915 return 1; 915 return 1;
916 case EMULATE_DO_MMIO: 916 case EMULATE_DO_MMIO:
917 ++kvm_stat.mmio_exits; 917 ++vcpu->stat.mmio_exits;
918 kvm_run->exit_reason = KVM_EXIT_MMIO; 918 kvm_run->exit_reason = KVM_EXIT_MMIO;
919 return 0; 919 return 0;
920 case EMULATE_FAIL: 920 case EMULATE_FAIL:
@@ -1054,7 +1054,7 @@ static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1054 unsigned long count; 1054 unsigned long count;
1055 gva_t address = 0; 1055 gva_t address = 0;
1056 1056
1057 ++kvm_stat.io_exits; 1057 ++vcpu->stat.io_exits;
1058 1058
1059 vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2; 1059 vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
1060 1060
@@ -1096,7 +1096,7 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1096 return 1; 1096 return 1;
1097 1097
1098 kvm_run->exit_reason = KVM_EXIT_HLT; 1098 kvm_run->exit_reason = KVM_EXIT_HLT;
1099 ++kvm_stat.halt_exits; 1099 ++vcpu->stat.halt_exits;
1100 return 0; 1100 return 0;
1101} 1101}
1102 1102
@@ -1264,7 +1264,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu,
1264 */ 1264 */
1265 if (kvm_run->request_interrupt_window && 1265 if (kvm_run->request_interrupt_window &&
1266 !vcpu->irq_summary) { 1266 !vcpu->irq_summary) {
1267 ++kvm_stat.irq_window_exits; 1267 ++vcpu->stat.irq_window_exits;
1268 kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; 1268 kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
1269 return 0; 1269 return 0;
1270 } 1270 }
@@ -1636,14 +1636,14 @@ again:
1636 r = handle_exit(vcpu, kvm_run); 1636 r = handle_exit(vcpu, kvm_run);
1637 if (r > 0) { 1637 if (r > 0) {
1638 if (signal_pending(current)) { 1638 if (signal_pending(current)) {
1639 ++kvm_stat.signal_exits; 1639 ++vcpu->stat.signal_exits;
1640 post_kvm_run_save(vcpu, kvm_run); 1640 post_kvm_run_save(vcpu, kvm_run);
1641 kvm_run->exit_reason = KVM_EXIT_INTR; 1641 kvm_run->exit_reason = KVM_EXIT_INTR;
1642 return -EINTR; 1642 return -EINTR;
1643 } 1643 }
1644 1644
1645 if (dm_request_for_irq_injection(vcpu, kvm_run)) { 1645 if (dm_request_for_irq_injection(vcpu, kvm_run)) {
1646 ++kvm_stat.request_irq_exits; 1646 ++vcpu->stat.request_irq_exits;
1647 post_kvm_run_save(vcpu, kvm_run); 1647 post_kvm_run_save(vcpu, kvm_run);
1648 kvm_run->exit_reason = KVM_EXIT_INTR; 1648 kvm_run->exit_reason = KVM_EXIT_INTR;
1649 return -EINTR; 1649 return -EINTR;
@@ -1672,7 +1672,7 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
1672{ 1672{
1673 uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info; 1673 uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
1674 1674
1675 ++kvm_stat.pf_guest; 1675 ++vcpu->stat.pf_guest;
1676 1676
1677 if (is_page_fault(exit_int_info)) { 1677 if (is_page_fault(exit_int_info)) {
1678 1678
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 37537af126d1..10845b7ff297 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1396,7 +1396,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1396 case EMULATE_DONE: 1396 case EMULATE_DONE:
1397 return 1; 1397 return 1;
1398 case EMULATE_DO_MMIO: 1398 case EMULATE_DO_MMIO:
1399 ++kvm_stat.mmio_exits; 1399 ++vcpu->stat.mmio_exits;
1400 kvm_run->exit_reason = KVM_EXIT_MMIO; 1400 kvm_run->exit_reason = KVM_EXIT_MMIO;
1401 return 0; 1401 return 0;
1402 case EMULATE_FAIL: 1402 case EMULATE_FAIL:
@@ -1425,7 +1425,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1425static int handle_external_interrupt(struct kvm_vcpu *vcpu, 1425static int handle_external_interrupt(struct kvm_vcpu *vcpu,
1426 struct kvm_run *kvm_run) 1426 struct kvm_run *kvm_run)
1427{ 1427{
1428 ++kvm_stat.irq_exits; 1428 ++vcpu->stat.irq_exits;
1429 return 1; 1429 return 1;
1430} 1430}
1431 1431
@@ -1492,7 +1492,7 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1492 unsigned long count; 1492 unsigned long count;
1493 gva_t address; 1493 gva_t address;
1494 1494
1495 ++kvm_stat.io_exits; 1495 ++vcpu->stat.io_exits;
1496 exit_qualification = vmcs_read64(EXIT_QUALIFICATION); 1496 exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
1497 in = (exit_qualification & 8) != 0; 1497 in = (exit_qualification & 8) != 0;
1498 size = (exit_qualification & 7) + 1; 1498 size = (exit_qualification & 7) + 1;
@@ -1682,7 +1682,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
1682 if (kvm_run->request_interrupt_window && 1682 if (kvm_run->request_interrupt_window &&
1683 !vcpu->irq_summary) { 1683 !vcpu->irq_summary) {
1684 kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; 1684 kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
1685 ++kvm_stat.irq_window_exits; 1685 ++vcpu->stat.irq_window_exits;
1686 return 0; 1686 return 0;
1687 } 1687 }
1688 return 1; 1688 return 1;
@@ -1695,7 +1695,7 @@ static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1695 return 1; 1695 return 1;
1696 1696
1697 kvm_run->exit_reason = KVM_EXIT_HLT; 1697 kvm_run->exit_reason = KVM_EXIT_HLT;
1698 ++kvm_stat.halt_exits; 1698 ++vcpu->stat.halt_exits;
1699 return 0; 1699 return 0;
1700} 1700}
1701 1701
@@ -1956,7 +1956,7 @@ again:
1956 1956
1957 reload_tss(); 1957 reload_tss();
1958 } 1958 }
1959 ++kvm_stat.exits; 1959 ++vcpu->stat.exits;
1960 1960
1961#ifdef CONFIG_X86_64 1961#ifdef CONFIG_X86_64
1962 if (is_long_mode(vcpu)) { 1962 if (is_long_mode(vcpu)) {
@@ -1988,14 +1988,14 @@ again:
1988 if (r > 0) { 1988 if (r > 0) {
1989 /* Give scheduler a change to reschedule. */ 1989 /* Give scheduler a change to reschedule. */
1990 if (signal_pending(current)) { 1990 if (signal_pending(current)) {
1991 ++kvm_stat.signal_exits; 1991 ++vcpu->stat.signal_exits;
1992 post_kvm_run_save(vcpu, kvm_run); 1992 post_kvm_run_save(vcpu, kvm_run);
1993 kvm_run->exit_reason = KVM_EXIT_INTR; 1993 kvm_run->exit_reason = KVM_EXIT_INTR;
1994 return -EINTR; 1994 return -EINTR;
1995 } 1995 }
1996 1996
1997 if (dm_request_for_irq_injection(vcpu, kvm_run)) { 1997 if (dm_request_for_irq_injection(vcpu, kvm_run)) {
1998 ++kvm_stat.request_irq_exits; 1998 ++vcpu->stat.request_irq_exits;
1999 post_kvm_run_save(vcpu, kvm_run); 1999 post_kvm_run_save(vcpu, kvm_run);
2000 kvm_run->exit_reason = KVM_EXIT_INTR; 2000 kvm_run->exit_reason = KVM_EXIT_INTR;
2001 return -EINTR; 2001 return -EINTR;
@@ -2021,7 +2021,7 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
2021{ 2021{
2022 u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); 2022 u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
2023 2023
2024 ++kvm_stat.pf_guest; 2024 ++vcpu->stat.pf_guest;
2025 2025
2026 if (is_page_fault(vect_info)) { 2026 if (is_page_fault(vect_info)) {
2027 printk(KERN_DEBUG "inject_page_fault: " 2027 printk(KERN_DEBUG "inject_page_fault: "