diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/examples/xc_dom_control.py | 8 | ||||
-rw-r--r-- | tools/xc/lib/xc_domain.c | 1 | ||||
-rw-r--r-- | tools/xc/lib/xc_linux_restore.c | 7 | ||||
-rw-r--r-- | tools/xc/lib/xc_linux_save.c | 207 | ||||
-rw-r--r-- | tools/xc/lib/xc_private.c | 64 | ||||
-rw-r--r-- | tools/xc/lib/xc_private.h | 5 | ||||
-rw-r--r-- | tools/xc/py/Xc.c | 30 | ||||
-rw-r--r-- | tools/xentrace/Makefile | 2 | ||||
-rw-r--r-- | tools/xentrace/formats | 49 | ||||
-rw-r--r-- | tools/xentrace/xentrace.c | 56 | ||||
-rw-r--r-- | tools/xentrace/xentrace_format | 52 |
11 files changed, 330 insertions, 151 deletions
diff --git a/tools/examples/xc_dom_control.py b/tools/examples/xc_dom_control.py index 877afa53d1..9feab009e3 100755 --- a/tools/examples/xc_dom_control.py +++ b/tools/examples/xc_dom_control.py @@ -136,15 +136,7 @@ elif cmd == 'suspend': pid = int(fd.readline()) os.kill(pid, signal.SIGTERM) - xc.domain_stop( dom=dom ) - - while not xc.domain_getinfo( first_dom=dom, max_doms=1 )[0]['stopped']: - print "Sleep..." - time.sleep(0.001); - rc = xc.linux_save( dom=dom, state_file=file, progress=1) - if rc == 0 : xc.domain_destroy( dom=dom, force=1 ) - else: xc.domain_start( dom=dom ) # sensible for production use elif cmd == 'cpu_bvtslice': if len(sys.argv) < 3: diff --git a/tools/xc/lib/xc_domain.c b/tools/xc/lib/xc_domain.c index 6d0dd6d0f3..97b2b26f6d 100644 --- a/tools/xc/lib/xc_domain.c +++ b/tools/xc/lib/xc_domain.c @@ -46,6 +46,7 @@ int xc_domain_stop(int xc_handle, dom0_op_t op; op.cmd = DOM0_STOPDOMAIN; op.u.stopdomain.domain = (domid_t)domid; + op.u.stopdomain.sync = 0; // async return do_dom0_op(xc_handle, &op); } diff --git a/tools/xc/lib/xc_linux_restore.c b/tools/xc/lib/xc_linux_restore.c index d66e22fd0a..4e89b5715f 100644 --- a/tools/xc/lib/xc_linux_restore.c +++ b/tools/xc/lib/xc_linux_restore.c @@ -592,14 +592,11 @@ int xc_linux_restore(int xc_handle, out: - if ( rc != 0 ) // destroy is something went wrong + if ( rc != 0 ) // destroy if something went wrong { if ( dom != 0 ) { - op.cmd = DOM0_DESTROYDOMAIN; - op.u.destroydomain.domain = (domid_t)dom; - op.u.destroydomain.force = 1; - (void)do_dom0_op(xc_handle, &op); + xc_domain_destroy( xc_handle, dom, 1 ); } } diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c index ceb5f02e15..857007fd3e 100644 --- a/tools/xc/lib/xc_linux_save.c +++ b/tools/xc/lib/xc_linux_save.c @@ -82,6 +82,67 @@ inline void set_bit ( int nr, volatile void * addr) (1 << (nr % (sizeof(unsigned long)*8) ) ); } +long long tv_to_us( struct timeval *new ) +{ + return (new->tv_sec * 1000000) + new->tv_usec; +} + +long long tvdelta( struct timeval *new, struct timeval *old ) +{ + return ((new->tv_sec - old->tv_sec)*1000000 ) + + (new->tv_usec - old->tv_usec); +} + +int track_cpu_usage_dom0( int xc_handle, int print ) +{ + static struct timeval wall_last; + static long long cpu_last; + + struct timeval wall_now; + long long cpu_now, wall_delta, cpu_delta; + + gettimeofday(&wall_now, NULL); + + cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000; + + wall_delta = tvdelta(&wall_now,&wall_last)/1000; + cpu_delta = (cpu_now - cpu_last)/1000; + + if(print) + printf("Dom0 : wall delta %lldms, cpu delta %lldms : %d%%\n", + wall_delta, cpu_delta, (cpu_delta*100)/wall_delta); + + cpu_last = cpu_now; + wall_last = wall_now; + + return 0; +} + +int track_cpu_usage_target( int xc_handle, u64 domid, int print ) +{ + static struct timeval wall_last; + static long long cpu_last; + + struct timeval wall_now; + long long cpu_now, wall_delta, cpu_delta; + + gettimeofday(&wall_now, NULL); + + cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000; + + wall_delta = tvdelta(&wall_now,&wall_last)/1000; + cpu_delta = (cpu_now - cpu_last)/1000; + + if(print) + printf("Target: wall delta %lldms, cpu delta %lldms : %d%%\n", + wall_delta, cpu_delta, (cpu_delta*100)/wall_delta); + + cpu_last = cpu_now; + wall_last = wall_now; + + return 0; +} + int xc_linux_save(int xc_handle, u64 domid, @@ -95,10 +156,11 @@ int xc_linux_save(int xc_handle, int verbose = flags & XCFLAGS_VERBOSE; int live = flags & XCFLAGS_LIVE; int debug = flags & XCFLAGS_DEBUG; - int sent_last_iter, sent_this_iter, max_iters; - - /* Remember if we stopped the guest, so we can restart it on exit. */ - int we_stopped_it = 0; + int sent_last_iter, sent_this_iter, skip_this_iter; + + /* Important tuning parameters */ + int max_iters = 29; // limit us to 30 times round loop + int max_factor = 3; // never send more than 3x nr_pfns /* The new domain's shared-info frame number. */ unsigned long shared_info_frame; @@ -137,11 +199,15 @@ int xc_linux_save(int xc_handle, /* number of pages we're dealing with */ unsigned long nr_pfns; - /* bitmap of pages left to send */ - unsigned long *to_send, *to_fix; - -//live=0; + /* bitmap of pages: + - that should be sent this iteration (unless later marked as skip); + - to skip this iteration because already dirty; + - to fixup by sending at the end if not already resent; */ + unsigned long *to_send, *to_skip, *to_fix; + int needed_to_fix = 0; + int total_sent = 0; + if ( mlock(&ctxt, sizeof(ctxt) ) ) { PERROR("Unable to mlock ctxt"); @@ -149,39 +215,16 @@ int xc_linux_save(int xc_handle, } /* Ensure that the domain exists, and that it is stopped. */ - for ( ; ; ) - { - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = &ctxt; - if ( (do_dom0_op(xc_handle, &op) < 0) || - ((u64)op.u.getdomaininfo.domain != domid) ) - { - PERROR("Could not get info on domain"); - goto out; - } - - memcpy(name, op.u.getdomaininfo.name, sizeof(name)); - shared_info_frame = op.u.getdomaininfo.shared_info_frame; - - if ( op.u.getdomaininfo.state == DOMSTATE_STOPPED ) - break; - we_stopped_it = 1; - - op.cmd = DOM0_STOPDOMAIN; - op.u.stopdomain.domain = (domid_t)domid; - if ( do_dom0_op(xc_handle, &op) != 0 ) - { - we_stopped_it = 0; - PERROR("Stopping target domain failed"); - goto out; - } - - usleep(1000); // 1ms - printf("Sleep for 1ms\n"); + if ( xc_domain_stop_sync( xc_handle, domid, &op, &ctxt ) ) + { + PERROR("Could not sync stop domain"); + goto out; } + memcpy(name, op.u.getdomaininfo.name, sizeof(name)); + shared_info_frame = op.u.getdomaininfo.shared_info_frame; + /* A cheesy test to see whether the domain contains valid state. */ if ( ctxt.pt_base == 0 ) { @@ -288,7 +331,6 @@ int xc_linux_save(int xc_handle, last_iter = 0; sent_last_iter = 1<<20; // 4GB's worth of pages - max_iters = 9; // limit us to 10 time round loop } else last_iter = 1; @@ -300,12 +342,14 @@ int xc_linux_save(int xc_handle, to_send = malloc( sz ); to_fix = calloc( 1, sz ); + to_skip = malloc( sz ); - if (!to_send || !to_fix) + if (!to_send || !to_fix || !to_skip) { ERROR("Couldn't allocate to_send array"); goto out; } + memset( to_send, 0xff, sz ); if ( mlock( to_send, sz ) ) @@ -313,6 +357,15 @@ int xc_linux_save(int xc_handle, PERROR("Unable to mlock to_send"); return 1; } + + /* (to fix is local only) */ + + if ( mlock( to_skip, sz ) ) + { + PERROR("Unable to mlock to_skip"); + return 1; + } + } @@ -369,8 +422,11 @@ int xc_linux_save(int xc_handle, goto out; } - /* Now write out each data page, canonicalising page tables as we go... */ + track_cpu_usage_dom0(xc_handle, 0); + track_cpu_usage_target( xc_handle, domid, 0); + /* Now write out each data page, canonicalising page tables as we go... */ + while(1) { unsigned int prev_pc, batch, sent_this_iter; @@ -378,6 +434,7 @@ int xc_linux_save(int xc_handle, iter++; sent_this_iter = 0; + skip_this_iter = 0; prev_pc = 0; verbose_printf("Saving memory pages: iter %d 0%%", iter); @@ -391,6 +448,18 @@ int xc_linux_save(int xc_handle, prev_pc = this_pc; } + /* slightly wasteful to peek the whole array evey time, + but this is fast enough for the moment. */ + + if ( !last_iter && + xc_shadow_control( xc_handle, domid, + DOM0_SHADOW_CONTROL_OP_PEEK, + to_skip, nr_pfns ) != nr_pfns ) + { + ERROR("Error peeking shadow bitmap"); + goto out; + } + /* load pfn_type[] with the mfn of all the pages we're doing in this batch. */ @@ -404,15 +473,29 @@ int xc_linux_save(int xc_handle, test_bit(n,to_send), live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&0xFFFFF]); + if (!last_iter && test_bit(n, to_send) && test_bit(n, to_skip)) + skip_this_iter++; // stats keeping - if ( !test_bit(n, to_send ) && - !( last_iter && test_bit(n, to_fix ) ) ) continue; + if (! ( (test_bit(n, to_send) && !test_bit(n, to_skip)) || + (test_bit(n, to_send) && last_iter) || + (test_bit(n, to_fix) && last_iter) ) ) + continue; + + /* we get here if: + 1. page is marked to_send & hasn't already been re-dirtied + 2. (ignore to_skip in last iteration) + 3. add in pages that still need fixup (net bufs) + */ pfn_batch[batch] = n; pfn_type[batch] = live_pfn_to_mfn_table[n]; if( pfn_type[batch] == 0x80000004 ) { + /* not currently in pusedo-physical map -- set bit + in to_fix that we must send this page in last_iter + unless its sent sooner anyhow */ + set_bit( n, to_fix ); if( iter>1 ) DDPRINTF("Urk! netbuf race: iter %d, pfn %lx. mfn %lx\n", @@ -422,6 +505,7 @@ int xc_linux_save(int xc_handle, if ( last_iter && test_bit(n, to_fix ) && !test_bit(n, to_send )) { + needed_to_fix++; DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n", iter,n,pfn_type[batch]); } @@ -567,9 +651,23 @@ int xc_linux_save(int xc_handle, munmap(region_base, batch*PAGE_SIZE); skip: + + total_sent += sent_this_iter; + + verbose_printf("\b\b\b\b100%% (pages sent= %d, skipped= %d )\n", + sent_this_iter, skip_this_iter ); + + track_cpu_usage_dom0(xc_handle, 1); + track_cpu_usage_target( xc_handle, domid, 1); + - verbose_printf("\b\b\b\b100%% (%d pages)\n", sent_this_iter ); - + if ( last_iter ) + { + verbose_printf("Total pages sent= %d (%.2fx)\n", + total_sent, ((float)total_sent)/nr_pfns ); + verbose_printf("(of which %d were fixups)\n", needed_to_fix ); + } + if ( debug && last_iter ) { int minusone = -1; @@ -592,18 +690,21 @@ int xc_linux_save(int xc_handle, if ( live ) { - if ( ( sent_this_iter > (sent_last_iter * 0.95) ) || - (iter >= max_iters) || (sent_this_iter < 10) ) + if ( + // ( sent_this_iter > (sent_last_iter * 0.95) ) || + (iter >= max_iters) || + (sent_this_iter+skip_this_iter < 10) || + (total_sent > nr_pfns*max_factor) ) { DPRINTF("Start last iteration\n"); last_iter = 1; - xc_domain_stop_sync( xc_handle, domid ); + xc_domain_stop_sync( xc_handle, domid, &op, NULL ); } if ( xc_shadow_control( xc_handle, domid, - DOM0_SHADOW_CONTROL_OP_CLEAN, + DOM0_SHADOW_CONTROL_OP_CLEAN2, to_send, nr_pfns ) != nr_pfns ) { ERROR("Error flushing shadow PT"); @@ -674,14 +775,6 @@ int xc_linux_save(int xc_handle, munmap(live_shinfo, PAGE_SIZE); out: - /* Restart the domain if we had to stop it to save its state. */ - if ( we_stopped_it ) - { - printf("Restart domain\n"); - op.cmd = DOM0_STARTDOMAIN; - op.u.startdomain.domain = (domid_t)domid; - (void)do_dom0_op(xc_handle, &op); - } if ( pfn_type != NULL ) free(pfn_type); diff --git a/tools/xc/lib/xc_private.c b/tools/xc/lib/xc_private.c index 015354fde5..9fd36455fd 100644 --- a/tools/xc/lib/xc_private.c +++ b/tools/xc/lib/xc_private.c @@ -377,51 +377,67 @@ int finish_mmu_updates(int xc_handle, mmu_t *mmu) /* this function is a hack until we get proper synchronous domain stop */ -int xc_domain_stop_sync( int xc_handle, domid_t domid ) +int xc_domain_stop_sync( int xc_handle, domid_t domid, + dom0_op_t *op, full_execution_context_t *ctxt) { - dom0_op_t op; int i; - - - op.cmd = DOM0_STOPDOMAIN; - op.u.stopdomain.domain = (domid_t)domid; - if ( do_dom0_op(xc_handle, &op) != 0 ) - { - PERROR("Stopping target domain failed"); - goto out; - } - usleep(100); // 100us + printf("Sleep:"); for(i=0;;i++) - { - if (i>0) - if (i==1) printf("Sleep."); - else printf("."); - - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = NULL; - if ( (do_dom0_op(xc_handle, &op) < 0) || - ((u64)op.u.getdomaininfo.domain != domid) ) + { + + op->cmd = DOM0_STOPDOMAIN; + op->u.stopdomain.domain = (domid_t)domid; + op->u.stopdomain.sync = 1; + do_dom0_op(xc_handle, op); + /* can't trust return code due to sync stop hack :-(( */ + + + op->cmd = DOM0_GETDOMAININFO; + op->u.getdomaininfo.domain = (domid_t)domid; + op->u.getdomaininfo.ctxt = ctxt; + if ( (do_dom0_op(xc_handle, op) < 0) || + ((u64)op->u.getdomaininfo.domain != domid) ) { PERROR("Could not get info on domain"); goto out; } - if ( op.u.getdomaininfo.state == DOMSTATE_STOPPED ) + if ( op->u.getdomaininfo.state == DOMSTATE_STOPPED ) { printf("Domain %lld stopped\n",domid); return 0; } - usleep(1000); + printf("."); + + //usleep(1000); } + printf("\n"); + out: return -1; } +long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid ) +{ + dom0_op_t op; + + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + op.u.getdomaininfo.ctxt = NULL; + if ( (do_dom0_op(xc_handle, &op) < 0) || + ((u64)op.u.getdomaininfo.domain != domid) ) + { + PERROR("Could not get info on domain"); + return -1; + } + return op.u.getdomaininfo.cpu_time; +} + + /**********************************************************************/ // this is shared between save and restore, and may be useful. diff --git a/tools/xc/lib/xc_private.h b/tools/xc/lib/xc_private.h index e3eff85e59..330edca50f 100644 --- a/tools/xc/lib/xc_private.h +++ b/tools/xc/lib/xc_private.h @@ -248,6 +248,9 @@ void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset, /*********************/ -int xc_domain_stop_sync( int xc_handle, domid_t dom ); +int xc_domain_stop_sync( int xc_handle, domid_t dom, + dom0_op_t *op, full_execution_context_t *ctxt ); + +long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid ); #endif /* __XC_PRIVATE_H__ */ diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c index 7bb1d877bd..8a6e3b22ef 100644 --- a/tools/xc/py/Xc.c +++ b/tools/xc/py/Xc.c @@ -214,6 +214,7 @@ static PyObject *pyxc_linux_save(PyObject *self, struct hostent *h; struct sockaddr_in s; int sockbufsize; + int rc = -1; int writerfn(void *fd, const void *buf, size_t count) { @@ -257,12 +258,24 @@ static PyObject *pyxc_linux_save(PyObject *self, if ( xc_linux_save(xc->xc_handle, dom, flags, writerfn, (void*)sd) == 0 ) { - close(sd); - Py_INCREF(zero); - return zero; + if ( read( sd, &rc, sizeof(int) ) != sizeof(int) ) + goto serr; + + if ( rc == 0 ) + { + printf("Migration succesful -- destroy local copy\n"); + xc_domain_destroy( xc->xc_handle, dom, 1 ); + close(sd); + Py_INCREF(zero); + return zero; + } + else + errno = rc; } serr: + printf("Migration failed -- restart local copy\n"); + xc_domain_start( xc->xc_handle, dom ); PyErr_SetFromErrno(xc_error); if ( sd >= 0 ) close(sd); return NULL; @@ -355,7 +368,7 @@ static PyObject *pyxc_linux_restore(PyObject *self, struct sockaddr_in s, d, p; socklen_t dlen, plen; int sockbufsize; - int on = 1; + int on = 1, rc = -1; int readerfn(void *fd, void *buf, size_t count) { @@ -413,13 +426,18 @@ static PyObject *pyxc_linux_restore(PyObject *self, sizeof sockbufsize) < 0 ) goto serr; - if ( xc_linux_restore(xc->xc_handle, dom, flags, - readerfn, (void*)sd, &dom) == 0 ) + rc = xc_linux_restore(xc->xc_handle, dom, flags, + readerfn, (void*)sd, &dom); + + write( sd, &rc, sizeof(int) ); + + if (rc == 0) { close(sd); Py_INCREF(zero); return zero; } + errno = rc; serr: PyErr_SetFromErrno(xc_error); diff --git a/tools/xentrace/Makefile b/tools/xentrace/Makefile index 4a63ae2b3e..d64d2a5a36 100644 --- a/tools/xentrace/Makefile +++ b/tools/xentrace/Makefile @@ -1,6 +1,6 @@ CC = gcc -CFLAGS = -Wall -O3 +CFLAGS = -Wall -O3 -Werror CFLAGS += -I../../xen/include/hypervisor-ifs CFLAGS += -I../../xenolinux-sparse/include CFLAGS += -I../xend/lib diff --git a/tools/xentrace/formats b/tools/xentrace/formats index 726c199bd9..9a5b157f47 100644 --- a/tools/xentrace/formats +++ b/tools/xentrace/formats @@ -1,14 +1,35 @@ -0x00010000 CPU%(cpu)d 0x%(tsc)x sched_add_domain(0x%(3)08x) [ dom id = 0x%(1)x%(2)08x ] -0x00010001 CPU%(cpu)d 0x%(tsc)x sched_rem_domain(0x%08(3)x) [ dom id = 0x%(1)x%(2)08x ] -0x00010002 CPU%(cpu)d 0x%(tsc)x __wake_up(0x%(3)08x) [ dom id = 0x%(1)x%(2)08x ] -0x00010003 CPU%(cpu)d 0x%(tsc)x do_block() [ current = 0x%(2)08x ] -0x00010004 CPU%(cpu)d 0x%(tsc)x do_yield() [ current = %(2)08x ] -0x00010005 CPU%(cpu)d 0x%(tsc)x do_set_timer_op(0x%(4)08x, 0x%(5)08x) [ current = 0x%(3)08x ] -0x00010006 CPU%(cpu)d 0x%(tsc)x sched_ctl(0x%(1)08x) -0x00010007 CPU%(cpu)d 0x%(tsc)x sched_adjdom(params) [ dom id = 0x%(1)x%(2)08x ] -0x00010008 CPU%(cpu)d 0x%(tsc)x __reschedule(0x%(3)08x) [ dom id = 0x%(1)x%(2)08x ] -0x00010009 CPU%(cpu)d 0x%(tsc)x switching to task_struct 0x%(1)08x [ dom id = 0x%(1)x ] -0x0001000A CPU%(cpu)d 0x%(tsc)x s_timer_fn(unused) -0x0001000B CPU%(cpu)d 0x%(tsc)x t_timer_fn(unused) -0x0001000C CPU%(cpu)d 0x%(tsc)x dom_timer_fn(data) -0x0001000D CPU%(cpu)d 0x%(tsc)x fallback_timer_fn(unused) +#0x00010000 CPU%(cpu)d %(tsc).6f sched_add_domain(0x%(3)08x) [ dom id = 0x%(1)x%(2)08x ] +#0x00010001 CPU%(cpu)d %(tsc).6f sched_rem_domain(0x%08(3)x) [ dom id = 0x%(1)x%(2)08x ] +#0x00010002 CPU%(cpu)d %(tsc).6f __wake_up(0x%(3)08x) [ dom id = 0x%(1)x%(2)08x ] +#0x00010003 CPU%(cpu)d %(tsc).6f do_block() [ current = 0x%(2)08x ] +#0x00010004 CPU%(cpu)d %(tsc).6f do_yield() [ current = %(2)08x ] +#0x00010005 CPU%(cpu)d %(tsc).6f do_set_timer_op(0x%(4)08x, 0x%(5)08x) [ current = 0x%(3)08x ] +#0x00010006 CPU%(cpu)d %(tsc).6f sched_ctl(0x%(1)08x) +#0x00010007 CPU%(cpu)d %(tsc).6f sched_adjdom(params) [ dom id = 0x%(1)x%(2)08x ] +#0x00010008 CPU%(cpu)d %(tsc).6f __reschedule(0x%(3)08x) [ dom id = 0x%(1)x%(2)08x ] +#0x00010009 CPU%(cpu)d %(tsc).6f switching to task_struct 0x%(1)08x [ dom id = 0x%(1)x ] +#0x0001000A CPU%(cpu)d %(tsc).6f s_timer_fn(unused) +#0x0001000B CPU%(cpu)d %(tsc).6f t_timer_fn(unused) +#0x0001000C CPU%(cpu)d %(tsc).6f dom_timer_fn(data) +#0x0001000D CPU%(cpu)d %(tsc).6f fallback_timer_fn(unused) + + +0x00020008 CPU%(cpu)d %(tsc).6f enter: dom0_create_dom ( ) +0x00030008 CPU%(cpu)d %(tsc).6f leave: dom0_create_dom ( ) + +0x00020009 CPU%(cpu)d %(tsc).6f enter: dom0_destroy_dom ( dom=0x%(2)x ) +0x00030009 CPU%(cpu)d %(tsc).6f leave: dom0_destroy_dom ( dom=0x%(2)x ) = %(1)d + +0x0002000A CPU%(cpu)d %(tsc).6f enter: dom0_start_dom ( dom=0x%(2)x ) +0x0003000A CPU%(cpu)d %(tsc).6f leave: dom0_start_dom ( dom=0x%(2)x ) = %(1)d +0x0002000B CPU%(cpu)d %(tsc).6f enter: dom0_stop_dom ( dom=0x%(2)x ) +0x0003000B CPU%(cpu)d %(tsc).6f leave: dom0_stop_dom ( dom=0x%(2)x ) = %(1)d +0x0002000C CPU%(cpu)d %(tsc).6f enter: dom0_getinfo ( dom=0x%(2)x ) +0x0003000C CPU%(cpu)d %(tsc).6f leave: dom0_getinfo ( dom=0x%(2)x ) = %(1)d +0x0002000D CPU%(cpu)d %(tsc).6f enter: dom0_build ( dom=0x%(2)x ) +0x0003000D CPU%(cpu)d %(tsc).6f leave: dom0_build ( dom=0x%(2)x ) = %(1)d + +0x00020019 CPU%(cpu)d %(tsc).6f enter: dom0_shadow_op ( dom=0x%(2)x, %(3)d ) +0x00030019 CPU%(cpu)d %(tsc).6f leave: dom0_shadow_op ( dom=0x%(2)x, %(3)d ) = %(1)d + +#0x0 CPU%(cpu)d %(tsc).6f %(event)x diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c index 157435baa0..dae9b67d80 100644 --- a/tools/xentrace/xentrace.c +++ b/tools/xentrace/xentrace.c @@ -227,10 +227,10 @@ struct t_rec **init_rec_ptrs(unsigned long tbufs_phys, * trace buffer. Each entry in this table corresponds to the tail index for a * particular trace buffer. */ -int *init_tail_idxs(struct t_buf **bufs, unsigned int num) +unsigned long *init_tail_idxs(struct t_buf **bufs, unsigned int num) { int i; - int *tails = calloc(num, sizeof(unsigned int)); + unsigned long *tails = calloc(num, sizeof(unsigned int)); if ( tails == NULL ) { @@ -276,16 +276,19 @@ unsigned int get_num_cpus() */ int monitor_tbufs(FILE *logfile) { - int i, j; + 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 * where they are mapped into user space. */ - int *tails; /* store tail indexes for the trace buffers */ + unsigned long *cons; /* store tail indexes for the trace buffers */ unsigned long tbufs_phys; /* physical address 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; + /* get number of logical CPUs (and therefore number of trace buffers) */ num = get_num_cpus(); @@ -293,39 +296,32 @@ int monitor_tbufs(FILE *logfile) get_tbufs(&tbufs_phys, &size); tbufs_mapped = map_tbufs(tbufs_phys, num, size); + size_in_recs = (size / sizeof(struct t_rec) )-1; + /* build arrays of convenience ptrs */ meta = init_bufs_ptrs (tbufs_mapped, num, size); data = init_rec_ptrs (tbufs_phys, tbufs_mapped, meta, num); - tails = init_tail_idxs (meta, num); + cons = init_tail_idxs (meta, num); /* now, scan buffers for events */ while ( !interrupted ) { for ( i = 0; ( i < num ) && !interrupted; i++ ) - { - signed long newdata = meta[i]->head - tails[i]; - signed long prewrap = newdata; - - /* correct newdata and prewrap in case of a pointer wrap */ - if ( newdata < 0 ) - { - newdata += meta[i]->size; - prewrap = meta[i]->size - tails[i]; - } - - if ( newdata >= opts.new_data_thresh ) - { - /* output pre-wrap data */ - for(j = 0; j < prewrap; j++) - write_rec(i, data[i] + tails[i] + j, logfile); - - /* output post-wrap data, if any */ - for(j = 0; j < (newdata - prewrap); j++) - write_rec(i, data[i] + j, logfile); - - tails[i] += newdata; - if(tails[i] >= meta[i]->size) tails[i] = 0; - } + { +/* printf("XX%d: cons=%ld head=%ld %p\n", i, + cons[i], meta[i]->head, data[i] + (cons[i] % size_in_recs) ); + */ + while( cons[i] < meta[i]->head ) + { +/* + if( (cons[i] % 6 ) == 0 ) + printf("%d: cons=%ld head=%ld %p\n", i, + cons[i], meta[i]->head, data[i] + (cons[i] % size_in_recs) ); + */ + write_rec(i, data[i] + (cons[i] % size_in_recs), logfile); + cons[i]++; + } + } nanosleep(&opts.poll_sleep, NULL); } @@ -333,7 +329,7 @@ int monitor_tbufs(FILE *logfile) /* cleanup */ free(meta); free(data); - free(tails); + free(cons); /* don't need to munmap - cleanup is automatic */ fclose(logfile); diff --git a/tools/xentrace/xentrace_format b/tools/xentrace/xentrace_format index 4014811249..d2e51265d4 100644 --- a/tools/xentrace/xentrace_format +++ b/tools/xentrace/xentrace_format @@ -4,7 +4,7 @@ # Program for reformatting trace buffer output according to user-supplied rules -import re, sys, string, signal, struct +import re, sys, string, signal, struct, os, getopt def usage(): print >> sys.stderr, \ @@ -43,6 +43,9 @@ def read_defs(defs_file): line = fd.readline() if not line: break + + if line[0] == '#' or line[0] == '\n': + continue m = reg.match(line) @@ -58,29 +61,61 @@ def sighand(x,y): ##### Main code +mhz = 0 + if len(sys.argv) < 2: usage() +try: + opts, arg = getopt.getopt(sys.argv[1:], "c:" ) + + for opt in opts: + if opt[0] == '-c' : mhz = int(opt[1]) + +except getopt.GetoptError: + usage() + +print mhz + signal.signal(signal.SIGTERM, sighand) signal.signal(signal.SIGHUP, sighand) signal.signal(signal.SIGINT, sighand) interrupted = 0 -defs = read_defs(sys.argv[1]) +defs = read_defs(arg[0]) + +print defs # structure of trace record + prepended CPU id (as output by xentrace): # CPU(I) TSC(Q) EVENT(L) D1(L) D2(L) D3(L) D4(L) D5(L) TRCREC = "IQLLLLLL" +last_tsc = [0,0,0,0,0,0,0,0] + +i=0 + while not interrupted: try: + i=i+1 line = sys.stdin.read(struct.calcsize(TRCREC)) if not line: break (cpu, tsc, event, d1, d2, d3, d4, d5) = struct.unpack(TRCREC, line) + #tsc = (tscH<<32) | tscL + + #print i, tsc + + if tsc < last_tsc[cpu]: + print "TSC stepped backward cpu %d ! %d %d" % (cpu,tsc,last_tsc[cpu]) + + last_tsc[cpu] = tsc + + if mhz: + tsc = tsc / (mhz*1000000.0) + args = {'cpu' : cpu, 'tsc' : tsc, 'event' : event, @@ -90,8 +125,15 @@ while not interrupted: '4' : d4, '5' : d5 } - if defs.has_key(str(event)): print defs[str(event)] % args - # silently skip lines we don't have a format for - a 'complain' option - # should be added if needed + try: + + if defs.has_key(str(event)): + print defs[str(event)] % args + else: + if defs.has_key(str(0)): print defs[str(0)] % args + except TypeError: + print defs[str(event)] + print args + except IOError, struct.error: sys.exit() |