ia64/xen-unstable

view xen/common/trace.c @ 17062:0769835cf50f

x86 shadow: Reduce scope of shadow lock.

emulate_map_dest doesn't require holding lock, since
only shadow related operation possibly involved is to
remove shadow which is less frequent and can acquire
lock inside. Rest are either guest table walk or
per-vcpu monitor table manipulation

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 14 10:33:12 2008 +0000 (2008-02-14)
parents 98e9d5d4b309
children d2010614d9f1
line source
1 /******************************************************************************
2 * common/trace.c
3 *
4 * Xen Trace Buffer
5 *
6 * Copyright (C) 2004 by Intel Research Cambridge
7 *
8 * Authors: Mark Williamson, mark.a.williamson@intel.com
9 * Rob Gardner, rob.gardner@hp.com
10 * Date: October 2005
11 *
12 * Copyright (C) 2005 Bin Ren
13 *
14 * The trace buffer code is designed to allow debugging traces of Xen to be
15 * generated on UP / SMP machines. Each trace entry is timestamped so that
16 * it's possible to reconstruct a chronological record of trace events.
17 */
19 #include <xen/config.h>
20 #include <asm/types.h>
21 #include <asm/io.h>
22 #include <xen/lib.h>
23 #include <xen/sched.h>
24 #include <xen/smp.h>
25 #include <xen/trace.h>
26 #include <xen/errno.h>
27 #include <xen/event.h>
28 #include <xen/softirq.h>
29 #include <xen/init.h>
30 #include <xen/mm.h>
31 #include <xen/percpu.h>
32 #include <asm/atomic.h>
33 #include <public/sysctl.h>
35 #ifdef CONFIG_COMPAT
36 #include <compat/trace.h>
37 #define xen_t_buf t_buf
38 CHECK_t_buf;
39 #undef xen_t_buf
40 #define TB_COMPAT IS_COMPAT(dom0)
41 #else
42 #define compat_t_rec t_rec
43 #define TB_COMPAT 0
44 #endif
46 /* opt_tbuf_size: trace buffer size (in pages) */
47 static unsigned int opt_tbuf_size = 0;
48 integer_param("tbuf_size", opt_tbuf_size);
50 /* Pointers to the meta-data objects for all system trace buffers */
51 static DEFINE_PER_CPU(struct t_buf *, t_bufs);
52 static DEFINE_PER_CPU(unsigned char *, t_data);
53 static int data_size;
55 /* High water mark for trace buffers; */
56 /* Send virtual interrupt when buffer level reaches this point */
57 static int t_buf_highwater;
59 /* Number of records lost due to per-CPU trace buffer being full. */
60 static DEFINE_PER_CPU(unsigned long, lost_records);
62 /* a flag recording whether initialization has been done */
63 /* or more properly, if the tbuf subsystem is enabled right now */
64 int tb_init_done __read_mostly;
66 /* which CPUs tracing is enabled on */
67 static cpumask_t tb_cpu_mask = CPU_MASK_ALL;
69 /* which tracing events are enabled */
70 static u32 tb_event_mask = TRC_ALL;
72 static void trace_notify_guest(void)
73 {
74 send_guest_global_virq(dom0, VIRQ_TBUF);
75 }
78 /**
79 * alloc_trace_bufs - performs initialization of the per-cpu trace buffers.
80 *
81 * This function is called at start of day in order to initialize the per-cpu
82 * trace buffers. The trace buffers are then available for debugging use, via
83 * the %TRACE_xD macros exported in <xen/trace.h>.
84 *
85 * This function may also be called later when enabling trace buffers
86 * via the SET_SIZE hypercall.
87 */
88 static int alloc_trace_bufs(void)
89 {
90 int i, order;
91 unsigned long nr_pages;
92 char *rawbuf;
93 struct t_buf *buf;
95 if ( opt_tbuf_size == 0 )
96 return -EINVAL;
98 nr_pages = num_online_cpus() * opt_tbuf_size;
99 order = get_order_from_pages(nr_pages);
100 data_size = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf));
102 if ( (rawbuf = alloc_xenheap_pages(order)) == NULL )
103 {
104 printk("Xen trace buffers: memory allocation failed\n");
105 opt_tbuf_size = 0;
106 return -EINVAL;
107 }
109 /* Share pages so that xentrace can map them. */
110 for ( i = 0; i < nr_pages; i++ )
111 share_xen_page_with_privileged_guests(
112 virt_to_page(rawbuf) + i, XENSHARE_writable);
114 for_each_online_cpu ( i )
115 {
116 buf = per_cpu(t_bufs, i) = (struct t_buf *)
117 &rawbuf[i*opt_tbuf_size*PAGE_SIZE];
118 buf->cons = buf->prod = 0;
119 per_cpu(t_data, i) = (unsigned char *)(buf + 1);
120 }
122 t_buf_highwater = data_size >> 1; /* 50% high water */
123 open_softirq(TRACE_SOFTIRQ, trace_notify_guest);
125 return 0;
126 }
129 /**
130 * tb_set_size - handle the logic involved with dynamically
131 * allocating and deallocating tbufs
132 *
133 * This function is called when the SET_SIZE hypercall is done.
134 */
135 static int tb_set_size(int size)
136 {
137 /*
138 * Setting size is a one-shot operation. It can be done either at
139 * boot time or via control tools, but not by both. Once buffers
140 * are created they cannot be destroyed.
141 */
142 if ( (opt_tbuf_size != 0) || (size <= 0) )
143 {
144 gdprintk(XENLOG_INFO, "tb_set_size from %d to %d not implemented\n",
145 opt_tbuf_size, size);
146 return -EINVAL;
147 }
149 opt_tbuf_size = size;
150 if ( alloc_trace_bufs() != 0 )
151 return -EINVAL;
153 printk("Xen trace buffers: initialized\n");
154 return 0;
155 }
158 /**
159 * init_trace_bufs - performs initialization of the per-cpu trace buffers.
160 *
161 * This function is called at start of day in order to initialize the per-cpu
162 * trace buffers. The trace buffers are then available for debugging use, via
163 * the %TRACE_xD macros exported in <xen/trace.h>.
164 */
165 void __init init_trace_bufs(void)
166 {
167 if ( opt_tbuf_size == 0 )
168 {
169 printk("Xen trace buffers: disabled\n");
170 return;
171 }
173 if ( alloc_trace_bufs() == 0 )
174 {
175 printk("Xen trace buffers: initialised\n");
176 wmb(); /* above must be visible before tb_init_done flag set */
177 tb_init_done = 1;
178 }
179 }
181 /**
182 * tb_control - sysctl operations on trace buffers.
183 * @tbc: a pointer to a xen_sysctl_tbuf_op_t to be filled out
184 */
185 int tb_control(xen_sysctl_tbuf_op_t *tbc)
186 {
187 static DEFINE_SPINLOCK(lock);
188 int rc = 0;
190 spin_lock(&lock);
192 switch ( tbc->cmd )
193 {
194 case XEN_SYSCTL_TBUFOP_get_info:
195 tbc->evt_mask = tb_event_mask;
196 tbc->buffer_mfn = opt_tbuf_size ? virt_to_mfn(per_cpu(t_bufs, 0)) : 0;
197 tbc->size = opt_tbuf_size * PAGE_SIZE;
198 break;
199 case XEN_SYSCTL_TBUFOP_set_cpu_mask:
200 xenctl_cpumap_to_cpumask(&tb_cpu_mask, &tbc->cpu_mask);
201 break;
202 case XEN_SYSCTL_TBUFOP_set_evt_mask:
203 tb_event_mask = tbc->evt_mask;
204 break;
205 case XEN_SYSCTL_TBUFOP_set_size:
206 rc = !tb_init_done ? tb_set_size(tbc->size) : -EINVAL;
207 break;
208 case XEN_SYSCTL_TBUFOP_enable:
209 /* Enable trace buffers. Check buffers are already allocated. */
210 if ( opt_tbuf_size == 0 )
211 rc = -EINVAL;
212 else
213 tb_init_done = 1;
214 break;
215 case XEN_SYSCTL_TBUFOP_disable:
216 /*
217 * Disable trace buffers. Just stops new records from being written,
218 * does not deallocate any memory.
219 */
220 tb_init_done = 0;
221 break;
222 default:
223 rc = -EINVAL;
224 break;
225 }
227 spin_unlock(&lock);
229 return rc;
230 }
232 static inline int calc_rec_size(int cycles, int extra)
233 {
234 int rec_size;
235 rec_size = 4;
236 if ( cycles )
237 rec_size += 8;
238 rec_size += extra;
239 return rec_size;
240 }
242 static inline int calc_unconsumed_bytes(struct t_buf *buf)
243 {
244 int x = buf->prod - buf->cons;
245 if ( x < 0 )
246 x += 2*data_size;
248 ASSERT(x >= 0);
249 ASSERT(x <= data_size);
251 return x;
252 }
254 static inline int calc_bytes_to_wrap(struct t_buf *buf)
255 {
256 int x = data_size - buf->prod;
257 if ( x <= 0 )
258 x += data_size;
260 ASSERT(x > 0);
261 ASSERT(x <= data_size);
263 return x;
264 }
266 static inline int calc_bytes_avail(struct t_buf *buf)
267 {
268 return data_size - calc_unconsumed_bytes(buf);
269 }
271 static inline struct t_rec *
272 next_record(struct t_buf *buf)
273 {
274 int x = buf->prod;
275 if ( x >= data_size )
276 x -= data_size;
278 ASSERT(x >= 0);
279 ASSERT(x < data_size);
281 return (struct t_rec *)&this_cpu(t_data)[x];
282 }
284 static inline int __insert_record(struct t_buf *buf,
285 unsigned long event,
286 int extra,
287 int cycles,
288 int rec_size,
289 unsigned char *extra_data)
290 {
291 struct t_rec *rec;
292 unsigned char *dst;
293 unsigned long extra_word = extra/sizeof(u32);
294 int local_rec_size = calc_rec_size(cycles, extra);
295 uint32_t next;
297 BUG_ON(local_rec_size != rec_size);
298 BUG_ON(extra & 3);
300 /* Double-check once more that we have enough space.
301 * Don't bugcheck here, in case the userland tool is doing
302 * something stupid. */
303 if ( calc_bytes_avail(buf) < rec_size )
304 {
305 printk("%s: %u bytes left (%u - ((%u - %u) %% %u) recsize %u.\n",
306 __func__,
307 calc_bytes_avail(buf),
308 data_size, buf->prod, buf->cons, data_size, rec_size);
309 return 0;
310 }
311 rmb();
313 rec = next_record(buf);
314 rec->event = event;
315 rec->extra_u32 = extra_word;
316 dst = (unsigned char *)rec->u.nocycles.extra_u32;
317 if ( (rec->cycles_included = cycles) != 0 )
318 {
319 u64 tsc = (u64)get_cycles();
320 rec->u.cycles.cycles_lo = (uint32_t)tsc;
321 rec->u.cycles.cycles_hi = (uint32_t)(tsc >> 32);
322 dst = (unsigned char *)rec->u.cycles.extra_u32;
323 }
325 if ( extra_data && extra )
326 memcpy(dst, extra_data, extra);
328 wmb();
330 next = buf->prod + rec_size;
331 if ( next >= 2*data_size )
332 next -= 2*data_size;
333 ASSERT(next >= 0);
334 ASSERT(next < 2*data_size);
335 buf->prod = next;
337 return rec_size;
338 }
340 static inline int insert_wrap_record(struct t_buf *buf, int size)
341 {
342 int space_left = calc_bytes_to_wrap(buf);
343 unsigned long extra_space = space_left - sizeof(u32);
344 int cycles = 0;
346 BUG_ON(space_left > size);
348 /* We may need to add cycles to take up enough space... */
349 if ( (extra_space/sizeof(u32)) > TRACE_EXTRA_MAX )
350 {
351 cycles = 1;
352 extra_space -= sizeof(u64);
353 ASSERT((extra_space/sizeof(u32)) <= TRACE_EXTRA_MAX);
354 }
356 return __insert_record(buf,
357 TRC_TRACE_WRAP_BUFFER,
358 extra_space,
359 cycles,
360 space_left,
361 NULL);
362 }
364 #define LOST_REC_SIZE 8
366 static inline int insert_lost_records(struct t_buf *buf)
367 {
368 struct {
369 u32 lost_records;
370 } ed;
372 ed.lost_records = this_cpu(lost_records);
374 this_cpu(lost_records) = 0;
376 return __insert_record(buf,
377 TRC_LOST_RECORDS,
378 sizeof(ed),
379 0 /* !cycles */,
380 LOST_REC_SIZE,
381 (unsigned char *)&ed);
382 }
385 /**
386 * trace - Enters a trace tuple into the trace buffer for the current CPU.
387 * @event: the event type being logged
388 * @d1...d5: the data items for the event being logged
389 *
390 * Logs a trace record into the appropriate buffer. Returns nonzero on
391 * failure, otherwise 0. Failure occurs only if the trace buffers are not yet
392 * initialised.
393 */
394 void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data)
395 {
396 struct t_buf *buf;
397 unsigned long flags, bytes_to_tail, bytes_to_wrap;
398 int rec_size, total_size;
399 int extra_word;
400 int started_below_highwater;
402 ASSERT(tb_init_done);
404 /* Convert byte count into word count, rounding up */
405 extra_word = (extra / sizeof(u32));
406 if ( (extra % sizeof(u32)) != 0 )
407 extra_word++;
409 ASSERT(extra_word <= TRACE_EXTRA_MAX);
410 extra_word = min_t(int, extra_word, TRACE_EXTRA_MAX);
412 /* Round size up to nearest word */
413 extra = extra_word * sizeof(u32);
415 if ( (tb_event_mask & event) == 0 )
416 return;
418 /* match class */
419 if ( ((tb_event_mask >> TRC_CLS_SHIFT) & (event >> TRC_CLS_SHIFT)) == 0 )
420 return;
422 /* then match subclass */
423 if ( (((tb_event_mask >> TRC_SUBCLS_SHIFT) & 0xf )
424 & ((event >> TRC_SUBCLS_SHIFT) & 0xf )) == 0 )
425 return;
427 if ( !cpu_isset(smp_processor_id(), tb_cpu_mask) )
428 return;
430 /* Read tb_init_done /before/ t_bufs. */
431 rmb();
433 buf = this_cpu(t_bufs);
435 local_irq_save(flags);
437 started_below_highwater = (calc_unconsumed_bytes(buf) < t_buf_highwater);
439 /* Calculate the record size */
440 rec_size = calc_rec_size(cycles, extra);
442 /* How many bytes are available in the buffer? */
443 bytes_to_tail = calc_bytes_avail(buf);
445 /* How many bytes until the next wrap-around? */
446 bytes_to_wrap = calc_bytes_to_wrap(buf);
448 /*
449 * Calculate expected total size to commit this record by
450 * doing a dry-run.
451 */
452 total_size = 0;
454 /* First, check to see if we need to include a lost_record.
455 */
456 if ( this_cpu(lost_records) )
457 {
458 if ( LOST_REC_SIZE > bytes_to_wrap )
459 {
460 total_size += bytes_to_wrap;
461 bytes_to_wrap = data_size;
462 }
463 total_size += LOST_REC_SIZE;
464 bytes_to_wrap -= LOST_REC_SIZE;
466 /* LOST_REC might line up perfectly with the buffer wrap */
467 if ( bytes_to_wrap == 0 )
468 bytes_to_wrap = data_size;
469 }
471 if ( rec_size > bytes_to_wrap )
472 {
473 total_size += bytes_to_wrap;
474 }
475 total_size += rec_size;
477 /* Do we have enough space for everything? */
478 if ( total_size > bytes_to_tail )
479 {
480 this_cpu(lost_records)++;
481 local_irq_restore(flags);
482 return;
483 }
485 /*
486 * Now, actually write information
487 */
488 bytes_to_wrap = calc_bytes_to_wrap(buf);
490 if ( this_cpu(lost_records) )
491 {
492 if ( LOST_REC_SIZE > bytes_to_wrap )
493 {
494 insert_wrap_record(buf, LOST_REC_SIZE);
495 bytes_to_wrap = data_size;
496 }
497 insert_lost_records(buf);
498 bytes_to_wrap -= LOST_REC_SIZE;
500 /* LOST_REC might line up perfectly with the buffer wrap */
501 if ( bytes_to_wrap == 0 )
502 bytes_to_wrap = data_size;
503 }
505 if ( rec_size > bytes_to_wrap )
506 insert_wrap_record(buf, rec_size);
508 /* Write the original record */
509 __insert_record(buf, event, extra, cycles, rec_size, extra_data);
511 local_irq_restore(flags);
513 /* Notify trace buffer consumer that we've crossed the high water mark. */
514 if ( started_below_highwater &&
515 (calc_unconsumed_bytes(buf) >= t_buf_highwater) )
516 raise_softirq(TRACE_SOFTIRQ);
517 }
519 /*
520 * Local variables:
521 * mode: C
522 * c-set-style: "BSD"
523 * c-basic-offset: 4
524 * tab-width: 4
525 * indent-tabs-mode: nil
526 * End:
527 */