update PAPI support. other process and child process monitoring.

This commit is contained in:
Ken Sato
2016-04-26 19:01:47 +09:00
parent 921280f85c
commit 130b1f4327
7 changed files with 259 additions and 88 deletions

View File

@@ -33,6 +33,7 @@
#define LAPIC_ID 0x020 #define LAPIC_ID 0x020
#define LAPIC_TIMER 0x320 #define LAPIC_TIMER 0x320
#define LAPIC_LVTPC 0x340
#define LAPIC_TIMER_INITIAL 0x380 #define LAPIC_TIMER_INITIAL 0x380
#define LAPIC_TIMER_CURRENT 0x390 #define LAPIC_TIMER_CURRENT 0x390
#define LAPIC_TIMER_DIVIDE 0x3e0 #define LAPIC_TIMER_DIVIDE 0x3e0
@@ -42,6 +43,7 @@
#define LAPIC_ICR2 0x310 #define LAPIC_ICR2 0x310
#define LAPIC_ESR 0x280 #define LAPIC_ESR 0x280
#define LOCAL_TIMER_VECTOR 0xef #define LOCAL_TIMER_VECTOR 0xef
#define LOCAL_PERF_VECTOR 0xf0
#define APIC_INT_LEVELTRIG 0x08000 #define APIC_INT_LEVELTRIG 0x08000
#define APIC_INT_ASSERT 0x04000 #define APIC_INT_ASSERT 0x04000
@@ -420,6 +422,7 @@ init_lapic()
} }
lapic_write(LAPIC_SPURIOUS, 0x1ff); lapic_write(LAPIC_SPURIOUS, 0x1ff);
lapic_write(LAPIC_LVTPC, LOCAL_PERF_VECTOR);
} }
void print_msr(int idx) void print_msr(int idx)
@@ -873,6 +876,15 @@ void handle_interrupt(int vector, struct x86_user_context *regs)
ihk_mc_spinlock_unlock(&v->runq_lock, irqstate); ihk_mc_spinlock_unlock(&v->runq_lock, irqstate);
dkprintf("timer[%lu]: CPU_FLAG_NEED_RESCHED \n", rdtsc()); dkprintf("timer[%lu]: CPU_FLAG_NEED_RESCHED \n", rdtsc());
} }
else if (vector == LOCAL_PERF_VECTOR) {
unsigned long value;
value = rdmsr(MSR_PERF_GLOBAL_STATUS);
wrmsr(MSR_PERF_GLOBAL_OVF_CTRL, value);
wrmsr(MSR_PERF_GLOBAL_OVF_CTRL, 0);
//TODO: counter overflow signal
//set_signal(0x1d, regs, NULL); // SIGIO
}
else if (vector >= IHK_TLB_FLUSH_IRQ_VECTOR_START && else if (vector >= IHK_TLB_FLUSH_IRQ_VECTOR_START &&
vector < IHK_TLB_FLUSH_IRQ_VECTOR_END) { vector < IHK_TLB_FLUSH_IRQ_VECTOR_END) {

View File

@@ -14,18 +14,24 @@
#include <registers.h> #include <registers.h>
extern unsigned int *x86_march_perfmap; extern unsigned int *x86_march_perfmap;
static unsigned long pmc_status = 0x0;
#define X86_CR4_PCE 0x00000100 #define X86_CR4_PCE 0x00000100
void x86_init_perfctr(void) void x86_init_perfctr(void)
{ {
unsigned long reg; unsigned long reg;
unsigned long value = 0;
/* Allow PMC to be read from user space */ /* Allow PMC to be read from user space */
asm volatile("movq %%cr4, %0" : "=r"(reg)); asm volatile("movq %%cr4, %0" : "=r"(reg));
reg |= X86_CR4_PCE; reg |= X86_CR4_PCE;
asm volatile("movq %0, %%cr4" : : "r"(reg)); asm volatile("movq %0, %%cr4" : : "r"(reg));
/* Enable PMC Control */
value = rdmsr(MSR_PERF_GLOBAL_CTRL);
value |= X86_IA32_PERF_COUNTERS_MASK;
value |= X86_IA32_FIXED_PERF_COUNTERS_MASK;
wrmsr(MSR_PERF_GLOBAL_CTRL, value);
} }
static int set_perfctr_x86_direct(int counter, int mode, unsigned int value) static int set_perfctr_x86_direct(int counter, int mode, unsigned int value)
@@ -287,7 +293,7 @@ unsigned long ihk_mc_perfctr_read_msr(int counter)
return retval; return retval;
} }
int ihk_mc_perfctr_alloc_counter() int ihk_mc_perfctr_alloc_counter(unsigned long pmc_status)
{ {
int i = 0; int i = 0;
int ret = -1; int ret = -1;
@@ -307,15 +313,3 @@ int ihk_mc_perfctr_alloc_counter()
return ret; return ret;
} }
void ihk_mc_perfctr_release_counter(int counter)
{
unsigned long value = 0;
value = rdmsr(MSR_PERF_GLOBAL_CTRL);
value &= ~(1UL << counter);
pmc_status &= ~(1UL << counter);
wrmsr(MSR_PERF_GLOBAL_CTRL, 0);
}

