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

[Xen-changelog] [xen-unstable] [xen][tracing] Introduce variable-size tr

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [xen][tracing] Introduce variable-size trace records
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 26 Sep 2007 03:41:04 -0700
Delivery-date: Wed, 26 Sep 2007 04:29:53 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User George Dunlap <gdunlap@xxxxxxxxxxxxx>
# Date 1190384767 -3600
# Node ID 7ed576909132407b0c98c8374c38179cda4cfd39
# Parent  517432b9f8b585df5b22ec3682ffba416e718d22
[xen][tracing] Introduce variable-size trace records

This patch introduces variable-size trace records.  Each record consists of
a 32-bit "header", an optional cycle count, and up to seven more 32-bit words.

The header is packed with the following information:
 bits  0-27: The trace event.
 bits 28-30: The number of 32-bit "extra" words in the records
 bit     31: Does the trace include a 64-bit tsc?

This patch standardizes behavior wrt 32 and 64-bit hypervisors and dom0s.

Note that this patch requires a new version of the xentrace daemon running in
dom0.  The new daemon, instead of pre-pending the cpu to every record as it
writes it, inserts a "cpu change" record to the trace file that record the
cpu and the number of records it's about to write.

Signed-off-by: George Dunlap <gdunlap@xxxxxxxxxxxxx>
---
 tools/xentrace/xentrace.c  |  140 +++++++++++++++----
 xen/common/trace.c         |  323 +++++++++++++++++++++++++++++++++++----------
 xen/include/public/trace.h |   43 ++++-
 xen/include/xen/trace.h    |   85 +++++++++--
 4 files changed, 460 insertions(+), 131 deletions(-)

diff -r 517432b9f8b5 -r 7ed576909132 tools/xentrace/xentrace.c
--- a/tools/xentrace/xentrace.c Fri Sep 21 16:52:17 2007 +0100
+++ b/tools/xentrace/xentrace.c Fri Sep 21 15:26:07 2007 +0100
@@ -22,6 +22,7 @@
 #include <signal.h>
 #include <inttypes.h>
 #include <string.h>
+#include <assert.h>
 
 #include <xen/xen.h>
 #include <xen/trace.h>
@@ -83,24 +84,58 @@ struct timespec millis_to_timespec(unsig
 }
 
 /**
- * write_rec - output a trace record in binary format
+ * write_buffer - write a section of the trace buffer
  * @cpu      - source buffer CPU ID
- * @rec      - trace record to output
+ * @start
+ * @size     - size of write (may be less than total window size)
+ * @total_size - total size of the window (0 on 2nd write of wrapped windows)
  * @out      - output stream
  *
- * Outputs the trace record to a filestream, prepending the CPU ID of the
- * source trace buffer.
- */
-void write_rec(unsigned int cpu, struct t_rec *rec, FILE *out)
+ * Outputs the trace buffer to a filestream, prepending the CPU and size
+ * of the buffer write.
+ */
+void write_buffer(unsigned int cpu, unsigned char *start, int size,
+               int total_size, int outfd)
 {
     size_t written = 0;
-    written += fwrite(&cpu, sizeof(cpu), 1, out);
-    written += fwrite(rec, sizeof(*rec), 1, out);
-    if ( written != 2 )
-    {
-        PERROR("Failed to write trace record");
-        exit(EXIT_FAILURE);
-    }
+    
+    /* Write a CPU_BUF record on each buffer "window" written.  Wrapped
+     * windows may involve two writes, so only write the record on the
+     * first write. */
+    if(total_size)
+    {
+        struct {
+            uint32_t header;
+            struct {
+                unsigned cpu;
+                unsigned byte_count;
+            } extra;
+        } rec;
+
+        rec.header = TRC_TRACE_CPU_CHANGE
+            | ((sizeof(rec.extra)/sizeof(uint32_t)) << TRACE_EXTRA_SHIFT);
+        rec.extra.cpu = cpu;
+        rec.extra.byte_count = total_size;
+
+        written = write(outfd, &rec, sizeof(rec));
+
+        if(written!=sizeof(rec)) {
+            fprintf(stderr, "Cannot write cpu change (write returned %d)\n",
+                    written);
+            goto fail;
+        }
+    }
+
+    written = write(outfd, start, size);
+    if ( written != size ) {
+        fprintf(stderr, "Write failed! (size %d, returned %d)\n",
+                size, written);
+        goto fail;
+    }
+    return;
+ fail:
+    PERROR("Failed to write trace data");
+    exit(EXIT_FAILURE);
 }
 
 static void get_tbufs(unsigned long *mfn, unsigned long *size)
