[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XENOPROFILE] Move code under xen/arch/x86/oprofile to xen/common.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Node ID fc11c91e537166535b797e39f381a474413af3f0 # Parent f555a90bcc373a7379bc18f875eac5e7c7122ae9 [XENOPROFILE] Move code under xen/arch/x86/oprofile to xen/common. Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx> --- xen/arch/x86/Rules.mk | 1 xen/arch/x86/oprofile/xenoprof.c | 691 -------------------------------------- xen/common/Makefile | 1 xen/common/xenoprof.c | 709 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 715 insertions(+), 687 deletions(-) diff -r f555a90bcc37 -r fc11c91e5371 xen/arch/x86/Rules.mk --- a/xen/arch/x86/Rules.mk Tue Nov 21 19:22:25 2006 +0000 +++ b/xen/arch/x86/Rules.mk Wed Nov 22 09:35:50 2006 +0000 @@ -3,6 +3,7 @@ HAS_ACPI := y HAS_VGA := y +xenoprof := y # # If you change any of these configuration options then you must diff -r f555a90bcc37 -r fc11c91e5371 xen/arch/x86/oprofile/xenoprof.c --- a/xen/arch/x86/oprofile/xenoprof.c Tue Nov 21 19:22:25 2006 +0000 +++ b/xen/arch/x86/oprofile/xenoprof.c Wed Nov 22 09:35:50 2006 +0000 @@ -2,699 +2,16 @@ * Copyright (C) 2005 Hewlett-Packard Co. * written by Aravind Menon & Jose Renato Santos * (email: xenoprof@xxxxxxxxxxxxx) + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * x86 specific part */ #include <xen/guest_access.h> #include <xen/sched.h> #include <public/xenoprof.h> #include <asm/hvm/support.h> - -#include "op_counter.h" - -/* Limit amount of pages used for shared buffer (per domain) */ -#define MAX_OPROF_SHARED_PAGES 32 - -/* Lock protecting the following global state */ -static DEFINE_SPINLOCK(xenoprof_lock); - -struct domain *active_domains[MAX_OPROF_DOMAINS]; -int active_ready[MAX_OPROF_DOMAINS]; -unsigned int adomains; - -struct domain *passive_domains[MAX_OPROF_DOMAINS]; -unsigned int pdomains; - -unsigned int activated; -struct domain *primary_profiler; -int xenoprof_state = XENOPROF_IDLE; - -u64 total_samples; -u64 invalid_buffer_samples; -u64 corrupted_buffer_samples; -u64 lost_samples; -u64 active_samples; -u64 passive_samples; -u64 idle_samples; -u64 others_samples; - - -extern int nmi_init(int *num_events, int *is_primary, char *cpu_type); -extern int nmi_reserve_counters(void); -extern int nmi_setup_events(void); -extern int nmi_enable_virq(void); -extern int nmi_start(void); -extern void nmi_stop(void); -extern void nmi_disable_virq(void); -extern void nmi_release_counters(void); - -int is_active(struct domain *d) -{ - struct xenoprof *x = d->xenoprof; - return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE)); -} - -int is_passive(struct domain *d) -{ - struct xenoprof *x = d->xenoprof; - return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE)); -} - -int is_profiled(struct domain *d) -{ - return (is_active(d) || is_passive(d)); -} - -static void xenoprof_reset_stat(void) -{ - total_samples = 0; - invalid_buffer_samples = 0; - corrupted_buffer_samples = 0; - lost_samples = 0; - active_samples = 0; - passive_samples = 0; - idle_samples = 0; - others_samples = 0; -} - -static void xenoprof_reset_buf(struct domain *d) -{ - int j; - struct xenoprof_buf *buf; - - if ( d->xenoprof == NULL ) - { - printk("xenoprof_reset_buf: ERROR - Unexpected " - "Xenoprof NULL pointer \n"); - return; - } - - for ( j = 0; j < MAX_VIRT_CPUS; j++ ) - { - buf = d->xenoprof->vcpu[j].buffer; - if ( buf != NULL ) - { - buf->event_head = 0; - buf->event_tail = 0; - } - } -} - -static char *alloc_xenoprof_buf(struct domain *d, int npages) -{ - char *rawbuf; - int i, order; - - /* allocate pages to store sample buffer shared with domain */ - order = get_order_from_pages(npages); - rawbuf = alloc_xenheap_pages(order); - if ( rawbuf == NULL ) - { - printk("alloc_xenoprof_buf(): memory allocation failed\n"); - return 0; - } - - /* Share pages so that kernel can map it */ - for ( i = 0; i < npages; i++ ) - share_xen_page_with_guest( - virt_to_page(rawbuf + i * PAGE_SIZE), - d, XENSHARE_writable); - - return rawbuf; -} - -static int alloc_xenoprof_struct( - struct domain *d, int max_samples, int is_passive) -{ - struct vcpu *v; - int nvcpu, npages, bufsize, max_bufsize; - unsigned max_max_samples; - int i; - - d->xenoprof = xmalloc(struct xenoprof); - - if ( d->xenoprof == NULL ) - { - printk ("alloc_xenoprof_struct(): memory " - "allocation (xmalloc) failed\n"); - return -ENOMEM; - } - - memset(d->xenoprof, 0, sizeof(*d->xenoprof)); - - nvcpu = 0; - for_each_vcpu ( d, v ) - nvcpu++; - - /* reduce max_samples if necessary to limit pages allocated */ - max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu; - max_max_samples = ( (max_bufsize - sizeof(struct xenoprof_buf)) / - sizeof(struct event_log) ) + 1; - if ( (unsigned)max_samples > max_max_samples ) - max_samples = max_max_samples; - - bufsize = sizeof(struct xenoprof_buf) + - (max_samples - 1) * sizeof(struct event_log); - npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1; - - d->xenoprof->rawbuf = alloc_xenoprof_buf(is_passive ? dom0 : d, npages); - - if ( d->xenoprof->rawbuf == NULL ) - { - xfree(d->xenoprof); - d->xenoprof = NULL; - return -ENOMEM; - } - - d->xenoprof->npages = npages; - d->xenoprof->nbuf = nvcpu; - d->xenoprof->bufsize = bufsize; - d->xenoprof->domain_ready = 0; - d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; - - /* Update buffer pointers for active vcpus */ - i = 0; - for_each_vcpu ( d, v ) - { - d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples; - d->xenoprof->vcpu[v->vcpu_id].buffer = - (struct xenoprof_buf *)&d->xenoprof->rawbuf[i * bufsize]; - d->xenoprof->vcpu[v->vcpu_id].buffer->event_size = max_samples; - d->xenoprof->vcpu[v->vcpu_id].buffer->vcpu_id = v->vcpu_id; - - i++; - /* in the unlikely case that the number of active vcpus changes */ - if ( i >= nvcpu ) - break; - } - - return 0; -} - -void free_xenoprof_pages(struct domain *d) -{ - struct xenoprof *x; - int order; - - x = d->xenoprof; - if ( x == NULL ) - return; - - if ( x->rawbuf != NULL ) - { - order = get_order_from_pages(x->npages); - free_xenheap_pages(x->rawbuf, order); - } - - xfree(x); - d->xenoprof = NULL; -} - -static int active_index(struct domain *d) -{ - int i; - - for ( i = 0; i < adomains; i++ ) - if ( active_domains[i] == d ) - return i; - - return -1; -} - -static int set_active(struct domain *d) -{ - int ind; - struct xenoprof *x; - - ind = active_index(d); - if ( ind < 0 ) - return -EPERM; - - x = d->xenoprof; - if ( x == NULL ) - return -EPERM; - - x->domain_ready = 1; - x->domain_type = XENOPROF_DOMAIN_ACTIVE; - active_ready[ind] = 1; - activated++; - - return 0; -} - -static int reset_active(struct domain *d) -{ - int ind; - struct xenoprof *x; - - ind = active_index(d); - if ( ind < 0 ) - return -EPERM; - - x = d->xenoprof; - if ( x == NULL ) - return -EPERM; - - x->domain_ready = 0; - x->domain_type = XENOPROF_DOMAIN_IGNORED; - active_ready[ind] = 0; - active_domains[ind] = NULL; - activated--; - put_domain(d); - - if ( activated <= 0 ) - adomains = 0; - - return 0; -} - -static void reset_passive(struct domain *d) -{ - struct xenoprof *x; - - if (d==0) - return; - - x = d->xenoprof; - if ( x == NULL ) - return; - - x->domain_type = XENOPROF_DOMAIN_IGNORED; - - return; -} - -static void reset_active_list(void) -{ - int i; - - for ( i = 0; i < adomains; i++ ) - { - if ( active_ready[i] ) - { - reset_active(active_domains[i]); - } - } - - adomains = 0; - activated = 0; -} - -static void reset_passive_list(void) -{ - int i; - - for ( i = 0; i < pdomains; i++ ) - { - reset_passive(passive_domains[i]); - put_domain(passive_domains[i]); - passive_domains[i] = NULL; - } - - pdomains = 0; -} - -static int add_active_list(domid_t domid) -{ - struct domain *d; - - if ( adomains >= MAX_OPROF_DOMAINS ) - return -E2BIG; - - d = find_domain_by_id(domid); - if ( d == NULL ) - return -EINVAL; - - active_domains[adomains] = d; - active_ready[adomains] = 0; - adomains++; - - return 0; -} - -static int add_passive_list(XEN_GUEST_HANDLE(void) arg) -{ - struct xenoprof_passive passive; - struct domain *d; - int ret = 0; - - if ( pdomains >= MAX_OPROF_DOMAINS ) - return -E2BIG; - - if ( copy_from_guest(&passive, arg, 1) ) - return -EFAULT; - - d = find_domain_by_id(passive.domain_id); - if ( d == NULL ) - return -EINVAL; - - if ( (d->xenoprof == NULL) && - ((ret = alloc_xenoprof_struct(d, passive.max_samples, 1)) < 0) ) { - put_domain(d); - return -ENOMEM; - } - - d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE; - passive.nbuf = d->xenoprof->nbuf; - passive.bufsize = d->xenoprof->bufsize; - passive.buf_maddr = __pa(d->xenoprof->rawbuf); - - if ( copy_to_guest(arg, &passive, 1) ) { - put_domain(d); - return -EFAULT; - } - - passive_domains[pdomains] = d; - pdomains++; - - return ret; -} - -void xenoprof_log_event( - struct vcpu *vcpu, unsigned long eip, int mode, int event) -{ - struct xenoprof_vcpu *v; - struct xenoprof_buf *buf; - int head; - int tail; - int size; - - - total_samples++; - - /* ignore samples of un-monitored domains */ - /* Count samples in idle separate from other unmonitored domains */ - if ( !is_profiled(vcpu->domain) ) - { - others_samples++; - return; - } - - v = &vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id]; - - /* Sanity check. Should never happen */ - if ( v->buffer == NULL ) - { - invalid_buffer_samples++; - return; - } - - buf = vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id].buffer; - - head = buf->event_head; - tail = buf->event_tail; - size = v->event_size; - - /* make sure indexes in shared buffer are sane */ - if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) ) - { - corrupted_buffer_samples++; - return; - } - - if ( (head == tail - 1) || (head == size - 1 && tail == 0) ) - { - buf->lost_samples++; - lost_samples++; - } - else - { - buf->event_log[head].eip = eip; - buf->event_log[head].mode = mode; - buf->event_log[head].event = event; - head++; - if ( head >= size ) - head = 0; - buf->event_head = head; - if ( is_active(vcpu->domain) ) - active_samples++; - else - passive_samples++; - if ( mode == 0 ) - buf->user_samples++; - else if ( mode == 1 ) - buf->kernel_samples++; - else - buf->xen_samples++; - } -} - -static int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg) -{ - struct xenoprof_init xenoprof_init; - int ret; - - if ( copy_from_guest(&xenoprof_init, arg, 1) ) - return -EFAULT; - - if ( (ret = nmi_init(&xenoprof_init.num_events, - &xenoprof_init.is_primary, - xenoprof_init.cpu_type)) ) - return ret; - - if ( copy_to_guest(arg, &xenoprof_init, 1) ) - return -EFAULT; - - if ( xenoprof_init.is_primary ) - primary_profiler = current->domain; - - return 0; -} - -static int xenoprof_op_get_buffer(XEN_GUEST_HANDLE(void) arg) -{ - struct xenoprof_get_buffer xenoprof_get_buffer; - struct domain *d = current->domain; - int ret; - - if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) ) - return -EFAULT; - - /* - * We allocate xenoprof struct and buffers only at first time xenoprof_get_buffer - * is called. Memory is then kept until domain is destroyed. - */ - if ( (d->xenoprof == NULL) && - ((ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0)) < 0) ) - return ret; - - xenoprof_reset_buf(d); - - d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; - d->xenoprof->domain_ready = 0; - if ( primary_profiler == current->domain ) - d->xenoprof->is_primary = 1; - else - d->xenoprof->is_primary = 0; - - xenoprof_get_buffer.nbuf = d->xenoprof->nbuf; - xenoprof_get_buffer.bufsize = d->xenoprof->bufsize; - xenoprof_get_buffer.buf_maddr = __pa(d->xenoprof->rawbuf); - - if ( copy_to_guest(arg, &xenoprof_get_buffer, 1) ) - return -EFAULT; - - return 0; -} - -#define NONPRIV_OP(op) ( (op == XENOPROF_init) \ - || (op == XENOPROF_enable_virq) \ - || (op == XENOPROF_disable_virq) \ - || (op == XENOPROF_get_buffer)) - -int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg) -{ - int ret = 0; - - if ( (op < 0) || (op>XENOPROF_last_op) ) - { - printk("xenoprof: invalid operation %d for domain %d\n", - op, current->domain->domain_id); - return -EINVAL; - } - - if ( !NONPRIV_OP(op) && (current->domain != primary_profiler) ) - { - printk("xenoprof: dom %d denied privileged operation %d\n", - current->domain->domain_id, op); - return -EPERM; - } - - spin_lock(&xenoprof_lock); - - switch ( op ) - { - case XENOPROF_init: - ret = xenoprof_op_init(arg); - break; - - case XENOPROF_get_buffer: - ret = xenoprof_op_get_buffer(arg); - break; - - case XENOPROF_reset_active_list: - { - reset_active_list(); - ret = 0; - break; - } - case XENOPROF_reset_passive_list: - { - reset_passive_list(); - ret = 0; - break; - } - case XENOPROF_set_active: - { - domid_t domid; - if ( xenoprof_state != XENOPROF_IDLE ) { - ret = -EPERM; - break; - } - if ( copy_from_guest(&domid, arg, 1) ) { - ret = -EFAULT; - break; - } - ret = add_active_list(domid); - break; - } - case XENOPROF_set_passive: - { - if ( xenoprof_state != XENOPROF_IDLE ) { - ret = -EPERM; - break; - } - ret = add_passive_list(arg); - break; - } - case XENOPROF_reserve_counters: - if ( xenoprof_state != XENOPROF_IDLE ) { - ret = -EPERM; - break; - } - ret = nmi_reserve_counters(); - if ( !ret ) - xenoprof_state = XENOPROF_COUNTERS_RESERVED; - break; - - case XENOPROF_counter: - { - struct xenoprof_counter counter; - if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED || adomains == 0) { - ret = -EPERM; - break; - } - - if ( copy_from_guest(&counter, arg, 1) ) { - ret = -EFAULT; - break; - } - - if ( counter.ind > OP_MAX_COUNTER ) { - ret = -E2BIG; - break; - } - - counter_config[counter.ind].count = (unsigned long) counter.count; - counter_config[counter.ind].enabled = (unsigned long) counter.enabled; - counter_config[counter.ind].event = (unsigned long) counter.event; - counter_config[counter.ind].kernel = (unsigned long) counter.kernel; - counter_config[counter.ind].user = (unsigned long) counter.user; - counter_config[counter.ind].unit_mask = (unsigned long) counter.unit_mask; - - ret = 0; - break; - } - - case XENOPROF_setup_events: - if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED ) { - ret = -EPERM; - break; - } - ret = nmi_setup_events(); - if ( !ret ) - xenoprof_state = XENOPROF_READY; - break; - - case XENOPROF_enable_virq: - { - int i; - if ( current->domain == primary_profiler ) - { - nmi_enable_virq(); - xenoprof_reset_stat(); - for ( i = 0; i < pdomains; i++ ) { - xenoprof_reset_buf(passive_domains[i]); - } - } - xenoprof_reset_buf(current->domain); - ret = set_active(current->domain); - break; - } - - case XENOPROF_start: - ret = -EPERM; - if ( (xenoprof_state == XENOPROF_READY) && - (activated == adomains) ) - ret = nmi_start(); - - if ( ret == 0 ) - xenoprof_state = XENOPROF_PROFILING; - break; - - case XENOPROF_stop: - if ( xenoprof_state != XENOPROF_PROFILING ) { - ret = -EPERM; - break; - } - nmi_stop(); - xenoprof_state = XENOPROF_READY; - break; - - case XENOPROF_disable_virq: - if ( (xenoprof_state == XENOPROF_PROFILING) && - (is_active(current->domain)) ) { - ret = -EPERM; - break; - } - ret = reset_active(current->domain); - break; - - case XENOPROF_release_counters: - ret = -EPERM; - if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) || - (xenoprof_state == XENOPROF_READY) ) - { - xenoprof_state = XENOPROF_IDLE; - nmi_release_counters(); - nmi_disable_virq(); - reset_passive_list(); - ret = 0; - } - break; - - case XENOPROF_shutdown: - ret = -EPERM; - if ( xenoprof_state == XENOPROF_IDLE ) - { - activated = 0; - adomains=0; - primary_profiler = NULL; - ret = 0; - } - break; - - default: - ret = -ENOSYS; - } - - spin_unlock(&xenoprof_lock); - - if ( ret < 0 ) - printk("xenoprof: operation %d failed for dom %d (status : %d)\n", - op, current->domain->domain_id, ret); - - return ret; -} int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs) { diff -r f555a90bcc37 -r fc11c91e5371 xen/common/Makefile --- a/xen/common/Makefile Tue Nov 21 19:22:25 2006 +0000 +++ b/xen/common/Makefile Wed Nov 22 09:35:50 2006 +0000 @@ -29,6 +29,7 @@ obj-y += xmalloc.o obj-$(perfc) += perfc.o obj-$(crash_debug) += gdbstub.o +obj-$(xenoprof) += xenoprof.o # Object file contains changeset and compiler information. version.o: $(BASEDIR)/include/xen/compile.h diff -r f555a90bcc37 -r fc11c91e5371 xen/common/xenoprof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/common/xenoprof.c Wed Nov 22 09:35:50 2006 +0000 @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2005 Hewlett-Packard Co. + * written by Aravind Menon & Jose Renato Santos + * (email: xenoprof@xxxxxxxxxxxxx) + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * arch generic xenoprof and IA64 support. + */ + +#include <xen/guest_access.h> +#include <xen/sched.h> +#include <public/xenoprof.h> +#include <asm/hvm/support.h> + +#include "../arch/x86/oprofile/op_counter.h" + +/* Limit amount of pages used for shared buffer (per domain) */ +#define MAX_OPROF_SHARED_PAGES 32 + +/* Lock protecting the following global state */ +static DEFINE_SPINLOCK(xenoprof_lock); + +struct domain *active_domains[MAX_OPROF_DOMAINS]; +int active_ready[MAX_OPROF_DOMAINS]; +unsigned int adomains; + +struct domain *passive_domains[MAX_OPROF_DOMAINS]; +unsigned int pdomains; + +unsigned int activated; +struct domain *primary_profiler; +int xenoprof_state = XENOPROF_IDLE; + +u64 total_samples; +u64 invalid_buffer_samples; +u64 corrupted_buffer_samples; +u64 lost_samples; +u64 active_samples; +u64 passive_samples; +u64 idle_samples; +u64 others_samples; + + +extern int nmi_init(int *num_events, int *is_primary, char *cpu_type); +extern int nmi_reserve_counters(void); +extern int nmi_setup_events(void); +extern int nmi_enable_virq(void); +extern int nmi_start(void); +extern void nmi_stop(void); +extern void nmi_disable_virq(void); +extern void nmi_release_counters(void); + +int is_active(struct domain *d) +{ + struct xenoprof *x = d->xenoprof; + return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE)); +} + +int is_passive(struct domain *d) +{ + struct xenoprof *x = d->xenoprof; + return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE)); +} + +int is_profiled(struct domain *d) +{ + return (is_active(d) || is_passive(d)); +} + +static void xenoprof_reset_stat(void) +{ + total_samples = 0; + invalid_buffer_samples = 0; + corrupted_buffer_samples = 0; + lost_samples = 0; + active_samples = 0; + passive_samples = 0; + idle_samples = 0; + others_samples = 0; +} + +static void xenoprof_reset_buf(struct domain *d) +{ + int j; + struct xenoprof_buf *buf; + + if ( d->xenoprof == NULL ) + { + printk("xenoprof_reset_buf: ERROR - Unexpected " + "Xenoprof NULL pointer \n"); + return; + } + + for ( j = 0; j < MAX_VIRT_CPUS; j++ ) + { + buf = d->xenoprof->vcpu[j].buffer; + if ( buf != NULL ) + { + buf->event_head = 0; + buf->event_tail = 0; + } + } +} + +static char *alloc_xenoprof_buf(struct domain *d, int npages) +{ + char *rawbuf; + int i, order; + + /* allocate pages to store sample buffer shared with domain */ + order = get_order_from_pages(npages); + rawbuf = alloc_xenheap_pages(order); + if ( rawbuf == NULL ) + { + printk("alloc_xenoprof_buf(): memory allocation failed\n"); + return 0; + } + + /* Share pages so that kernel can map it */ + for ( i = 0; i < npages; i++ ) + share_xen_page_with_guest( + virt_to_page(rawbuf + i * PAGE_SIZE), + d, XENSHARE_writable); + + return rawbuf; +} + +static int alloc_xenoprof_struct( + struct domain *d, int max_samples, int is_passive) +{ + struct vcpu *v; + int nvcpu, npages, bufsize, max_bufsize; + unsigned max_max_samples; + int i; + + d->xenoprof = xmalloc(struct xenoprof); + + if ( d->xenoprof == NULL ) + { + printk ("alloc_xenoprof_struct(): memory " + "allocation (xmalloc) failed\n"); + return -ENOMEM; + } + + memset(d->xenoprof, 0, sizeof(*d->xenoprof)); + + nvcpu = 0; + for_each_vcpu ( d, v ) + nvcpu++; + + /* reduce max_samples if necessary to limit pages allocated */ + max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu; + max_max_samples = ( (max_bufsize - sizeof(struct xenoprof_buf)) / + sizeof(struct event_log) ) + 1; + if ( (unsigned)max_samples > max_max_samples ) + max_samples = max_max_samples; + + bufsize = sizeof(struct xenoprof_buf) + + (max_samples - 1) * sizeof(struct event_log); + npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1; + + d->xenoprof->rawbuf = alloc_xenoprof_buf(is_passive ? dom0 : d, npages); + + if ( d->xenoprof->rawbuf == NULL ) + { + xfree(d->xenoprof); + d->xenoprof = NULL; + return -ENOMEM; + } + + d->xenoprof->npages = npages; + d->xenoprof->nbuf = nvcpu; + d->xenoprof->bufsize = bufsize; + d->xenoprof->domain_ready = 0; + d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; + + /* Update buffer pointers for active vcpus */ + i = 0; + for_each_vcpu ( d, v ) + { + d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples; + d->xenoprof->vcpu[v->vcpu_id].buffer = + (struct xenoprof_buf *)&d->xenoprof->rawbuf[i * bufsize]; + d->xenoprof->vcpu[v->vcpu_id].buffer->event_size = max_samples; + d->xenoprof->vcpu[v->vcpu_id].buffer->vcpu_id = v->vcpu_id; + + i++; + /* in the unlikely case that the number of active vcpus changes */ + if ( i >= nvcpu ) + break; + } + + return 0; +} + +void free_xenoprof_pages(struct domain *d) +{ + struct xenoprof *x; + int order; + + x = d->xenoprof; + if ( x == NULL ) + return; + + if ( x->rawbuf != NULL ) + { + order = get_order_from_pages(x->npages); + free_xenheap_pages(x->rawbuf, order); + } + + xfree(x); + d->xenoprof = NULL; +} + +static int active_index(struct domain *d) +{ + int i; + + for ( i = 0; i < adomains; i++ ) + if ( active_domains[i] == d ) + return i; + + return -1; +} + +static int set_active(struct domain *d) +{ + int ind; + struct xenoprof *x; + + ind = active_index(d); + if ( ind < 0 ) + return -EPERM; + + x = d->xenoprof; + if ( x == NULL ) + return -EPERM; + + x->domain_ready = 1; + x->domain_type = XENOPROF_DOMAIN_ACTIVE; + active_ready[ind] = 1; + activated++; + + return 0; +} + +static int reset_active(struct domain *d) +{ + int ind; + struct xenoprof *x; + + ind = active_index(d); + if ( ind < 0 ) + return -EPERM; + + x = d->xenoprof; + if ( x == NULL ) + return -EPERM; + + x->domain_ready = 0; + x->domain_type = XENOPROF_DOMAIN_IGNORED; + active_ready[ind] = 0; + active_domains[ind] = NULL; + activated--; + put_domain(d); + + if ( activated <= 0 ) + adomains = 0; + + return 0; +} + +static void reset_passive(struct domain *d) +{ + struct xenoprof *x; + + if ( d == 0 ) + return; + + x = d->xenoprof; + if ( x == NULL ) + return; + + x->domain_type = XENOPROF_DOMAIN_IGNORED; +} + +static void reset_active_list(void) +{ + int i; + + for ( i = 0; i < adomains; i++ ) + if ( active_ready[i] ) + reset_active(active_domains[i]); + + adomains = 0; + activated = 0; +} + +static void reset_passive_list(void) +{ + int i; + + for ( i = 0; i < pdomains; i++ ) + { + reset_passive(passive_domains[i]); + put_domain(passive_domains[i]); + passive_domains[i] = NULL; + } + + pdomains = 0; +} + +static int add_active_list(domid_t domid) +{ + struct domain *d; + + if ( adomains >= MAX_OPROF_DOMAINS ) + return -E2BIG; + + d = find_domain_by_id(domid); + if ( d == NULL ) + return -EINVAL; + + active_domains[adomains] = d; + active_ready[adomains] = 0; + adomains++; + + return 0; +} + +static int add_passive_list(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_passive passive; + struct domain *d; + int ret = 0; + + if ( pdomains >= MAX_OPROF_DOMAINS ) + return -E2BIG; + + if ( copy_from_guest(&passive, arg, 1) ) + return -EFAULT; + + d = find_domain_by_id(passive.domain_id); + if ( d == NULL ) + return -EINVAL; + + if ( (d->xenoprof == NULL) && + ((ret = alloc_xenoprof_struct(d, passive.max_samples, 1)) < 0) ) + { + put_domain(d); + return -ENOMEM; + } + + d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE; + passive.nbuf = d->xenoprof->nbuf; + passive.bufsize = d->xenoprof->bufsize; + passive.buf_maddr = __pa(d->xenoprof->rawbuf); + + if ( copy_to_guest(arg, &passive, 1) ) + { + put_domain(d); + return -EFAULT; + } + + passive_domains[pdomains] = d; + pdomains++; + + return ret; +} + +void xenoprof_log_event( + struct vcpu *vcpu, unsigned long eip, int mode, int event) +{ + struct xenoprof_vcpu *v; + struct xenoprof_buf *buf; + int head; + int tail; + int size; + + + total_samples++; + + /* ignore samples of un-monitored domains */ + /* Count samples in idle separate from other unmonitored domains */ + if ( !is_profiled(vcpu->domain) ) + { + others_samples++; + return; + } + + v = &vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id]; + + /* Sanity check. Should never happen */ + if ( v->buffer == NULL ) + { + invalid_buffer_samples++; + return; + } + + buf = vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id].buffer; + + head = buf->event_head; + tail = buf->event_tail; + size = v->event_size; + + /* make sure indexes in shared buffer are sane */ + if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) ) + { + corrupted_buffer_samples++; + return; + } + + if ( (head == tail - 1) || (head == size - 1 && tail == 0) ) + { + buf->lost_samples++; + lost_samples++; + } + else + { + buf->event_log[head].eip = eip; + buf->event_log[head].mode = mode; + buf->event_log[head].event = event; + head++; + if ( head >= size ) + head = 0; + buf->event_head = head; + if ( is_active(vcpu->domain) ) + active_samples++; + else + passive_samples++; + if ( mode == 0 ) + buf->user_samples++; + else if ( mode == 1 ) + buf->kernel_samples++; + else + buf->xen_samples++; + } +} + +static int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_init xenoprof_init; + int ret; + + if ( copy_from_guest(&xenoprof_init, arg, 1) ) + return -EFAULT; + + if ( (ret = nmi_init(&xenoprof_init.num_events, + &xenoprof_init.is_primary, + xenoprof_init.cpu_type)) ) + return ret; + + if ( copy_to_guest(arg, &xenoprof_init, 1) ) + return -EFAULT; + + if ( xenoprof_init.is_primary ) + primary_profiler = current->domain; + + return 0; +} + +static int xenoprof_op_get_buffer(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_get_buffer xenoprof_get_buffer; + struct domain *d = current->domain; + int ret; + + if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) ) + return -EFAULT; + + /* + * We allocate xenoprof struct and buffers only at first time + * get_buffer is called. Memory is then kept until domain is destroyed. + */ + if ( d->xenoprof == NULL ) + { + ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0); + if ( ret < 0 ) + return ret; + } + + xenoprof_reset_buf(d); + + d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; + d->xenoprof->domain_ready = 0; + d->xenoprof->is_primary = (primary_profiler == current->domain); + + xenoprof_get_buffer.nbuf = d->xenoprof->nbuf; + xenoprof_get_buffer.bufsize = d->xenoprof->bufsize; + xenoprof_get_buffer.buf_maddr = __pa(d->xenoprof->rawbuf); + + if ( copy_to_guest(arg, &xenoprof_get_buffer, 1) ) + return -EFAULT; + + return 0; +} + +#define NONPRIV_OP(op) ( (op == XENOPROF_init) \ + || (op == XENOPROF_enable_virq) \ + || (op == XENOPROF_disable_virq) \ + || (op == XENOPROF_get_buffer)) + +int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg) +{ + int ret = 0; + + if ( (op < 0) || (op > XENOPROF_last_op) ) + { + printk("xenoprof: invalid operation %d for domain %d\n", + op, current->domain->domain_id); + return -EINVAL; + } + + if ( !NONPRIV_OP(op) && (current->domain != primary_profiler) ) + { + printk("xenoprof: dom %d denied privileged operation %d\n", + current->domain->domain_id, op); + return -EPERM; + } + + spin_lock(&xenoprof_lock); + + switch ( op ) + { + case XENOPROF_init: + ret = xenoprof_op_init(arg); + break; + + case XENOPROF_get_buffer: + ret = xenoprof_op_get_buffer(arg); + break; + + case XENOPROF_reset_active_list: + { + reset_active_list(); + ret = 0; + break; + } + case XENOPROF_reset_passive_list: + { + reset_passive_list(); + ret = 0; + break; + } + case XENOPROF_set_active: + { + domid_t domid; + if ( xenoprof_state != XENOPROF_IDLE ) + { + ret = -EPERM; + break; + } + if ( copy_from_guest(&domid, arg, 1) ) + { + ret = -EFAULT; + break; + } + ret = add_active_list(domid); + break; + } + case XENOPROF_set_passive: + { + if ( xenoprof_state != XENOPROF_IDLE ) + { + ret = -EPERM; + break; + } + ret = add_passive_list(arg); + break; + } + case XENOPROF_reserve_counters: + if ( xenoprof_state != XENOPROF_IDLE ) + { + ret = -EPERM; + break; + } + ret = nmi_reserve_counters(); + if ( !ret ) + xenoprof_state = XENOPROF_COUNTERS_RESERVED; + break; + + case XENOPROF_counter: + { + struct xenoprof_counter counter; + if ( (xenoprof_state != XENOPROF_COUNTERS_RESERVED) || + (adomains == 0) ) + { + ret = -EPERM; + break; + } + + if ( copy_from_guest(&counter, arg, 1) ) + return -EFAULT; + + if ( counter.ind > OP_MAX_COUNTER ) + return -E2BIG; + + counter_config[counter.ind].count = counter.count; + counter_config[counter.ind].enabled = counter.enabled; + counter_config[counter.ind].event = counter.event; + counter_config[counter.ind].kernel = counter.kernel; + counter_config[counter.ind].user = counter.user; + counter_config[counter.ind].unit_mask = counter.unit_mask; + + ret = 0; + break; + } + + case XENOPROF_setup_events: + if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED ) + { + ret = -EPERM; + break; + } + ret = nmi_setup_events(); + if ( !ret ) + xenoprof_state = XENOPROF_READY; + break; + + case XENOPROF_enable_virq: + { + int i; + if ( current->domain == primary_profiler ) + { + nmi_enable_virq(); + xenoprof_reset_stat(); + for ( i = 0; i < pdomains; i++ ) + xenoprof_reset_buf(passive_domains[i]); + } + xenoprof_reset_buf(current->domain); + ret = set_active(current->domain); + break; + } + + case XENOPROF_start: + ret = -EPERM; + if ( (xenoprof_state == XENOPROF_READY) && + (activated == adomains) ) + ret = nmi_start(); + + if ( ret == 0 ) + xenoprof_state = XENOPROF_PROFILING; + break; + + case XENOPROF_stop: + if ( xenoprof_state != XENOPROF_PROFILING ) { + ret = -EPERM; + break; + } + nmi_stop(); + xenoprof_state = XENOPROF_READY; + break; + + case XENOPROF_disable_virq: + if ( (xenoprof_state == XENOPROF_PROFILING) && + (is_active(current->domain)) ) + { + ret = -EPERM; + break; + } + ret = reset_active(current->domain); + break; + + case XENOPROF_release_counters: + ret = -EPERM; + if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) || + (xenoprof_state == XENOPROF_READY) ) + { + xenoprof_state = XENOPROF_IDLE; + nmi_release_counters(); + nmi_disable_virq(); + reset_passive_list(); + ret = 0; + } + break; + + case XENOPROF_shutdown: + ret = -EPERM; + if ( xenoprof_state == XENOPROF_IDLE ) + { + activated = 0; + adomains=0; + primary_profiler = NULL; + ret = 0; + } + break; + + default: + ret = -ENOSYS; + } + + spin_unlock(&xenoprof_lock); + + if ( ret < 0 ) + printk("xenoprof: operation %d failed for dom %d (status : %d)\n", + op, current->domain->domain_id, ret); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |