aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2007-01-11 02:15:38 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2007-01-11 21:18:21 -0500
commit07031e14c1127fc7e1a5b98dfcc59f434e025104 (patch)
treebe4f545e674c529abb0f51c8b87e1f7137c9acb6
parente3881a6816b45668df60a426e5c3431ece1539a7 (diff)
[PATCH] KVM: add VM-exit profiling
This adds the profile=kvm boot option, which enables KVM to profile VM exits. Use: "readprofile -m ./System.map | sort -n" to see the resulting output: [...] 18246 serial_out 148.3415 18945 native_flush_tlb 378.9000 23618 serial_in 212.7748 29279 __spin_unlock_irq 622.9574 43447 native_apic_write 2068.9048 52702 enable_8259A_irq 742.2817 54250 vgacon_scroll 89.3740 67394 ide_inb 6126.7273 79514 copy_page_range 98.1654 84868 do_wp_page 86.6000 140266 pit_read 783.6089 151436 ide_outb 25239.3333 152668 native_io_delay 21809.7143 174783 mask_and_ack_8259A 783.7803 362404 native_set_pte_at 36240.4000 1688747 total 0.5009 Signed-off-by: Ingo Molnar <mingo@elte.hu> Acked-by: Avi Kivity <avi@qumranet.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/kvm/svm.c8
-rw-r--r--drivers/kvm/vmx.c7
-rw-r--r--include/linux/profile.h1
-rw-r--r--kernel/profile.c14
4 files changed, 30 insertions, 0 deletions
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index ccc06b1b91b5..714f6a7841cd 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -17,6 +17,7 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/vmalloc.h> 18#include <linux/vmalloc.h>
19#include <linux/highmem.h> 19#include <linux/highmem.h>
20#include <linux/profile.h>
20#include <asm/desc.h> 21#include <asm/desc.h>
21 22
22#include "kvm_svm.h" 23#include "kvm_svm.h"
@@ -1558,6 +1559,13 @@ again:
1558 1559
1559 reload_tss(vcpu); 1560 reload_tss(vcpu);
1560 1561
1562 /*
1563 * Profile KVM exit RIPs:
1564 */
1565 if (unlikely(prof_on == KVM_PROFILING))
1566 profile_hit(KVM_PROFILING,
1567 (void *)(unsigned long)vcpu->svm->vmcb->save.rip);
1568
1561 stgi(); 1569 stgi();
1562 1570
1563 kvm_reput_irq(vcpu); 1571 kvm_reput_irq(vcpu);
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index d4701cb4c654..ce219e3f557f 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -21,6 +21,7 @@
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/mm.h> 22#include <linux/mm.h>
23#include <linux/highmem.h> 23#include <linux/highmem.h>
24#include <linux/profile.h>
24#include <asm/io.h> 25#include <asm/io.h>
25#include <asm/desc.h> 26#include <asm/desc.h>
26 27
@@ -1859,6 +1860,12 @@ again:
1859 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); 1860 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
1860#endif 1861#endif
1861 1862
1863 /*
1864 * Profile KVM exit RIPs:
1865 */
1866 if (unlikely(prof_on == KVM_PROFILING))
1867 profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
1868
1862 kvm_run->exit_type = 0; 1869 kvm_run->exit_type = 0;
1863 if (fail) { 1870 if (fail) {
1864 kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; 1871 kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
diff --git a/include/linux/profile.h b/include/linux/profile.h
index 5670b340c4ef..eec48f5f9348 100644
--- a/include/linux/profile.h
+++ b/include/linux/profile.h
@@ -15,6 +15,7 @@ extern int prof_on __read_mostly;
15#define CPU_PROFILING 1 15#define CPU_PROFILING 1
16#define SCHED_PROFILING 2 16#define SCHED_PROFILING 2
17#define SLEEP_PROFILING 3 17#define SLEEP_PROFILING 3
18#define KVM_PROFILING 4
18 19
19struct proc_dir_entry; 20struct proc_dir_entry;
20struct pt_regs; 21struct pt_regs;
diff --git a/kernel/profile.c b/kernel/profile.c
index 11550b2290b6..a6574a18514e 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -40,7 +40,10 @@ int (*timer_hook)(struct pt_regs *) __read_mostly;
40 40
41static atomic_t *prof_buffer; 41static atomic_t *prof_buffer;
42static unsigned long prof_len, prof_shift; 42static unsigned long prof_len, prof_shift;
43
43int prof_on __read_mostly; 44int prof_on __read_mostly;
45EXPORT_SYMBOL_GPL(prof_on);
46
44static cpumask_t prof_cpu_mask = CPU_MASK_ALL; 47static cpumask_t prof_cpu_mask = CPU_MASK_ALL;
45#ifdef CONFIG_SMP 48#ifdef CONFIG_SMP
46static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits); 49static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
@@ -52,6 +55,7 @@ static int __init profile_setup(char * str)
52{ 55{
53 static char __initdata schedstr[] = "schedule"; 56 static char __initdata schedstr[] = "schedule";
54 static char __initdata sleepstr[] = "sleep"; 57 static char __initdata sleepstr[] = "sleep";
58 static char __initdata kvmstr[] = "kvm";
55 int par; 59 int par;
56 60
57 if (!strncmp(str, sleepstr, strlen(sleepstr))) { 61 if (!strncmp(str, sleepstr, strlen(sleepstr))) {
@@ -72,6 +76,15 @@ static int __init profile_setup(char * str)
72 printk(KERN_INFO 76 printk(KERN_INFO
73 "kernel schedule profiling enabled (shift: %ld)\n", 77 "kernel schedule profiling enabled (shift: %ld)\n",
74 prof_shift); 78 prof_shift);
79 } else if (!strncmp(str, kvmstr, strlen(kvmstr))) {
80 prof_on = KVM_PROFILING;
81 if (str[strlen(kvmstr)] == ',')
82 str += strlen(kvmstr) + 1;
83 if (get_option(&str, &par))
84 prof_shift = par;
85 printk(KERN_INFO
86 "kernel KVM profiling enabled (shift: %ld)\n",
87 prof_shift);
75 } else if (get_option(&str, &par)) { 88 } else if (get_option(&str, &par)) {
76 prof_shift = par; 89 prof_shift = par;
77 prof_on = CPU_PROFILING; 90 prof_on = CPU_PROFILING;
@@ -318,6 +331,7 @@ out:
318 local_irq_restore(flags); 331 local_irq_restore(flags);
319 put_cpu(); 332 put_cpu();
320} 333}
334EXPORT_SYMBOL_GPL(profile_hits);
321 335
322static int __devinit profile_cpu_callback(struct notifier_block *info, 336static int __devinit profile_cpu_callback(struct notifier_block *info,
323 unsigned long action, void *__cpu) 337 unsigned long action, void *__cpu)