WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 5 of 5] xenalyze: Handle new IRQ tracing
From: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
Date: Fri, 7 Oct 2011 11:39:43 +0100
Cc: george.dunlap@xxxxxxxxxxxxx
Delivery-date: Fri, 07 Oct 2011 03:42:13 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <patchbomb.1317983978@elijah>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <patchbomb.1317983978@elijah>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mercurial-patchbomb/1.4.3
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