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

📄 perfmon.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		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;	/*	 * for range restriction: psr.db must be cleared or the	 * the PMU will ignore the debug registers.	 *	 * XXX: may need more in system wide mode,	 * no task can have this bit set?	 */	if (ia64_psr(regs)->db == 1) return -EINVAL;	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);		copy_to_user(req, &tmp, sizeof(tmp));	}	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) {		#ifdef CONFIG_SMP		local_cpu_data->pfm_dcr_pp  = 1;#else		pfm_tasklist_toggle_pp(1);#endif		/* 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);			return -EINVAL;		}		/* set user level psr.up */		ia64_psr(regs)->up = 1;		/* start monitoring at kernel level */		__asm__ __volatile__ ("sum psr.up;;"::: "memory");		ia64_srlz_i();	}	return 0;}static intpfm_enable(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->ctx_fl_system == 0 && PMU_OWNER()  && PMU_OWNER() != current) 		pfm_lazy_save_regs(PMU_OWNER());	/* reset all registers to stable quiet state */	ia64_reset_pmu(task);	/* make sure nothing starts */	if (ctx->ctx_fl_system) {		ia64_psr(regs)->pp = 0;		ia64_psr(regs)->up = 0; /* just to make sure! */		/* make sure monitoring is stopped */		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");		ia64_srlz_i();#ifdef CONFIG_SMP		local_cpu_data->pfm_syst_wide = 1;		local_cpu_data->pfm_dcr_pp    = 0;#endif	} else {		/*		 * needed in case the task was a passive task during		 * a system wide session and now wants to have its own		 * session		 */		ia64_psr(regs)->pp = 0; /* just to make sure! */		ia64_psr(regs)->up = 0;		/* make sure monitoring is stopped */		__asm__ __volatile__ ("rum psr.up;;"::: "memory");		ia64_srlz_i();		DBprintk(("clearing psr.sp for [%d]\n", current->pid));		/* allow user level control  */		ia64_psr(regs)->sp = 0;		/* PMU state will be saved/restored on ctxsw */		task->thread.flags |= IA64_THREAD_PM_VALID;	}	SET_PMU_OWNER(task);	ctx->ctx_flags.state = PFM_CTX_ENABLED;	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());	/* simply unfreeze */	ia64_set_pmc(0, 0);	ia64_srlz_d();	return 0;}static intpfm_get_pmc_reset(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 int cnum;	int i;	for (i = 0; i < count; i++, req++) {		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;		cnum = tmp.reg_num;		if (!PMC_IS_IMPL(cnum)) goto abort_mission;		tmp.reg_value = reset_pmcs[cnum];		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;	}	return 0;abort_mission:	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);	/* 	 * XXX: if this fails, we stick with the original failure, flag not updated!	 */	copy_to_user(req, &tmp, sizeof(tmp));	return -EINVAL;}/* * functions MUST be listed in the increasing order of their index (see permfon.h) */static pfm_cmd_desc_t pfm_cmd_tab[]={/* 0  */{ NULL, 0, 0, 0}, /* not used *//* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, /* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},/* 5  */{ pfm_start, PFM

⌨️ 快捷键说明

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