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