📄 perfmon.c
字号:
for (i = 0; mask; i++, mask>>=1) { /* skip non used pmds */ if ((mask & 0x1) == 0) continue; if (PMD_IS_COUNTING(i)) { /* * we split the 64bit value according to * counter width */ val = ctx->ctx_pmds[i].val & ovfl_mask; ctx->ctx_pmds[i].val &= ~ovfl_mask; } else { val = ctx->ctx_pmds[i].val; } ia64_set_pmd(i, val); DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, val)); } /* * restore the PMCs */ mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { if ((mask & 0x1) == 0UL) continue; th->pmcs[i] = ctx->ctx_pmcs[i]; ia64_set_pmc(i, th->pmcs[i]); DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i])); } ia64_srlz_d(); /* * must restore DBR/IBR because could be modified while masked * XXX: need to optimize */ if (ctx->ctx_fl_using_dbreg) { pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); } /* * now restore PSR */ if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { /* enable dcr pp */ ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP); ia64_srlz_i(); } pfm_set_psr_l(psr);}static inline voidpfm_save_pmds(unsigned long *pmds, unsigned long mask){ int i; ia64_srlz_d(); for (i=0; mask; i++, mask>>=1) { if (mask & 0x1) pmds[i] = ia64_get_pmd(i); }}/* * reload from thread state (used for ctxw only) */static inline voidpfm_restore_pmds(unsigned long *pmds, unsigned long mask){ int i; unsigned long val, ovfl_val = pmu_conf->ovfl_val; for (i=0; mask; i++, mask>>=1) { if ((mask & 0x1) == 0) continue; val = PMD_IS_COUNTING(i) ? pmds[i] & ovfl_val : pmds[i]; ia64_set_pmd(i, val); } ia64_srlz_d();}/* * propagate PMD from context to thread-state */static inline voidpfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx){ struct thread_struct *thread = &task->thread; unsigned long ovfl_val = pmu_conf->ovfl_val; unsigned long mask = ctx->ctx_all_pmds[0]; unsigned long val; int i; DPRINT(("mask=0x%lx\n", mask)); for (i=0; mask; i++, mask>>=1) { val = ctx->ctx_pmds[i].val; /* * We break up the 64 bit value into 2 pieces * the lower bits go to the machine state in the * thread (will be reloaded on ctxsw in). * The upper part stays in the soft-counter. */ if (PMD_IS_COUNTING(i)) { ctx->ctx_pmds[i].val = val & ~ovfl_val; val &= ovfl_val; } thread->pmds[i] = val; DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n", i, thread->pmds[i], ctx->ctx_pmds[i].val)); }}/* * propagate PMC from context to thread-state */static inline voidpfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx){ struct thread_struct *thread = &task->thread; unsigned long mask = ctx->ctx_all_pmcs[0]; int i; DPRINT(("mask=0x%lx\n", mask)); for (i=0; mask; i++, mask>>=1) { /* masking 0 with ovfl_val yields 0 */ thread->pmcs[i] = ctx->ctx_pmcs[i]; DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i])); }}static inline voidpfm_restore_pmcs(unsigned long *pmcs, unsigned long mask){ int i; for (i=0; mask; i++, mask>>=1) { if ((mask & 0x1) == 0) continue; ia64_set_pmc(i, pmcs[i]); } ia64_srlz_d();}static inline intpfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b){ return memcmp(a, b, sizeof(pfm_uuid_t));}static inline intpfm_buf_fmt_exit(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, struct pt_regs *regs){ int ret = 0; if (fmt->fmt_exit) ret = (*fmt->fmt_exit)(task, buf, regs); return ret;}static inline intpfm_buf_fmt_getsize(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size){ int ret = 0; if (fmt->fmt_getsize) ret = (*fmt->fmt_getsize)(task, flags, cpu, arg, size); return ret;}static inline intpfm_buf_fmt_validate(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg){ int ret = 0; if (fmt->fmt_validate) ret = (*fmt->fmt_validate)(task, flags, cpu, arg); return ret;}static inline intpfm_buf_fmt_init(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg){ int ret = 0; if (fmt->fmt_init) ret = (*fmt->fmt_init)(task, buf, flags, cpu, arg); return ret;}static inline intpfm_buf_fmt_restart(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs){ int ret = 0; if (fmt->fmt_restart) ret = (*fmt->fmt_restart)(task, ctrl, buf, regs); return ret;}static inline intpfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs){ int ret = 0; if (fmt->fmt_restart_active) ret = (*fmt->fmt_restart_active)(task, ctrl, buf, regs); return ret;}static pfm_buffer_fmt_t *__pfm_find_buffer_fmt(pfm_uuid_t uuid){ struct list_head * pos; pfm_buffer_fmt_t * entry; list_for_each(pos, &pfm_buffer_fmt_list) { entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list); if (pfm_uuid_cmp(uuid, entry->fmt_uuid) == 0) return entry; } return NULL;} /* * find a buffer format based on its uuid */static pfm_buffer_fmt_t *pfm_find_buffer_fmt(pfm_uuid_t uuid){ pfm_buffer_fmt_t * fmt; spin_lock(&pfm_buffer_fmt_lock); fmt = __pfm_find_buffer_fmt(uuid); spin_unlock(&pfm_buffer_fmt_lock); return fmt;} intpfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt){ int ret = 0; /* some sanity checks */ if (fmt == NULL || fmt->fmt_name == NULL) return -EINVAL; /* we need at least a handler */ if (fmt->fmt_handler == NULL) return -EINVAL; /* * XXX: need check validity of fmt_arg_size */ spin_lock(&pfm_buffer_fmt_lock); if (__pfm_find_buffer_fmt(fmt->fmt_uuid)) { printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name); ret = -EBUSY; goto out; } list_add(&fmt->fmt_list, &pfm_buffer_fmt_list); printk(KERN_INFO "perfmon: added sampling format %s\n", fmt->fmt_name);out: spin_unlock(&pfm_buffer_fmt_lock); return ret;}EXPORT_SYMBOL(pfm_register_buffer_fmt);intpfm_unregister_buffer_fmt(pfm_uuid_t uuid){ pfm_buffer_fmt_t *fmt; int ret = 0; spin_lock(&pfm_buffer_fmt_lock); fmt = __pfm_find_buffer_fmt(uuid); if (!fmt) { printk(KERN_ERR "perfmon: cannot unregister format, not found\n"); ret = -EINVAL; goto out; } list_del_init(&fmt->fmt_list); printk(KERN_INFO "perfmon: removed sampling format: %s\n", fmt->fmt_name);out: spin_unlock(&pfm_buffer_fmt_lock); return ret;}EXPORT_SYMBOL(pfm_unregister_buffer_fmt);static intpfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu){ unsigned long flags; /* * validy checks on cpu_mask have been done upstream */ LOCK_PFS(flags); DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", pfm_sessions.pfs_sys_sessions, pfm_sessions.pfs_task_sessions, pfm_sessions.pfs_sys_use_dbregs, is_syswide, cpu)); if (is_syswide) { /* * cannot mix system wide and per-task sessions */ if (pfm_sessions.pfs_task_sessions > 0UL) { DPRINT(("system wide not possible, %u conflicting task_sessions\n", pfm_sessions.pfs_task_sessions)); goto abort; } if (pfm_sessions.pfs_sys_session[cpu]) goto error_conflict; DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id())); pfm_sessions.pfs_sys_session[cpu] = task; pfm_sessions.pfs_sys_sessions++ ; } else { if (pfm_sessions.pfs_sys_sessions) goto abort; pfm_sessions.pfs_task_sessions++; } DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", pfm_sessions.pfs_sys_sessions, pfm_sessions.pfs_task_sessions, pfm_sessions.pfs_sys_use_dbregs, is_syswide, cpu)); UNLOCK_PFS(flags); return 0;error_conflict: DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", pfm_sessions.pfs_sys_session[cpu]->pid, smp_processor_id()));abort: UNLOCK_PFS(flags); return -EBUSY;}static intpfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu){ unsigned long flags; /* * validy checks on cpu_mask have been done upstream */ LOCK_PFS(flags); DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", pfm_sessions.pfs_sys_sessions, pfm_sessions.pfs_task_sessions, pfm_sessions.pfs_sys_use_dbregs, is_syswide, cpu)); if (is_syswide) { pfm_sessions.pfs_sys_session[cpu] = NULL; /* * would not work with perfmon+more than one bit in cpu_mask */ if (ctx && ctx->ctx_fl_using_dbreg) { if (pfm_sessions.pfs_sys_use_dbregs == 0) { printk(KERN_ERR "perfmon: invalid release for ctx %p sys_use_dbregs=0\n", ctx); } else { pfm_sessions.pfs_sys_use_dbregs--; } } pfm_sessions.pfs_sys_sessions--; } else { pfm_sessions.pfs_task_sessions--; } DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", pfm_sessions.pfs_sys_sessions, pfm_sessions.pfs_task_sessions, pfm_sessions.pfs_sys_use_dbregs, is_syswide, cpu)); UNLOCK_PFS(flags); return 0;}/* * removes virtual mapping of the sampling buffer. * IMPORTANT: cannot be called with interrupts disable, e.g. inside * a PROTECT_CTX() section. */static intpfm_remove_smpl_mapping(struct task_struct *task, void *vaddr, unsigned long size){ int r; /* sanity checks */ if (task->mm == NULL || size == 0UL || vaddr == NULL) { printk(KERN_ERR "perfmon: pfm_remove_smpl_mapping [%d] invalid context mm=%p\n", task->pid, task->mm); return -EINVAL; } DPRINT(("smpl_vaddr=%p size=%lu\n", vaddr, size)); /* * does the actual unmapping */ down_write(&task->mm->mmap_sem); DPRINT(("down_write done smpl_vaddr=%p size=%lu\n", vaddr, size)); r = pfm_do_munmap(task->mm, (unsigned long)vaddr, size, 0); up_write(&task->mm->mmap_sem); if (r !=0) { printk(KERN_ERR "perfmon: [%d] unable to unmap sampling buffer @%p size=%lu\n", task->pid, vaddr, size); } DPRINT(("do_unmap(%p, %lu)=%d\n", vaddr, size, r)); return 0;}/* * free actual physical storage used by sampling buffer */#if 0static intpfm_free_smpl_buffer(pfm_context_t *ctx){ pfm_buffer_fmt_t *fmt; if (ctx->ctx_smpl_hdr == NULL) goto invalid_free; /* * we won't use the buffer format anymore */ fmt = ctx->ctx_buf_fmt; DPRINT(("sampling buffer @%p size %lu vaddr=%p\n", ctx->ctx_smpl_hdr, ctx->ctx_smpl_size, ctx->ctx_smpl_vaddr)); pfm_buf_fmt_exit(fmt, current, NULL, NULL); /* * free the buffer */ pfm_rvfree(ctx->ctx_smpl_hdr, ctx->ctx_smpl_size); ctx->ctx_smpl_hdr = NULL; ctx->ctx_smpl_size = 0UL; return 0;invalid_free: printk(KERN_ERR "perfmon: pfm_free_smpl_buffer [%d] no buffer\n", current->pid); return -EINVAL;}#endifstatic inline voidpfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt){ if (fmt == NULL) return; pfm_buf_fmt_exit(fmt, current, NULL, NULL);}/* * pfmfs should _never_ be mounted by userland - too much of security hassle, * no real gain from having the whole whorehouse mounted. So we don't need * any operations on the root directory. However, we need a non-trivial * d_name - pfm: will go nicely and kill the special-casing in procfs. */static struct vfsmount *pfmfs_mnt;static int __initinit_pfm_fs(void){ int err = register_filesystem(&pfm_fs_type); if (!err) { pfmfs_mnt = kern_mount(&pfm_fs_type); err = PTR_ERR(pfmfs_mnt); if (IS_ERR(pfmfs_mnt)) unregister_filesystem(&pfm_fs_type); else err = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -