diff options
author | Avi Kivity <avi@qumranet.com> | 2007-04-19 10:27:43 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:30 -0400 |
commit | 1165f5fec18c077bdba88e7125fd41f8e3617cb4 (patch) | |
tree | a1931bfddfabaa909f4ebd14a5c00a549d1e37ec /drivers | |
parent | 3fca03653010b8c5fa63b99fc94c78cbfb433d00 (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')
-rw-r--r-- | drivers/kvm/kvm.h | 35 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 61 | ||||
-rw-r--r-- | drivers/kvm/mmu.c | 2 | ||||
-rw-r--r-- | drivers/kvm/paging_tmpl.h | 2 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 14 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 18 |
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 | ||
239 | struct 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 | |||
239 | struct kvm_vcpu { | 255 | struct 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 | ||
350 | struct 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 | |||
366 | struct descriptor_table { | 368 | struct 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 | ||
427 | extern struct kvm_stat kvm_stat; | ||
428 | extern struct kvm_arch_ops *kvm_arch_ops; | 429 | extern 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); | |||
51 | static LIST_HEAD(vm_list); | 51 | static LIST_HEAD(vm_list); |
52 | 52 | ||
53 | struct kvm_arch_ops *kvm_arch_ops; | 53 | struct kvm_arch_ops *kvm_arch_ops; |
54 | struct kvm_stat kvm_stat; | 54 | |
55 | EXPORT_SYMBOL_GPL(kvm_stat); | 55 | #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) |
56 | 56 | ||
57 | static struct kvm_stats_debugfs_item { | 57 | static 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 | ||
77 | static struct dentry *debugfs_dir; | 77 | static 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 | ||
2933 | static 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 | |||
2951 | static void stat_set(void *offset, u64 val) | ||
2952 | { | ||
2953 | } | ||
2954 | |||
2955 | DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n"); | ||
2956 | |||
2933 | static __init void kvm_init_debug(void) | 2957 | static __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 | ||
2943 | static void kvm_exit_debug(void) | 2968 | static 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 | ||
937 | static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) | 937 | static 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) | |||
1425 | static int handle_external_interrupt(struct kvm_vcpu *vcpu, | 1425 | static 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: " |