@@ -233,12 +268,12 @@ struct t_buf **init_bufs_ptrs(void *bufs
  * mapped in user space.  Note that the trace buffer metadata contains machine
  * pointers - the array returned allows more convenient access to them.
  */
-struct t_rec **init_rec_ptrs(struct t_buf **meta, unsigned int num)
+unsigned char **init_rec_ptrs(struct t_buf **meta, unsigned int num)
 {
     int i;
-    struct t_rec **data;
-    
-    data = calloc(num, sizeof(struct t_rec *));
+    unsigned char **data;
+    
+    data = calloc(num, sizeof(unsigned char *));
     if ( data == NULL )
     {
         PERROR("Failed to allocate memory for data pointers\n");
@@ -246,7 +281,7 @@ struct t_rec **init_rec_ptrs(struct t_bu
     }
 
     for ( i = 0; i < num; i++ )
-        data[i] = (struct t_rec *)(meta[i] + 1);
+        data[i] = (unsigned char *)(meta[i] + 1);
 
     return data;
 }
@@ -281,19 +316,19 @@ unsigned int get_num_cpus(void)
  * monitor_tbufs - monitor the contents of tbufs and output to a file
  * @logfile:       the FILE * representing the file to log to
  */
-int monitor_tbufs(FILE *logfile)
+int monitor_tbufs(int outfd)
 {
     int i;
 
     void *tbufs_mapped;          /* pointer to where the tbufs are mapped    */
     struct t_buf **meta;         /* pointers to the trace buffer metadata    */
-    struct t_rec **data;         /* pointers to the trace buffer data areas
+    unsigned char **data;        /* pointers to the trace buffer data areas
                                   * where they are mapped into user space.   */
     unsigned long tbufs_mfn;     /* mfn of the tbufs                         */
     unsigned int  num;           /* number of trace buffers / logical CPUS   */
     unsigned long size;          /* size of a single trace buffer            */
 
-    int size_in_recs;
+    unsigned long data_size;
 
     /* get number of logical CPUs (and therefore number of trace buffers) */
     num = get_num_cpus();
@@ -302,7 +337,7 @@ int monitor_tbufs(FILE *logfile)
     get_tbufs(&tbufs_mfn, &size);
     tbufs_mapped = map_tbufs(tbufs_mfn, num, size);
 
-    size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec);
+    data_size = (size - sizeof(struct t_buf));
 
     /* build arrays of convenience ptrs */
     meta  = init_bufs_ptrs(tbufs_mapped, num, size);
@@ -317,13 +352,48 @@ int monitor_tbufs(FILE *logfile)
     {
         for ( i = 0; (i < num) && !interrupted; i++ )
         {
-            while ( meta[i]->cons != meta[i]->prod )
+            unsigned long start_offset, end_offset, window_size, cons, prod;
+            rmb(); /* read prod, then read item. */
+                
+            /* Read window information only once. */
+            cons = meta[i]->cons;
+            prod = meta[i]->prod;
+            
+            if(cons == prod)
+                continue;
+           
+            assert(prod > cons);
+
+            window_size = prod - cons;
+            start_offset = cons % data_size;
+            end_offset = prod % data_size;
+
+            if(end_offset > start_offset)
             {
-                rmb(); /* read prod, then read item. */
-                write_rec(i, data[i] + meta[i]->cons % size_in_recs, logfile);
-                mb(); /* read item, then update cons. */
-                meta[i]->cons++;
+                /* If window does not wrap, write in one big chunk */
+                write_buffer(i, data[i]+start_offset,
+                             window_size,
+                             window_size,
+                             outfd);
             }
+            else
+            {
+                /* If wrapped, write in two chunks:
+                 * - first, start to the end of the buffer
+                 * - second, start of buffer to end of window
+                 */
+                write_buffer(i, data[i]+start_offset,
+                             data_size - start_offset,
+                             window_size,
+                             outfd);
+                write_buffer(i, data[i],
+                             end_offset,
+                             0,
+                             outfd);
+            }
+
+            mb(); /* read buffer, then update cons. */
+            meta[i]->cons = meta[i]->prod;
         }
 
         nanosleep(&opts.poll_sleep, NULL);
@@ -333,7 +403,7 @@ int monitor_tbufs(FILE *logfile)
     free(meta);
     free(data);
     /* don't need to munmap - cleanup is automatic */
-    fclose(logfile);
+    close(outfd);
 
     return 0;
 }
@@ -503,7 +573,6 @@ int main(int argc, char **argv)
 int main(int argc, char **argv)
 {
     int outfd = 1, ret;
-    FILE *logfile;
     struct sigaction act;
 
     opts.outfile = 0;
@@ -537,8 +606,6 @@ int main(int argc, char **argv)
         exit(EXIT_FAILURE);
     }
 
-    logfile = fdopen(outfd, "w");
-    
     /* ensure that if we get a signal, we'll do cleanup, then exit */
     act.sa_handler = close_handler;
     act.sa_flags = 0;
@@ -547,7 +614,16 @@ int main(int argc, char **argv)
     sigaction(SIGTERM, &act, NULL);
     sigaction(SIGINT,  &act, NULL);
 
-    ret = monitor_tbufs(logfile);
+    ret = monitor_tbufs(outfd);
 
     return ret;
 }
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r 517432b9f8b5 -r 7ed576909132 xen/common/trace.c
--- a/xen/common/trace.c        Fri Sep 21 16:52:17 2007 +0100
+++ b/xen/common/trace.c        Fri Sep 21 15:26:07 2007 +0100
@@ -43,19 +43,14 @@ CHECK_t_buf;
 #define TB_COMPAT 0
 #endif
 
-typedef union {
-       struct t_rec *nat;
-       struct compat_t_rec *cmp;
-} t_rec_u;
-
 /* opt_tbuf_size: trace buffer size (in pages) */
 static unsigned int opt_tbuf_size = 0;
 integer_param("tbuf_size", opt_tbuf_size);
 
 /* Pointers to the meta-data objects for all system trace buffers */
 static DEFINE_PER_CPU(struct t_buf *, t_bufs);
-static DEFINE_PER_CPU(t_rec_u, t_recs);
-static int nr_recs;
+static DEFINE_PER_CPU(unsigned char *, t_data);
+static int data_size;
 
 /* High water mark for trace buffers; */
 /* Send virtual interrupt when buffer level reaches this point */
@@ -102,8 +97,7 @@ static int alloc_trace_bufs(void)
 
     nr_pages = num_online_cpus() * opt_tbuf_size;
     order    = get_order_from_pages(nr_pages);
-    nr_recs  = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf)) /
-        (!TB_COMPAT ? sizeof(struct t_rec) : sizeof(struct compat_t_rec));
+    data_size  = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf));
     
     if ( (rawbuf = alloc_xenheap_pages(order)) == NULL )
     {
@@ -122,10 +116,10 @@ static int alloc_trace_bufs(void)
         buf = per_cpu(t_bufs, i) = (struct t_buf *)
             &rawbuf[i*opt_tbuf_size*PAGE_SIZE];
         buf->cons = buf->prod = 0;
-        per_cpu(t_recs, i).nat = (struct t_rec *)(buf + 1);
-    }
-
-    t_buf_highwater = nr_recs >> 1; /* 50% high water */
+        per_cpu(t_data, i) = (unsigned char *)(buf + 1);
+    }
+
+    t_buf_highwater = data_size >> 1; /* 50% high water */
     open_softirq(TRACE_SOFTIRQ, trace_notify_guest);
 
     return 0;
@@ -235,6 +229,129 @@ int tb_control(xen_sysctl_tbuf_op_t *tbc
     return rc;
 }
 
+static inline int calc_rec_size(int cycles, int extra) 
+{
+    int rec_size;
+    rec_size = 4;
+    if(cycles)
+        rec_size += 8;
+    rec_size += extra;
+    return rec_size;
+}
+
+static inline int calc_bytes_to_wrap(struct t_buf *buf)
+{
+    return data_size - (buf->prod % data_size);
+}
+
+static inline unsigned calc_bytes_avail(struct t_buf *buf)
+{
+    return data_size - (buf->prod - buf->cons);
+}
+
+static inline int __insert_record(struct t_buf *buf,
+                                  unsigned long event,
+                                  int extra,
+                                  int cycles,
+                                  int rec_size,
+                                  unsigned char * extra_data) 
+{
+    struct t_rec *rec;
+    unsigned char * dst;
+    unsigned long extra_word = extra/sizeof(u32);
+    int local_rec_size = calc_rec_size(cycles, extra);
+
+    BUG_ON(local_rec_size != rec_size);
+
+    /* Double-check once more that we have enough space.
+     * Don't bugcheck here, in case the userland tool is doing
+     * something stupid. */
+    if(calc_bytes_avail(buf) < rec_size )
+    {
+        printk("%s: %u bytes left (%u - (%u - %u)) recsize %u.\n",
+               __func__,
+               data_size - (buf->prod - buf->cons),
+               data_size,
+               buf->prod, buf->cons, rec_size);
+        return 0;
+    }
+    rmb();
+
+    rec = (struct t_rec *)&this_cpu(t_data)[buf->prod % data_size];
+    rec->header = event;
+    rec->header |= extra_word << TRACE_EXTRA_SHIFT;
+    if(cycles) 
+    {
+        u64 tsc = (u64)get_cycles();
+
+        rec->header |= TRC_HD_CYCLE_FLAG;
+        rec->u.cycles.cycles_lo = tsc & ((((u64)1)<<32)-1);
+        rec->u.cycles.cycles_hi = tsc >> 32;
+        dst = rec->u.cycles.data;
+    } 
+    else
+        dst = rec->u.nocycles.data;
+
+    if(extra_data && extra)
+        memcpy(dst, extra_data, extra);
+
+    wmb();
+    buf->prod+=rec_size;
+
+    return rec_size;
+}
+
+static inline int insert_wrap_record(struct t_buf *buf, int size)
+{
+    int space_left = calc_bytes_to_wrap(buf);
+    unsigned long extra_space = space_left - sizeof(u32);
+    int cycles=0;
+
+    if(space_left > size)
+        printk("%s: space_left %d, size %d!\n",
+               __func__, space_left, size);
+
+    BUG_ON(space_left > size);
+
+    /* We may need to add cycles to take up enough space... */
+    if((extra_space/sizeof(u32)) > TRACE_EXTRA_MAX)
+    {
+        cycles = 1;
+        extra_space -= sizeof(u64);
+        
+        ASSERT((extra_space/sizeof(u32)) <= TRACE_EXTRA_MAX);
+    }
+
+
+    return __insert_record(buf,
+                    TRC_TRACE_WRAP_BUFFER,
+                    extra_space,
+                    cycles,
+                    space_left,
+                    NULL);
+}
+
+#define LOST_REC_SIZE 8
+
+static inline int insert_lost_records(struct t_buf *buf)
+{
+    struct {
+        u32 lost_records;
+    } ed;
+
+    ed.lost_records = this_cpu(lost_records);
+
+    this_cpu(lost_records) = 0;
+
+    return __insert_record(buf,
+                           TRC_LOST_RECORDS,
+                           sizeof(ed),
+                           0 /* !cycles */,
+                           LOST_REC_SIZE,
+                           (unsigned char *)&ed);
+}
+
+
 /**
  * trace - Enters a trace tuple into the trace buffer for the current CPU.
  * @event: the event type being logged
@@ -244,14 +361,32 @@ int tb_control(xen_sysctl_tbuf_op_t *tbc
  * failure, otherwise 0.  Failure occurs only if the trace buffers are not yet
  * initialised.
  */
-void trace(u32 event, unsigned long d1, unsigned long d2,
-           unsigned long d3, unsigned long d4, unsigned long d5)
+void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data)
 {
     struct t_buf *buf;
-    t_rec_u rec;
-    unsigned long flags;
+    unsigned long flags, bytes_to_tail, bytes_to_wrap;
+    int rec_size, total_size;
+    int extra_word;
+    int started_below_highwater;
+
+    if(!tb_init_done)
+        return;
+
+    /* Convert byte count into word count, rounding up */
+    extra_word = (extra / sizeof(u32));
+    if((extra % sizeof(u32)) != 0)
+        extra_word++;
     
-    BUG_ON(!tb_init_done);
+#if !NDEBUG
+    ASSERT(extra_word<=TRACE_EXTRA_MAX);
+#else
+    /* Not worth crashing a production system over */
+    if(extra_word > TRACE_EXTRA_MAX)
+        extra_word = TRACE_EXTRA_MAX;
+#endif
+
+    /* Round size up to nearest word */
+    extra = extra_word * sizeof(u32);
 
     if ( (tb_event_mask & event) == 0 )
         return;
@@ -275,73 +410,125 @@ void trace(u32 event, unsigned long d1, 
 
     local_irq_save(flags);
 
-    /* Check if space for two records (we write two if there are lost recs). */
-    if ( (buf->prod - buf->cons) >= (nr_recs - 1) )
+    started_below_highwater = ( (buf->prod - buf->cons) < t_buf_highwater );
+
+    /* Calculate the record size */
+    rec_size = calc_rec_size(cycles, extra);
+ 
+    /* How many bytes are available in the buffer? */
+    bytes_to_tail = calc_bytes_avail(buf);
+    
+    /* How many bytes until the next wrap-around? */
+    bytes_to_wrap = calc_bytes_to_wrap(buf);
+    
+    /* 
+     * Calculate expected total size to commit this record by
+     * doing a dry-run.
+     */
+    total_size = 0;
+
+    /* First, check to see if we need to include a lost_record.
+     *
+     * calc_bytes_to_wrap() involves integer division, which we'd like to
+     * avoid if we can.  So do the math, check it in debug versions, and
+     * do a final check always if we happen to write a record.
+     */
+    if(this_cpu(lost_records))
+    {
+        if(LOST_REC_SIZE > bytes_to_wrap)
+        {
+            total_size += bytes_to_wrap;
+            bytes_to_wrap = data_size;
+        } 
+        else
+        {
+            bytes_to_wrap -= LOST_REC_SIZE;
+            if(bytes_to_wrap == 0)
+                bytes_to_wrap == data_size;
+        }
+        total_size += LOST_REC_SIZE;
+    }
+
+    ASSERT(bytes_to_wrap == calc_bytes_to_wrap(buf));
+
+    if(rec_size > bytes_to_wrap)
+    {
+        total_size += bytes_to_wrap;
+        bytes_to_wrap = data_size;
+    } 
+    else
+    {
+        bytes_to_wrap -= rec_size;
+    }
+
+    total_size += rec_size;
+
+    /* Do we have enough space for everything? */
+    if(total_size > bytes_to_tail) 
     {
         this_cpu(lost_records)++;
         local_irq_restore(flags);
         return;
     }
 
-    if ( unlikely(this_cpu(lost_records) != 0) )
-    {
-        if ( !TB_COMPAT )
+    /*
+     * Now, actually write information 
+     */
+    bytes_to_wrap = calc_bytes_to_wrap(buf);
+
+    if(this_cpu(lost_records))
+    {
+        if(LOST_REC_SIZE > bytes_to_wrap)
         {
-            rec.nat = &this_cpu(t_recs).nat[buf->prod % nr_recs];
-            memset(rec.nat, 0, sizeof(*rec.nat));
-            rec.nat->cycles  = (u64)get_cycles();
-            rec.nat->event   = TRC_LOST_RECORDS;
-            rec.nat->data[0] = this_cpu(lost_records);
-            this_cpu(lost_records) = 0;
-        }
+            insert_wrap_record(buf, LOST_REC_SIZE);
+            bytes_to_wrap = data_size;
+        } 
         else
         {
-            rec.cmp = &this_cpu(t_recs).cmp[buf->prod % nr_recs];
-            memset(rec.cmp, 0, sizeof(*rec.cmp));
-            rec.cmp->cycles  = (u64)get_cycles();
-            rec.cmp->event   = TRC_LOST_RECORDS;
-            rec.cmp->data[0] = this_cpu(lost_records);
-            this_cpu(lost_records) = 0;
+            bytes_to_wrap -= LOST_REC_SIZE;
+            /* LOST_REC might line up perfectly with the buffer wrap */
+            if(bytes_to_wrap == 0)
+                bytes_to_wrap = data_size;
         }
-
-        wmb();
-        buf->prod++;
-    }
-
-    if ( !TB_COMPAT )
-    {
-        rec.nat = &this_cpu(t_recs).nat[buf->prod % nr_recs];
-        rec.nat->cycles  = (u64)get_cycles();
-        rec.nat->event   = event;
-        rec.nat->data[0] = d1;
-        rec.nat->data[1] = d2;
-        rec.nat->data[2] = d3;
-        rec.nat->data[3] = d4;
-        rec.nat->data[4] = d5;
-    }
-    else
-    {
-        rec.cmp = &this_cpu(t_recs).cmp[buf->prod % nr_recs];
-        rec.cmp->cycles  = (u64)get_cycles();
-        rec.cmp->event   = event;
-        rec.cmp->data[0] = d1;
-        rec.cmp->data[1] = d2;
-        rec.cmp->data[2] = d3;
-        rec.cmp->data[3] = d4;
-        rec.cmp->data[4] = d5;
-    }
-
-    wmb();
-    buf->prod++;
+        insert_lost_records(buf);
+    }
+
+    ASSERT(bytes_to_wrap == calc_bytes_to_wrap(buf));
+
+    if(rec_size > bytes_to_wrap)
+    {
+        insert_wrap_record(buf, rec_size);
+    } 
+
+    /* Write the original record */
+    __insert_record(buf, event, extra, cycles, rec_size, extra_data);
 
     local_irq_restore(flags);
 
     /*
-     * Notify trace buffer consumer that we've reached the high water mark.
+     * Notify trace buffer consumer that we've crossed the high water mark.
      *
      */
-    if ( (buf->prod - buf->cons) == t_buf_highwater )
+    if ( started_below_highwater
+         && ( (buf->prod - buf->cons) > t_buf_highwater ) )
         raise_softirq(TRACE_SOFTIRQ);
+}
+
+
+void __trace_fixed(u32 event, unsigned long d1, unsigned long d2,
+           unsigned long d3, unsigned long d4, unsigned long d5)
+{
+    u32 extra_data[5];
+    
+    /* In a 64-bit hypervisor, this will truncate to 32 bits. */
+    extra_data[0]=d1;
+    extra_data[1]=d2;
+    extra_data[2]=d3;
+    extra_data[3]=d4;
+    extra_data[4]=d5;
+
+    __trace_var(event, 1/* include cycles */, sizeof(*extra_data)*5,
+              (unsigned char *)extra_data);
 }
 
 /*
diff -r 517432b9f8b5 -r 7ed576909132 xen/include/public/trace.h
--- a/xen/include/public/trace.h        Fri Sep 21 16:52:17 2007 +0100
+++ b/xen/include/public/trace.h        Fri Sep 21 15:26:07 2007 +0100
@@ -26,14 +26,21 @@
 #ifndef __XEN_PUBLIC_TRACE_H__
 #define __XEN_PUBLIC_TRACE_H__
 
+#define TRACE_EXTRA_MAX    7
+#define TRACE_EXTRA_SHIFT 28
+
 /* Trace classes */
 #define TRC_CLS_SHIFT 16
