Re: exit timing analysis v1 - comments&discussions welcome

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Today I refactored my code in a way that it might eventually get upstream.
That means I removed some debug blocks, made it configurable and print output only on request per sysrq. Feel free to review that code now, otherwise wait for my separate rfc post that will follow ~next week.

Additionally I realized in a discussion that my host system was still configured in demo mode (X11+xfce, dhcpd, avahi, ... running in host). I took some updated numbers without all those background activities - testacase again boot, login, ls, kill.

I intend to the irq path in detail as suggested and first of all I'll try to get some timing of the "segments" of such a call. This should show us where we loose our "constant base time" and give me some hints when looking at it in detail.

FYI - new numbers without high background load (monospace recommended):
NOPV:
MMIO count 10105 min 46 max 1534 sum 2952467 avg 292.1788 stddev 295.933 % 2.04 DCR count 5428 min 40 max 209 sum 246168 avg 45.3515 stddev 6.758 % 0.17 SIGNAL count 695 min 65 max 3755 sum 89767 avg 129.1612 stddev 314.421 % 0.06 ITLBREAL count 80045 min 13 max 108 sum 1063127 avg 13.2816 stddev 2.338 % 0.73 ITLBVIRT count 1000585 min 21 max 264827 sum 24300596 avg 24.2864 stddev 264.753 % 16.78 DTLBREAL count 91206 min 13 max 69 sum 1285214 avg 14.0913 stddev 2.225 % 0.89 DTLBVIRT count 977434 min 21 max 1446 sum 24007008 avg 24.5613 stddev 4.426 % 16.58 SYSCALL count 10460 min 11 max 55 sum 116447 avg 11.1326 stddev 1.929 % 0.08 ISI count 11724 min 11 max 61 sum 130007 avg 11.0890 stddev 1.929 % 0.09 DSI count 20737 min 11 max 57 sum 230009 avg 11.0917 stddev 1.914 % 0.16 EMULINST count 5683356 min 11 max 3778 sum 79339467 avg 13.9600 stddev 50.275 % 54.78 DEC count 13079 min 50 max 826 sum 732712 avg 56.0220 stddev 22.382 % 0.51 EXTINT count 55 min 30 max 1478 sum 10996 avg 199.9273 stddev 238.150 % 0.01 FP_UNAVAIL count 280 min 11 max 53 sum 3163 avg 11.2964 stddev 3.495 % 0.00 TIMEINGUEST count 7905189 min 0 max 3688 sum 10330742 avg 1.3068 stddev 8.970 % 7.13 csum 15810378 sumsum 144837890 => ~2:24 runtime sumavg 7241894

PV:
MMIO count 12505 min 46 max 3087 sum 3693782 avg 295.3844 stddev 260.788 % 4.01 DCR count 5595 min 40 max 706 sum 273578 avg 48.8969 stddev 31.305 % 0.30 SIGNAL count 654 min 65 max 4132 sum 300027 avg 458.7569 stddev 571.130 % 0.33 ITLBREAL count 71711 min 13 max 104 sum 943053 avg 13.1507 stddev 2.360 % 1.02 ITLBVIRT count 750649 min 21 max 1503 sum 18178245 avg 24.2167 stddev 7.335 % 19.71 DTLBREAL count 83356 min 13 max 102 sum 1146242 avg 13.7512 stddev 2.406 % 1.24 DTLBPV count 30086 min 20 max 237 sum 653556 avg 21.7229 stddev 4.639 % 0.71 DTLBVIRT count 772811 min 21 max 713 sum 19079477 avg 24.6884 stddev 6.593 % 20.69 SYSCALL count 7647 min 11 max 57 sum 84821 avg 11.0921 stddev 1.897 % 0.09 HCALL count 1 min 19 max 19 sum 19 avg 19.0000 stddev 0.000 % 0.00 ISI count 9895 min 11 max 73 sum 109667 avg 11.0831 stddev 1.904 % 0.12 DSI count 17974 min 10 max 57 sum 199504 avg 11.0996 stddev 2.046 % 0.22 EMULINST count 2567245 min 11 max 4212 sum 40501314 avg 15.7762 stddev 65.673 % 43.92 DEC count 7488 min 51 max 641 sum 426813 avg 56.9996 stddev 23.893 % 0.46 EXTINT count 2215 min 31 max 1677 sum 297495 avg 134.3093 stddev 116.219 % 0.32 FP_UNAVAIL count 258 min 11 max 11 sum 2838 avg 11.0000 stddev 0.000 % 0.00 TIMEINGUEST count 4340090 min 0 max 3850 sum 6316079 avg 1.4553 stddev 12.599 % 6.85 csum 8680180 sumsum 92206510 => ~1:32 runtime sumavg 4610325

Hollis Blanchard wrote:
On Thu, 2008-09-25 at 17:32 +0800, Liu Yu-B13201 wrote:
On Wed, 2008-09-24 at 11:24 +0200, Christian Ehrhardt wrote:
count min max sum avg stddev time% EMULINST 6,423,699 12 247,582
91,732,705
14.2804       241.200     45.36
ITLBVIRT 1,777,242 21 264,257
47,116,557
26.5111       286.040     23.30
DTLBVIRT 1,544,241 22 263,947
41,765,447
27.0459       218.997     20.65
(The max here is of course when the guest was de-scheduled in favor of
another host process.)

I think it's interesting that the min instruction emulation time is 12
usecs. In fact, our "null" exits where we do almost no processing (ISI,
DSI, syscall) are 11 usecs, which suggests we have a problem with
interrupt handler overhead (for all exit types).

Will you consider about moving tlb manipulation out of entering path?
Examining the modify array may cost some time.

Yes, definitely.

That's about the only thing I can see in the 440 interrupt path that
might take significant time. Unfortunately we can't profile that code
because we have no performance counters, so finding the problem will
require some experimentation.


--

Grüsse / regards, Christian Ehrhardt
IBM Linux Technology Center, Open Virtualization

diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -348,5 +348,12 @@
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif
 
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+	DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, arch.timing_exit.tv32.tbu));
+	DEFINE(VCPU_TIMING_EXIT_TBL, offsetof(struct kvm_vcpu, arch.timing_exit.tv32.tbl));
+	DEFINE(VCPU_TIMING_LAST_ENTER_TBU, offsetof(struct kvm_vcpu, arch.timing_last_enter.tv32.tbu));
+	DEFINE(VCPU_TIMING_LAST_ENTER_TBL, offsetof(struct kvm_vcpu, arch.timing_last_enter.tv32.tbl));
+#endif
+
 	return 0;
 }
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -37,6 +37,14 @@
 	  Provides host support for KVM on Book E PowerPC processors. Currently
 	  this works on 440 processors only.
 
+config KVM_BOOKE_EXIT_TIMING
+	bool "Trace detailed exit Timing"
+	depends on KVM_BOOKE_HOST
+	---help---
+	  Inserts code to trace timestamps for every exit/enter cycle. A report
+	  can be triggered using debugfs entry TODO.
+	  This adds overhead, it's not recommended for production environments.
+
 config KVM_TRACE
 	bool "KVM trace support"
 	depends on KVM && MARKERS && SYSFS
diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c
--- a/arch/powerpc/kvm/booke_guest.c
+++ b/arch/powerpc/kvm/booke_guest.c
@@ -56,6 +56,21 @@
 	{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
 	{ NULL }
 };
+
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+u32 last_exit_type;
+u32 timing_count_type[__NUMBER_OF_KVM_EXIT_TYPES];
+u64 timing_sum_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+u64 timing_sum_quad_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+u64 timing_min_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+u64 timing_max_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+u64 timing_last_exit;
+struct sysrq_key_op trigger_print_exit_timing_op = {
+        .handler        = print_exit_timing_handler,
+        .help_msg       = "Print KVm PowerPC exit timings",
+        .action_msg     = "Printing KVM PowerPC exit timings",
+};
+#endif
 
 static const u32 interrupt_msr_mask[16] = {
 	[BOOKE_INTERRUPT_CRITICAL]      = MSR_ME,
@@ -261,6 +276,9 @@
 	enum emulation_result er;
 	int r = RESUME_HOST;
 
+	/* update before a new last_exit_type is written */
+	update_exit_timing(&(vcpu->arch));
+
 	local_irq_enable();
 
 	run->exit_reason = KVM_EXIT_UNKNOWN;
@@ -285,10 +303,13 @@
 		 * misses before ceding control. */
 		if (need_resched())
 			cond_resched();
-		if (exit_nr == BOOKE_INTERRUPT_DECREMENTER)
+		if (exit_nr == BOOKE_INTERRUPT_DECREMENTER) {
 			vcpu->stat.dec_exits++;
-		else
+			set_last_exit_type(DEC_EXITS);
+		} else {
 			vcpu->stat.ext_intr_exits++;
+			set_last_exit_type(EXT_INTR_EXITS);
+		}
 		r = RESUME_GUEST;
 		break;
 
@@ -299,6 +320,7 @@
 			vcpu->arch.esr = vcpu->arch.fault_esr;
 			kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM);
 			r = RESUME_GUEST;
+			set_last_exit_type(USR_PR_INST);
 			break;
 		}
 
@@ -308,10 +330,12 @@
 			/* Future optimization: only reload non-volatiles if
 			 * they were actually modified by emulation. */
 			vcpu->stat.emulated_inst_exits++;
+			set_last_exit_type(EMULATED_INST_EXITS);
 			r = RESUME_GUEST_NV;
 			break;
 		case EMULATE_DO_DCR:
 			run->exit_reason = KVM_EXIT_DCR;
+			set_last_exit_type(DCR_EXITS);
 			r = RESUME_HOST;
 			break;
 		case EMULATE_FAIL:
@@ -331,6 +355,7 @@
 
 	case BOOKE_INTERRUPT_FP_UNAVAIL:
 		kvmppc_queue_exception(vcpu, exit_nr);
+		set_last_exit_type(FP_UNAVAIL);
 		r = RESUME_GUEST;
 		break;
 
@@ -339,6 +364,7 @@
 		vcpu->arch.esr = vcpu->arch.fault_esr;
 		kvmppc_queue_exception(vcpu, exit_nr);
 		vcpu->stat.dsi_exits++;
+		set_last_exit_type(DSI_EXITS);
 		r = RESUME_GUEST;
 		break;
 
@@ -346,6 +372,7 @@
 		vcpu->arch.esr = vcpu->arch.fault_esr;
 		kvmppc_queue_exception(vcpu, exit_nr);
 		vcpu->stat.isi_exits++;
+		set_last_exit_type(ISI_EXITS);
 		r = RESUME_GUEST;
 		break;
 
@@ -353,9 +380,11 @@
 		if (vcpu->arch.last_inst == KVM_HYPERCALL_BIN) {
 			kvmppc_do_hypercall(vcpu);
 			vcpu->stat.hcall_exits++;
+			set_last_exit_type(HCALL_EXITS);
 		} else {
 			kvmppc_queue_exception(vcpu, exit_nr);
 			vcpu->stat.syscall_exits++;
+			set_last_exit_type(SYSCALL_EXITS);
 		}
 		r = RESUME_GUEST;
 		break;
@@ -370,6 +399,7 @@
 			 vcpu->arch.pvmem_gpaddr >> KVM_PPCPV_MAGIC_PAGE_SHIFT,
 			 0, KVM_PPCPV_MAGIC_PAGE_FLAGS);
 			vcpu->stat.dtlb_pvmem_miss_exits++;
+			set_last_exit_type(DTLB_PVMEM_MISS_EXITS);
 			r = RESUME_GUEST;
 			break;
 		}
@@ -382,6 +412,7 @@
 			vcpu->arch.dear = vcpu->arch.fault_dear;
 			vcpu->arch.esr = vcpu->arch.fault_esr;
 			vcpu->stat.dtlb_real_miss_exits++;
+			set_last_exit_type(DTLB_REAL_MISS_EXITS);
 			r = RESUME_GUEST;
 			break;
 		}
@@ -399,11 +430,13 @@
 			kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
 			               gtlbe->word2);
 			vcpu->stat.dtlb_virt_miss_exits++;
+			set_last_exit_type(DTLB_VIRT_MISS_EXITS);
 			r = RESUME_GUEST;
 		} else {
 			/* Guest has mapped and accessed a page which is not
 			 * actually RAM. */
 			r = kvmppc_emulate_mmio(run, vcpu);
+			set_last_exit_type(MMIO_EXITS);
 		}
 
 		break;
@@ -422,10 +455,12 @@
 			/* The guest didn't have a mapping for it. */
 			kvmppc_queue_exception(vcpu, exit_nr);
 			vcpu->stat.itlb_real_miss_exits++;
+			set_last_exit_type(ITLB_REAL_MISS_EXITS);
 			break;
 		}
 
 		vcpu->stat.itlb_virt_miss_exits++;
+		set_last_exit_type(ITLB_VIRT_MISS_EXITS);
 
 		gfn = tlb_xlate(gtlbe, eaddr) >> PAGE_SHIFT;
 
@@ -458,6 +493,7 @@
 		mtspr(SPRN_DBSR, dbsr);
 
 		run->exit_reason = KVM_EXIT_DEBUG;
+		set_last_exit_type(DEBUG_EXITS);
 		r = RESUME_HOST;
 		break;
 	}
@@ -482,6 +518,7 @@
 			r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
 
 			vcpu->stat.signal_exits++;
+			set_last_exit_type(SIGNAL_EXITS);
 		} else {
 			vcpu->stat.light_exits++;
 		}
@@ -495,6 +532,7 @@
 			break;
 		case KVM_EXIT_INTR:
 			vcpu->stat.signal_exits++;
+			set_last_exit_type(SIGNAL_EXITS);
 			break;
 		}
 	}
@@ -535,6 +573,8 @@
 	 * real timebase frequency. Accordingly, it must see the state of
 	 * CCR1[TCS]. */
 	vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
+
+	init_exit_timing(&(vcpu->arch));
 
 	return 0;
 }
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -109,6 +109,18 @@
 
 	li	r6, 1
 	slw	r6, r6, r5
+
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+	/* save exit time */
+..exit_tbu_overflow_loop:
+	mfspr	r7, SPRN_TBRU
+	mfspr	r8, SPRN_TBRL
+	mfspr	r9, SPRN_TBRU
+	cmpw	r9, r7
+	bne	..exit_tbu_overflow_loop
+	stw	r8, VCPU_TIMING_EXIT_TBL(r4)
+	stw	r9, VCPU_TIMING_EXIT_TBU(r4)
+#endif
 
 	/* Save the faulting instruction and all GPRs for emulation. */
 	andi.	r7, r6, NEED_INST_MASK
@@ -415,6 +427,18 @@
 	lwz	r3, VCPU_SPRG7(r4)
 	mtspr	SPRN_SPRG7, r3
 
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+	/* save enter time */
+..enter_tbu_overflow_loop:
+	mfspr	r6, SPRN_TBRU
+	mfspr	r7, SPRN_TBRL
+	mfspr	r8, SPRN_TBRU
+	cmpw	r8, r6
+	bne	..enter_tbu_overflow_loop
+	stw	r7, VCPU_TIMING_LAST_ENTER_TBL(r4)
+	stw	r8, VCPU_TIMING_LAST_ENTER_TBU(r4)
+#endif
+
 	/* Finish loading guest volatiles and jump to guest. */
 	lwz	r3, VCPU_CTR(r4)
 	mtctr	r3
diff --git a/include/asm-powerpc/kvm_host.h b/include/asm-powerpc/kvm_host.h
--- a/include/asm-powerpc/kvm_host.h
+++ b/include/asm-powerpc/kvm_host.h
@@ -25,6 +25,12 @@
 #include <linux/types.h>
 #include <linux/kvm_types.h>
 #include <asm/kvm_asm.h>
+
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+#include <asm/time.h>
+#include <asm-generic/div64.h>
+#include <linux/sysrq.h>
+#endif
 
 #define KVM_MAX_VCPUS 1
 #define KVM_MEMORY_SLOTS 32
@@ -66,6 +72,55 @@
 	u32 halt_wakeup;
 };
 
+enum kvm_exit_types {
+	MMIO_EXITS,
+	DCR_EXITS,
+	SIGNAL_EXITS,
+	ITLB_REAL_MISS_EXITS,
+	ITLB_VIRT_MISS_EXITS,
+	DTLB_REAL_MISS_EXITS,
+	DTLB_PVMEM_MISS_EXITS,
+	DTLB_VIRT_MISS_EXITS,
+	SYSCALL_EXITS,
+	HCALL_EXITS,
+	ISI_EXITS,
+	DSI_EXITS,
+	EMULATED_INST_EXITS,
+	DEC_EXITS,
+	EXT_INTR_EXITS,
+	HALT_WAKEUP,
+	USR_PR_INST,
+	FP_UNAVAIL,
+	DEBUG_EXITS,
+	TIMEINGUEST,
+	__NUMBER_OF_KVM_EXIT_TYPES
+};
+
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+static const char* kvm_exit_names[__NUMBER_OF_KVM_EXIT_TYPES] = {
+	"MMIO",
+	"DCR",
+	"SIGNAL",
+	"ITLBREAL",
+	"ITLBVIRT",
+	"DTLBREAL",
+	"DTLBPV",
+	"DTLBVIRT",
+	"SYSCALL",
+	"HCALL",
+	"ISI",
+	"DSI",
+	"EMULINST",
+	"DEC",
+	"EXTINT",
+	"HALT",
+	"USR_PR_INST",
+	"FP_UNAVAIL",
+	"DEBUG",
+	"TIMEINGUEST"
+};
+#endif
+
 struct tlbe {
 	u32 tid; /* Only the low 8 bits are used. */
 	u32 word0;
@@ -75,6 +130,16 @@
 
 struct kvm_arch {
 };
+
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+/* allow access to big endian 32bit upper/lower parts and 64bit var */
+typedef union {
+	u64 tv64;
+	struct {
+		u32 tbu, tbl;
+	} tv32;
+} exit_timing_t;
+#endif
 
 struct kvm_vcpu_arch {
 	/* Unmodified copy of the guest's TLB. */
@@ -139,6 +204,11 @@
 	u32 dbcr0;
 	u32 dbcr1;
 
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+	exit_timing_t timing_exit;
+	exit_timing_t timing_last_enter;
+#endif
+
 	u32 last_inst;
 	u32 fault_dear;
 	u32 fault_esr;
@@ -165,4 +235,131 @@
 	int singlestep;
 };
 
+#ifdef CONFIG_KVM_BOOKE_EXIT_TIMING
+/* helpers for instruction timing, allocated in arch/powerpc/kvm/powerpc.c */
+extern u32 last_exit_type;
+extern u32 timing_count_type[__NUMBER_OF_KVM_EXIT_TYPES];
+extern u64 timing_sum_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+extern u64 timing_sum_quad_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+extern u64 timing_min_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+extern u64 timing_max_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+extern u64 timing_last_exit;
+extern struct sysrq_key_op trigger_print_exit_timing_op;
+
+static void print_exit_timing_handler(int key, struct tty_struct *tty)
+{
+	int i;
+	u64 min, max;
+
+	printk(KERN_ERR"### start exit timing statistics ###\n");
+	for (i=0; i<__NUMBER_OF_KVM_EXIT_TYPES; i++) {
+		if (timing_min_duration[i]==0xFFFFFFFF)
+			min = 0;
+		else
+			min = timing_min_duration[i];
+		if (timing_max_duration[i]==0)
+			max = 0;
+		else
+			max = timing_max_duration[i];
+
+		printk(KERN_ERR"exit type %2d (%12s) count %10d min %10lld max %10lld sum %20lld sum_quad %20lld\n",
+				i, kvm_exit_names[i], timing_count_type[i], timing_min_duration[i], timing_max_duration[i],
+				timing_sum_duration[i], timing_sum_quad_duration[i]);
+	}
+	printk(KERN_ERR"please post calc: avg = sum/count; stddev = sqrt((sum_quad/count)-(sum_dur/count)²)\n");
+	printk(KERN_ERR"### end exit timing statistics ###\n");
+}
+
+static inline void print_exit_timing(void) {
+	print_exit_timing_handler(0,NULL);
+}
+
+static inline void init_exit_timing(struct kvm_vcpu_arch* vcpu_arch)
+{
+	int i;
+
+	last_exit_type=0xDEAD;
+	for (i=0; i<__NUMBER_OF_KVM_EXIT_TYPES; i++) {
+		timing_count_type[i]=0;
+		timing_max_duration[i]=0;
+		timing_min_duration[i]=0xFFFFFFFF;
+		timing_sum_duration[i]=0;
+		timing_sum_quad_duration[i]=0;
+	}
+	vcpu_arch->timing_exit.tv64 = 0;
+	timing_last_exit = 0;
+	vcpu_arch->timing_last_enter.tv64 = 0;
+
+	if (register_sysrq_key('y', &trigger_print_exit_timing_op))
+		printk(KERN_ERR"%s - failed to register sysrq key\n", __func__);
+		
+/* TODO unregister_sysrq_key(int key, struct sysrq_key_op *op_p) */
+}
+
+static inline void set_last_exit_type(int type)
+{
+	last_exit_type=type;
+}
+
+static inline void add_exit_timing(u64 duration, int type)
+{
+	u64 old; 
+	
+	do_div(duration, tb_ticks_per_usec);
+	if (unlikely(duration > 0xFFFFFFFF)) {
+		printk(KERN_ERR"%s - duration too big, **2 would overflow duration %lld max 4294967295 type %d exit # of type %d (tb_ticks_per_usec=%ld)\n",
+				__func__, duration, type, timing_count_type[type], tb_ticks_per_usec);
+		print_exit_timing();
+	}
+		
+
+	timing_count_type[type]++;
+
+	/* sum */
+	old = timing_sum_duration[type];
+	timing_sum_duration[type] += duration;
+	if (unlikely(old > timing_sum_duration[type])) {
+		printk(KERN_ERR"%s - wraparound adding sum of durations old %lld new %lld type %d exit # of type %d\n",
+				__func__, old, timing_sum_duration[type], type, timing_count_type[type]);
+		print_exit_timing();
+	}
+
+	/* square sum */
+	old = timing_sum_quad_duration[type];
+	timing_sum_quad_duration[type] += (duration*duration);
+	if (unlikely(old > timing_sum_quad_duration[type])) {
+		printk(KERN_ERR"%s - wraparound adding sum of squared durations old %lld new %lld type %d exit # of type %d\n",
+				__func__, old, timing_sum_quad_duration[type], type, timing_count_type[type]);
+		print_exit_timing();
+	}
+
+	/* set min/max */
+	if (unlikely(duration < timing_min_duration[type]))
+		timing_min_duration[type] = duration;
+	if (unlikely(duration > timing_max_duration[type]))
+		timing_max_duration[type] = duration;
+}
+
+static inline void update_exit_timing(struct kvm_vcpu_arch* vcpu_arch)
+{
+	u64 exit = timing_last_exit;
+	u64 enter = vcpu_arch->timing_last_enter.tv64;
+
+	/* save exit time to use it next exit when the related enter time is known */
+	timing_last_exit = vcpu_arch->timing_exit.tv64;
+
+	if (unlikely(last_exit_type==0xDEAD))
+		return; /* skip first incomplete enter/exit cycle */
+
+	/* update statistics for average and standard deviation */
+	add_exit_timing((enter - exit), last_exit_type);
+	/* enter -> timing_last_exit is time spent in guest - log this too */
+	add_exit_timing((timing_last_exit - enter), TIMEINGUEST);
+}
+#else
+static inline void init_exit_timing(struct kvm_vcpu_arch* vcpu_arch) {}
+static inline void set_last_exit_type(int type) {}
+static inline void update_exit_timing(struct kvm_vcpu_arch* vcpu_arch) {}
+#endif /* CONFIG_KVM_BOOKE_EXIT_TIMING */
+
 #endif /* __POWERPC_KVM_HOST_H__ */

[Index of Archives]     [KVM Development]     [KVM ARM]     [KVM ia64]     [Linux Virtualization]     [Linux USB Devel]     [Linux Video]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux