[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 04 of 12] xenalyze: Introduce generic summary functionality
Allow generic processing of hvm traces to generate summary information, connected to specific exit reasons. This makes hvm_generic_postprocess the default handler (which means it can be overriden in hvm_set_postprocess()), and also replaces hvm_exception_nmi_generic_postprocess with the hvm_generic_postprocess. Also add a handler for exits without an HVM trace, and make a header for hvm_pf_xen_summary(). Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx> diff -r 47d436ca14d1 -r 844117c5a51e xenalyze.c --- a/xenalyze.c Mon Nov 28 16:16:23 2011 +0000 +++ b/xenalyze.c Mon Nov 28 16:16:23 2011 +0000 @@ -953,6 +953,7 @@ char * hvm_trap_name[HVM_TRAP_MAX] = { enum { + HVM_EVENT_HANDLER_NONE = 0, HVM_EVENT_HANDLER_PF_XEN = 1, HVM_EVENT_HANDLER_PF_INJECT, HVM_EVENT_HANDLER_INJ_EXC, @@ -984,7 +985,7 @@ enum { HVM_EVENT_HANDLER_MAX }; char * hvm_event_handler_name[HVM_EVENT_HANDLER_MAX] = { - NULL, + "(no handler)", "pf_xen", "pf_inject", "inj_exc", @@ -1343,6 +1344,7 @@ struct hvm_data { struct event_cycle_summary cr_write[CR_MAX]; struct event_cycle_summary cr3_write_resyncs[RESYNCS_MAX+1]; struct event_cycle_summary vmcall[HYPERCALL_MAX+1]; + struct event_cycle_summary generic[HVM_EVENT_HANDLER_MAX]; struct hvm_gi_struct { int count; struct cycle_summary runtime[GUEST_INTERRUPT_CASE_MAX]; @@ -3073,12 +3075,12 @@ int __hvm_set_summary_handler(struct hvm return -EINVAL; } -void hvm_exception_nmi_generic_postprocess(struct hvm_data *h); +void hvm_generic_postprocess(struct hvm_data *h); static int hvm_set_postprocess(struct hvm_data *h, void (*s)(struct hvm_data *h)) { if ( h->post_process == NULL - || h->post_process == hvm_exception_nmi_generic_postprocess ) + || h->post_process == hvm_generic_postprocess ) { h->post_process = s; return 0; @@ -3099,26 +3101,35 @@ static inline int is_valid_addr64(unsign void hvm_pf_xen_summary(struct hvm_data *h, void *d) { int i,j, k; - + + printf(" page_fault\n"); for(i=0; i<PF_XEN_MAX; i++) { - PRINT_SUMMARY(h->summary.pf_xen[i], - " %-25s ", pf_xen_name[i]); + if( pf_xen_name[i] ) + { + PRINT_SUMMARY(h->summary.pf_xen[i], + " %-25s ", pf_xen_name[i]); + } + else + { + PRINT_SUMMARY(h->summary.pf_xen[i], + " [%23d] ", i); + } switch(i){ case PF_XEN_NON_EMULATE: for(j=0; j<PF_XEN_NON_EMUL_MAX; j++) PRINT_SUMMARY(h->summary.pf_xen_non_emul[j], - " *%-13s ", pf_xen_non_emul_name[j]); + " *%-13s ", pf_xen_non_emul_name[j]); break; case PF_XEN_EMULATE: for(j=0; j<PF_XEN_EMUL_MAX; j++) { PRINT_SUMMARY(h->summary.pf_xen_emul[j], - " *%-13s ", pf_xen_emul_name[j]); + " *%-13s ", pf_xen_emul_name[j]); if(j == PF_XEN_EMUL_EARLY_UNSHADOW) { int k; for(k=0; k<5; k++) { PRINT_SUMMARY(h->summary.pf_xen_emul_early_unshadow[k], - " +[%d] ", k); + " +[%d] ", k); } } } @@ -3126,14 +3137,14 @@ void hvm_pf_xen_summary(struct hvm_data case PF_XEN_FIXUP: for(j=0; j<PF_XEN_FIXUP_MAX; j++) { PRINT_SUMMARY(h->summary.pf_xen_fixup[j], - " *%-13s ", pf_xen_fixup_name[j]); + " *%-13s ", pf_xen_fixup_name[j]); if(j == PF_XEN_FIXUP_UNSYNC ) { for(k=0; k<PF_XEN_FIXUP_UNSYNC_RESYNC_MAX; k++) { PRINT_SUMMARY(h->summary.pf_xen_fixup_unsync_resync[k], - " +[%3d] ", k); + " +[%3d] ", k); } PRINT_SUMMARY(h->summary.pf_xen_fixup_unsync_resync[k], - " +[max] "); + " +[max] "); } } break; @@ -4552,6 +4563,10 @@ void hvm_intr_process(struct hvm_data *h update_eip(&h->v->d->interrupt_eip_list, rip, 0, 0, NULL); } + /* Disable generic postprocessing */ + /* FIXME: Do the summary stuff in a post-processor */ + h->post_process = NULL; + if(opt.summary_info) { if(opt.summary) hvm_set_summary_handler(h, hvm_intr_summary, NULL); @@ -4631,25 +4646,6 @@ void hvm_pf_inject_process(struct record } } -void hvm_exception_nmi_generic_postprocess(struct hvm_data *h) -{ - static int warned = 0; - if(opt.dump_cooked) - { - printf(" %s exnmi no_handler\n", - h->dump_header); - } - - if(opt.summary_info) - update_summary(&h->summary.pf_xen[PF_XEN_NO_HANDLER], - h->arc_cycles); - - if(!warned) { - warned++; - fprintf(warn, "Strange, no handler for exnmi!\n"); - } -} - void hvm_npf_process(struct record_info *ri, struct hvm_data *h) { struct { @@ -4694,31 +4690,86 @@ void hvm_rdtsc_process(struct record_inf h->last_rdtsc = r->tsc; } +void hvm_generic_summary(struct hvm_data *h, void *data) +{ + int evt = (int)data; + + assert(evt < HVM_EVENT_HANDLER_MAX); + + PRINT_SUMMARY(h->summary.generic[evt], + " %s ", hvm_event_handler_name[evt]); + +} + void hvm_generic_postprocess(struct hvm_data *h) { + int evt = 0; + static unsigned registered[HVM_EVENT_HANDLER_MAX] = { 0 }; + + if ( h->inflight.generic.event ) + evt = (h->inflight.generic.event - TRC_HVM_HANDLER) & ~TRC_64_FLAG; + else { + static unsigned warned[HVM_EXIT_REASON_MAX] = { 0 }; + /* Some exits we don't expect a handler; just return */ + if(opt.svm_mode) + { + } + else + { + switch(h->exit_reason) + { + /* These just need us to go through the return path */ + case EXIT_REASON_PENDING_INTERRUPT: + case EXIT_REASON_TPR_BELOW_THRESHOLD: + /* Not much to log now; may need later */ + case EXIT_REASON_WBINVD: + return; + default: + break; + } + } + 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); + 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); + error(ERR_RECORD, NULL); + return; + } + if(opt.summary_info) { + update_summary(&h->summary.generic[evt], + h->arc_cycles); + + /* NB that h->exit_reason may be 0, so we offset by 1 */ + if ( registered[evt] ) + { + static unsigned warned[HVM_EXIT_REASON_MAX] = { 0 }; + if ( registered[evt] != h->exit_reason+1 && !warned[h->exit_reason]) + { + fprintf(warn, "%s: HVM evt %x in %x and %x!\n", + __func__, evt, registered[evt]-1, h->exit_reason); + warned[h->exit_reason]=1; + } + } + else + { + int ret; + if((ret=__hvm_set_summary_handler(h, hvm_generic_summary, (void *)evt))) + fprintf(stderr, "%s: hvm_set_summary_handler returned %d\n", + __func__, ret); + registered[evt]=h->exit_reason+1; + } /* HLT checked at hvm_vmexit_close() */ } - - if(opt.dump_cooked) - { - int i, evt = h->event_handler; - - if(evt < HVM_EVENT_HANDLER_MAX) - printf(" %s %s [", - h->dump_header, - hvm_event_handler_name[evt]); - else - printf(" %s %d [", - h->dump_header, - evt); - - for(i=0; i<4; i++) { - printf(" %x", h->inflight.generic.d[i]); - } - - printf(" ]\n"); - } } void hvm_generic_dump(struct record_info *ri, char * prefix) @@ -4878,18 +4929,15 @@ needs_vmexit: case TRC_HVM_CLTS: case TRC_HVM_LMSW: case TRC_HVM_LMSW64: - default: - if ( h->post_process != NULL ) - fprintf(warn, "Strange, h->postprocess already set!\n"); - /* Guest NMI should expect h->postprocess to be set. - FIXME: Handle NMI specially. */ + case TRC_HVM_NMI: case TRC_HVM_CR_READ: case TRC_HVM_CR_READ64: - case TRC_HVM_NMI: - /* FIXME: Really should check to make sure post_process is NULL or the exnmi default... */ + 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); - h->post_process = hvm_generic_postprocess; if(opt.dump_all) { hvm_generic_dump(ri, "]"); @@ -5168,18 +5216,8 @@ void hvm_vmexit_process(struct record_in h->wrmap_bf = 0; h->short_summary_done = 0; - h->post_process = NULL; - if(!opt.svm_mode) - { - switch(h->exit_reason) - { - case EXIT_REASON_EXCEPTION_NMI: - h->post_process = hvm_exception_nmi_generic_postprocess; - break; - default: - ; - } - } + h->post_process = hvm_generic_postprocess; + h->inflight.generic.event = 0; { struct time_struct t; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |