[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.