mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
Add new operation XENOPROF_get_buffer in xenoprof hypercall. Also
remove buffer related arguments from XENOPROF_init operation. This is the first step to allow dynamic mapping/unmapping of xenoprof buffers to enable profiling a domain in passive mode and then switch to active mode (or vice-versa). Currently a domain can only be profiled in a single mode. Also passive domains cannot have oprofile builtin the kernel or passive profiling will fail. Signed-off-by: Jose Renato Santos <jsantos@hpl.hp.com>
This commit is contained in:
1 parent
80f2588d2b
commit
d4b644873d
3 files changed
+101
-72
No files matched your search
@@ -32,6 +32,8 @@
|
||||
#include <../../../drivers/oprofile/cpu_buffer.h>
|
||||
#include <../../../drivers/oprofile/event_buffer.h>
|
||||
|
||||
#define MAX_XENOPROF_SAMPLES 16
|
||||
|
||||
static int xenoprof_start(void);
|
||||
static void xenoprof_stop(void);
|
||||
|
||||
@@ -43,7 +45,7 @@ static int active_defined;
|
||||
/* sample buffers shared with Xen */
|
||||
xenoprof_buf_t * xenoprof_buf[MAX_VIRT_CPUS];
|
||||
/* Shared buffer area */
|
||||
char * shared_buffer;
|
||||
char * shared_buffer = NULL;
|
||||
/* Number of buffers in shared area (one per VCPU) */
|
||||
int nbuf;
|
||||
/* Mappings of VIRQ_XENOPROF to irq number (per cpu) */
|
||||
@@ -233,13 +235,57 @@ static int bind_virq(void)
|
||||
}
|
||||
|
||||
|
||||
static int map_xenoprof_buffer(int max_samples)
|
||||
{
|
||||
struct xenoprof_get_buffer get_buffer;
|
||||
struct xenoprof_buf *buf;
|
||||
int npages, ret, i;
|
||||
struct vm_struct *area;
|
||||
|
||||
if ( shared_buffer )
|
||||
return 0;
|
||||
|
||||
get_buffer.max_samples = max_samples;
|
||||
|
||||
if ( (ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, &get_buffer)) )
|
||||
return ret;
|
||||
|
||||
nbuf = get_buffer.nbuf;
|
||||
npages = (get_buffer.bufsize * nbuf - 1) / PAGE_SIZE + 1;
|
||||
|
||||
area = alloc_vm_area(npages * PAGE_SIZE);
|
||||
if (area == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if ( (ret = direct_kernel_remap_pfn_range(
|
||||
(unsigned long)area->addr,
|
||||
get_buffer.buf_maddr >> PAGE_SHIFT,
|
||||
npages * PAGE_SIZE, __pgprot(_KERNPG_TABLE), DOMID_SELF)) ) {
|
||||
vunmap(area->addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
shared_buffer = area->addr;
|
||||
for (i=0; i< nbuf; i++) {
|
||||
buf = (struct xenoprof_buf*)
|
||||
&shared_buffer[i * get_buffer.bufsize];
|
||||
BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
|
||||
xenoprof_buf[buf->vcpu_id] = buf;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int xenoprof_setup(void)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = bind_virq();
|
||||
if (ret)
|
||||
if ( (ret = map_xenoprof_buffer(MAX_XENOPROF_SAMPLES)) )
|
||||
return ret;
|
||||
|
||||
if ( (ret = bind_virq()) )
|
||||
return ret;
|
||||
|
||||
if (is_primary) {
|
||||
@@ -482,51 +528,19 @@ static int using_xenoprof;
|
||||
int __init oprofile_arch_init(struct oprofile_operations * ops)
|
||||
{
|
||||
struct xenoprof_init init;
|
||||
struct xenoprof_buf *buf;
|
||||
int npages, ret, i;
|
||||
struct vm_struct *area;
|
||||
int ret, i;
|
||||
|
||||
init.max_samples = 16;
|
||||
ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init);
|
||||
|
||||
if (!ret) {
|
||||
pgprot_t prot = __pgprot(_KERNPG_TABLE);
|
||||
|
||||
num_events = init.num_events;
|
||||
is_primary = init.is_primary;
|
||||
nbuf = init.nbuf;
|
||||
|
||||
/* just in case - make sure we do not overflow event list
|
||||
(i.e. counter_config list) */
|
||||
(i.e. counter_config list) */
|
||||
if (num_events > OP_MAX_COUNTER)
|
||||
num_events = OP_MAX_COUNTER;
|
||||
|
||||
npages = (init.bufsize * nbuf - 1) / PAGE_SIZE + 1;
|
||||
|
||||
area = alloc_vm_area(npages * PAGE_SIZE);
|
||||
if (area == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = direct_kernel_remap_pfn_range(
|
||||
(unsigned long)area->addr,
|
||||
init.buf_maddr >> PAGE_SHIFT,
|
||||
npages * PAGE_SIZE, prot, DOMID_SELF);
|
||||
if (ret) {
|
||||
vunmap(area->addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
shared_buffer = area->addr;
|
||||
|
||||
for (i=0; i< nbuf; i++) {
|
||||
buf = (struct xenoprof_buf*)
|
||||
&shared_buffer[i * init.bufsize];
|
||||
BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
|
||||
xenoprof_buf[buf->vcpu_id] = buf;
|
||||
}
|
||||
|
||||
/* cpu_type is detected by Xen */
|
||||
cpu_type[XENOPROF_CPU_TYPE_SIZE-1] = 0;
|
||||
strncpy(cpu_type, init.cpu_type, XENOPROF_CPU_TYPE_SIZE - 1);
|
||||
@@ -541,7 +555,6 @@ int __init oprofile_arch_init(struct oprofile_operations * ops)
|
||||
|
||||
active_defined = 0;
|
||||
}
|
||||
out:
|
||||
printk(KERN_INFO "oprofile_arch_init: ret %d, events %d, "
|
||||
"is_primary %d\n", ret, num_events, is_primary);
|
||||
return ret;
|
||||
|
||||
@@ -437,54 +437,59 @@ void xenoprof_log_event(
|
||||
int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
struct xenoprof_init xenoprof_init;
|
||||
int is_primary, num_events;
|
||||
struct domain *d = current->domain;
|
||||
int ret;
|
||||
|
||||
if ( copy_from_guest(&xenoprof_init, arg, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
ret = nmi_init(&num_events,
|
||||
&is_primary,
|
||||
xenoprof_init.cpu_type);
|
||||
if ( ret < 0 )
|
||||
goto err;
|
||||
if ( (ret = nmi_init(&xenoprof_init.num_events,
|
||||
&xenoprof_init.is_primary,
|
||||
xenoprof_init.cpu_type)) )
|
||||
return ret;
|
||||
|
||||
if ( is_primary )
|
||||
if ( copy_to_guest(arg, &xenoprof_init, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
if ( xenoprof_init.is_primary )
|
||||
primary_profiler = current->domain;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_init
|
||||
* 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_init.max_samples, 0)) < 0) )
|
||||
goto err;
|
||||
((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;
|
||||
d->xenoprof->is_primary = is_primary;
|
||||
|
||||
xenoprof_init.is_primary = is_primary;
|
||||
xenoprof_init.num_events = num_events;
|
||||
xenoprof_init.nbuf = d->xenoprof->nbuf;
|
||||
xenoprof_init.bufsize = d->xenoprof->bufsize;
|
||||
xenoprof_init.buf_maddr = __pa(d->xenoprof->rawbuf);
|
||||
|
||||
if ( copy_to_guest(arg, &xenoprof_init, 1) )
|
||||
{
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
if ( primary_profiler == current->domain )
|
||||
primary_profiler = NULL;
|
||||
return ret;
|
||||
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 PRIV_OP(op) ( (op == XENOPROF_set_active) \
|
||||
@@ -512,6 +517,10 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
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();
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#define XENOPROF_disable_virq 11
|
||||
#define XENOPROF_release_counters 12
|
||||
#define XENOPROF_shutdown 13
|
||||
#define XENOPROF_get_buffer 14
|
||||
#define XENOPROF_last_op 14
|
||||
|
||||
#define MAX_OPROF_EVENTS 32
|
||||
#define MAX_OPROF_DOMAINS 25
|
||||
@@ -56,17 +58,22 @@ typedef struct xenoprof_buf xenoprof_buf_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xenoprof_buf_t);
|
||||
|
||||
struct xenoprof_init {
|
||||
int32_t max_samples;
|
||||
int32_t num_events;
|
||||
int32_t is_primary;
|
||||
int32_t nbuf;
|
||||
int32_t bufsize;
|
||||
uint64_t buf_maddr;
|
||||
char cpu_type[XENOPROF_CPU_TYPE_SIZE];
|
||||
};
|
||||
typedef struct xenoprof_init xenoprof_init_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xenoprof_init_t);
|
||||
|
||||
struct xenoprof_get_buffer {
|
||||
int32_t max_samples;
|
||||
int32_t nbuf;
|
||||
int32_t bufsize;
|
||||
uint64_t buf_maddr;
|
||||
};
|
||||
typedef struct xenoprof_get_buffer xenoprof_get_buffer_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xenoprof_get_buffer_t);
|
||||
|
||||
struct xenoprof_counter {
|
||||
uint32_t ind;
|
||||
uint64_t count;
|
||||
|
||||