From 130b1f43276f37d0cab1e69661adad2dfb990669 Mon Sep 17 00:00:00 2001 From: Ken Sato Date: Tue, 26 Apr 2016 19:01:47 +0900 Subject: [PATCH] update PAPI support. other process and child process monitoring. --- arch/x86/kernel/cpu.c | 12 ++ arch/x86/kernel/perfctr.c | 22 +-- kernel/include/process.h | 8 + kernel/process.c | 12 ++ kernel/syscall.c | 282 +++++++++++++++++++++++++++--------- lib/include/ihk/perfctr.h | 3 +- lib/include/mc_perf_event.h | 8 +- 7 files changed, 259 insertions(+), 88 deletions(-) diff --git a/arch/x86/kernel/cpu.c b/arch/x86/kernel/cpu.c index 9f8cb0d0..edc389f0 100644 --- a/arch/x86/kernel/cpu.c +++ b/arch/x86/kernel/cpu.c @@ -33,6 +33,7 @@ #define LAPIC_ID 0x020 #define LAPIC_TIMER 0x320 +#define LAPIC_LVTPC 0x340 #define LAPIC_TIMER_INITIAL 0x380 #define LAPIC_TIMER_CURRENT 0x390 #define LAPIC_TIMER_DIVIDE 0x3e0 @@ -42,6 +43,7 @@ #define LAPIC_ICR2 0x310 #define LAPIC_ESR 0x280 #define LOCAL_TIMER_VECTOR 0xef +#define LOCAL_PERF_VECTOR 0xf0 #define APIC_INT_LEVELTRIG 0x08000 #define APIC_INT_ASSERT 0x04000 @@ -420,6 +422,7 @@ init_lapic() } lapic_write(LAPIC_SPURIOUS, 0x1ff); + lapic_write(LAPIC_LVTPC, LOCAL_PERF_VECTOR); } 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); 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 && vector < IHK_TLB_FLUSH_IRQ_VECTOR_END) { diff --git a/arch/x86/kernel/perfctr.c b/arch/x86/kernel/perfctr.c index 188bb942..e587a449 100644 --- a/arch/x86/kernel/perfctr.c +++ b/arch/x86/kernel/perfctr.c @@ -14,18 +14,24 @@ #include extern unsigned int *x86_march_perfmap; -static unsigned long pmc_status = 0x0; #define X86_CR4_PCE 0x00000100 void x86_init_perfctr(void) { unsigned long reg; + unsigned long value = 0; /* Allow PMC to be read from user space */ asm volatile("movq %%cr4, %0" : "=r"(reg)); reg |= X86_CR4_PCE; 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) @@ -287,7 +293,7 @@ unsigned long ihk_mc_perfctr_read_msr(int counter) return retval; } -int ihk_mc_perfctr_alloc_counter() +int ihk_mc_perfctr_alloc_counter(unsigned long pmc_status) { int i = 0; int ret = -1; @@ -307,15 +313,3 @@ int ihk_mc_perfctr_alloc_counter() 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); -} - diff --git a/kernel/include/process.h b/kernel/include/process.h index 7b775b83..b00a742a 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -447,6 +447,14 @@ struct process { long maxrss; 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); diff --git a/kernel/process.c b/kernel/process.c index 13b43cdd..8a783a97 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -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 void procfs_create_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; 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); waitq_init(&proc->waitpid_q); ihk_atomic_set(&proc->refcount, 2); + proc->monitoring_event = NULL; } void @@ -2627,6 +2630,15 @@ redo: /* Set up new TLS.. */ 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) { last = ihk_mc_switch_context(&prev->ctx, &next->ctx, prev); } diff --git a/kernel/syscall.c b/kernel/syscall.c index 23820637..2db813e2 100644 --- a/kernel/syscall.c +++ b/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 long arch_ptrace(long request, int pid, long addr, long data); 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, struct program_load_desc *pn, @@ -604,6 +605,9 @@ terminate(int rc, int sig) int *ids = NULL; struct syscall_request request IHK_DMA_ALIGN; + // sync perf info + if(proc->monitoring_event) + sync_child_event(proc->monitoring_event); // clean up threads mcs_rwlock_reader_lock(&proc->threads_lock, &lock); // conflict clone 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) { int cpuid; + struct thread *old = cpu_local_var(current); + struct process *oldproc = old->proc; + struct process *newproc; struct thread *new; struct syscall_request request1 IHK_DMA_ALIGN; int ptrace_event = 0; @@ -1832,7 +1839,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, return -EAGAIN; } - new = clone_thread(cpu_local_var(current), curpc, + new = clone_thread(old, curpc, newsp ? newsp : cursp, clone_flags); if (!new) { @@ -1840,6 +1847,8 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, return -ENOMEM; } + newproc = new->proc; + cpu_set(cpuid, &new->vm->address_space->cpu_set, &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.args[0] = 0; 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; } - new->proc->pid = do_syscall(&request1, ihk_mc_get_processor_id(), 0); - if (new->proc->pid == -1) { + newproc->pid = do_syscall(&request1, ihk_mc_get_processor_id(), 0); + if (newproc->pid == -1) { kprintf("ERROR: forking host process\n"); /* TODO: clean-up new */ @@ -1876,7 +1885,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, new->vm->region.user_start; /* 3rd parameter denotes new rpgtable of host process */ 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", 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)) { 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) { @@ -1922,8 +1935,7 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, new->tlsblock_base = tlsblock_base; } else { - new->tlsblock_base = - cpu_local_var(current)->tlsblock_base; + new->tlsblock_base = old->tlsblock_base; } 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; chain_thread(new); if (!(clone_flags & CLONE_VM)) { - new->proc->status = PS_RUNNING; + newproc->status = PS_RUNNING; if(clone_flags & CLONE_PARENT){ struct mcs_rwlock_node_irqsave lock; - struct process *proc = cpu_local_var(current)->proc; struct process *parent; struct mcs_rwlock_node parent_lock; - mcs_rwlock_reader_lock(&proc->update_lock, &lock); - parent = proc->ppid_parent; + mcs_rwlock_reader_lock(&oldproc->update_lock, &lock); + parent = oldproc->ppid_parent; mcs_rwlock_reader_lock_noirq(&parent->update_lock, &parent_lock); if(parent->status == PS_EXITED || parent->status == PS_ZOMBIE){ mcs_rwlock_reader_unlock_noirq(&parent->update_lock, &parent_lock); parent = cpu_local_var(resource_set)->pid1; mcs_rwlock_reader_lock_noirq(&parent->update_lock, &parent_lock); } - new->proc->parent = parent; - new->proc->ppid_parent = parent; - new->proc->nowait = 1; - chain_process(new->proc); + newproc->parent = parent; + newproc->ppid_parent = parent; + newproc->nowait = 1; + chain_process(newproc); 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 - chain_process(new->proc); + chain_process(newproc); } - if (cpu_local_var(current)->proc->ptrace) { - ptrace_event = ptrace_check_clone_event(cpu_local_var(current), clone_flags); + if (oldproc->ptrace) { + ptrace_event = ptrace_check_clone_event(old, clone_flags); 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", - cpuid, new->proc->pid, - cpu_local_var(current)->tid, + cpuid, newproc->pid, + old->tid, new->tid); runq_add_thread(new, cpuid); @@ -2604,7 +2615,38 @@ SYSCALL_DECLARE(signalfd4) } 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; enum ihk_perfctr_type type; @@ -2631,48 +2673,74 @@ perf_counter_init(struct mc_perf_event *event) type = PERFCTR_MAX_TYPE; } - event->counter = ihk_mc_perfctr_alloc_counter(); - ret = ihk_mc_perfctr_init(event->counter, type, mode); + ret = ihk_mc_perfctr_init(event->counter_id, 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) { // PAPI_REF_CYC counted by fixed counter - if((attr->config & 0x0000ffff) == 0x00000300) { - event->counter = 2 + X86_IA32_BASE_FIXED_PERF_COUNTERS; - ret = ihk_mc_perfctr_fixed_init(event->counter, mode); + if(event->counter_id >= X86_IA32_BASE_FIXED_PERF_COUNTERS) { + ret = ihk_mc_perfctr_fixed_init(event->counter_id, mode); + ihk_mc_perfctr_set(event->counter_id, event->sample_freq * -1); + ihk_mc_perfctr_start(1UL << event->counter_id); return ret; } - // apply MODE to config(event_code) - attr->config &= ~(3 << 16); - if(mode & PERFCTR_USER_MODE) { - 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); + ret = ihk_mc_perfctr_init_raw(event->counter_id, attr->config, mode); + ihk_mc_perfctr_set(event->counter_id, event->sample_freq * -1); + ihk_mc_perfctr_start(1UL << event->counter_id); } else { // Not supported type. ret = -1; } - if(ret >= 0) { - ret = ihk_mc_perfctr_reset(event->counter); - } - return ret; } unsigned long perf_event_read_value(struct mc_perf_event *event) { - unsigned long total = 0; - int counter = event->counter; + unsigned long rtn_count = 0; + 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 @@ -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) { - int counter = event->counter; + int counter_id; + struct mc_perf_event *leader = event->group_leader, *sub; - if((1UL << counter & X86_IA32_PERF_COUNTERS_MASK) | - (1UL << counter & X86_IA32_FIXED_PERF_COUNTERS_MASK)) { - ihk_mc_perfctr_start(1UL << counter); + counter_id = leader->counter_id; + if((1UL << counter_id & X86_IA32_PERF_COUNTERS_MASK) | + (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 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) | - (1UL << counter & X86_IA32_FIXED_PERF_COUNTERS_MASK)) { - ihk_mc_perfctr_stop(1UL << counter); + 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_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); 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) { 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; 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; 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; 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; default : 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; - ihk_mc_perfctr_release_counter(event->counter); kfree(event); return 0; @@ -2827,7 +2968,6 @@ perf_mmap(struct mckfd *sfd, ihk_mc_user_context_t *ctx) return rc; } -extern unsigned long ihk_mc_perfctr_get_info(); SYSCALL_DECLARE(perf_event_open) { struct syscall_request request IHK_DMA_ALIGN; @@ -2846,10 +2986,7 @@ SYSCALL_DECLARE(perf_event_open) int not_supported_flag = 0; // check Not supported - if(pid != 0) { - not_supported_flag = 1; - } - if(cpu != -1) { + if(cpu > 0) { not_supported_flag = 1; } if(flags > 0) { @@ -2873,15 +3010,19 @@ SYSCALL_DECLARE(perf_event_open) event = kmalloc(sizeof(struct mc_perf_event), IHK_MC_AP_NOWAIT); if(!event) return -ENOMEM; - event->cpu_id = thread->cpu_id; event->attr = (struct perf_event_attr)*attr; event->sample_freq = attr->sample_freq; 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->sibling_list); if(group_fd == -1) { event->group_leader = event; + event->pmc_status = 0x0UL; } else { for(cfd = proc->mckfd; cfd; cfd = cfd->next) { 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; - if(event->counter < 0) + if(event->counter_id < 0) return -1; request.number = __NR_perf_event_open; @@ -4226,6 +4367,7 @@ SYSCALL_DECLARE(exit) return 0; } thread->status = PS_EXITED; + sync_child_event(thread->proc->monitoring_event); mcs_rwlock_reader_unlock(&proc->threads_lock, &lock); release_thread(thread); diff --git a/lib/include/ihk/perfctr.h b/lib/include/ihk/perfctr.h index e432413d..82221038 100644 --- a/lib/include/ihk/perfctr.h +++ b/lib/include/ihk/perfctr.h @@ -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); unsigned long ihk_mc_perfctr_read(int counter); unsigned long ihk_mc_perfctr_read_msr(int counter); -int ihk_mc_perfctr_alloc_counter(); -void ihk_mc_perfctr_release_counter(int counter); +int ihk_mc_perfctr_alloc_counter(unsigned long pmc_status); #endif diff --git a/lib/include/mc_perf_event.h b/lib/include/mc_perf_event.h index 670fe081..8cdacde1 100644 --- a/lib/include/mc_perf_event.h +++ b/lib/include/mc_perf_event.h @@ -214,16 +214,20 @@ struct perf_event_attr { #endif }; - struct mc_perf_event { struct perf_event_attr attr; 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; + struct mc_perf_event *parent; struct mc_perf_event *group_leader; struct list_head sibling_list; int nr_siblings; + int pid; struct list_head group_entry; };