|
[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 |