📄 perfmon.c
字号:
#if 0 /* * in case of non blocking mode, then it's just a matter of * of reseting the sampling buffer (if any) index. The PMU * is already active. */ /* * must reset the header count first */ if (CTX_HAS_SMPL(ctx)) { DBprintk(("resetting sampling indexes for %d \n", task->pid)); ctx->ctx_psb->psb_hdr->hdr_count = 0; ctx->ctx_psb->psb_index = 0; }#endif return 0;}static intpfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ /* we don't quite support this right now */ if (task != current) return -EINVAL; /* * Cannot do anything before PMU is enabled */ if (!CTX_IS_ENABLED(ctx)) return -EINVAL; DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", current->pid, ctx->ctx_fl_system, PMU_OWNER(), current)); /* simply stop monitoring but not the PMU */ if (ctx->ctx_fl_system) { /* disable dcr pp */ ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); /* stop monitoring */ __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); ia64_srlz_i(); local_cpu_data->pfm_dcr_pp = 0; ia64_psr(regs)->pp = 0; } else { /* stop monitoring */ __asm__ __volatile__ ("rum psr.up;;"::: "memory"); ia64_srlz_i(); /* * clear user level psr.up */ ia64_psr(regs)->up = 0; } return 0;}static intpfm_disable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ /* we don't quite support this right now */ if (task != current) return -EINVAL; if (!CTX_IS_ENABLED(ctx)) return -EINVAL; /* * stop monitoring, freeze PMU, and save state in context * this call will clear IA64_THREAD_PM_VALID for per-task sessions. */ pfm_flush_regs(task); if (ctx->ctx_fl_system) { ia64_psr(regs)->pp = 0; } else { ia64_psr(regs)->up = 0; } /* * goes back to default behavior: no user level control * no need to change live psr.sp because useless at the kernel level */ ia64_psr(regs)->sp = 1; DBprintk(("enabling psr.sp for [%d]\n", current->pid)); ctx->ctx_flags.state = PFM_CTX_DISABLED; return 0;}static intpfm_context_destroy(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ /* we don't quite support this right now */ if (task != current) return -EINVAL; /* * if context was never enabled, then there is not much * to do */ if (!CTX_IS_ENABLED(ctx)) goto skipped_stop; /* * Disable context: stop monitoring, flush regs to software state (useless here), * and freeze PMU * * The IA64_THREAD_PM_VALID is cleared by pfm_flush_regs() called from pfm_disable() */ pfm_disable(task, ctx, arg, count, regs); if (ctx->ctx_fl_system) { ia64_psr(regs)->pp = 0; } else { ia64_psr(regs)->up = 0; }skipped_stop: /* * remove sampling buffer mapping, if any */ if (ctx->ctx_smpl_vaddr) { pfm_remove_smpl_mapping(task); ctx->ctx_smpl_vaddr = 0UL; } /* now free context and related state */ pfm_context_exit(task); return 0;}/* * does nothing at the moment */static intpfm_context_unprotect(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ return 0;}static intpfm_protect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ DBprintk(("context from [%d] is protected\n", task->pid)); /* * from now on, only the creator of the context has access to it */ ctx->ctx_fl_protected = 1; /* * reinforce secure monitoring: cannot toggle psr.up */ ia64_psr(regs)->sp = 1; return 0;}static intpfm_debug(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ unsigned int mode = *(unsigned int *)arg; pfm_sysctl.debug = mode == 0 ? 0 : 1; printk("perfmon debugging %s\n", pfm_sysctl.debug ? "on" : "off"); return 0;}#ifdef PFM_PMU_USES_DBRtypedef struct { unsigned long ibr_mask:56; unsigned long ibr_plm:4; unsigned long ibr_ig:3; unsigned long ibr_x:1;} ibr_mask_reg_t;typedef struct { unsigned long dbr_mask:56; unsigned long dbr_plm:4; unsigned long dbr_ig:2; unsigned long dbr_w:1; unsigned long dbr_r:1;} dbr_mask_reg_t;typedef union { unsigned long val; ibr_mask_reg_t ibr; dbr_mask_reg_t dbr;} dbreg_t;static intpfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs){ struct thread_struct *thread = &task->thread; pfm_context_t *ctx = task->thread.pfm_context; pfarg_dbreg_t tmp, *req = (pfarg_dbreg_t *)arg; dbreg_t dbreg; unsigned int rnum; int first_time; int i, ret = 0; /* * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w * ensuring that no real breakpoint can be installed via this call. */ first_time = ctx->ctx_fl_using_dbreg == 0; /* * check for debug registers in system wide mode * */ LOCK_PFS(); if (ctx->ctx_fl_system && first_time) { if (pfm_sessions.pfs_ptrace_use_dbregs) ret = -EBUSY; else pfm_sessions.pfs_sys_use_dbregs++; } UNLOCK_PFS(); if (ret != 0) return ret; if (ctx->ctx_fl_system) { /* we mark ourselves as owner of the debug registers */ ctx->ctx_fl_using_dbreg = 1; DBprintk(("system-wide setting fl_using_dbreg for [%d]\n", task->pid)); } else if (first_time) { ret= -EBUSY; if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) { DBprintk(("debug registers already in use for [%d]\n", task->pid)); goto abort_mission; } /* we mark ourselves as owner of the debug registers */ ctx->ctx_fl_using_dbreg = 1; DBprintk(("setting fl_using_dbreg for [%d]\n", task->pid)); /* * Given debug registers cannot be used for both debugging * and performance monitoring at the same time, we reuse * the storage area to save and restore the registers on ctxsw. */ memset(task->thread.dbr, 0, sizeof(task->thread.dbr)); memset(task->thread.ibr, 0, sizeof(task->thread.ibr)); } if (first_time) { DBprintk(("[%d] clearing ibrs,dbrs\n", task->pid)); /* * clear hardware registers to make sure we don't * pick up stale state. * * for a system wide session, we do not use * thread.dbr, thread.ibr because this process * never leaves the current CPU and the state * is shared by all processes running on it */ for (i=0; i < pmu_conf.num_ibrs; i++) { ia64_set_ibr(i, 0UL); } ia64_srlz_i(); for (i=0; i < pmu_conf.num_dbrs; i++) { ia64_set_dbr(i, 0UL); } ia64_srlz_d(); } ret = -EFAULT; /* * Now install the values into the registers */ for (i = 0; i < count; i++, req++) { if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission; rnum = tmp.dbreg_num; dbreg.val = tmp.dbreg_value; ret = -EINVAL; if ((mode == 0 && !IBR_IS_IMPL(rnum)) || ((mode == 1) && !DBR_IS_IMPL(rnum))) { DBprintk(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", rnum, dbreg.val, mode, i, count)); goto abort_mission; } /* * make sure we do not install enabled breakpoint */ if (rnum & 0x1) { if (mode == 0) dbreg.ibr.ibr_x = 0; else dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; } /* * clear return flags and copy back to user * * XXX: fix once EAGAIN is implemented */ ret = -EFAULT; PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0); if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission; /* * Debug registers, just like PMC, can only be modified * by a kernel call. Moreover, perfmon() access to those * registers are centralized in this routine. The hardware * does not modify the value of these registers, therefore, * if we save them as they are written, we can avoid having * to save them on context switch out. This is made possible * by the fact that when perfmon uses debug registers, ptrace() * won't be able to modify them concurrently. */ if (mode == 0) { CTX_USED_IBR(ctx, rnum); ia64_set_ibr(rnum, dbreg.val); ia64_srlz_i(); thread->ibr[rnum] = dbreg.val; DBprintk(("write ibr%u=0x%lx used_ibrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_ibrs[0])); } else { CTX_USED_DBR(ctx, rnum); ia64_set_dbr(rnum, dbreg.val); ia64_srlz_d(); thread->dbr[rnum] = dbreg.val; DBprintk(("write dbr%u=0x%lx used_dbrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_dbrs[0])); } } return 0;abort_mission: /* * in case it was our first attempt, we undo the global modifications */ if (first_time) { LOCK_PFS(); if (ctx->ctx_fl_system) { pfm_sessions.pfs_sys_use_dbregs--; } UNLOCK_PFS(); ctx->ctx_fl_using_dbreg = 0; } /* * install error return flag */ if (ret != -EFAULT) { /* * XXX: for now we can only come here on EINVAL */ PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL); if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT; } return ret;}static intpfm_write_ibrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ /* we don't quite support this right now */ if (task != current) return -EINVAL; if (!CTX_IS_ENABLED(ctx)) return -EINVAL; return pfm_write_ibr_dbr(0, task, arg, count, regs);}static intpfm_write_dbrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ /* we don't quite support this right now */ if (task != current) return -EINVAL; if (!CTX_IS_ENABLED(ctx)) return -EINVAL; return pfm_write_ibr_dbr(1, task, arg, count, regs);}#endif /* PFM_PMU_USES_DBR */static intpfm_get_features(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ pfarg_features_t tmp; memset(&tmp, 0, sizeof(tmp)); tmp.ft_version = PFM_VERSION; tmp.ft_smpl_version = PFM_SMPL_VERSION; if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT; return 0;}static intpfm_start(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){ /* we don't quite support this right now */ if (task != current) return -EINVAL; /* * Cannot do anything before PMU is enabled */ if (!CTX_IS_ENABLED(ctx)) return -EINVAL; DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", current->pid, ctx->ctx_fl_system, PMU_OWNER(), current)); if (PMU_OWNER() != task) { printk("perfmon: pfm_start task [%d] not pmu owner\n", task->pid); return -EINVAL; } if (ctx->ctx_fl_system) { local_cpu_data->pfm_dcr_pp = 1; /* set user level psr.pp */ ia64_psr(regs)->pp = 1; /* start monitoring at kernel level */ __asm__ __volatile__ ("ssm psr.pp;;"::: "memory"); /* enable dcr pp */ ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); ia64_srlz_i(); } else { if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) { printk("perfmon: pfm_start task flag not set for [%d]\n", task->pid
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -