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

📄 perfmon.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/*	 * we have to set this here event hough we haven't necessarily started monitoring	 * because we may be context switched out	 */	if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID;	return 0;}static intpfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count){	struct thread_struct *th = &ta->thread;	pfm_context_t *ctx = th->pfm_context;	unsigned long val=0;	perfmon_req_t tmp;	int i;	/*	 * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING	 * This is required when the monitoring has been stoppped by user of kernel.	 * If ity is still going on, then that's fine because we a re not gauranteed	 * to return an accurate value in this case	 */	/* XXX: ctx locking may be required here */	for (i = 0; i < count; i++, req++) {		unsigned long reg_val = ~0, ctx_val = ~0;		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;		if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL;		if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) {			if (ta == current){				val = ia64_get_pmd(tmp.pfr_reg.reg_num);			} else {				val = reg_val = th->pmd[tmp.pfr_reg.reg_num];			}			val &= pmu_conf.perf_ovfl_val;			/*			 * lower part of .val may not be zero, so we must be an addition because of			 * residual count (see update_counters).			 */			val += ctx_val = ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val;		} else {			/* for now */			if (ta != current) return -EINVAL;			ia64_srlz_d();			val = ia64_get_pmd(tmp.pfr_reg.reg_num);		}		tmp.pfr_reg.reg_value = val;		DBprintk((" reading PMD[%ld]=0x%lx reg=0x%lx ctx_val=0x%lx pmc=0x%lx\n", 					tmp.pfr_reg.reg_num, val, reg_val, ctx_val, ia64_get_pmc(tmp.pfr_reg.reg_num)));		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;	}	return 0;}static intpfm_do_restart(struct task_struct *task){	struct thread_struct *th = &task->thread;	pfm_context_t *ctx = th->pfm_context;	void *sem = &ctx->ctx_restart_sem;	if (task == current) {		DBprintk((" restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));		pfm_reset_regs(ctx);		/*		 * 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_smpl_buf->psb_hdr->hdr_count = 0;			ctx->ctx_smpl_buf->psb_index = 0;		}		/* pfm_reset_smpl_buffers(ctx,th->pfm_ovfl_regs);*/		/* simply unfreeze */		ia64_set_pmc(0, 0);		ia64_srlz_d();		return 0;	}	/* check if blocking */	if (CTX_OVFL_NOBLOCK(ctx) == 0) {		DBprintk((" unblocking %d \n", task->pid));		up(sem);		return 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_smpl_buf->psb_hdr->hdr_count = 0;		ctx->ctx_smpl_buf->psb_index = 0;	}	return 0;}/* * system-wide mode: propagate activation/desactivation throughout the tasklist * * XXX: does not work for SMP, of course */static voidpfm_process_tasklist(int cmd){	struct task_struct *p;	struct pt_regs *regs;	for_each_task(p) {		regs = (struct pt_regs *)((unsigned long)p + IA64_STK_OFFSET);		regs--;		ia64_psr(regs)->pp = cmd;	}}static intdo_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs){	perfmon_req_t tmp;	struct thread_struct *th = &task->thread;	pfm_context_t *ctx = th->pfm_context;	memset(&tmp, 0, sizeof(tmp));	if (ctx == NULL && cmd != PFM_CREATE_CONTEXT && cmd < PFM_DEBUG_BASE) {		DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid));		return -EINVAL;	}	switch (cmd) {		case PFM_CREATE_CONTEXT:			/* a context has already been defined */			if (ctx) return -EBUSY;			/*			 * cannot directly create a context in another process			 */			if (task != current) return -EINVAL;			if (req == NULL || count != 1) return -EINVAL;			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;			return pfm_context_create(flags, req);		case PFM_WRITE_PMCS:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;			return pfm_write_pmcs(task, req, count);		case PFM_WRITE_PMDS:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;			return pfm_write_pmds(task, req, count);		case PFM_START:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			if (PMU_OWNER()  && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER());			SET_PMU_OWNER(current);			/* will start monitoring right after rfi */			ia64_psr(regs)->up = 1;			ia64_psr(regs)->pp = 1;			if (ctx->ctx_fl_system) {				pfm_process_tasklist(1);				pfs_info.pfs_pp = 1;			}			/*			 * mark the state as valid.			 * this will trigger save/restore at context switch			 */			if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID;			ia64_set_pmc(0, 0);			ia64_srlz_d();			break;		case PFM_ENABLE:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			if (PMU_OWNER()  && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER());			/* reset all registers to stable quiet state */			ia64_reset_pmu();			/* make sure nothing starts */			ia64_psr(regs)->up = 0;			ia64_psr(regs)->pp = 0;			/* do it on the live register as well */			__asm__ __volatile__ ("rsm psr.pp|psr.pp;;"::: "memory");			SET_PMU_OWNER(current);			/*			 * mark the state as valid.			 * this will trigger save/restore at context switch			 */			if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID;			/* simply unfreeze */			ia64_set_pmc(0, 0);			ia64_srlz_d();			break;		case PFM_DISABLE:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			/* simply freeze */			ia64_set_pmc(0, 1);			ia64_srlz_d();			/*			 * XXX: cannot really toggle IA64_THREAD_PM_VALID			 * but context is still considered valid, so any 			 * read request would return something valid. Same			 * thing when this task terminates (pfm_flush_regs()).			 */			break;		case PFM_READ_PMDS:			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;			if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;			return pfm_read_pmds(task, req, count);	      case PFM_STOP:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			/* simply stop monitors, not PMU */			ia64_psr(regs)->up = 0;			ia64_psr(regs)->pp = 0;			if (ctx->ctx_fl_system) {				pfm_process_tasklist(0);				pfs_info.pfs_pp = 0;			}			break;	      case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */			if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system==0) {				printk(" PFM_RESTART not monitoring\n");				return -EINVAL;			}			if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) {				printk("task %d without pmu_frozen set\n", task->pid);				return -EINVAL;			}			return pfm_do_restart(task); /* we only look at first entry */	      case PFM_DESTROY_CONTEXT:			/* we don't quite support this right now */			if (task != current) return -EINVAL;			/* first stop monitors */			ia64_psr(regs)->up = 0;			ia64_psr(regs)->pp = 0;			/* then freeze PMU */			ia64_set_pmc(0, 1);			ia64_srlz_d();			/* don't save/restore on context switch */			if (ctx->ctx_fl_system ==0) task->thread.flags &= ~IA64_THREAD_PM_VALID;			SET_PMU_OWNER(NULL);			/* now free context and related state */			pfm_context_exit(task);			break;	      case PFM_DEBUG_ON:			printk("perfmon debugging on\n");			pfm_debug = 1;			break;	      case PFM_DEBUG_OFF:			printk("perfmon debugging off\n");			pfm_debug = 0;			break;	      default:			DBprintk((" UNknown command 0x%x\n", cmd));			return -EINVAL;	}	return 0;}/* * XXX: do something better here */static intperfmon_bad_permissions(struct task_struct *task){	/* stolen from bad_signal() */	return (current->session != task->session)	    && (current->euid ^ task->suid) && (current->euid ^ task->uid)	    && (current->uid ^ task->suid) && (current->uid ^ task->uid);}asmlinkage intsys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack){	struct pt_regs *regs = (struct pt_regs *) &stack;	struct task_struct *child = current;	int ret = -ESRCH;	/* sanity check:	 *	 * ensures that we don't do bad things in case the OS	 * does not have enough storage to save/restore PMC/PMD	 */	if (PERFMON_IS_DISABLED()) return -ENOSYS;	/* XXX: pid interface is going away in favor of pfm context */	if (pid != current->pid) {		read_lock(&tasklist_lock);		child = find_task_by_pid(pid);		if (!child) goto abort_call;		ret = -EPERM;		if (perfmon_bad_permissions(child)) goto abort_call;		/*		 * XXX: need to do more checking here		 */		if (child->state != TASK_ZOMBIE && child->state != TASK_STOPPED) {			DBprintk((" warning process %d not in stable state %ld\n", pid, child->state));		}	}	ret = do_perfmonctl(child, cmd, flags, req, count, regs);abort_call:	if (child != current) read_unlock(&tasklist_lock);	return ret;}#if __GNUC__ >= 3void asmlinkagepfm_block_on_overflow(void)#elsevoid asmlinkagepfm_block_on_overflow(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7)#endif{	struct thread_struct *th = &current->thread;	pfm_context_t *ctx = current->thread.pfm_context;	int ret;	/*	 * NO matter what notify_pid is,	 * we clear overflow, won't notify again	 */	th->pfm_must_block = 0;	/*	 * do some sanity checks first	 */	if (!ctx) {		printk("perfmon: process %d has no PFM context\n", current->pid);		return;	}	if (ctx->ctx_notify_task == 0) {		printk("perfmon: process %d has no task to notify\n", current->pid);		return;	}	DBprintk((" current=%d task=%d\n", current->pid, ctx->ctx_notify_task->pid));	/* should not happen */	if (CTX_OVFL_NOBLOCK(ctx)) {		printk("perfmon: process %d non-blocking ctx should not be here\n", current->pid);		return;	}	DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid));	/*	 * may go through without blocking on SMP systems	 * if restart has been received already by the time we call down()	 */	ret = down_interruptible(&ctx->ctx_restart_sem);	DBprintk((" CPU%d %d after sleep ret=%d\n", smp_processor_id(), current->pid, ret));	/*	 * in case of interruption of down() we don't restart anything	 */	if (ret >= 0) {		/* we reactivate on context switch */		ctx->ctx_fl_frozen = 0;		/*		 * the ovfl_sem is cleared by the restart task and this is safe because we always		 * use the local reference		 */		pfm_reset_regs(ctx);		/*		 * Unlock sampling buffer and reset index atomically		 * XXX: not really needed when blocking		 */		if (CTX_HAS_SMPL(ctx)) {			ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0;			ctx->ctx_smpl_buf->psb_index = 0;		}		DBprintk((" CPU%d %d unfreeze PMU\n", smp_processor_id(), current->pid));		ia64_set_pmc(0, 0);		ia64_srlz_d();		/* state restored, can go back to work (user mode) */	}}/* * main overflow processing routine. * it can be called from the interrupt path or explicitely during the context switch code * Return:

⌨️ 快捷键说明

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