View File

@@ -447,6 +447,14 @@ struct process {
long maxrss; long maxrss;
long maxrss_children; long maxrss_children;
// perf_event
int perf_status;
#define PP_NONE 0
#define PP_RESET 1
#define PP_COUNT 2
#define PP_STOP 3
struct mc_perf_event *monitoring_event;
}; };
void hold_thread(struct thread *ftn); void hold_thread(struct thread *ftn);

View File

@@ -64,6 +64,8 @@ int ptrace_detach(int pid, int data);
extern unsigned long do_kill(struct thread *, int pid, int tid, int sig, struct siginfo *info, int ptracecont); extern unsigned long do_kill(struct thread *, int pid, int tid, int sig, struct siginfo *info, int ptracecont);
extern void procfs_create_thread(struct thread *); extern void procfs_create_thread(struct thread *);
extern void procfs_delete_thread(struct thread *); extern void procfs_delete_thread(struct thread *);
extern void perf_start(struct mc_perf_event *event);
extern void perf_reset(struct mc_perf_event *event);
struct list_head resource_set_list; struct list_head resource_set_list;
mcs_rwlock_lock_t resource_set_lock; mcs_rwlock_lock_t resource_set_lock;
@@ -100,6 +102,7 @@ init_process(struct process *proc, struct process *parent)
ihk_mc_spinlock_init(&proc->mckfd_lock); ihk_mc_spinlock_init(&proc->mckfd_lock);
waitq_init(&proc->waitpid_q); waitq_init(&proc->waitpid_q);
ihk_atomic_set(&proc->refcount, 2); ihk_atomic_set(&proc->refcount, 2);
proc->monitoring_event = NULL;
} }
void void
@@ -2627,6 +2630,15 @@ redo:
/* Set up new TLS.. */ /* Set up new TLS.. */
ihk_mc_init_user_tlsbase(next->uctx, next->tlsblock_base); ihk_mc_init_user_tlsbase(next->uctx, next->tlsblock_base);
/* Performance monitoring inherit */
if(next->proc->monitoring_event) {
if(next->proc->perf_status == PP_RESET)
perf_reset(next->proc->monitoring_event);
if(next->proc->perf_status != PP_COUNT) {
perf_reset(next->proc->monitoring_event);
perf_start(next->proc->monitoring_event);
}
}
if (prev) { if (prev) {
last = ihk_mc_switch_context(&prev->ctx, &next->ctx, prev); last = ihk_mc_switch_context(&prev->ctx, &next->ctx, prev);
} }

View File

@@ -115,6 +115,7 @@ extern void free_all_process_memory_range(struct process_vm *vm);
extern int arch_clear_host_user_space(); extern int arch_clear_host_user_space();
extern long arch_ptrace(long request, int pid, long addr, long data); extern long arch_ptrace(long request, int pid, long addr, long data);
extern struct cpu_local_var *clv; extern struct cpu_local_var *clv;
extern void sync_child_event(struct mc_perf_event *event);
int prepare_process_ranges_args_envs(struct thread *thread, int prepare_process_ranges_args_envs(struct thread *thread,
struct program_load_desc *pn, struct program_load_desc *pn,
@@ -604,6 +605,9 @@ terminate(int rc, int sig)
int *ids = NULL; int *ids = NULL;
struct syscall_request request IHK_DMA_ALIGN; struct syscall_request request IHK_DMA_ALIGN;
// sync perf info
if(proc->monitoring_event)
sync_child_event(proc->monitoring_event);
// clean up threads // clean up threads
mcs_rwlock_reader_lock(&proc->threads_lock, &lock); // conflict clone mcs_rwlock_reader_lock(&proc->threads_lock, &lock); // conflict clone
mcs_rwlock_writer_lock_noirq(&proc->update_lock, &updatelock); mcs_rwlock_writer_lock_noirq(&proc->update_lock, &updatelock);
@@ -1784,6 +1788,9 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
unsigned long cursp) unsigned long cursp)
{ {
int cpuid; int cpuid;
struct thread *old = cpu_local_var(current);
struct process *oldproc = old->proc;
struct process *newproc;
struct thread *new; struct thread *new;
struct syscall_request request1 IHK_DMA_ALIGN; struct syscall_request request1 IHK_DMA_ALIGN;
int ptrace_event = 0; int ptrace_event = 0;
@@ -1832,7 +1839,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
return -EAGAIN; return -EAGAIN;
} }
new = clone_thread(cpu_local_var(current), curpc, new = clone_thread(old, curpc,
newsp ? newsp : cursp, clone_flags); newsp ? newsp : cursp, clone_flags);
if (!new) { if (!new) {
@@ -1840,6 +1847,8 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
return -ENOMEM; return -ENOMEM;
} }
newproc = new->proc;
cpu_set(cpuid, &new->vm->address_space->cpu_set, cpu_set(cpuid, &new->vm->address_space->cpu_set,
&new->vm->address_space->cpu_set_lock); &new->vm->address_space->cpu_set_lock);
@@ -1851,11 +1860,11 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
request1.number = __NR_fork; request1.number = __NR_fork;
request1.args[0] = 0; request1.args[0] = 0;
if(clone_flags & CLONE_PARENT){ if(clone_flags & CLONE_PARENT){
if(cpu_local_var(current)->proc->ppid_parent->pid != 1) if(oldproc->ppid_parent->pid != 1)
request1.args[0] = clone_flags; request1.args[0] = clone_flags;
} }
new->proc->pid = do_syscall(&request1, ihk_mc_get_processor_id(), 0); newproc->pid = do_syscall(&request1, ihk_mc_get_processor_id(), 0);
if (new->proc->pid == -1) { if (newproc->pid == -1) {
kprintf("ERROR: forking host process\n"); kprintf("ERROR: forking host process\n");
/* TODO: clean-up new */ /* TODO: clean-up new */
@@ -1876,7 +1885,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
new->vm->region.user_start; new->vm->region.user_start;
/* 3rd parameter denotes new rpgtable of host process */ /* 3rd parameter denotes new rpgtable of host process */
request1.args[2] = virt_to_phys(new->vm->address_space->page_table); request1.args[2] = virt_to_phys(new->vm->address_space->page_table);
request1.args[3] = new->proc->pid; request1.args[3] = newproc->pid;
dkprintf("fork(): requesting PTE clear and rpgtable (0x%lx) update\n", dkprintf("fork(): requesting PTE clear and rpgtable (0x%lx) update\n",
request1.args[2]); request1.args[2]);
@@ -1884,6 +1893,10 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
if (do_syscall(&request1, ihk_mc_get_processor_id(), new->proc->pid)) { if (do_syscall(&request1, ihk_mc_get_processor_id(), new->proc->pid)) {
kprintf("ERROR: clearing PTEs in host process\n"); kprintf("ERROR: clearing PTEs in host process\n");
} }
if(oldproc->monitoring_event &&
oldproc->monitoring_event->attr.inherit){
newproc->monitoring_event = oldproc->monitoring_event;
}
} }
if (clone_flags & CLONE_PARENT_SETTID) { if (clone_flags & CLONE_PARENT_SETTID) {
@@ -1922,8 +1935,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
new->tlsblock_base = tlsblock_base; new->tlsblock_base = tlsblock_base;
} }
else { else {
new->tlsblock_base = new->tlsblock_base = old->tlsblock_base;
cpu_local_var(current)->tlsblock_base;
} }
ihk_mc_syscall_ret(new->uctx) = 0; ihk_mc_syscall_ret(new->uctx) = 0;
@@ -1931,42 +1943,41 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
new->status = PS_RUNNING; new->status = PS_RUNNING;
chain_thread(new); chain_thread(new);
if (!(clone_flags & CLONE_VM)) { if (!(clone_flags & CLONE_VM)) {
new->proc->status = PS_RUNNING; newproc->status = PS_RUNNING;
if(clone_flags & CLONE_PARENT){ if(clone_flags & CLONE_PARENT){
struct mcs_rwlock_node_irqsave lock; struct mcs_rwlock_node_irqsave lock;
struct process *proc = cpu_local_var(current)->proc;
struct process *parent; struct process *parent;
struct mcs_rwlock_node parent_lock; struct mcs_rwlock_node parent_lock;
mcs_rwlock_reader_lock(&proc->update_lock, &lock); mcs_rwlock_reader_lock(&oldproc->update_lock, &lock);
parent = proc->ppid_parent; parent = oldproc->ppid_parent;
mcs_rwlock_reader_lock_noirq(&parent->update_lock, &parent_lock); mcs_rwlock_reader_lock_noirq(&parent->update_lock, &parent_lock);
if(parent->status == PS_EXITED || parent->status == PS_ZOMBIE){ if(parent->status == PS_EXITED || parent->status == PS_ZOMBIE){
mcs_rwlock_reader_unlock_noirq(&parent->update_lock, &parent_lock); mcs_rwlock_reader_unlock_noirq(&parent->update_lock, &parent_lock);
parent = cpu_local_var(resource_set)->pid1; parent = cpu_local_var(resource_set)->pid1;
mcs_rwlock_reader_lock_noirq(&parent->update_lock, &parent_lock); mcs_rwlock_reader_lock_noirq(&parent->update_lock, &parent_lock);
} }
new->proc->parent = parent; newproc->parent = parent;
new->proc->ppid_parent = parent; newproc->ppid_parent = parent;
new->proc->nowait = 1; newproc->nowait = 1;
chain_process(new->proc); chain_process(newproc);
mcs_rwlock_reader_unlock_noirq(&parent->update_lock, &parent_lock); mcs_rwlock_reader_unlock_noirq(&parent->update_lock, &parent_lock);
mcs_rwlock_reader_unlock(&proc->update_lock, &lock); mcs_rwlock_reader_unlock(&oldproc->update_lock, &lock);
} }
else else
chain_process(new->proc); chain_process(newproc);
} }
if (cpu_local_var(current)->proc->ptrace) { if (oldproc->ptrace) {
ptrace_event = ptrace_check_clone_event(cpu_local_var(current), clone_flags); ptrace_event = ptrace_check_clone_event(old, clone_flags);
if (ptrace_event) { if (ptrace_event) {
ptrace_report_clone(cpu_local_var(current), new, ptrace_event); ptrace_report_clone(old, new, ptrace_event);
} }
} }
dkprintf("clone: kicking scheduler!,cpuid=%d pid=%d tid %d -> tid=%d\n", dkprintf("clone: kicking scheduler!,cpuid=%d pid=%d tid %d -> tid=%d\n",
cpuid, new->proc->pid, cpuid, newproc->pid,
cpu_local_var(current)->tid, old->tid,
new->tid); new->tid);
runq_add_thread(new, cpuid); runq_add_thread(new, cpuid);
@@ -2604,7 +2615,38 @@ SYSCALL_DECLARE(signalfd4)
} }
int int
perf_counter_init(struct mc_perf_event *event) perf_counter_alloc(struct mc_perf_event *event)
{
int ret = 0;
struct perf_event_attr *attr = &event->attr;
struct mc_perf_event *leader = event->group_leader;
if(attr->type == PERF_TYPE_HARDWARE) {
event->counter_id = ihk_mc_perfctr_alloc_counter(leader->pmc_status);
} else if(attr->type == PERF_TYPE_RAW) {
// PAPI_REF_CYC counted by fixed counter
if((attr->config & 0x0000ffff) == 0x00000300) {
event->counter_id = 2 + X86_IA32_BASE_FIXED_PERF_COUNTERS;
return ret;
}
event->counter_id = ihk_mc_perfctr_alloc_counter(leader->pmc_status);
} else {
// Not supported type.
ret = -1;
}
if(ret >= 0) {
leader->pmc_status |= 1UL << event->counter_id;
}
return ret;
}
int
perf_counter_start(struct mc_perf_event *event)
{ {
int ret = 0; int ret = 0;
enum ihk_perfctr_type type; enum ihk_perfctr_type type;
@@ -2631,48 +2673,74 @@ perf_counter_init(struct mc_perf_event *event)
type = PERFCTR_MAX_TYPE; type = PERFCTR_MAX_TYPE;
} }
event->counter = ihk_mc_perfctr_alloc_counter(); ret = ihk_mc_perfctr_init(event->counter_id, type, mode);
ret = ihk_mc_perfctr_init(event->counter, type, mode); ihk_mc_perfctr_set(event->counter_id, event->sample_freq * -1);
ihk_mc_perfctr_start(1UL << event->counter_id);
} else if(attr->type == PERF_TYPE_RAW) { } else if(attr->type == PERF_TYPE_RAW) {
// PAPI_REF_CYC counted by fixed counter // PAPI_REF_CYC counted by fixed counter
if((attr->config & 0x0000ffff) == 0x00000300) { if(event->counter_id >= X86_IA32_BASE_FIXED_PERF_COUNTERS) {
event->counter = 2 + X86_IA32_BASE_FIXED_PERF_COUNTERS; ret = ihk_mc_perfctr_fixed_init(event->counter_id, mode);
ret = ihk_mc_perfctr_fixed_init(event->counter, mode); ihk_mc_perfctr_set(event->counter_id, event->sample_freq * -1);
ihk_mc_perfctr_start(1UL << event->counter_id);
return ret; return ret;
} }
// apply MODE to config(event_code) ret = ihk_mc_perfctr_init_raw(event->counter_id, attr->config, mode);
attr->config &= ~(3 << 16); ihk_mc_perfctr_set(event->counter_id, event->sample_freq * -1);
if(mode & PERFCTR_USER_MODE) { ihk_mc_perfctr_start(1UL << event->counter_id);
attr->config |= 1 << 16;
}
if(mode & PERFCTR_KERNEL_MODE) {
attr->config |= 1 << 17;
}
event->counter = ihk_mc_perfctr_alloc_counter();
ret = ihk_mc_perfctr_init_raw(event->counter, attr->config, mode);
} else { } else {
// Not supported type. // Not supported type.
ret = -1; ret = -1;
} }
if(ret >= 0) {
ret = ihk_mc_perfctr_reset(event->counter);
}
return ret; return ret;
} }
unsigned long perf_event_read_value(struct mc_perf_event *event) unsigned long perf_event_read_value(struct mc_perf_event *event)
{ {
unsigned long total = 0; unsigned long rtn_count = 0;
int counter = event->counter; int counter_id = event->counter_id;
total += ihk_mc_perfctr_read(counter); if(event->pid == 0)
event->count = ihk_mc_perfctr_read(counter_id);
return total; rtn_count += event->count;
if(event->attr.inherit)
rtn_count += event->child_count_total;
return rtn_count;
}
void sync_child_event(struct mc_perf_event *event)
{
struct mc_perf_event *leader;
struct mc_perf_event *sub;
if(!event)
return;
if(!(event->attr.inherit) && (event->pid == 0))
return;
leader = event->group_leader;
if(leader->pid == 0){
leader->child_count_total += ihk_mc_perfctr_read(leader->counter_id);
}
else if(leader->pid > 0) {
leader->count = ihk_mc_perfctr_read(leader->counter_id);
}
else
return; // Error
list_for_each_entry(sub, &leader->sibling_list, group_entry) {
if(event->pid == 0){
sub->child_count_total += ihk_mc_perfctr_read(sub->counter_id);
}
else if(event->pid > 0) {
sub->count = ihk_mc_perfctr_read(sub->counter_id);
}
}
} }
static int static int
@@ -2744,25 +2812,67 @@ perf_read(struct mckfd *sfd, ihk_mc_user_context_t *ctx)
} }
static void void
perf_start(struct mc_perf_event *event) perf_start(struct mc_perf_event *event)
{ {
int counter = event->counter; int counter_id;
struct mc_perf_event *leader = event->group_leader, *sub;
if((1UL << counter & X86_IA32_PERF_COUNTERS_MASK) | counter_id = leader->counter_id;
(1UL << counter & X86_IA32_FIXED_PERF_COUNTERS_MASK)) { if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) |
ihk_mc_perfctr_start(1UL << counter); (1UL << counter_id & X86_IA32_FIXED_PERF_COUNTERS_MASK)) {
perf_counter_start(leader);
}
list_for_each_entry(sub, &leader->sibling_list, group_entry) {
counter_id = sub->counter_id;
if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) |
(1UL << counter_id & X86_IA32_FIXED_PERF_COUNTERS_MASK)) {
perf_counter_start(sub);
}
}
cpu_local_var(current)->proc->perf_status = PP_COUNT;
}
void
perf_reset(struct mc_perf_event *event)
{
int counter_id;
struct mc_perf_event *leader = event->group_leader, *sub;
counter_id = leader->counter_id;
if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) |
(1UL << counter_id & X86_IA32_FIXED_PERF_COUNTERS_MASK)) {
ihk_mc_perfctr_reset(counter_id);
}
list_for_each_entry(sub, &leader->sibling_list, group_entry) {
counter_id = sub->counter_id;
if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) |
(1UL << counter_id & X86_IA32_FIXED_PERF_COUNTERS_MASK)) {
ihk_mc_perfctr_reset(counter_id);
}
} }
} }
static void static void
perf_stop(struct mc_perf_event *event) perf_stop(struct mc_perf_event *event)
{ {
int counter = event->counter; int counter_id;
struct mc_perf_event *leader = event->group_leader, *sub;
if((1UL << counter & X86_IA32_PERF_COUNTERS_MASK) | counter_id = leader->counter_id;
(1UL << counter & X86_IA32_FIXED_PERF_COUNTERS_MASK)) { if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) |
ihk_mc_perfctr_stop(1UL << counter); (1UL << counter_id & X86_IA32_FIXED_PERF_COUNTERS_MASK)) {
ihk_mc_perfctr_stop(1UL << counter_id);
}
list_for_each_entry(sub, &leader->sibling_list, group_entry) {
counter_id = sub->counter_id;
if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) |
(1UL << counter_id & X86_IA32_FIXED_PERF_COUNTERS_MASK)) {
ihk_mc_perfctr_stop(1UL << counter_id);
}
} }
} }
@@ -2771,20 +2881,52 @@ perf_ioctl(struct mckfd *sfd, ihk_mc_user_context_t *ctx)
{ {
unsigned int cmd = ihk_mc_syscall_arg1(ctx); unsigned int cmd = ihk_mc_syscall_arg1(ctx);
struct mc_perf_event *event = (struct mc_perf_event*)sfd->data; struct mc_perf_event *event = (struct mc_perf_event*)sfd->data;
int counter = event->counter; int counter_id = event->counter_id;
struct mcs_rwlock_node_irqsave lock;
struct process *proc;
switch (cmd) { switch (cmd) {
case PERF_EVENT_IOC_ENABLE: case PERF_EVENT_IOC_ENABLE:
perf_start(event); if(event->pid == 0){
cpu_local_var(current)->proc->monitoring_event = event;
perf_start(event);
}
else if(event->pid > 0){
proc = find_process(event->pid, &lock);
if(!proc)
return -EINVAL;
if(proc->monitoring_event == NULL){
proc->monitoring_event = event;
proc->perf_status = PP_RESET;
}
process_unlock(proc, &lock);
}
break; break;
case PERF_EVENT_IOC_DISABLE: case PERF_EVENT_IOC_DISABLE:
perf_stop(event); if(event->pid == 0){
perf_stop(event);
}
cpu_local_var(current)->proc->monitoring_event = NULL;
cpu_local_var(current)->proc->perf_status = PP_NONE;
// TODO: stop other process
/*
else if(event->pid > 0){
proc = find_process(event->pid, &lock);
if(!proc)
return -EINVAL;
proc->monitoring_event = NULL;
proc->perf_status = PP_NONE;
process_unlock(proc, &lock);
}
*/
break; break;
case PERF_EVENT_IOC_RESET: case PERF_EVENT_IOC_RESET:
ihk_mc_perfctr_set(counter, event->sample_freq * -1); // TODO: reset other process
ihk_mc_perfctr_reset(counter_id);
break; break;
case PERF_EVENT_IOC_REFRESH: case PERF_EVENT_IOC_REFRESH:
ihk_mc_perfctr_set(counter, event->sample_freq * -1); // TODO: refresh other process
ihk_mc_perfctr_set(counter_id, event->sample_freq * -1);
break; break;
default : default :
return -1; return -1;
@@ -2798,7 +2940,6 @@ perf_close(struct mckfd *sfd, ihk_mc_user_context_t *ctx)
{ {
struct mc_perf_event *event = (struct mc_perf_event*)sfd->data; struct mc_perf_event *event = (struct mc_perf_event*)sfd->data;
ihk_mc_perfctr_release_counter(event->counter);
kfree(event); kfree(event);
return 0; return 0;
@@ -2827,7 +2968,6 @@ perf_mmap(struct mckfd *sfd, ihk_mc_user_context_t *ctx)
return rc; return rc;
} }
extern unsigned long ihk_mc_perfctr_get_info();
SYSCALL_DECLARE(perf_event_open) SYSCALL_DECLARE(perf_event_open)
{ {
struct syscall_request request IHK_DMA_ALIGN; struct syscall_request request IHK_DMA_ALIGN;
@@ -2846,10 +2986,7 @@ SYSCALL_DECLARE(perf_event_open)
int not_supported_flag = 0; int not_supported_flag = 0;
// check Not supported // check Not supported
if(pid != 0) { if(cpu > 0) {
not_supported_flag = 1;
}
if(cpu != -1) {
not_supported_flag = 1; not_supported_flag = 1;
} }
if(flags > 0) { if(flags > 0) {
@@ -2873,15 +3010,19 @@ SYSCALL_DECLARE(perf_event_open)
event = kmalloc(sizeof(struct mc_perf_event), IHK_MC_AP_NOWAIT); event = kmalloc(sizeof(struct mc_perf_event), IHK_MC_AP_NOWAIT);
if(!event) if(!event)
return -ENOMEM; return -ENOMEM;
event->cpu_id = thread->cpu_id;
event->attr = (struct perf_event_attr)*attr; event->attr = (struct perf_event_attr)*attr;
event->sample_freq = attr->sample_freq; event->sample_freq = attr->sample_freq;
event->nr_siblings = 0; event->nr_siblings = 0;
event->count = 0;
event->child_count_total = 0;
event->parent = NULL;
event->pid = pid;
INIT_LIST_HEAD(&event->group_entry); INIT_LIST_HEAD(&event->group_entry);
INIT_LIST_HEAD(&event->sibling_list); INIT_LIST_HEAD(&event->sibling_list);
if(group_fd == -1) { if(group_fd == -1) {
event->group_leader = event; event->group_leader = event;
event->pmc_status = 0x0UL;
} else { } else {
for(cfd = proc->mckfd; cfd; cfd = cfd->next) { for(cfd = proc->mckfd; cfd; cfd = cfd->next) {
if(cfd->fd == group_fd) { if(cfd->fd == group_fd) {
@@ -2893,9 +3034,9 @@ SYSCALL_DECLARE(perf_event_open)
} }
} }
if(perf_counter_init(event) < 0) if(perf_counter_alloc(event) < 0)
return -1; return -1;
if(event->counter < 0) if(event->counter_id < 0)
return -1; return -1;
request.number = __NR_perf_event_open; request.number = __NR_perf_event_open;
@@ -4226,6 +4367,7 @@ SYSCALL_DECLARE(exit)
return 0; return 0;
} }
thread->status = PS_EXITED; thread->status = PS_EXITED;
sync_child_event(thread->proc->monitoring_event);
mcs_rwlock_reader_unlock(&proc->threads_lock, &lock); mcs_rwlock_reader_unlock(&proc->threads_lock, &lock);
release_thread(thread); release_thread(thread);

View File

@@ -58,8 +58,7 @@ int ihk_mc_perfctr_set(int counter, unsigned long value);
int ihk_mc_perfctr_read_mask(unsigned long counter_mask, unsigned long *value); int ihk_mc_perfctr_read_mask(unsigned long counter_mask, unsigned long *value);
unsigned long ihk_mc_perfctr_read(int counter); unsigned long ihk_mc_perfctr_read(int counter);
unsigned long ihk_mc_perfctr_read_msr(int counter); unsigned long ihk_mc_perfctr_read_msr(int counter);
int ihk_mc_perfctr_alloc_counter(); int ihk_mc_perfctr_alloc_counter(unsigned long pmc_status);
void ihk_mc_perfctr_release_counter(int counter);
#endif #endif

View File

@@ -214,16 +214,20 @@ struct perf_event_attr {
#endif #endif
}; };
struct mc_perf_event { struct mc_perf_event {
struct perf_event_attr attr; struct perf_event_attr attr;
int cpu_id; int cpu_id;
int counter; int counter_id; // counter_id
unsigned long count; // counter_value
unsigned long child_count_total; // child_counter_value
unsigned long pmc_status;
unsigned long sample_freq; unsigned long sample_freq;
struct mc_perf_event *parent;
struct mc_perf_event *group_leader; struct mc_perf_event *group_leader;
struct list_head sibling_list; struct list_head sibling_list;
int nr_siblings; int nr_siblings;
int pid;
struct list_head group_entry; struct list_head group_entry;
}; };