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

📄 perfmon.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef PFM_PMU_USES_DBR/* * Only call this function when a process it trying to * write the debug registers (reading is always allowed) */intpfm_use_debug_registers(struct task_struct *task){	pfm_context_t *ctx = task->thread.pfm_context;	int ret = 0;	DBprintk(("called for [%d]\n", task->pid));	/*	 * do it only once	 */	if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0;	/*	 * Even on SMP, we do not need to use an atomic here because	 * the only way in is via ptrace() and this is possible only when the	 * process is stopped. Even in the case where the ctxsw out is not totally	 * completed by the time we come here, there is no way the 'stopped' process	 * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine.	 * So this is always safe.	 */	if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1;	LOCK_PFS();	/*	 * We cannot allow setting breakpoints when system wide monitoring	 * sessions are using the debug registers.	 */	if (pfm_sessions.pfs_sys_use_dbregs> 0)		ret = -1;	else		pfm_sessions.pfs_ptrace_use_dbregs++;	DBprintk(("ptrace_use_dbregs=%u  sys_use_dbregs=%u by [%d] ret = %d\n", 		  pfm_sessions.pfs_ptrace_use_dbregs, 		  pfm_sessions.pfs_sys_use_dbregs, 		  task->pid, ret));	UNLOCK_PFS();	return ret;}/* * This function is called for every task that exits with the * IA64_THREAD_DBG_VALID set. This indicates a task which was * able to use the debug registers for debugging purposes via * ptrace(). Therefore we know it was not using them for * perfmormance monitoring, so we only decrement the number * of "ptraced" debug register users to keep the count up to date */intpfm_release_debug_registers(struct task_struct *task){	int ret;	LOCK_PFS();	if (pfm_sessions.pfs_ptrace_use_dbregs == 0) {		printk(KERN_DEBUG "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n",		       task->pid);		ret = -1;	}  else {		pfm_sessions.pfs_ptrace_use_dbregs--;		ret = 0;	}	UNLOCK_PFS();	return ret;}#else /* PFM_PMU_USES_DBR is true *//* * in case, the PMU does not use the debug registers, these two functions are nops. * The first function is called from arch/ia64/kernel/ptrace.c. * The second function is called from arch/ia64/kernel/process.c. */intpfm_use_debug_registers(struct task_struct *task){	return 0;}intpfm_release_debug_registers(struct task_struct *task){	return 0;}#endif /* PFM_PMU_USES_DBR */static intpfm_restart(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 	 struct pt_regs *regs){	void *sem = &ctx->ctx_restart_sem;	/* 	 * Cannot do anything before PMU is enabled 	 */	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;	if (task == current) {		DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", 			task->pid, 			ctx->ctx_fl_frozen,			ctx->ctx_ovfl_regs[0]));		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);		ctx->ctx_ovfl_regs[0] = 0UL;		/*		 * We ignore block/don't block because we never block		 * for a self-monitoring process.		 */		ctx->ctx_fl_frozen = 0;		if (CTX_HAS_SMPL(ctx)) {			ctx->ctx_psb->psb_hdr->hdr_count = 0;			ctx->ctx_psb->psb_index = 0;		}		/* simply unfreeze */		pfm_unfreeze_pmu();		return 0;	} 	/* restart on another task */	/*	 * if blocking, then post the semaphore.	 * if non-blocking, then we ensure that the task will go into	 * pfm_overflow_must_block() before returning to user mode. 	 * We cannot explicitely reset another task, it MUST always	 * be done by the task itself. This works for system wide because	 * the tool that is controlling the session is doing "self-monitoring".	 *	 * XXX: what if the task never goes back to user?	 *	 */	if (CTX_OVFL_NOBLOCK(ctx) == 0) {		DBprintk(("unblocking %d \n", task->pid));		up(sem);	} else {		task->thread.pfm_ovfl_block_reset = 1;	}#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 */		pfm_clear_psr_pp();		ia64_srlz_i();		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);		ia64_psr(regs)->pp = 0;	} else {		/* stop monitoring */		pfm_clear_psr_up();		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){	/*	 * 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	 */	if (ctx->ctx_fl_unsecure == 0) ia64_psr(regs)->sp = 1;	DBprintk(("[%d] protected psr.sp=%d\n", task->pid, ia64_psr(regs)->sp));	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(KERN_INFO "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		 */

⌨️ 快捷键说明

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