[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 5 of 5] xenalyze: Handle new IRQ tracing



Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>

diff -r 21e56bad8f2c -r 4833fe142a4f analyze.h
--- a/analyze.h Fri Oct 07 11:35:45 2011 +0100
+++ b/analyze.h Fri Oct 07 11:36:27 2011 +0100
@@ -7,10 +7,23 @@
 #define TRC_MEM_MAIN     4
 #define TRC_PV_MAIN      5
 #define TRC_SHADOW_MAIN  6
-#define TRC_PM_MAIN      7
+#define TRC_HW_MAIN      7
 
 #define TRC_LOST_RECORDS_END    (TRC_GEN + 50)
 
+#define NR_CPUS 128
+#if __x86_64__
+# define BITS_PER_LONG 64
+#else
+# define BITS_PER_LONG 32
+#endif
+
+#define BITS_TO_LONGS(bits) \
+    (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+    unsigned long name[BITS_TO_LONGS(bits)]
+typedef struct cpumask{ DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
+
 enum {
     TRCE_SFLAG_SET_AD,
     TRCE_SFLAG_SET_A,
diff -r 21e56bad8f2c -r 4833fe142a4f trace.h
--- a/trace.h   Fri Oct 07 11:35:45 2011 +0100
+++ b/trace.h   Fri Oct 07 11:36:27 2011 +0100
@@ -38,7 +38,7 @@
 #define TRC_MEM      0x0010f000    /* Xen memory trace         */
 #define TRC_PV       0x0020f000    /* Xen PV traces            */
 #define TRC_SHADOW   0x0040f000    /* Xen shadow tracing       */
-#define TRC_PM       0x0080f000    /* Xen power management trace */
+#define TRC_HW       0x0080f000    /* Xen hardware-related traces */
 #define TRC_GUEST    0x0800f000    /* Guest-generated traces   */
 #define TRC_ALL      0x0ffff000
 #define TRC_HD_TO_EVENT(x) ((x)&0x0fffffff)
@@ -57,11 +57,13 @@
 #define TRC_SCHED_CLASS     0x00022000   /* Scheduler-specific    */
 #define TRC_SCHED_VERBOSE   0x00028000   /* More inclusive scheduling */
 
+#define TRC_HW_PM           0x00801000   /* Power management traces */
+#define TRC_HW_IRQ          0x00802000   /* Traces relating to the handling of 
IRQs */
+
 /* Trace events per class */
 #define TRC_LOST_RECORDS        (TRC_GEN + 1)
 #define TRC_TRACE_WRAP_BUFFER  (TRC_GEN + 2)
 #define TRC_TRACE_CPU_CHANGE    (TRC_GEN + 3)
-#define TRC_TRACE_IRQ           (TRC_GEN + 4)
 
 #define TRC_SCHED_RUNSTATE_CHANGE   (TRC_SCHED_MIN + 1)
 #define TRC_SCHED_CONTINUE_RUNNING  (TRC_SCHED_MIN + 2)
@@ -164,14 +166,25 @@
 #define TRC_HVM_IOPORT_WRITE    (TRC_HVM_HANDLER + 0x216)
 #define TRC_HVM_IOMEM_WRITE     (TRC_HVM_HANDLER + 0x217)
 
-/* trace subclasses for power management */
-#define TRC_PM_FREQ     0x00801000      /* xen cpu freq events */
-#define TRC_PM_IDLE     0x00802000      /* xen cpu idle events */
+/* trace events for per class */
+#define TRC_PM_FREQ_CHANGE      (TRC_HW_PM + 0x01)
+#define TRC_PM_IDLE_ENTRY       (TRC_HW_PM + 0x02)
+#define TRC_PM_IDLE_EXIT        (TRC_HW_PM  + 0x03)
 
-/* trace events for per class */
-#define TRC_PM_FREQ_CHANGE      (TRC_PM_FREQ + 0x01)
-#define TRC_PM_IDLE_ENTRY       (TRC_PM_IDLE + 0x01)
-#define TRC_PM_IDLE_EXIT        (TRC_PM_IDLE + 0x02)
+#define TRC_HW_IRQ_MOVE_CLEANUP_DELAY (TRC_HW_IRQ + 0x1)
+#define TRC_HW_IRQ_MOVE_CLEANUP       (TRC_HW_IRQ + 0x2)
+#define TRC_HW_IRQ_BIND_VECTOR        (TRC_HW_IRQ + 0x3)
+#define TRC_HW_IRQ_CLEAR_VECTOR       (TRC_HW_IRQ + 0x4)
+#define TRC_HW_IRQ_MOVE_FINISH        (TRC_HW_IRQ + 0x5)
+#define TRC_HW_IRQ_ASSIGN_VECTOR      (TRC_HW_IRQ + 0x6)
+#define TRC_HW_IRQ_UNMAPPED_VECTOR    (TRC_HW_IRQ + 0x7)
+#define TRC_HW_IRQ_HANDLED            (TRC_HW_IRQ + 0x8)
+#define TRC_HW_IRQ_MSI_WRITE          (TRC_HW_IRQ + 0x9)
+#define TRC_HW_IRQ_MAP_PIRQ_MSI       (TRC_HW_IRQ + 0xa)
+#define TRC_HW_IRQ_MAP_PIRQ_GSI       (TRC_HW_IRQ + 0xb)
+#define TRC_HW_IRQ_MSI_SET_AFFINITY   (TRC_HW_IRQ + 0x10)
+#define TRC_HW_IRQ_SET_DESC_AFFINITY  (TRC_HW_IRQ + 0x11)
+#define TRC_HW_IRQ_IOMMU_AMD_IRE      (TRC_HW_IRQ + 0x12)
 
 /* This structure represents a single trace buffer record. */
 struct t_rec {
diff -r 21e56bad8f2c -r 4833fe142a4f xenalyze.c
--- a/xenalyze.c        Fri Oct 07 11:35:45 2011 +0100
+++ b/xenalyze.c        Fri Oct 07 11:36:27 2011 +0100
@@ -144,6 +144,7 @@ struct {
         scatterplot_pcpu:1,
         scatterplot_extint_cycles:1,
         scatterplot_rdtsc:1,
+        scatterplot_irq:1,
         histogram_interrupt_eip:1,
         interval_mode:1,
         dump_cooked:1,
@@ -218,6 +219,7 @@ struct {
     .scatterplot_pcpu=0,
     .scatterplot_extint_cycles=0,
     .scatterplot_rdtsc=0,
+    .scatterplot_irq=0,
     .histogram_interrupt_eip=0,
     .dump_cooked = 0,
     .dump_all = 0,
@@ -7564,9 +7566,6 @@ void mem_process(struct pcpu_info *p) {
 }
 
 /* ---- PM ---- */
-#define TRC_PM_FREQ_CHANGE      (TRC_PM_FREQ + 0x01)
-#define TRC_PM_IDLE_ENTRY       (TRC_PM_IDLE + 0x01)
-#define TRC_PM_IDLE_EXIT        (TRC_PM_IDLE + 0x02)
 #define CSTATE_MAX 5
 #define CSTATE_INVALID ((CSTATE_MAX)+1)
 void pm_process(struct pcpu_info *p) {
@@ -7609,7 +7608,383 @@ void pm_process(struct pcpu_info *p) {
     
 }
 
-
+/*
+ * IRQ related stuff
+ */
+
+#define MAX_VECTOR 256
+int global_vector_used[256] = {0};
+struct pci_dev {
+    uint8_t bus;
+    uint8_t devfn;
+    int vector_used[MAX_VECTOR];
+    struct pci_dev *next;
+} *pdev_list;
+
+#define MAX_IRQ 512
+struct irq_desc {
+    enum {
+        IRQ_NONE,
+        IRQ_MSI,
+        IRQ_GSI
+    } type;
+    struct pci_dev *dev;
+} irq_table[MAX_IRQ];
+
+struct pci_dev * pdev_find(uint8_t bus, uint8_t devfn)
+{
+    struct pci_dev *d, *n, **q;
+
+    /* Look for domain, keeping track of the last pointer so we can add
+       a domain if we need to. */
+    for ( d = pdev_list, q=&pdev_list ;
+          d &&  ( (d->bus < bus)
+                  || (d->bus == bus && d->devfn < devfn) ) ;
+          q = &d->next, d=d->next ) ;
+
+    if(d && d->bus == bus && d->devfn == devfn)
+        return d;
+
+    /* Make a new domain */
+    fprintf(warn, "Creating pdev %02x:%02x.%x\n", bus, devfn>>4, devfn&3);
+
+    if((n=malloc(sizeof(*n)))==NULL)
+    {
+        fprintf(stderr, "%s: malloc %zd failed!\n", __func__, sizeof(*n));
+        error(ERR_SYSTEM, NULL);
+    }
+
+    bzero(n, sizeof(*n));
+
+    n->bus=bus;
+    n->devfn=devfn;
+    
+    /* Insert it into the list */
+    n->next = d;
+    *q = n;
+
+    return n;
+}
+
+void irq_process(struct pcpu_info *p) {
+    struct record_info *ri = &p->ri;
+
+    switch ( ri->event )
+    {
+    case TRC_HW_IRQ_BIND_VECTOR:
+    {
+        struct {
+            int irq, vec;
+            unsigned mask[4];
+        } *r = (typeof(r))ri->d;
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_bind_vector irq %x vec %x mask %04x %04x %04x 
%04x\n",
+                   ri->dump_header,
+                   r->irq, r->vec,
+                   r->mask[3],
+                   r->mask[2],
+                   r->mask[1],
+                   r->mask[0]);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_HANDLED:
+    {
+        struct {
+            int irq, start_tsc, end_tsc;
+        } *r = (typeof(r))ri->d;
+        int arctime;
+
+        arctime = r->end_tsc - r->start_tsc;
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_handled irq %x %d (%d,%d)\n",
+                   ri->dump_header,
+                   r->irq, arctime, r->start_tsc, r->end_tsc);
+        }
+        if ( opt.scatterplot_irq )
+        {
+            struct time_struct t;
+            
+            abs_cycles_to_time(ri->tsc, &t);
+            
+            printf("i%x %u.%09u %d\n",
+                   (unsigned)r->irq,
+                   t.s, t.ns,
+                   p->pid);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_ASSIGN_VECTOR:
+    {
+        struct {
+            int irq, vec;
+            unsigned mask[4];
+        } *r = (typeof(r))ri->d;
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_assign_vector irq %x vec %x mask %04x %04x %04x 
%04x\n",
+                   ri->dump_header,
+                   r->irq, r->vec,
+                   r->mask[3],
+                   r->mask[2],
+                   r->mask[1],
+                   r->mask[0]);
+        }
+        if ( r->irq < MAX_IRQ
+             && r->vec < MAX_VECTOR )
+        {
+            if ( irq_table[r->irq].type == IRQ_MSI )
+            {
+                if(global_vector_used[r->vec])
+                    fprintf(warn, "  Vector collision on global table!\n");
+                global_vector_used[r->vec]=1;
+            }
+            if( irq_table[r->irq].dev )
+            {
+                struct pci_dev * pdev=irq_table[r->irq].dev;
+            
+                if(pdev->vector_used[r->vec])
+                    fprintf(warn, "  Vector collision on %02x.%02x!\n",
+                            pdev->bus, pdev->devfn);
+                pdev->vector_used[r->vec]=1;
+            }
+        }
+        break;
+    }
+    case TRC_HW_IRQ_MOVE_CLEANUP_DELAY:
+    {
+        struct {
+            int irq, vec, cpu;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_move_cleanup_delay irq %x vec %x cpu %d\n",
+                   ri->dump_header,
+                   r->irq, r->vec, r->cpu);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_MOVE_CLEANUP:
+    {
+        struct {
+            int irq;
+            int vec;
+            int cpu;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_move_cleanup irq %x vec %x cpu %d\n",
+                   ri->dump_header,
+                   r->irq, r->vec, r->cpu);
+        }
+        if ( r->irq < MAX_IRQ 
+             && r->vec < MAX_VECTOR )
+        {
+            if ( irq_table[r->irq].type == IRQ_MSI )
+            {
+                if(!global_vector_used[r->vec])
+                    fprintf(warn,"  Strange, cleanup on non-used vector\n");
+                global_vector_used[r->vec]=0;
+            }
+            if ( irq_table[r->irq].dev )
+            {
+                struct pci_dev * pdev=irq_table[r->irq].dev;
+            
+                if(!pdev->vector_used[r->vec])
+                    fprintf(warn,"  Strange, cleanup on non-used vector\n");
+                pdev->vector_used[r->vec]=0;
+            }
+        }
+        break;
+    }
+    case TRC_HW_IRQ_UNMAPPED_VECTOR:
+    {
+        struct {
+            int vec;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_unmapped_vector vec %x\n",
+                   ri->dump_header,
+                   r->vec);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_MSI_WRITE:
+    {
+        struct {
+            unsigned address_lo, address_hi;
+            unsigned data;
+            unsigned irq:16, pos:16;
+            uint8_t func, slot, bus, type;
+            unsigned mask_base;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_msi_write irq %x t %x base %x addr %x %x data %x 
pci %02x:%02x.%x %x\n",
+                   ri->dump_header,
+                   r->irq,
+                   r->type,
+                   r->mask_base,
+                   r->address_hi, r->address_lo,
+                   r->data,
+                   r->bus, r->slot, r->func, r->pos);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_IOMMU_AMD_IRE:
+    {
+        struct {
+            uint16_t bdf, id;
+            int offset;
+            uint8_t dest_mode, dev_mode, vector, dest;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_iommu_ire bdf %x id %x offset %x dest_mode %x 
dev_mode %x vec %x dest %x\n",
+                   ri->dump_header,
+                   r->bdf, r->id,
+                   r->offset,
+                   r->dest_mode, r->dev_mode,
+                   r->vector, r->dest);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_MAP_PIRQ_MSI:
+    {
+        struct {
+            unsigned domain:16,
+                pirq:16,
+                irq:16,
+                bus:16,
+                devfn:16,
+                entry_nr:16;
+        } *r = (typeof(r))ri->d;
+
+        if ( r->irq < MAX_IRQ )
+        {
+            struct irq_desc *irq=irq_table+r->irq;
+
+            if ( irq->dev )
+            {
+                fprintf(warn, "Strange, irq %d already has dev %02x:%x.%x!\n",
+                        r->irq, irq->dev->bus,
+                        irq->dev->devfn>>4,
+                        irq->dev->devfn&3);
+            }
+            else
+            {
+                struct pci_dev *pdev = pdev_find(r->bus, r->devfn);
+
+                irq->dev=pdev;
+                irq->type=IRQ_MSI;
+            }
+        }
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_map_pirq_msi d%d pirq %x(%d) irq %x bus %x devfn 
%x entry %x\n",
+                   ri->dump_header,
+                   r->domain,
+                   r->pirq,
+                   r->pirq,
+                   r->irq,
+                   r->bus,
+                   r->devfn,
+                   r->entry_nr);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_MAP_PIRQ_GSI:
+    {
+        struct {
+            unsigned domain, pirq, irq;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_map_pirq_gsi d%d pirq %x(%d) irq %x\n",
+                   ri->dump_header,
+                   r->domain,
+                   r->pirq,
+                   r->pirq,
+                   r->irq);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_MSI_SET_AFFINITY:
+    {
+        struct {
+            unsigned irq, apic_id, vector;
+        } *r = (typeof(r))ri->d;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_msi_set_affinity irq %x apicid %x vec %x\n",
+                   ri->dump_header,
+                   r->irq,
+                   r->apic_id,
+                   r->vector);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_SET_DESC_AFFINITY:
+    {
+        struct {
+            unsigned line:16, irq:16;
+            char fname[24]; /* Extra 7 words; 6 words * 4 = 24 */
+        } *r = (typeof(r))ri->d;
+        char fname[25];
+        int i;
+
+        for(i=0; i<24; i++)
+            fname[i]=r->fname[i];
+        fname[i]=0;
+
+        if ( opt.dump_all )
+        {
+            printf(" %s irq_set_desc_affinity irq %x %s:%d\n",
+                   ri->dump_header,
+                   r->irq,
+                   fname,
+                   r->line);
+        }
+        break;
+    }
+    case TRC_HW_IRQ_CLEAR_VECTOR:
+    case TRC_HW_IRQ_MOVE_FINISH :
+    default:
+        if(opt.dump_all || opt.dump_cooked) {
+            dump_generic(stdout, ri);
+        }
+        break;
+    }
+}
+
+#define TRC_HW_SUB_PM 1
+#define TRC_HW_SUB_IRQ 2
+void hw_process(struct pcpu_info *p)
+{
+    struct record_info *ri = &p->ri;
+
+    switch(ri->evt.sub)
+    {
+    case TRC_HW_SUB_PM:
+        pm_process(p);
+        break;
+    case TRC_HW_SUB_IRQ:
+        irq_process(p);
+        break;
+    }
+
+}
 /* ---- Base ----- */
 void dump_generic(FILE * f, struct record_info *ri)
 {
@@ -8404,8 +8779,8 @@ void process_record(struct pcpu_info *p)
         case TRC_MEM_MAIN:
             mem_process(p);
             break;
-        case TRC_PM_MAIN:
-            pm_process(p);
+        case TRC_HW_MAIN:
+            hw_process(p);
             break;
         case TRC_DOM0OP_MAIN:
         default:
@@ -8868,6 +9243,7 @@ enum {
     OPT_SCATTERPLOT_PCPU,
     OPT_SCATTERPLOT_EXTINT_CYCLES,
     OPT_SCATTERPLOT_RDTSC,
+    OPT_SCATTERPLOT_IRQ,
     OPT_HISTOGRAM_INTERRUPT_EIP,
     /* Interval options */
     OPT_INTERVAL_CR3_SCHEDULE_TIME,
@@ -9119,6 +9495,10 @@ error_t cmd_parser(int key, char *arg, s
         G.output_defined = 1;
         opt.scatterplot_rdtsc=1;
         break;
+    case OPT_SCATTERPLOT_IRQ:
+        G.output_defined = 1;
+        opt.scatterplot_irq=1;
+        break;
     case OPT_SCATTERPLOT_IO:
     {
         char * inval;
@@ -9521,6 +9901,11 @@ const struct argp_option cmd_opts[] =  {
       .group = OPT_GROUP_EXTRA,
       .doc = "Output scatterplot of rdtsc values.", },
 
+    { .name = "scatterplot-irq",
+      .key = OPT_SCATTERPLOT_IRQ,
+      .group = OPT_GROUP_EXTRA,
+      .doc = "Output scatterplot of irqs on pcpus.", },
+
     { .name = "histogram-interrupt-eip",
       .key = OPT_HISTOGRAM_INTERRUPT_EIP,
       .arg = "vector[,increment]",

_______________________________________________
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®.