# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1202723181 0
# Node ID 98e9d5d4b309c82886d7740aa88c29c334a4fff9
# Parent 7d03c0b0750482ec96ec9fcf93c2b585f7740af5
xentrace: Allow xentrace to handle >4G of trace data.
It was previously assert'ing when it hit 4G.
Also, because the trace buffer is not a power of 2 in size,
using modulo arithmetic to address the buffer does not work
when the index wraps around 2^32.
This patch fixes both issues, and as a side effect, removes all
integer division from the hypervisor side of the trace mechanism.
Signed-off-by: Michael A Fetterman <Michael.Fetterman@xxxxxxxxxxxx>
---
tools/xentrace/xentrace.c | 15 +++++++--
xen/common/trace.c | 71 +++++++++++++++++++++++++++++++++------------
xen/include/public/trace.h | 8 +++++
3 files changed, 73 insertions(+), 21 deletions(-)
diff -r 7d03c0b07504 -r 98e9d5d4b309 tools/xentrace/xentrace.c
--- a/tools/xentrace/xentrace.c Mon Feb 11 09:45:36 2008 +0000
+++ b/tools/xentrace/xentrace.c Mon Feb 11 09:46:21 2008 +0000
@@ -362,9 +362,18 @@ int monitor_tbufs(int outfd)
if ( cons == prod )
continue;
- assert(prod > cons);
-
- window_size = prod - cons;
+ assert(cons < 2*data_size);
+ assert(prod < 2*data_size);
+
+ // NB: if (prod<cons), then (prod-cons)%data_size will not yield
+ // the correct answer because data_size is not a power of 2.
+ if ( prod < cons )
+ window_size = (prod + 2*data_size) - cons;
+ else
+ window_size = prod - cons;
+ assert(window_size > 0);
+ assert(window_size <= data_size);
+
start_offset = cons % data_size;
end_offset = prod % data_size;
diff -r 7d03c0b07504 -r 98e9d5d4b309 xen/common/trace.c
--- a/xen/common/trace.c Mon Feb 11 09:45:36 2008 +0000
+++ b/xen/common/trace.c Mon Feb 11 09:46:21 2008 +0000
@@ -239,14 +239,46 @@ static inline int calc_rec_size(int cycl
return rec_size;
}
+static inline int calc_unconsumed_bytes(struct t_buf *buf)
+{
+ int x = buf->prod - buf->cons;
+ if ( x < 0 )
+ x += 2*data_size;
+
+ ASSERT(x >= 0);
+ ASSERT(x <= data_size);
+
+ return x;
+}
+
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);
+ int x = data_size - buf->prod;
+ if ( x <= 0 )
+ x += data_size;
+
+ ASSERT(x > 0);
+ ASSERT(x <= data_size);
+
+ return x;
+}
+
+static inline int calc_bytes_avail(struct t_buf *buf)
+{
+ return data_size - calc_unconsumed_bytes(buf);
+}
+
+static inline struct t_rec *
+next_record(struct t_buf *buf)
+{
+ int x = buf->prod;
+ if ( x >= data_size )
+ x -= data_size;
+
+ ASSERT(x >= 0);
+ ASSERT(x < data_size);
+
+ return (struct t_rec *)&this_cpu(t_data)[x];
}
static inline int __insert_record(struct t_buf *buf,
@@ -260,24 +292,25 @@ static inline int __insert_record(struct
unsigned char *dst;
unsigned long extra_word = extra/sizeof(u32);
int local_rec_size = calc_rec_size(cycles, extra);
+ uint32_t next;
BUG_ON(local_rec_size != rec_size);
+ BUG_ON(extra & 3);
/* 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",
+ printk("%s: %u bytes left (%u - ((%u - %u) %% %u) recsize %u.\n",
__func__,
- data_size - (buf->prod - buf->cons),
- data_size,
- buf->prod, buf->cons, rec_size);
+ calc_bytes_avail(buf),
+ data_size, buf->prod, buf->cons, data_size, rec_size);
return 0;
}
rmb();
- rec = (struct t_rec *)&this_cpu(t_data)[buf->prod % data_size];
+ rec = next_record(buf);
rec->event = event;
rec->extra_u32 = extra_word;
dst = (unsigned char *)rec->u.nocycles.extra_u32;
@@ -293,7 +326,13 @@ static inline int __insert_record(struct
memcpy(dst, extra_data, extra);
wmb();
- buf->prod += rec_size;
+
+ next = buf->prod + rec_size;
+ if ( next >= 2*data_size )
+ next -= 2*data_size;
+ ASSERT(next >= 0);
+ ASSERT(next < 2*data_size);
+ buf->prod = next;
return rec_size;
}
@@ -395,7 +434,7 @@ void __trace_var(u32 event, int cycles,
local_irq_save(flags);
- started_below_highwater = ((buf->prod - buf->cons) < t_buf_highwater);
+ started_below_highwater = (calc_unconsumed_bytes(buf) < t_buf_highwater);
/* Calculate the record size */
rec_size = calc_rec_size(cycles, extra);
@@ -413,10 +452,6 @@ void __trace_var(u32 event, int cycles,
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) )
{
@@ -477,7 +512,7 @@ void __trace_var(u32 event, int cycles,
/* Notify trace buffer consumer that we've crossed the high water mark. */
if ( started_below_highwater &&
- ((buf->prod - buf->cons) >= t_buf_highwater) )
+ (calc_unconsumed_bytes(buf) >= t_buf_highwater) )
raise_softirq(TRACE_SOFTIRQ);
}
diff -r 7d03c0b07504 -r 98e9d5d4b309 xen/include/public/trace.h
--- a/xen/include/public/trace.h Mon Feb 11 09:45:36 2008 +0000
+++ b/xen/include/public/trace.h Mon Feb 11 09:46:21 2008 +0000
@@ -141,6 +141,14 @@ struct t_rec {
* field, indexes into an array of struct t_rec's.
*/
struct t_buf {
+ /* Assume the data buffer size is X. X is generally not a power of 2.
+ * CONS and PROD are incremented modulo (2*X):
+ * 0 <= cons < 2*X
+ * 0 <= prod < 2*X
+ * This is done because addition modulo X breaks at 2^32 when X is not a
+ * power of 2:
+ * (((2^32 - 1) % X) + 1) % X != (2^32) % X
+ */
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. */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|