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

📄 perfmon.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * This file implements the perfmon subsystem which is used * to program the IA-64 Performance Monitoring Unit (PMU). * * Originaly Written by Ganesh Venkitachalam, IBM Corp. * Copyright (C) 1999 Ganesh Venkitachalam <venkitac@us.ibm.com> * * Modifications by Stephane Eranian, Hewlett-Packard Co. * Modifications by David Mosberger-Tang, Hewlett-Packard Co. * * Copyright (C) 1999-2002  Hewlett Packard Co *               Stephane Eranian <eranian@hpl.hp.com> *               David Mosberger-Tang <davidm@hpl.hp.com> */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/smp_lock.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/vmalloc.h>#include <linux/wrapper.h>#include <linux/mm.h>#include <linux/sysctl.h>#include <asm/bitops.h>#include <asm/errno.h>#include <asm/page.h>#include <asm/perfmon.h>#include <asm/processor.h>#include <asm/signal.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/delay.h> /* for ia64_get_itc() */#ifdef CONFIG_PERFMON/* * For PMUs which rely on the debug registers for some features, you must * you must enable the following flag to activate the support for * accessing the registers via the perfmonctl() interface. */#if defined(CONFIG_ITANIUM) || defined(CONFIG_MCKINLEY)#define PFM_PMU_USES_DBR	1#endif/* * perfmon context states */#define PFM_CTX_DISABLED	0#define PFM_CTX_ENABLED		1/* * Reset register flags */#define PFM_PMD_LONG_RESET	1#define PFM_PMD_SHORT_RESET	2/* * Misc macros and definitions */#define PMU_FIRST_COUNTER	4#define PMU_MAX_PMCS		256#define PMU_MAX_PMDS		256/* * type of a PMU register (bitmask). * bitmask structure: * 	bit0   : register implemented * 	bit1   : end marker  * 	bit2-3 : reserved * 	bit4-7 : register type * 	bit8-31: reserved */#define PFM_REG_IMPL		0x1 /* register implemented */#define PFM_REG_END		0x2 /* end marker */#define PFM_REG_MONITOR		(0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */#define PFM_REG_COUNTING	(0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */#define PFM_REG_CONTROL		(0x3<<4|PFM_REG_IMPL) /* PMU control register */#define	PFM_REG_CONFIG		(0x4<<4|PFM_REG_IMPL) /* refine configuration */#define PFM_REG_BUFFER	 	(0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */#define PMC_IS_LAST(i)	(pmu_conf.pmc_desc[i].type & PFM_REG_END)#define PMD_IS_LAST(i)	(pmu_conf.pmd_desc[i].type & PFM_REG_END)#define PFM_IS_DISABLED() pmu_conf.disabled#define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)#define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)/* i assume unsigned */#define PMC_IS_IMPL(i)	  (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL))#define PMD_IS_IMPL(i)	  (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL))/* XXX: these three assume that register i is implemented */#define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)#define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)#define PMC_IS_MONITOR(i)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)#define PMC_DFL_VAL(i)     pmu_conf.pmc_desc[i].default_value#define PMC_RSVD_MASK(i)   pmu_conf.pmc_desc[i].reserved_mask#define PMD_PMD_DEP(i)	   pmu_conf.pmd_desc[i].dep_pmd[0]#define PMC_PMD_DEP(i)	   pmu_conf.pmc_desc[i].dep_pmd[0]/* k assume unsigned */#define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)#define DBR_IS_IMPL(k)	  (k<pmu_conf.num_dbrs)#define CTX_IS_ENABLED(c) 	((c)->ctx_flags.state == PFM_CTX_ENABLED)#define CTX_OVFL_NOBLOCK(c)	((c)->ctx_fl_block == 0)#define CTX_INHERIT_MODE(c)	((c)->ctx_fl_inherit)#define CTX_HAS_SMPL(c)		((c)->ctx_psb != NULL)/* XXX: does not support more than 64 PMDs */#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask)#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL)#define CTX_USED_IBR(ctx,n) 	(ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64)#define CTX_USED_DBR(ctx,n) 	(ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64)#define CTX_USES_DBREGS(ctx)	(((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1)#define LOCK_CTX(ctx)	spin_lock(&(ctx)->ctx_lock)#define UNLOCK_CTX(ctx)	spin_unlock(&(ctx)->ctx_lock)#define SET_PMU_OWNER(t)    do { pmu_owners[smp_processor_id()].owner = (t); } while(0)#define PMU_OWNER()	    pmu_owners[smp_processor_id()].owner#define LOCK_PFS()	    spin_lock(&pfm_sessions.pfs_lock)#define UNLOCK_PFS()	    spin_unlock(&pfm_sessions.pfs_lock)#define PFM_REG_RETFLAG_SET(flags, val)	do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0)#ifdef CONFIG_SMP#define cpu_is_online(i) (cpu_online_map & (1UL << i))#else#define cpu_is_online(i)        (i==0)#endif/* * debugging */#define DBprintk(a) \	do { \		if (pfm_sysctl.debug >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \	} while (0)#define DBprintk_ovfl(a) \	do { \		if (pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \	} while (0)/*  * Architected PMC structure */typedef struct {	unsigned long pmc_plm:4;	/* privilege level mask */	unsigned long pmc_ev:1;		/* external visibility */	unsigned long pmc_oi:1;		/* overflow interrupt */	unsigned long pmc_pm:1;		/* privileged monitor */	unsigned long pmc_ig1:1;	/* reserved */	unsigned long pmc_es:8;		/* event select */	unsigned long pmc_ig2:48;	/* reserved */} pfm_monitor_t;/* * There is one such data structure per perfmon context. It is used to describe the * sampling buffer. It is to be shared among siblings whereas the pfm_context  * is not. * Therefore we maintain a refcnt which is incremented on fork(). * This buffer is private to the kernel only the actual sampling buffer  * including its header are exposed to the user. This construct allows us to  * export the buffer read-write, if needed, without worrying about security  * problems. */typedef struct _pfm_smpl_buffer_desc {	spinlock_t		psb_lock;	/* protection lock */	unsigned long		psb_refcnt;	/* how many users for the buffer */	int			psb_flags;	/* bitvector of flags (not yet used) */	void			*psb_addr;	/* points to location of first entry */	unsigned long		psb_entries;	/* maximum number of entries */	unsigned long		psb_size;	/* aligned size of buffer */	unsigned long		psb_index;	/* next free entry slot XXX: must use the one in buffer */	unsigned long		psb_entry_size;	/* size of each entry including entry header */	perfmon_smpl_hdr_t	*psb_hdr;	/* points to sampling buffer header */	struct _pfm_smpl_buffer_desc *psb_next;	/* next psb, used for rvfreeing of psb_hdr */} pfm_smpl_buffer_desc_t;/* * psb_flags */#define PSB_HAS_VMA	0x1		/* a virtual mapping for the buffer exists */#define LOCK_PSB(p)	spin_lock(&(p)->psb_lock)#define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)/* * 64-bit software counter structure */typedef struct {	u64 val;	/* virtual 64bit counter value */	u64 lval;	/* last value */	u64 long_reset;	/* reset value on sampling overflow */	u64 short_reset;/* reset value on overflow */	u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */	u64 seed;	/* seed for random-number generator */	u64 mask;	/* mask for random-number generator */	unsigned int flags; /* notify/do not notify */} pfm_counter_t;/* * perfmon context. One per process, is cloned on fork() depending on  * inheritance flags */typedef struct {	unsigned int state:1;		/* 0=disabled, 1=enabled */	unsigned int inherit:2;		/* inherit mode */	unsigned int block:1;		/* when 1, task will blocked on user notifications */	unsigned int system:1;		/* do system wide monitoring */	unsigned int frozen:1;		/* pmu must be kept frozen on ctxsw in */	unsigned int protected:1;	/* allow access to creator of context only */	unsigned int using_dbreg:1;	/* using range restrictions (debug registers) */	unsigned int reserved:24;} pfm_context_flags_t;/* * perfmon context: encapsulates all the state of a monitoring session * XXX: probably need to change layout */typedef struct pfm_context {	pfm_smpl_buffer_desc_t	*ctx_psb;		/* sampling buffer, if any */	unsigned long		ctx_smpl_vaddr;		/* user level virtual address of smpl buffer */	spinlock_t		ctx_lock;	pfm_context_flags_t	ctx_flags;		/* block/noblock */	struct task_struct	*ctx_notify_task;	/* who to notify on overflow */	struct task_struct	*ctx_owner;		/* pid of creator (debug) */	unsigned long		ctx_ovfl_regs[4];	/* which registers overflowed (notification) */	unsigned long		ctx_smpl_regs[4];	/* which registers to record on overflow */	struct semaphore	ctx_restart_sem;   	/* use for blocking notification mode */	unsigned long		ctx_used_pmds[4];	/* bitmask of PMD used                 */	unsigned long		ctx_reload_pmds[4];	/* bitmask of PMD to reload on ctxsw   */	unsigned long		ctx_used_pmcs[4];	/* bitmask PMC used by context         */	unsigned long		ctx_reload_pmcs[4];	/* bitmask of PMC to reload on ctxsw   */	unsigned long		ctx_used_ibrs[4];	/* bitmask of used IBR (speedup ctxsw) */	unsigned long		ctx_used_dbrs[4];	/* bitmask of used DBR (speedup ctxsw) */	pfm_counter_t		ctx_soft_pmds[IA64_NUM_PMD_REGS]; /* XXX: size should be dynamic */	u64			ctx_saved_psr;		/* copy of psr used for lazy ctxsw */	unsigned long		ctx_saved_cpus_allowed;	/* copy of the task cpus_allowed (system wide) */	unsigned long		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */	atomic_t		ctx_saving_in_progress;	/* flag indicating actual save in progress */	atomic_t		ctx_is_busy;		/* context accessed by overflow handler */	atomic_t		ctx_last_cpu;		/* CPU id of current or last CPU used */} pfm_context_t;#define ctx_fl_inherit		ctx_flags.inherit#define ctx_fl_block		ctx_flags.block#define ctx_fl_system		ctx_flags.system#define ctx_fl_frozen		ctx_flags.frozen#define ctx_fl_protected	ctx_flags.protected#define ctx_fl_using_dbreg	ctx_flags.using_dbreg/* * global information about all sessions * mostly used to synchronize between system wide and per-process */typedef struct {	spinlock_t		pfs_lock;		   /* lock the structure */	unsigned int 		pfs_task_sessions;	   /* number of per task sessions */	unsigned int		pfs_sys_sessions;	   /* number of per system wide sessions */	unsigned int		pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */	unsigned int		pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */} pfm_session_t;/* * information about a PMC or PMD. * dep_pmd[]: a bitmask of dependent PMD registers  * dep_pmc[]: a bitmask of dependent PMC registers */typedef struct {	unsigned int		type;	int			pm_pos;	unsigned long		default_value;	/* power-on default value */	unsigned long		reserved_mask;	/* bitmask of reserved bits */	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);	unsigned long		dep_pmd[4];	unsigned long		dep_pmc[4];} pfm_reg_desc_t;/* assume cnum is a valid monitor */#define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)#define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)#define PMD_WR_FUNC(cnum)	(pmu_conf.pmd_desc[cnum].write_check)#define PMD_RD_FUNC(cnum)	(pmu_conf.pmd_desc[cnum].read_check)/* * This structure is initialized at boot time and contains * a description of the PMU main characteristics. */typedef struct {	unsigned int  disabled;		/* indicates if perfmon is working properly */	unsigned long ovfl_val;		/* overflow value for generic counters   */	unsigned long impl_pmcs[4];	/* bitmask of implemented PMCS */	unsigned long impl_pmds[4];	/* bitmask of implemented PMDS */	unsigned int  num_pmcs;		/* number of implemented PMCS */	unsigned int  num_pmds;		/* number of implemented PMDS */	unsigned int  num_ibrs;		/* number of implemented IBRS */	unsigned int  num_dbrs;		/* number of implemented DBRS */	unsigned int  num_counters;	/* number of PMD/PMC counters */	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register dependencies descriptions */	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register dependencies descriptions */} pmu_config_t;/* * structure used to pass argument to/from remote CPU  * using IPI to check and possibly save the PMU context on SMP systems. * * not used in UP kernels */typedef struct {	struct task_struct *task;	/* which task we are interested in */	int retval;			/* return value of the call: 0=you can proceed, 1=need to wait for completion */} pfm_smp_ipi_arg_t;/* * perfmon command descriptions */typedef struct {	int		(*cmd_func)(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);	int		cmd_flags;	unsigned int	cmd_narg;	size_t		cmd_argsize;} pfm_cmd_desc_t;#define PFM_CMD_PID		0x1	/* command requires pid argument */#define PFM_CMD_ARG_READ	0x2	/* command must read argument(s) */#define PFM_CMD_ARG_RW		0x4	/* command must read/write argument(s) */#define PFM_CMD_CTX		0x8	/* command needs a perfmon context */#define PFM_CMD_NOCHK		0x10	/* command does not need to check task's state */#define PFM_CMD_IDX(cmd)	(cmd)#define PFM_CMD_IS_VALID(cmd)	((PFM_CMD_IDX(cmd) >= 0) && (PFM_CMD_IDX(cmd) < PFM_CMD_COUNT) \				  && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL)#define PFM_CMD_USE_PID(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0)#define PFM_CMD_READ_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0)#define PFM_CMD_RW_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0)#define PFM_CMD_USE_CTX(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0)#define PFM_CMD_CHK(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0)#define PFM_CMD_ARG_MANY	-1 /* cannot be zero */#define PFM_CMD_NARG(cmd)	(pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg)#define PFM_CMD_ARG_SIZE(cmd)	(pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize)typedef struct {	int	debug;		/* turn on/off debugging via syslog */	int	debug_ovfl;	/* turn on/off debug printk in overflow handler */	int	fastctxsw;	/* turn on/off fast (unsecure) ctxsw */} pfm_sysctl_t;typedef struct {	unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */	unsigned long pfm_recorded_samples_count;	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;} pfm_stats_t;/* * perfmon internal variables */static pfm_session_t	pfm_sessions;	/* global sessions information */static struct proc_dir_entry *perfmon_dir; /* for debug only */static pfm_stats_t	pfm_stats[NR_CPUS];static pfm_intr_handler_desc_t	*pfm_alternate_intr_handler;/* sysctl() controls */static pfm_sysctl_t pfm_sysctl;static ctl_table pfm_ctl_table[]={	{1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},	{2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},	{3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,},	{ 0, },};static ctl_table pfm_sysctl_dir[] = {	{1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, 	{0,},};static ctl_table pfm_sysctl_root[] = {	{1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, 	{0,},};static struct ctl_table_header *pfm_sysctl_header;static void pfm_vm_close(struct vm_area_struct * area);static struct vm_operations_struct pfm_vm_ops={	close: pfm_vm_close};/* * keep track of task owning the PMU per CPU. */static struct {	struct task_struct *owner;	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;} pmu_owners[NR_CPUS];/* * forward declarations */static void pfm_reset_pmu(struct task_struct *);#ifdef CONFIG_SMPstatic void pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx);#endifstatic void pfm_lazy_save_regs (struct task_struct *ta);#if   defined(CONFIG_ITANIUM)#include "perfmon_itanium.h"#elif defined(CONFIG_MCKINLEY)#include "perfmon_mckinley.h"#else#include "perfmon_generic.h"#endifstatic inline unsigned longpfm_read_soft_counter(pfm_context_t *ctx, int i){	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val);}static inline voidpfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val){	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.ovfl_val;	/*	 * writing to unimplemented part is ignore, so we do not need to	 * mask off top part	 */	ia64_set_pmd(i, val & pmu_conf.ovfl_val);}/*

⌨️ 快捷键说明

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