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

📄 perfmon.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Code to configure and utilize the ppc64 pmc hardware.  Generally, the * following functions are supported: *    1. Kernel profile based on decrementer ticks *    2. Kernel profile based on PMC execution cycles *    3. Trace based on arbitrary PMC counter *    4. Timeslice data capture of arbitrary collections of PMCs * * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com> */#include <asm/proc_fs.h>#include <asm/paca.h>#include <asm/iSeries/ItLpPaca.h>#include <asm/iSeries/ItLpQueue.h>#include <asm/processor.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <asm/pmc.h>#include <asm/uaccess.h>#include <asm/naca.h>#include <asm/perfmon.h>#include <asm/iSeries/HvCall.h>#include <asm/hvcall.h>extern char _stext[], _etext[], _end[];struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, 0, 0, PMC_STATE_INITIAL};int alloc_perf_buffer(int size);int free_perf_buffer(void);int clear_buffers(void);void pmc_stop(void *data);void pmc_clear(void *data);void pmc_start(void *data);void pmc_touch_bolted(void *data);void dump_pmc_struct(struct perfmon_struct *perfdata);void dump_hardware_pmc_struct(void *perfdata);int  decr_profile(void *data);int  pmc_profile(struct perfmon_struct *perfdata);int  pmc_set_general(struct perfmon_struct *perfdata);int  pmc_set_user_general(struct perfmon_struct *perfdata);void pmc_configure(void *data);int pmc_timeslice_enable(struct perfmon_struct *perfdata);int pmc_timeslice_disable(struct perfmon_struct *perfdata);int pmc_timeslice_set(struct perfmon_struct *perfdata);void pmc_dump_timeslice(struct perfmon_struct *perfdata);void pmc_trace_rec_type(unsigned long type);void pmc_timeslice_data_collect(void *data);int pmc_timeslice_tick(void);int perfmon_buffer_ctl(void *data);int perfmon_dump_ctl(void *data);int perfmon_profile_ctl(void *data);int perfmon_trace_ctl(void *data);int perfmon_timeslice_ctl(void *data);#define PMC_MAX_CPUS     48#define PMC_MAX_COUNTERS 8#define PMC_SLICES_STAR  64#define PMC_SLICES_GP    28#define PMC_SLICES_MAX   64#define PMC_TICK_FACTOR  10int pmc_timeslice_enabled = 0, pmc_timeslice_top = 0;int pmc_tick_count[PMC_MAX_CPUS], pmc_timeslice[PMC_MAX_CPUS];unsigned long pmc_timeslice_data[PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS];/* * DRENG: todo: * add api to add config entries (entry, values), and bump pmc_timeslice_top *   value * add api to get data from kernel (entry, values) */unsigned long pmc_timeslice_config[PMC_SLICES_MAX * 5];static spinlock_t pmc_lock = SPIN_LOCK_UNLOCKED;asmlinkage intsys_perfmonctl (int cmd, void *data) { 	struct perfmon_struct *pdata;	int err;	printk("sys_perfmonctl: cmd = 0x%x\n", cmd); 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));	switch(cmd) {	case PMC_CMD_BUFFER:		perfmon_buffer_ctl(data); 		break;	case PMC_CMD_DUMP:		perfmon_dump_ctl(data); 		break;	case PMC_CMD_DECR_PROFILE: /* NIA time sampling */		decr_profile(data); 		break;	case PMC_CMD_PROFILE:		perfmon_profile_ctl(pdata); 		break;	case PMC_CMD_TRACE:		perfmon_trace_ctl(pdata); 		break;	case PMC_CMD_TIMESLICE:		perfmon_timeslice_ctl(pdata); 		break;#if 0	case PMC_OP_TIMESLICE:		pmc_enable_timeslice(pdata); 		break;	case PMC_OP_DUMP_TIMESLICE:		pmc_dump_timeslice(pdata); 		smp_call_function(pmc_dump_timeslice, (void *)pdata, 0, 1);		break;#endif	default:		printk("Perfmon: Unknown command\n");		break;	}	kfree(pdata); 	return 0;}int perfmon_buffer_ctl(void *data) {	struct perfmon_struct *pdata;	int err;	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));	switch(pdata->header.subcmd) {	case PMC_SUBCMD_BUFFER_ALLOC:		alloc_perf_buffer(0); 		break;	case PMC_SUBCMD_BUFFER_FREE:		free_perf_buffer(); 		break;	case PMC_SUBCMD_BUFFER_CLEAR:		clear_buffers();		break;	default:		return(-1); 	}	return(0); }int alloc_perf_buffer(int size) {	int i;	printk("Perfmon: allocate buffer\n");	if(perfmon_base.state == PMC_STATE_INITIAL) {		perfmon_base.profile_length = (((unsigned long) &_etext - 				   (unsigned long) &_stext) >> 2) * sizeof(int);		perfmon_base.profile_buffer = (unsigned long)btmalloc(perfmon_base.profile_length);		perfmon_base.trace_length = 1024*1024*16;		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);		perfmon_base.timeslice_length = PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS;		perfmon_base.timeslice_buffer = (unsigned long)pmc_timeslice_data;		if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {			memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);			printk("Profile buffer created at address 0x%lx of length 0x%lx\n",			       perfmon_base.profile_buffer, perfmon_base.profile_length); 		} else {			printk("Profile buffer creation failed\n");			return 0;		}		/* Fault in the first bolted segment - it then remains in the stab for all time */		pmc_touch_bolted(NULL); 		smp_call_function(pmc_touch_bolted, (void *)NULL, 0, 1);		for (i=0; i<MAX_PACAS; ++i) {			paca[i].prof_shift = 2;			paca[i].prof_len = perfmon_base.profile_length;			paca[i].prof_buffer = (unsigned *)(perfmon_base.profile_buffer);			paca[i].prof_stext = (unsigned *)&_stext;			paca[i].prof_etext = (unsigned *)&_etext;			mb();		} 		perfmon_base.state = PMC_STATE_READY; 	}	return 0;}int free_perf_buffer() {	printk("Perfmon: free buffer\n");	if(perfmon_base.state == PMC_STATE_INITIAL) {		printk("Perfmon: free buffer failed - no buffer was allocated.\n"); 		return -1;	}	btfree((void *)perfmon_base.profile_buffer); 	btfree((void *)perfmon_base.trace_buffer); 	perfmon_base.profile_length = 0;	perfmon_base.profile_buffer = 0;	perfmon_base.trace_buffer   = 0;	perfmon_base.trace_length   = 0;	perfmon_base.trace_end      = 0;	perfmon_base.state = PMC_STATE_INITIAL; 	return(0); }int clear_buffers() {	int i, j;	if(perfmon_base.state == PMC_STATE_INITIAL) {		printk("Perfmon: clear buffer failed - no buffer was allocated.\n"); 		return -1;	}	printk("Perfmon: clear buffer\n");		/* Stop counters on all [PMC_MAX_CPUS]processors -- blocking */	pmc_stop(NULL); 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);		/* Clear the buffers */	memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);	memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);	memset((char *)perfmon_base.timeslice_buffer, 0, perfmon_base.timeslice_length);		/* Reset the trace buffer point */	perfmon_base.trace_end = 0;		for (i=0; i<MAX_PACAS; ++i) {		for(j=0; j<8; j++) {			paca[i].pmcc[j] = 0;		}	}#if 0	/* Reset the timeslice data */	for(i=0; i<(PMC_MAX_CPUS*PMC_MAX_COUNTERS*PMC_SLICES_MAX); i++) {		pmc_timeslice_data[i] = 0;	}#endif	/* Restart counters on all processors -- blocking */	pmc_start(NULL); 	smp_call_function(pmc_start, (void *)NULL, 0, 1);	return(0); }void pmc_stop(void *data) {	/* Freeze all counters, leave everything else alone */	mtspr(MMCR0, mfspr( MMCR0 ) | 0x80000000);}void pmc_clear(void *data) {	mtspr(PMC1, 0); mtspr(PMC2, 0);	mtspr(PMC3, 0); mtspr(PMC4, 0);	mtspr(PMC5, 0); mtspr(PMC6, 0);	mtspr(PMC7, 0); mtspr(PMC8, 0);	mtspr(MMCR0, 0); mtspr(MMCR1, 0); mtspr(MMCRA, 0);}void pmc_start(void *data) {	/* Free all counters, leave everything else alone */	mtspr(MMCR0, mfspr( MMCR0 ) & 0x7fffffff);}void pmc_touch_bolted(void *data) {	volatile int touch;	/* Hack to fault the buffer into the segment table */	touch = *((int *)(perfmon_base.profile_buffer));}int perfmon_dump_ctl(void *data) {	struct perfmon_struct *pdata;	int err;	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));	switch(pdata->header.subcmd) {	case PMC_SUBCMD_DUMP_COUNTERS:		dump_pmc_struct(pdata);		// copy_to_user(data, pdata, sizeof(struct perfmon_struct));		break;	case PMC_SUBCMD_DUMP_HARDWARE:		dump_hardware_pmc_struct(pdata);		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);		break;	}	return(0); }void dump_pmc_struct(struct perfmon_struct *perfdata) {	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;	if(cpu > MAX_PACAS) return;	printk("PMC Control Mode: 0x%lx\n", perfmon_base.state);	printk("PMC[1 - 2] = 0x%16.16lx 0x%16.16lx\n",	       paca[cpu].pmcc[0], paca[cpu].pmcc[1]);	printk("PMC[3 - 4] = 0x%16.16lx 0x%16.16lx\n",	       paca[cpu].pmcc[2], paca[cpu].pmcc[3]);	printk("PMC[5 - 6] = 0x%16.16lx 0x%16.16lx\n",	       paca[cpu].pmcc[4], paca[cpu].pmcc[5]);	printk("PMC[7 - 8] = 0x%16.16lx 0x%16.16lx\n",	       paca[cpu].pmcc[6], paca[cpu].pmcc[7]);	perfdata->vdata.pmc_info.mode = perfmon_base.state;	for(i = 0; i < 11; i++) 		perfdata->vdata.pmc_info.pmc_base[i]  = paca[cpu].pmc[i];	for(i = 0; i < 8; i++) 		perfdata->vdata.pmc_info.pmc_cumulative[i]  = paca[cpu].pmcc[i];}void dump_hardware_pmc_struct(void *perfdata) {	unsigned int cpu = smp_processor_id();	printk("PMC[%2.2d][1 - 4]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",	       cpu, (u32) mfspr(PMC1),(u32) mfspr(PMC2),(u32) mfspr(PMC3),(u32) mfspr(PMC4));	printk("PMC[%2.2d][5 - 8]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",	       cpu, (u32) mfspr(PMC5),(u32) mfspr(PMC6),(u32) mfspr(PMC7),(u32) mfspr(PMC8));	printk("MMCR[%2.2d][0,1,A] = 0x%8.8x 0x%8.8x 0x%8.8x\n",	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));}int decr_profile(void *data){	int i;	printk("Perfmon: NIA decrementer profile\n");	if(perfmon_base.state == PMC_STATE_INITIAL) {		printk("Perfmon: failed - no buffer was allocated.\n"); 		return -1;	}		/* Stop counters on all processors -- blocking */	pmc_stop(NULL); 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);		for (i=0; i<MAX_PACAS; ++i) {		paca[i].prof_mode = PMC_STATE_DECR_PROFILE;	}		perfmon_base.state = PMC_STATE_DECR_PROFILE; 	mb(); 	return 0;}int perfmon_profile_ctl(void *data) {	struct perfmon_struct *pdata;	int err;	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));	switch(pdata->header.subcmd) {	case PMC_SUBCMD_PROFILE_CYCLE:		pmc_profile(pdata); 		break;	default:		return(-1);	}	return(0); }int perfmon_trace_ctl(void *data) {	struct perfmon_struct *pdata;	int err;	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));	pmc_set_general(pdata); #if 0        /* Reimplement at some point ... */	pmc_set_user_general(pdata); #endif	return(0); }int perfmon_timeslice_ctl(void *data) {	struct perfmon_struct *pdata;	int err;	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));	switch(pdata->header.subcmd) {

⌨️ 快捷键说明

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