From f34ffe2dfdd3a58cdb484870fb6c010faa82175d Mon Sep 17 00:00:00 2001 From: "iap10@freefall.cl.cam.ac.uk" Date: Sat, 13 Aug 2005 20:47:47 +0000 Subject: Add some profiling support for writeable pagetables. Signed-off-by: ian@xensource.com --- xen/Rules.mk | 2 +- xen/arch/x86/mm.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++- xen/arch/x86/traps.c | 2 +- xen/common/perfc.c | 9 ++++ xen/include/asm-x86/mm.h | 18 ++++++- 5 files changed, 163 insertions(+), 5 deletions(-) diff --git a/xen/Rules.mk b/xen/Rules.mk index d14d388017..dfa613f70f 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -2,7 +2,7 @@ # If you change any of these configuration options then you must # 'make clean' before rebuilding. # -verbose ?= n +verbose ?= y debug ?= n perfc ?= n perfc_arrays?= n diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index ff4de80b6b..8cbb7cb2d1 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2625,6 +2625,129 @@ int ptwr_debug = 0x0; #define PTWR_PRINTK(_f, _a...) ((void)0) #endif + +#ifdef PERF_ARRAYS + +/**************** writeable pagetables profiling functions *****************/ + +#define ptwr_eip_buckets 256 + +int ptwr_eip_stat_threshold[] = {1, 10, 50, 100, L1_PAGETABLE_ENTRIES}; + +#define ptwr_eip_stat_thresholdN (sizeof(ptwr_eip_stat_threshold)/sizeof(int)) + +struct { + unsigned long eip; + domid_t id; + u32 val[ptwr_eip_stat_thresholdN]; +} typedef ptwr_eip_stat_t; + +ptwr_eip_stat_t ptwr_eip_stats[ptwr_eip_buckets]; + +static inline unsigned int ptwr_eip_stat_hash( unsigned long eip, domid_t id ) +{ + return (((unsigned long) id) ^ eip ^ (eip>>8) ^ (eip>>16) ^ (eip>24)) % + ptwr_eip_buckets; +} + +static void ptwr_eip_stat_inc(u32 *n) +{ + (*n)++; + if(*n == 0) + { + (*n)=~0; + /* rescale all buckets */ + int i; + for(i=0;i>1; + } + } +} + +static void ptwr_eip_stat_update( unsigned long eip, domid_t id, int modified ) +{ + int i, b; + + i = b = ptwr_eip_stat_hash( eip, id ); + + do + { + if (!ptwr_eip_stats[i].eip) + { /* doesn't exist */ + ptwr_eip_stats[i].eip = eip; + ptwr_eip_stats[i].id = id; + memset(ptwr_eip_stats[i].val,0, sizeof(ptwr_eip_stats[i].val)); + } + + if (ptwr_eip_stats[i].eip == eip) + { + int j; + for(j=0;j=ptwr_eip_stat_thresholdN); + ptwr_eip_stat_inc(&(ptwr_eip_stats[i].val[j])); + return; + } + i = (i+1) % ptwr_eip_buckets; + } + while(i!=b); + + printk("ptwr_eip_stat: too many EIPs in use!\n"); + + ptwr_eip_stat_print(); + ptwr_eip_stat_reset(); +} + +void ptwr_eip_stat_reset() +{ + memset( ptwr_eip_stats, 0, sizeof(ptwr_eip_stats)); +} + +void ptwr_eip_stat_print() +{ + struct domain *e; + domid_t d; + + for_each_domain(e) + { + int i; + d = e->domain_id; + + for(i=0;iarch.ptwr[which].page); unmap_domain_page(pl1e); perfc_incr_histo(wpt_updates, modified, PT_UPDATES); + ptwr_eip_stat_update( d->arch.ptwr[which].eip, d->domain_id, modified); d->arch.ptwr[which].prev_nr_updates = modified; /* @@ -2897,7 +3021,8 @@ static struct x86_mem_emulator ptwr_mem_emulator = { }; /* Write page fault handler: check if guest is trying to modify a PTE. */ -int ptwr_do_page_fault(struct domain *d, unsigned long addr) +int ptwr_do_page_fault(struct domain *d, unsigned long addr, + struct cpu_user_regs *regs) { unsigned long pfn; struct pfn_info *page; @@ -2933,6 +3058,10 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr) return 0; } +#if 0 /* Leave this in as useful for debugging */ + goto emulate; +#endif + /* Get the L2 index at which this L1 p.t. is always mapped. */ l2_idx = page->u.inuse.type_info & PGT_va_mask; if ( unlikely(l2_idx >= PGT_va_unknown) ) @@ -3002,7 +3131,11 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr) d->arch.ptwr[which].l1va = addr | 1; d->arch.ptwr[which].l2_idx = l2_idx; d->arch.ptwr[which].vcpu = current; - + +#ifdef PERF_ARRAYS + d->arch.ptwr[which].eip = regs->eip; +#endif + /* For safety, disconnect the L1 p.t. page from current space. */ if ( which == PTWR_PT_ACTIVE ) { diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index d3878cb1b8..8d5f08e060 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -438,7 +438,7 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) && KERNEL_MODE(v, regs) && ((regs->error_code & 3) == 3) && /* write-protection fault */ - ptwr_do_page_fault(d, addr) ) + ptwr_do_page_fault(d, addr, regs) ) { UNLOCK_BIGLOCK(d); return EXCRET_fault_fixed; diff --git a/xen/common/perfc.c b/xen/common/perfc.c index 7363fb98c7..afb9af0bfa 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -7,6 +7,7 @@ #include #include #include +#include #undef PERFCOUNTER #undef PERFCOUNTER_CPU @@ -81,6 +82,10 @@ void perfc_printall(unsigned char key) } printk("\n"); } + +#ifdef PERF_ARRAYS + ptwr_eip_stat_print(); +#endif } void perfc_reset(unsigned char key) @@ -118,6 +123,10 @@ void perfc_reset(unsigned char key) break; } } + +#ifdef PERF_ARRAYS + ptwr_eip_stat_reset(); +#endif } static dom0_perfc_desc_t perfc_d[NR_PERFCTRS]; diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index f50b4d8028..505481253e 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -316,6 +316,9 @@ struct ptwr_info { unsigned int prev_nr_updates; /* Exec domain which created writable mapping. */ struct vcpu *vcpu; + /* EIP of the address which took the original write fault + used for stats collection only */ + unsigned long eip; }; #define PTWR_PT_ACTIVE 0 @@ -327,7 +330,8 @@ struct ptwr_info { int ptwr_init(struct domain *); void ptwr_destroy(struct domain *); void ptwr_flush(struct domain *, const int); -int ptwr_do_page_fault(struct domain *, unsigned long); +int ptwr_do_page_fault(struct domain *, unsigned long, + struct cpu_user_regs *); int revalidate_l1(struct domain *, l1_pgentry_t *, l1_pgentry_t *); void cleanup_writable_pagetable(struct domain *d); @@ -353,6 +357,18 @@ void audit_domains(void); #endif +#ifdef PERF_ARRAYS + +void ptwr_eip_stat_reset(); +void ptwr_eip_stat_print(); + +#else + +#define ptwr_eip_stat_reset() ((void)0) +#define ptwr_eip_stat_print() ((void)0) + +#endif + int new_guest_cr3(unsigned long pfn); void propagate_page_fault(unsigned long addr, u16 error_code); -- cgit v1.2.3