-#define TRC_GEN     0x0001f000    /* General trace            */
-#define TRC_SCHED   0x0002f000    /* Xen Scheduler trace      */
-#define TRC_DOM0OP  0x0004f000    /* Xen DOM0 operation trace */
-#define TRC_HVM     0x0008f000    /* Xen HVM trace            */
-#define TRC_MEM     0x0010f000    /* Xen memory trace         */
-#define TRC_ALL     0xfffff000
+#define TRC_GEN      0x0001f000    /* General trace            */
+#define TRC_SCHED    0x0002f000    /* Xen Scheduler trace      */
+#define TRC_DOM0OP   0x0004f000    /* Xen DOM0 operation trace */
+#define TRC_HVM      0x0008f000    /* Xen HVM trace            */
+#define TRC_MEM      0x0010f000    /* Xen memory trace         */
+#define TRC_ALL      0x0ffff000
+#define TRC_HD_TO_EVENT(x) ((x)&0x0fffffff)
+#define TRC_HD_CYCLE_FLAG (1UL<<31)
+#define TRC_HD_INCLUDES_CYCLE_COUNT(x) ( !!( (x) & TRC_HD_CYCLE_FLAG ) )
+#define TRC_HD_EXTRA(x)    (((x)>>TRACE_EXTRA_SHIFT)&TRACE_EXTRA_MAX)
 
 /* Trace subclasses */
 #define TRC_SUBCLS_SHIFT 12
@@ -44,6 +51,8 @@
 
 /* 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_SCHED_DOM_ADD       (TRC_SCHED +  1)
 #define TRC_SCHED_DOM_REM       (TRC_SCHED +  2)
@@ -92,9 +101,19 @@
 
 /* This structure represents a single trace buffer record. */
 struct t_rec {
-    uint64_t cycles;          /* cycle counter timestamp */
-    uint32_t event;           /* event ID                */
-    unsigned long data[5];    /* event data items        */
+    uint32_t header;           /* 31   : Cycles included?
+                                  30-28: # of extra words
+                                  27- 0: event ID                */
+    union {
+        struct {
+            uint32_t cycles_lo, cycles_hi; /* cycle counter timestamp */
+            unsigned char data[28];        /* event data items        */
+        } cycles;
+        struct {
+            unsigned char data[28];        /* event data items        */
+        } nocycles;
+    }u;
+        
 };
 
 /*
@@ -102,9 +121,9 @@ struct t_rec {
  * field, indexes into an array of struct t_rec's.
  */
 struct t_buf {
-    uint32_t cons;      /* Next item to be consumed by control tools. */
-    uint32_t prod;      /* Next item to be produced by Xen.           */
-    /* 'nr_recs' records follow immediately after the meta-data header.    */
+    uint32_t cons;   /* Offset of next item to be consumed by control tools. */
+    uint32_t prod;   /* Offset of next item to be produced by Xen.           */
+    /*  Records follow immediately after the meta-data header.    */
 };
 
 #endif /* __XEN_PUBLIC_TRACE_H__ */
