Clearing out my local queue of changes before applying other''s.
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349261311 -3600 # Node ID 3230041f50a54889784121579604412fdc260228 # Parent 4d47a8934b40556dd98428361c482be419c643be xenalyze: Add HVM_EVENT_VLAPIC Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -958,6 +958,7 @@ enum { HVM_EVENT_REALMODE_EMULATE, HVM_EVENT_TRAP, HVM_EVENT_TRAP_DEBUG, + HVM_EVENT_VLAPIC, HVM_EVENT_HANDLER_MAX }; char * hvm_event_handler_name[HVM_EVENT_HANDLER_MAX] = { @@ -993,6 +994,7 @@ char * hvm_event_handler_name[HVM_EVENT_ "realmode_emulate", "trap", "trap_debug", + "vlapic" }; enum {
George Dunlap
2012-Oct-10 11:17 UTC
[PATCH 2 of 7] xenalyze: Process NPFs as generic for summary purposes
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349261558 -3600 # Node ID 4ea8fb7197ff3fad82b224a65cdfbe86db66d6ab # Parent 3230041f50a54889784121579604412fdc260228 xenalyze: Process NPFs as generic for summary purposes Moves the "generic" post-processing initialization into a function, and calls that function for NPF processes, so that we can get summary information about NPF. Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -4640,6 +4640,8 @@ void hvm_pf_inject_process(struct record } } +void hvm_generic_postprocess_init(struct record_info *ri, struct hvm_data *h); + void hvm_npf_process(struct record_info *ri, struct hvm_data *h) { struct { @@ -4654,6 +4656,9 @@ void hvm_npf_process(struct record_info ri->dump_header, (unsigned long long)r->gpa, r->qualification, (unsigned long long)r->mfn, r->p2mt); + + if ( opt.summary_info ) + hvm_generic_postprocess_init(ri, h); } void hvm_rdtsc_process(struct record_info *ri, struct hvm_data *h) @@ -4695,6 +4700,15 @@ void hvm_generic_summary(struct hvm_data } +void hvm_generic_postprocess_init(struct record_info *ri, struct hvm_data *h) +{ + if ( h->post_process != hvm_generic_postprocess ) + fprintf(warn, "%s: Strange, h->postprocess set!\n", + __func__); + h->inflight.generic.event = ri->event; + bcopy(h->d, h->inflight.generic.d, sizeof(unsigned int) * 4); +} + void hvm_generic_postprocess(struct hvm_data *h) { long evt = 0; @@ -4930,15 +4944,10 @@ needs_vmexit: case TRC_HVM_CR_READ: case TRC_HVM_CR_READ64: default: - if ( h->post_process != hvm_generic_postprocess ) - fprintf(warn, "%s: Strange, h->postprocess set!\n", - __func__); - h->inflight.generic.event = ri->event; - bcopy(h->d, h->inflight.generic.d, sizeof(unsigned int) * 4); if(opt.dump_all) - { hvm_generic_dump(ri, "]"); - } + if(opt.summary_info) + hvm_generic_postprocess_init(ri, h); break; } }
George Dunlap
2012-Oct-10 11:17 UTC
[PATCH 3 of 7] xenalyze: Don''t warn about switching paging levels unless verbosity>=6
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349261732 -3600 # Node ID 3aad48bd6ca3213c598d16c307ba531dc45d6240 # Parent 4ea8fb7197ff3fad82b224a65cdfbe86db66d6ab xenalyze: Don''t warn about switching paging levels unless verbosity>=6 During boot, the guest paging levels changes back and forth frequently, leading to spam when your''e doing the analysis. Don''t print these messages escept at verbosity level 6 (the default is 5). Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -5158,8 +5158,9 @@ void hvm_vmexit_process(struct record_in if(ri->event == TRC_HVM_VMEXIT64) { if(v->guest_paging_levels != 4) { - fprintf(warn, "%s: VMEXIT64, but guest_paging_levels %d. Switching to 4.\n", - __func__, v->guest_paging_levels); + if ( verbosity >= 6 ) + fprintf(warn, "%s: VMEXIT64, but guest_paging_levels %d. Switching to 4.\n", + __func__, v->guest_paging_levels); v->guest_paging_levels = 4; } if(!is_valid_addr64(r->x64.rip)) @@ -5171,10 +5172,14 @@ void hvm_vmexit_process(struct record_in if(v->guest_paging_levels == 4) { int new_paging_levels = opt.default_guest_paging_levels; + if(new_paging_levels == 4) new_paging_levels = 2; /* Wild guess */ - fprintf(warn, "%s: VMEXIT, but guest_paging_levels %d. Switching to %d(default).\n", - __func__, v->guest_paging_levels, new_paging_levels); + + if ( verbosity >= 6 ) + fprintf(warn, "%s: VMEXIT, but guest_paging_levels %d. Switching to %d(default).\n", + __func__, v->guest_paging_levels, new_paging_levels); + v->guest_paging_levels = new_paging_levels; } h->rip = r->x32.eip;
George Dunlap
2012-Oct-10 11:17 UTC
[PATCH 4 of 7] xenalyze: Make the warnigns in hvm_generic_postprocess more informative
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349262302 -3600 # Node ID 6e0e841283e5e68f03fe64d1c107942ab501846a # Parent 3aad48bd6ca3213c598d16c307ba531dc45d6240 xenalyze: Make the warnigns in hvm_generic_postprocess more informative Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -4739,16 +4739,19 @@ void hvm_generic_postprocess(struct hvm_ if ( !warned[h->exit_reason] ) { /* If we aren''t a known exception, warn and log results */ - fprintf(warn, "%s: Strange, exit %x missing a handler\n", - __func__, h->exit_reason); + fprintf(warn, "%s: Strange, exit %x(%s) missing a handler\n", + __func__, h->exit_reason, + (h->exit_reason > h->exit_reason_max) + ? "[clipped]" + : h->exit_reason_name[h->exit_reason]); warned[h->exit_reason]=1; } } - if ( evt > HVM_EVENT_HANDLER_MAX || evt < 0) - { - fprintf(warn, "%s: invalid hvm event %x\n", - __func__, h->inflight.generic.event); + if ( evt >= HVM_EVENT_HANDLER_MAX || evt < 0) + { + fprintf(warn, "%s: invalid hvm event %lx(%x)\n", + __func__, evt, h->inflight.generic.event); error(ERR_RECORD, NULL); return; }
George Dunlap
2012-Oct-10 11:17 UTC
[PATCH 5 of 7] xenalzye: Also strip write bit when processing a generic event
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349262739 -3600 # Node ID 344f6609af3335e1e27ef55c686c57ff33402d46 # Parent 6e0e841283e5e68f03fe64d1c107942ab501846a xenalzye: Also strip write bit when processing a generic event Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -4715,7 +4715,8 @@ void hvm_generic_postprocess(struct hvm_ static unsigned registered[HVM_EVENT_HANDLER_MAX] = { 0 }; if ( h->inflight.generic.event ) - evt = (h->inflight.generic.event - TRC_HVM_HANDLER) & ~TRC_64_FLAG; + evt = (h->inflight.generic.event - TRC_HVM_HANDLER) + & ~(TRC_64_FLAG|HVM_IO_ASSIST_WRITE); else { static unsigned warned[HVM_EXIT_REASON_MAX] = { 0 }; /* Some exits we don''t expect a handler; just return */
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349263139 -3600 # Node ID 703cd2301a0a04934d30c7e4f7357df82ed12677 # Parent 344f6609af3335e1e27ef55c686c57ff33402d46 xenalyze: Handle 64-bit MMIO Also use "TRC_HVM_IOPORT_WRITE" rather than adding in the IO_ASSIST_WRITE flag. Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -4903,12 +4903,13 @@ needs_vmexit: hvm_pf_xen_process(ri, h); break; case TRC_HVM_IOPORT_READ: - case TRC_HVM_IOPORT_READ|HVM_IO_ASSIST_WRITE: + case TRC_HVM_IOPORT_WRITE: hvm_io_assist_process(ri, h); break; case TRC_HVM_IOMEM_READ: - case TRC_HVM_IOMEM_READ|HVM_IO_ASSIST_WRITE: - /* FIXME: 64-bit */ + case TRC_HVM_IOMEM_WRITE: + case TRC_HVM_IOMEM_READ|TRC_64_FLAG: + case TRC_HVM_IOMEM_WRITE|TRC_64_FLAG: hvm_mmio_assist_process(ri, h); break; case TRC_HVM_CR_WRITE:
George Dunlap
2012-Oct-10 11:17 UTC
[PATCH 7 of 7] xenalyze: Analyze populate-on-demand reclamation patterns
# HG changeset patch # User George Dunlap <george.dunlap@eu.citrix.com> # Date 1349264664 -3600 # Node ID 393e0ead61a506f8bd1dea55ed7b3611ec4c7c1f # Parent 703cd2301a0a04934d30c7e4f7357df82ed12677 xenalyze: Analyze populate-on-demand reclamation patterns This includes attempting to classify each reclamation to see if it was the result of a fault or of ballooning, as well as tracking the order of the pages reclaimed. Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -1723,6 +1723,21 @@ char * domain_runstate_name[] = { [DOMAIN_RUNSTATE_LOST]="lost", }; +enum { + POD_RECLAIM_CONTEXT_UNKNOWN=0, + POD_RECLAIM_CONTEXT_FAULT, + POD_RECLAIM_CONTEXT_BALLOON, + POD_RECLAIM_CONTEXT_MAX +}; + +char * pod_reclaim_context_name[] = { + [POD_RECLAIM_CONTEXT_UNKNOWN]="unknown", + [POD_RECLAIM_CONTEXT_FAULT]="fault", + [POD_RECLAIM_CONTEXT_BALLOON]="balloon", +}; + +#define POD_ORDER_MAX 4 + struct domain_data { struct domain_data *next; int did; @@ -1747,6 +1762,14 @@ struct domain_data { int done_for[MEM_MAX]; int done_for_interval[MEM_MAX]; } memops; + + struct { + int reclaim_order[POD_ORDER_MAX]; + int reclaim_context[POD_RECLAIM_CONTEXT_MAX]; + int reclaim_context_order[POD_RECLAIM_CONTEXT_MAX][POD_ORDER_MAX]; + /* FIXME: Do a full cycle summary */ + int populate_order[POD_ORDER_MAX]; + } pod; }; struct domain_data * domain_list=NULL; @@ -7396,7 +7419,7 @@ void sched_process(struct pcpu_info *p) /* ---- Memory ---- */ void mem_summary_domain(struct domain_data *d) { - int i; + int i, j; printf(" Grant table ops:\n"); @@ -7413,23 +7436,103 @@ void mem_summary_domain(struct domain_da printf(" %-14s: %d\n", mem_name[i], d->memops.done_for[i]); + + printf(" Populate-on-demand:\n"); + printf(" Populated:\n"); + for(i=0; i<4; i++) + { + if ( d->pod.populate_order[i] ) + printf(" [%d] %d\n", i, + d->pod.populate_order[i]); + } + printf(" Reclaim order:\n"); + for(i=0; i<4; i++) + { + if ( d->pod.reclaim_order[i] ) + printf(" [%d] %d\n", i, + d->pod.reclaim_order[i]); + } + printf(" Reclaim contexts:\n"); + for(j=0; j<POD_RECLAIM_CONTEXT_MAX; j++) + { + if ( d->pod.reclaim_context[j] ) + { + printf(" * [%s] %d\n", + pod_reclaim_context_name[j], + d->pod.reclaim_context[j]); + for(i=0; i<4; i++) + { + if ( d->pod.reclaim_context_order[j][i] ) + printf(" [%d] %d\n", i, + d->pod.reclaim_context_order[j][i]); + } + } + } +} + +int p2m_canonical_order(int order) +{ + if ( order % 9 + || (order / 9) > 2 ) + { + fprintf(warn, "%s: Strange, non-canonical order %d\n", + __func__, order); + order = 4; + } else { + order /= 9; + } + return order; } void mem_pod_zero_reclaim_process(struct pcpu_info *p) { struct record_info *ri = &p->ri; + int context = POD_RECLAIM_CONTEXT_UNKNOWN; + struct vcpu_data *v = p->current; struct { uint64_t gfn, mfn; int d:16,order:16; } *r = (typeof(r))ri->d; + if ( v && v->hvm.vmexit_valid ) + { + switch(v->hvm.exit_reason) + { + case EXIT_REASON_EPT_VIOLATION: + case EXIT_REASON_EXCEPTION_NMI: + context = POD_RECLAIM_CONTEXT_FAULT; + break; + case EXIT_REASON_VMCALL: + context = POD_RECLAIM_CONTEXT_BALLOON; + break; + } + } + if ( opt.dump_all ) { - printf(" %s pod_zero_reclaim d%d o%d g %llx m %llx\n", + printf(" %s pod_zero_reclaim d%d o%d g %llx m %llx ctx %s\n", ri->dump_header, r->d, r->order, - (unsigned long long)r->gfn, (unsigned long long)r->mfn); + (unsigned long long)r->gfn, (unsigned long long)r->mfn, + pod_reclaim_context_name[context]); + + } + + if ( opt.summary_info ) + { + struct domain_data *d; + + if ( v && (d=v->d) ) + { + int order; + + order = p2m_canonical_order(r->order); + + d->pod.reclaim_order[order]++; + d->pod.reclaim_context[context]++; + d->pod.reclaim_context_order[context][order]++; + } } } @@ -7449,6 +7552,21 @@ void mem_pod_populate_process(struct pcp r->d, r->order, (unsigned long long)r->gfn, (unsigned long long)r->mfn); } + + if ( opt.summary_info ) + { + struct vcpu_data *v = p->current; + struct domain_data *d; + + if ( v && (d=v->d) ) + { + int order; + + order = p2m_canonical_order(r->order); + + d->pod.populate_order[order]++; + } + } } void mem_pod_superpage_splinter_process(struct pcpu_info *p)