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
|