]> xenbits.xensource.com Git - xen.git/commitdiff
xentrace: Allow xentrace to handle >4G of trace data.
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 11 Feb 2008 09:46:21 +0000 (09:46 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 11 Feb 2008 09:46:21 +0000 (09:46 +0000)
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@cl.cam.ac.uk>
tools/xentrace/xentrace.c
xen/common/trace.c
xen/include/public/trace.h

index 26415bdb7d728096aa55ec64110452d015ad5aae..bd276cc3eddf2bdf4e3df9442a8f0f2a10782253 100644 (file)
@@ -362,9 +362,18 @@ int monitor_tbufs(int outfd)
             if ( cons == prod )
                 continue;
            
-            assert(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);
 
-            window_size = prod - cons;
             start_offset = cons % data_size;
             end_offset = prod % data_size;
 
index d2f8fceeaea3029b20ab106a4f60f71eea5cac96..863816b9eeeea851da58d2656e5f9a0225dfbaac 100644 (file)
@@ -239,14 +239,46 @@ static inline int calc_rec_size(int cycles, int extra)
     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);
+    int x = data_size - buf->prod;
+    if ( x <= 0 )
+        x += data_size;
+
+    ASSERT(x > 0);
+    ASSERT(x <= data_size);
+
+    return x;
 }
 
-static inline unsigned calc_bytes_avail(struct t_buf *buf)
+static inline int calc_bytes_avail(struct t_buf *buf)
 {
-    return data_size - (buf->prod - buf->cons);
+    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 t_buf *buf,
     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 t_buf *buf,
         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, int extra, unsigned char *extra_data)
 
     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, int extra, unsigned char *extra_data)
     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, int extra, unsigned char *extra_data)
 
     /* 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);
 }
 
index 4cbb8963422322c79a06b89f5a240636daba1616..21fe15ffb99f1fb4d6bfd43419af33798e828465 100644 (file)
@@ -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.    */