mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Add some profiling support for writeable pagetables.
Signed-off-by: ian@xensource.com
This commit is contained in:
1 parent
ab7d21ef3a
commit
f34ffe2dfd
5 files changed
+163
-5
No files matched your search
+1
-1
@@ -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
|
||||
|
||||
+135
-2
@@ -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<ptwr_eip_buckets;i++)
|
||||
{
|
||||
int j;
|
||||
for(j=0;j<ptwr_eip_stat_thresholdN;j++)
|
||||
ptwr_eip_stats[i].val[j] =
|
||||
(((u64)ptwr_eip_stats[i].val[j])+1)>>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;j++)
|
||||
{
|
||||
if(modified <= ptwr_eip_stat_threshold[j])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
BUG_ON(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;i<ptwr_eip_buckets;i++)
|
||||
{
|
||||
if ( ptwr_eip_stats[i].eip && ptwr_eip_stats[i].id == d )
|
||||
{
|
||||
int j;
|
||||
printk("D %d eip %08lx ",
|
||||
ptwr_eip_stats[i].id, ptwr_eip_stats[i].eip );
|
||||
|
||||
for(j=0;j<ptwr_eip_stat_thresholdN;j++)
|
||||
printk("<=%u %4u \t",
|
||||
ptwr_eip_stat_threshold[j],
|
||||
ptwr_eip_stats[i].val[j] );
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* PERF_ARRAYS */
|
||||
|
||||
#define ptwr_eip_stat_update( eip, id, modified ) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
/* Re-validate a given p.t. page, given its prior snapshot */
|
||||
int revalidate_l1(
|
||||
struct domain *d, l1_pgentry_t *l1page, l1_pgentry_t *snapshot)
|
||||
@@ -2742,6 +2865,7 @@ void ptwr_flush(struct domain *d, const int which)
|
||||
modified = revalidate_l1(d, pl1e, d->arch.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 )
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xen/spinlock.h>
|
||||
#include <public/dom0_ops.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <xen/mm.h>
|
||||
|
||||
#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];
|
||||
|
||||
@@ -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);
|
||||
|
||||