diff -r 517432b9f8b5 -r 7ed576909132 xen/include/xen/trace.h
--- a/xen/include/xen/trace.h   Fri Sep 21 16:52:17 2007 +0100
+++ b/xen/include/xen/trace.h   Fri Sep 21 15:26:07 2007 +0100
@@ -33,27 +33,74 @@ void init_trace_bufs(void);
 /* used to retrieve the physical address of the trace buffers */
 int tb_control(struct xen_sysctl_tbuf_op *tbc);
 
-void trace(u32 event, unsigned long d1, unsigned long d2,
+void __trace_fixed(u32 event, unsigned long d1, unsigned long d2,
            unsigned long d3, unsigned long d4, unsigned long d5);
+void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data);
 
-/* Avoids troubling the caller with casting their arguments to a trace macro */
-#define trace_do_casts(e,d1,d2,d3,d4,d5) \
-    do {                                 \
-        if ( unlikely(tb_init_done) )    \
-            trace(e,                     \
-                  (unsigned long)(d1),   \
-                  (unsigned long)(d2),   \
-                  (unsigned long)(d3),   \
-                  (unsigned long)(d4),   \
-                  (unsigned long)(d5));  \
+static inline void trace_fixed(u32 event, unsigned long d1,
+                               unsigned long d2, unsigned long d3,
+                               unsigned long d4, unsigned long d5)
+{
+    if( unlikely(tb_init_done) )
+        __trace_fixed(event, d1, d2, d3, d4, d5);
+}
+
+static inline void trace_var(u32 event, int cycles, int extra,
+                               unsigned char *extra_data)
+{
+    if( unlikely(tb_init_done) )
+        __trace_var(event, cycles, extra, extra_data);
+}
+
+/* Convenience macros for calling the trace function. */
+#define TRACE_0D(_e)                            \
+    do {                                        \
+        trace_var(_e, 1, 0, NULL);              \
+    } while ( 0 )
+  
+#define TRACE_1D(_e,_d)                                         \
+    do {                                                        \
+        u32 _d1;                                                \
+        _d1 = _d;                                               \
+        trace_var(_e, 1, sizeof(_d1), (unsigned char *)&_d1);  \
+    } while ( 0 )
+ 
+#define TRACE_2D(_e,d1,d2)                                      \
+    do {                                                       \
+        u32 _d[2];                                             \
+        _d[0]=d1;                                              \
+        _d[1]=d2;                                              \
+        trace_var(_e, 1, sizeof(*_d)*2, (unsigned char *)_d);  \
+    } while ( 0 )
+ 
+#define TRACE_3D(_e,d1,d2,d3)                                   \
+    do {                                                        \
+        u32 _d[3];                                              \
+        _d[0]=d1;                                               \
+        _d[1]=d2;                                               \
+        _d[2]=d3;                                               \
+        trace_var(_e, 1, sizeof(*_d)*3, (unsigned char *)_d);  \
+    } while ( 0 )
+ 
+#define TRACE_4D(_e,d1,d2,d3,d4)                                \
+    do {                                                        \
+        u32 _d[4];                                              \
+        _d[0]=d1;                                               \
+        _d[1]=d2;                                               \
+        _d[2]=d3;                                               \
+        _d[3]=d4;                                               \
+        trace_var(_e, 1, sizeof(*_d)*4, (unsigned char *)_d);  \
+    } while ( 0 )
+ 
+#define TRACE_5D(_e,d1,d2,d3,d4,d5)                             \
+    do {                                                       \
+        u32 _d[5];                                             \
+        _d[0]=d1;                                              \
+        _d[1]=d2;                                              \
+        _d[2]=d3;                                              \
+        _d[3]=d4;                                              \
+        _d[4]=d5;                                              \
+        trace_var(_e, 1, sizeof(*_d)*5, (unsigned char *)_d);  \
     } while ( 0 )
 
-/* Convenience macros for calling the trace function. */
-#define TRACE_0D(event)                trace_do_casts(event,0, 0, 0, 0, 0 )
-#define TRACE_1D(event,d)              trace_do_casts(event,d, 0, 0, 0, 0 )
-#define TRACE_2D(event,d1,d2)          trace_do_casts(event,d1,d2,0, 0, 0 )
-#define TRACE_3D(event,d1,d2,d3)       trace_do_casts(event,d1,d2,d3,0, 0 )
-#define TRACE_4D(event,d1,d2,d3,d4)    trace_do_casts(event,d1,d2,d3,d4,0 )
-#define TRACE_5D(event,d1,d2,d3,d4,d5) trace_do_casts(event,d1,d2,d3,d4,d5)
-
 #endif /* __XEN_TRACE_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [xen][tracing] Introduce variable-size trace records, Xen patchbot-unstable <=