update PAPI support. other process and child process monitoring.
This commit is contained in:
@@ -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) {
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
282
kernel/syscall.c
282
kernel/syscall.c
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user