⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perfmon.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		task->cpus_allowed = tmp.ctx_cpu_mask;		task->need_resched = 1;		DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid, task->cpus_allowed));	}	return 0;buffer_error:	pfm_context_free(ctx);error:	pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask);abort:	/* make sure we don't leave anything behind */	task->thread.pfm_context = NULL;	return ret;}static inline unsigned longpfm_new_counter_value (pfm_counter_t *reg, int is_long_reset){	unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset;	unsigned long new_seed, old_seed = reg->seed, mask = reg->mask;	extern unsigned long carta_random32 (unsigned long seed);	if (reg->flags & PFM_REGFL_RANDOM) {		new_seed = carta_random32(old_seed);		val -= (old_seed & mask);	/* counter values are negative numbers! */		if ((mask >> 32) != 0)			/* construct a full 64-bit random value: */			new_seed |= carta_random32(old_seed >> 32) << 32;		reg->seed = new_seed;	}	reg->lval = val;	return val;}static voidpfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag){	unsigned long mask = ovfl_regs[0];	unsigned long reset_others = 0UL;	unsigned long val;	int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);	/*	 * now restore reset value on sampling overflowed counters	 */	mask >>= PMU_FIRST_COUNTER;	for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {		if (mask & 0x1) {			val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);			reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0];			DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid,				  is_long_reset ? "long" : "short", i, val));			/* upper part is ignored on rval */			pfm_write_soft_counter(ctx, i, val);		}	}	/*	 * Now take care of resetting the other registers	 */	for(i = 0; reset_others; i++, reset_others >>= 1) {		if ((reset_others & 0x1) == 0) continue;		val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);		if (PMD_IS_COUNTING(i)) {			pfm_write_soft_counter(ctx, i, val);		} else {			ia64_set_pmd(i, val);		}		DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid,			  is_long_reset ? "long" : "short", i, val));	}	ia64_srlz_d();}static intpfm_write_pmcs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){	struct thread_struct *th = &task->thread;	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;	unsigned long value, reset_pmds;	unsigned int cnum, reg_flags, flags;	int is_monitor, is_counting;	int i, ret = -EINVAL;#define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z))	/* we don't quite support this right now */	if (task != current) return -EINVAL;	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;	/* XXX: ctx locking may be required here */	for (i = 0; i < count; i++, req++) {		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;		cnum       = tmp.reg_num;		reg_flags  = tmp.reg_flags;		value      = tmp.reg_value;		reset_pmds = tmp.reg_reset_pmds[0];		flags      = 0;		is_counting = PMC_IS_COUNTING(cnum);		is_monitor  = PMC_IS_MONITOR(cnum);		/* 		 * we reject all non implemented PMC as well		 * as attempts to modify PMC[0-3] which are used		 * as status registers by the PMU		 */		if (!PMC_IS_IMPL(cnum) || cnum < 4) {			DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum));			goto error;		}		/*		 * If the PMC is a monitor, then if the value is not the default:		 * 	- system-wide session: PMCx.pm=1 (privileged monitor)		 * 	- per-task           : PMCx.pm=0 (user monitor)		 */		if ((is_monitor || is_counting) && value != PMC_DFL_VAL(cnum) && PFM_CHECK_PMC_PM(ctx, cnum, value)) {			DBprintk(("pmc%u pmc_pm=%ld fl_system=%d\n", 				cnum, 				PMC_PM(cnum, value), 				ctx->ctx_fl_system));			goto error;		}		if (is_counting) {			pfm_monitor_t *p = (pfm_monitor_t *)&value;			/*		 	 * enforce generation of overflow interrupt. Necessary on all		 	 * CPUs.		 	 */			p->pmc_oi = 1;			if (reg_flags & PFM_REGFL_OVFL_NOTIFY) {				/*			 	 * must have a target for the signal			 	 */				if (ctx->ctx_notify_task == NULL) {					DBprintk(("cannot set ovfl_notify: no notify_task\n"));					goto error;				}				flags |= PFM_REGFL_OVFL_NOTIFY;			}			if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM;			/* verify validity of reset_pmds */			if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) {				DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum));				goto error;			}		} else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {				DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum));				goto error;		}		/*		 * execute write checker, if any		 */		if (PMC_WR_FUNC(cnum)) {			ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs);			if (ret) goto error;			ret = -EINVAL;		}		/*		 * no error on this register		 */		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);		/*		 * update register return value, abort all if problem during copy.		 * we only modify the reg_flags field. no check mode is fine because		 * access has been verified upfront in sys_perfmonctl().		 *		 * If this fails, then the software state is not modified		 */		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;		/*		 * Now we commit the changes to the software state		 */		/* 		 * full flag update each time a register is programmed		 */		ctx->ctx_soft_pmds[cnum].flags = flags;		if (is_counting) {			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds;			/* mark all PMDS to be accessed as used */			CTX_USED_PMD(ctx, reset_pmds);		}		/*		 * Needed in case the user does not initialize the equivalent		 * PMD. Clearing is done in reset_pmu() so there is no possible		 * leak here.		 */		CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]);		/* 		 * keep copy the pmc, used for register reload		 */		th->pmc[cnum] = value;		ia64_set_pmc(cnum, value);		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 			  task->pid, cnum, value, 			  ctx->ctx_soft_pmds[cnum].flags, 			  ctx->ctx_used_pmds[0]));	}	return 0;error:	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;	DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret));	return ret;}static intpfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;	unsigned long value, hw_value;	unsigned int cnum;	int i;	int ret = -EINVAL;	/* 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;	/* XXX: ctx locking may be required here */	for (i = 0; i < count; i++, req++) {		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;		cnum  = tmp.reg_num;		value = tmp.reg_value;		if (!PMD_IS_IMPL(cnum)) {			DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum));			goto abort_mission;		}		/*		 * execute write checker, if any		 */		if (PMD_WR_FUNC(cnum)) {			unsigned long v = value;			ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs);			if (ret) goto abort_mission;			value = v;			ret = -EINVAL;		}		hw_value = value;		/*		 * no error on this register		 */		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;		/*		 * now commit changes to software state		 */		/* update virtualized (64bits) counter */		if (PMD_IS_COUNTING(cnum)) {			ctx->ctx_soft_pmds[cnum].lval = value;			ctx->ctx_soft_pmds[cnum].val  = value & ~pmu_conf.ovfl_val;			hw_value = value & pmu_conf.ovfl_val;			ctx->ctx_soft_pmds[cnum].long_reset  = tmp.reg_long_reset;			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;			ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed;			ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask;		}		/* keep track of what we use */		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);		/* mark this register as used as well */		CTX_USED_PMD(ctx, RDEP(cnum));		/* writes to unimplemented part is ignored, so this is safe */		ia64_set_pmd(cnum, hw_value);		/* to go away */		ia64_srlz_d();		DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx  short_reset=0x%lx "			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx psr=%d\n",				task->pid, cnum,				value, hw_value,				ctx->ctx_soft_pmds[cnum].val,				ctx->ctx_soft_pmds[cnum].short_reset,				ctx->ctx_soft_pmds[cnum].long_reset,				ia64_get_pmd(cnum) & pmu_conf.ovfl_val,				PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N',				ctx->ctx_used_pmds[0],				ctx->ctx_soft_pmds[cnum].reset_pmds[0], ia64_psr(regs)->sp));	}	return 0;abort_mission:	/*	 * for now, we have only one possibility for error	 */	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);	/*	 * we change the return value to EFAULT in case we cannot write register return code.	 * The caller first must correct this error, then a resubmission of the request will	 * eventually yield the EINVAL.	 */	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;	DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret));	return ret;}static intpfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs){	struct thread_struct *th = &task->thread;	unsigned long val, lval;	pfarg_reg_t *req = (pfarg_reg_t *)arg;	unsigned int cnum, reg_flags = 0;	int i, ret = 0;#if __GNUC__ < 3	int foo;#endif	if (!CTX_IS_ENABLED(ctx)) {		DBprintk(("context for [%d] is disabled\n", task->pid));		return -EINVAL;	}	/*	 * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING	 * This is required when the monitoring has been stoppped by user or kernel.	 * If it is still going on, then that's fine because we a re not guaranteed	 * to return an accurate value in this case.	 */	/* XXX: ctx locking may be required here */	/*	 * should we need to access the PMU, serialization is needed	 */	ia64_srlz_d();	for (i = 0; i < count; i++, req++) {#if __GNUC__ < 3		foo = __get_user(cnum, &req->reg_num);		if (foo) return -EFAULT;		foo = __get_user(reg_flags, &req->reg_flags);		if (foo) return -EFAULT;#else		if (__get_user(cnum, &req->reg_num)) return -EFAULT;		if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT;#endif		lval = 0UL;		if (!PMD_IS_IMPL(cnum)) goto abort_mission;		/*		 * we can only read the register that we use. That includes		 * the one we explicitely initialize AND the one we want included		 * in the sampling buffer (smpl_regs).		 *		 * Having this restriction allows optimization in the ctxsw routine		 * without compromising security (leaks)		 */		if (!CTX_IS_USED_PMD(ctx, cnum)) goto abort_mission;		/*		 * we can access the registers directly only when task		 * is the OWNER of the local PMU. In SMP, this can		 * happen only when task == current. In addition		 * this can happen when task != currrent but		 * only in UP mode.		 */		if (task == PMU_OWNER()) {			val = ia64_get_pmd(cnum);			DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val));		} else {			/* context has been saved */			val = th->pmd[cnum];		}		if (PMD_IS_COUNTING(cnum)) {			/*			 * XXX: need to check for overflow			 */			val &= pmu_conf.ovfl_val;			val += ctx->ctx_soft_pmds[cnum].val;			lval = ctx->ctx_soft_pmds[cnum].lval;		} 		/*		 * execute read checker, if any		 */		if (PMD_RD_FUNC(cnum)) {			unsigned long v = val;			ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs);			val = v;		}		PFM_REG_RETFLAG_SET(reg_flags, ret);		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 					cnum, ret, val, ia64_get_pmc(cnum)));		/*		 * update register return value, abort all if problem during copy.		 * we only modify the reg_flags field. no check mode is fine because		 * access has been verified upfront in sys_perfmonctl().		 */		if (__put_user(cnum, &req->reg_num)) return -EFAULT;		if (__put_user(val, &req->reg_value)) return -EFAULT;		if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT;		if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT;	}	return 0;abort_mission:	PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL);	/* 	 * XXX: if this fails, we stick with the original failure, flag not updated!	 */	__put_user(reg_flags, &req->reg_flags);	return -EINVAL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -