diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-04-14 14:21:12 +0100 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-04-14 14:21:12 +0100 |
commit | e4287d87ae819e65b7bd4a074264c184959475d9 (patch) | |
tree | a646bceb0d034c37404a1903911edb55ffa08eb8 /tools/xenmon/xenbaked.c | |
parent | 2256643d06799d4ff0b1f7c5e542cd5af6f7670e (diff) | |
download | xen-e4287d87ae819e65b7bd4a074264c184959475d9.tar.gz xen-e4287d87ae819e65b7bd4a074264c184959475d9.tar.bz2 xen-e4287d87ae819e65b7bd4a074264c184959475d9.zip |
This is a patch for XenMon which only applies to the userspace tools.
The primary purpose of this patch is to add support for non-polling
access to the xen trace buffers. The hypervisor changes have already
been accepted.
Also included are a few bug fixes and some minor new features:
1. If xenmon is run without first allocating trace buffers (via
'setsize') and enabling them (via 'tbctl'), then this is done
automatically using sensible defaults.
2. There was a bug that caused the first second's worth of data output
from xenmon to be erroneous; This has been fixed.
3. There was a bug that caused xenmon to sometimes not display data for
newly created domains; This has also been fixed.
4. The xenmon display has a 'heartbeat' which flickers once per second.
This is to show that xenmon is still alive, even though the display
isn't changing at all, a situation that can happen sometimes when there
is nothing at all happening on a particular cpu.
5. Added cpu utilization display to the top of the xenmon window.
6. Added a bunch of options in xenmon to control exactly which metrics
are displayed, so the screen doesn't get cluttered with stuff you're not
interested in. The new options are:
--allocated
--noallocated
--blocked
--noblocked
--waited
--nowaited
--excount
--noexcount
--iocount
--noiocount
7. Added an option ("--cpu=N") to xenmon to specify which physical cpu
you'd like data displayed for.
8. Updated the README with information about default trace buffer size, etc.
Signed-off-by: Rob Gardner <rob.gardner@hp.com>
Diffstat (limited to 'tools/xenmon/xenbaked.c')
-rw-r--r-- | tools/xenmon/xenbaked.c | 153 |
1 files changed, 142 insertions, 11 deletions
diff --git a/tools/xenmon/xenbaked.c b/tools/xenmon/xenbaked.c index a7cd4be2d0..876be1d68e 100644 --- a/tools/xenmon/xenbaked.c +++ b/tools/xenmon/xenbaked.c @@ -7,6 +7,7 @@ * * Copyright (C) 2004 by Intel Research Cambridge * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins + * Copyright (C) 2006 by Hewlett Packard Fort Collins * * Authors: Diwaker Gupta, diwaker.gupta@hp.com * Rob Gardner, rob.gardner@hp.com @@ -42,6 +43,8 @@ #include <xenctrl.h> #include <xen/xen.h> #include <string.h> +#include <sys/select.h> +#include <xen/linux/evtchn.h> #include "xc_private.h" typedef struct { int counter; } atomic_t; @@ -81,6 +84,7 @@ settings_t opts; int interrupted = 0; /* gets set if we get a SIGHUP */ int rec_count = 0; +int wakeups = 0; time_t start_time; int dom0_flips = 0; @@ -88,8 +92,6 @@ _new_qos_data *new_qos; _new_qos_data **cpu_qos_data; -#define ID(X) ((X>NDOMAINS-1)?(NDOMAINS-1):X) - // array of currently running domains, indexed by cpu int *running = NULL; @@ -223,6 +225,9 @@ void dump_stats(void) printf("processed %d total records in %d seconds (%ld per second)\n", rec_count, (int)run_time, rec_count/run_time); + printf("woke up %d times in %d seconds (%ld per second)\n", wakeups, + (int) run_time, wakeups/run_time); + check_gotten_sum(); } @@ -243,6 +248,112 @@ void log_event(int event_id) stat_map[0].event_count++; // other } +#define EVTCHN_DEV_NAME "/dev/xen/evtchn" +#define EVTCHN_DEV_MAJOR 10 +#define EVTCHN_DEV_MINOR 201 + +int virq_port; +int eventchn_fd = -1; + +/* Returns the event channel handle. */ +/* Stolen from xenstore code */ +int eventchn_init(void) +{ + struct stat st; + struct ioctl_evtchn_bind_virq bind; + int rc; + + // to revert to old way: + if (0) + return -1; + + /* Make sure any existing device file links to correct device. */ + if ((lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) || + (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR))) + (void)unlink(EVTCHN_DEV_NAME); + + reopen: + eventchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR); + if (eventchn_fd == -1) { + if ((errno == ENOENT) && + ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) && + (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, + makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) == 0)) + goto reopen; + return -errno; + } + + if (eventchn_fd < 0) + perror("Failed to open evtchn device"); + + bind.virq = VIRQ_TBUF; + rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_VIRQ, &bind); + if (rc == -1) + perror("Failed to bind to domain exception virq port"); + virq_port = rc; + + return eventchn_fd; +} + +void wait_for_event(void) +{ + int ret; + fd_set inset; + evtchn_port_t port; + struct timeval tv; + + if (eventchn_fd < 0) { + nanosleep(&opts.poll_sleep, NULL); + return; + } + + FD_ZERO(&inset); + FD_SET(eventchn_fd, &inset); + tv.tv_sec = 1; + tv.tv_usec = 0; + // tv = millis_to_timespec(&opts.poll_sleep); + ret = select(eventchn_fd+1, &inset, NULL, NULL, &tv); + + if ( (ret == 1) && FD_ISSET(eventchn_fd, &inset)) { + if (read(eventchn_fd, &port, sizeof(port)) != sizeof(port)) + perror("Failed to read from event fd"); + + // if (port == virq_port) + // printf("got the event I was looking for\r\n"); + + if (write(eventchn_fd, &port, sizeof(port)) != sizeof(port)) + perror("Failed to write to event fd"); + } +} + +void enable_tracing_or_die(int xc_handle) +{ + int enable = 1; + int tbsize = DEFAULT_TBUF_SIZE; + + if (xc_tbuf_enable(xc_handle, enable) != 0) { + if (xc_tbuf_set_size(xc_handle, tbsize) != 0) { + perror("set_size Hypercall failure"); + exit(1); + } + printf("Set default trace buffer allocation (%d pages)\n", tbsize); + if (xc_tbuf_enable(xc_handle, enable) != 0) { + perror("Could not enable trace buffers\n"); + exit(1); + } + } + else + printf("Tracing enabled\n"); +} + +void disable_tracing(void) +{ + int enable = 0; + int xc_handle = xc_interface_open(); + + xc_tbuf_enable(xc_handle, enable); + xc_interface_close(xc_handle); +} /** @@ -258,6 +369,17 @@ void get_tbufs(unsigned long *mfn, unsigned long *size) int ret; dom0_op_t op; /* dom0 op we'll build */ int xc_handle = xc_interface_open(); /* for accessing control interface */ + unsigned int tbsize; + + enable_tracing_or_die(xc_handle); + + if (xc_tbuf_get_size(xc_handle, &tbsize) != 0) { + perror("Failure to get tbuf info from Xen. Guess size is 0?"); + exit(1); + } + else + printf("Current tbuf size: 0x%x\n", tbsize); + op.cmd = DOM0_TBUFCONTROL; op.interface_version = DOM0_INTERFACE_VERSION; @@ -448,6 +570,11 @@ int monitor_tbufs(void) meta = init_bufs_ptrs (tbufs_mapped, num, size); data = init_rec_ptrs(meta, num); + // Set up event channel for select() + if (eventchn_init() < 0) { + fprintf(stderr, "Failed to initialize event channel; Using POLL method\r\n"); + } + /* now, scan buffers for events */ while ( !interrupted ) { @@ -460,7 +587,8 @@ int monitor_tbufs(void) meta[i]->cons++; } - nanosleep(&opts.poll_sleep, NULL); + wait_for_event(); + wakeups++; } /* cleanup */ @@ -640,6 +768,7 @@ int main(int argc, char **argv) dump_stats(); msync(new_qos, sizeof(_new_qos_data), MS_SYNC); + disable_tracing(); return ret; } @@ -737,7 +866,9 @@ void qos_update_thread(int cpu, int domid, uint64_t now) start = new_qos->domain_info[id].start_time; if (start > now) { // wrapped around run_time = now + (~0ULL - start); - printf("warning: start > now\n"); + // this could happen if there is nothing going on within a cpu; + // in this case the idle domain would run forever + // printf("warning: start > now\n"); } else run_time = now - start; @@ -746,11 +877,11 @@ void qos_update_thread(int cpu, int domid, uint64_t now) new_qos->domain_info[id].ns_oncpu_since_boot += run_time; new_qos->domain_info[id].start_time = now; new_qos->domain_info[id].ns_since_boot += time_since_update; -#if 1 + new_qos->qdata[n].ns_gotten[id] += run_time; - if (domid == 0 && cpu == 1) - printf("adding run time for dom0 on cpu1\r\n"); -#endif + // if (domid == 0 && cpu == 1) + // printf("adding run time for dom0 on cpu1\r\n"); + } new_qos->domain_info[id].runnable_at_last_update = domain_runnable(domid); @@ -916,13 +1047,13 @@ void qos_state_runnable(int cpu, int domid, uint64_t now) { int id = ID(domid); + qos_update_thread_stats(cpu, domid, now); + if (domain_runnable(id)) // double call? return; new_qos->domain_info[id].runnable = 1; update_blocked_time(domid, now); - qos_update_thread_stats(cpu, domid, now); - new_qos->domain_info[id].blocked_start_time = 0; /* invalidate */ new_qos->domain_info[id].runnable_start_time = now; // runnable_start_time[id] = now; @@ -951,7 +1082,7 @@ int domain_ok(int cpu, int domid, uint64_t now) if (domid == IDLE_DOMAIN_ID) domid = NDOMAINS-1; if (domid < 0 || domid >= NDOMAINS) { - printf("bad domain id: %d\n", domid); + printf("bad domain id: %d\r\n", domid); return 0; } if (new_qos->domain_info[domid].in_use == 0) |