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@cl.cam.ac.uk>
This commit is contained in:
Keir Fraser committed 2008-02-11 09:46:21 +00:00
1 parent 4be9201e8c
commit d37035e9f9
3 files changed
+70 -18

No files matched your search

+11 -2
View 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;
+51 -16
View File
@@ -239,14 +239,46 @@ static inline int calc_rec_size(int cycles, int extra)
return rec_size;
}
static inline int calc_bytes_to_wrap(struct t_buf *buf)
static inline int calc_unconsumed_bytes(struct t_buf *buf)
{
return data_size - (buf->prod % data_size);
int x = buf->prod - buf->cons;
if ( x < 0 )
x += 2*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_to_wrap(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 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);
}
+8
View 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. */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.