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

📄 monprof.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * monprof.c:
 * This command and support code allow the monitor to provide an application
 * with some system profiling capabilities.  The function "profiler"
 * is part of the API to allow the application to take advantage of this.
 *
 * The basic assumption is that the application has the ability to insert
 * a call to mon_profiler() in its system tick handler (actually the call
 * can be put anywhere in the application, but this is the most logical
 * place to put it).  The content of the structure passed in to
 * mon_profiler() depends on what kind of profiling the application wants
 * to do.  The tool works partially through calls made by the application
 * into the monitor's api (mon_profiler()) and partially through
 * interaction with the user at the monitor command line.  The runtime
 * profiling calls are done in application space, but the initial setup of
 * the profiling session is done at the CLI.
 * 
 * There are a few different profiling mechanisms in place...
 *
 * FUNCTION LOGGING:
 * This capability makes the same assumption regarding the symtbl file
 * as does strace... That the symbols are listed in the file in ascending
 * address order.  Ideally, the only symbols in the file would be the
 * functions, so some processing can be done on the symtbl file prior to
 * putting it on the target, this would help (not mandatory).  At the CLI,
 * the user issues the "prof finit [address]" command.  This initializes
 * a table in the monitor that contains one pdata structure for each entry
 * in the symtbl file.  The pdata structure simply contains the starting
 * address and a pass count for each entry in symtbl. After this
 * initialization, runtime profiling can start.  This is used by setting
 * the MONPROF_FUNCLOG (see monprof.h) flag in the 'type' member of the
 * monprof structure.  Upon entry into the profiler, the 'pc' member of
 * the incoming structure is assumed to contain the address that was
 * executing at the time of the interrupt.  The profiler uses a simple
 * binary search to scan through all entries in the table to find the 
 * symbol (function) that the address falls within.  When this is found,
 * that entry's pass count variable is incremented.  At some point later,
 * profiling is completed and the user can dump the results to show the 
 * user what functions were hogging the CPU during the profiling session.
 *
 *    Example setup:
 *		prof init			# Initialize internals.
 *		prof funccfg		# Configure function logging using symtbl.
 *		prof on				# Enable profiling.
 *  
 *
 * PC LOGGING:
 * This capability assumes that every instruction is the same size (typical
 * for RISC CPUs).  It uses a block of memory equal in size to the .text
 * section of the application and treats that block as a table of counters.
 * Each time the profiler is called, the PC (along with some delta) is
 * used as an offset into the table and that offset is incremented.
 * This may be used as a better alternative to the FUNCTION LOGGING
 * mechanism described above; but it does have some additional requirements,
 * (fixed-width instruction & extra ram space == .text size) so it may not
 * be an option.
 *
 *    Example setup:
 *		prof init						# Initialize internals.
 *		prof pccfg 4 0x22000 0x10000	# Configure pc logging for 32-bit
 *										# instructions. The .text space of
 *										# the application starts at 0x22000
 *										# with a size of 0x10000 bytes.
 *		prof on							# Enable profiling.
 *
 * TASK ID LOGGING:
 * Similar to function logging except that the MONPROF_TIDLOG flag is set
 * in the 'type' member, and the 'tid' member is used...
 * The user initializes with the "prof tinit {count}" command.  The count
 * is the maximum number of unique task ids expected.  The monitor builds
 * another table and as each tid comes in through mon_profiler, if this is
 * the first time mon_profiler() is being called with the specific incoming
 * tid value, then it is added to the list of pdata structures and the pass
 * count is set to 1; otherwise if it has already been logged, only the
 * pass count is incremented.
 *
 *    Example setup:
 *		prof init			# Initialize internals.
 *		prof tidcfg	16		# Configure tid logging for 16 unique tids.
 *		prof on				# Enable profiling.
 *  
 * 
 *	General notice:
 *	This code is part of a boot-monitor package developed as a generic base
 *	platform for embedded system designs.  As such, it is likely to be
 *	distributed to various projects beyond the control of the original
 *	author.  Please notify the author of any enhancements made or bugs found
 *	so that all may benefit from the changes.  In addition, notification back
 *	to the author will allow the new user to pick up changes that may have
 *	been made by other users after this version of the code was distributed.
 *
 *	Note1: the majority of this code was edited with 4-space tabs.
 *	Note2: as more and more contributions are accepted, the term "author"
 *		   is becoming a mis-representation of credit.
 *
 *	Original author:	Ed Sutter
 *	Email:				esutter@lucent.com
 *	Phone:				908-582-2351
 */
#include "config.h"
#include "monprof.h"
#if INCLUDE_PROFILER
#include "stddefs.h"
#include "genlib.h"
#include "ctype.h"
#include "cli.h"
#include "tfs.h"
#include "tfsprivate.h"

#define HALF(m)	(m >> 1)

/* pdata:
 * One of these represents each symbol (or tid) in the profiling session. 
 * For MONPROF_FUNCLOG, the data member is the starting address of the symbol
 * and for MONPROF_TIDLOG, the data member is the tid value.
 */
struct pdata {
	ulong	data;			/* Start of symbol or tid. */
	int		pcount;			/* Pass count. */
};

static int prof_Enabled;		/* If set, profiler runs; else return. */ 
static int prof_BadSymCnt;		/* Number of hits not within a symbol. */
static int prof_CallCnt;		/* Number of times profiler was called. */
static int prof_FuncTot;		/* Number of functions being profiled. */
static int prof_TidTot;			/* Number of TIDs being profiled. */
static int prof_TidTally;		/* Number of unique TIDs logged so far. */
static int prof_TidOverflow;	/* More TIDs than the table was built for. */
static int prof_PcTot;			/* Number of instructions being profiled. */
static int prof_PcDelta;		/* Delta between .text space and PC table. */
static int prof_PcWidth;		/* Width (2 or 4) of PC table elements. */
static int prof_PcOORCnt;		/* Out-of-range hit count for PC profiler */
static ulong prof_PcTxtEnd;		/* End of .text area being profiled */
static ulong prof_PcTxtBase;	/* Base of .text area being profiled */

static struct pdata *prof_FuncTbl;
static struct pdata *prof_TidTbl;
static uchar  *prof_PcTbl;
static char prof_SymFile[TFSNAMESIZE+1];

void
profiler(struct monprof *mpp)
{
	struct pdata *current, *base;
	int nmem;

	if (prof_Enabled == 0)
		return;

	if (mpp->type & MONPROF_FUNCLOG) {
		nmem = prof_FuncTot;
		base = prof_FuncTbl;
		while(nmem) {
			current = &base[HALF(nmem)];
			if (mpp->pc < current->data)
				nmem = HALF(nmem);
			else if (mpp->pc > current->data) {
				if (mpp->pc < (current+1)->data) {
					current->pcount++;
					goto tidlog;
				}
				else {
					base = current + 1;
					nmem = (HALF(nmem)) - (nmem ? 0 : 1);
				}
			}
			else {
				current->pcount++;
				goto tidlog;
			}
		}
		prof_BadSymCnt++;
	}
tidlog:
	if (mpp->type & MONPROF_TIDLOG) {
		/* First see if the tid is already in the table.  If it is,
		 * increment the pcount.  If it isn't add it to the table.
		 */
		nmem = prof_TidTally;
		base = prof_TidTbl;
		while(nmem) {
			current = &base[HALF(nmem)];
			if (mpp->tid < current->data)
				nmem = HALF(nmem);
			else if (mpp->tid > current->data) {
				base = current + 1;
				nmem = (HALF(nmem)) - (nmem ? 0 : 1);
			}
			else {
				current->pcount++;
				goto pclog;
			}
		}
		/* Since we got here, the tid must not be in the table, so
		 * do an insertion into the table.  Items are in the table in
		 * ascending order.
		 */
		if (prof_TidTally == 0) {
			prof_TidTbl->pcount = 1;
			prof_TidTbl->data = mpp->tid;
			prof_TidTally++;
		}
		else if (prof_TidTally >= prof_TidTot) {
			prof_TidOverflow++;
		}
		else {
			current = prof_TidTbl + prof_TidTally - 1;
			while(current >= prof_TidTbl) {
				if (mpp->tid > current->data) {
					current++;
					current->pcount = 1;
					current->data = mpp->tid;
					break;
				}
				else {
					*(current+1) = *current;
					if (current == prof_TidTbl) {
						current->pcount = 1;
						current->data = mpp->tid;
						break;
					}
				}
				current--;
			}
			prof_TidTally++;
		}
	}
pclog:
	if (mpp->type & MONPROF_PCLOG) {
		ulong offset;

		if ((mpp->pc > prof_PcTxtEnd) || (mpp->pc < prof_PcTxtBase)) {
			prof_PcOORCnt++;
		}
		else {
			offset = mpp->pc - prof_PcDelta;
			switch(prof_PcWidth) {
				case 2:
					(*(ushort *)offset)++;
					break;
				case 4:
					(*(ulong *)offset)++;
					break;
			}
		}
	}
	prof_CallCnt++;
	return;
}

int
prof_GetSymFile(void)
{
	int	tfd;

	if (prof_SymFile[0] == 0) {
		tfd = SymFileFd(1);
	}
	else {
		tfd = tfsopen(prof_SymFile,TFS_RDONLY,0);
		if (tfd < 0) {
			printf("%s: %s\n",prof_SymFile,(char *)tfsctrl(TFS_ERRMSG,tfd,0));
		}
	}
	return(tfd);
}

void
prof_ShowStats(int minhit, int more)
{
	int		i, tfd, linecount;
	ulong	notused;
	char	symname[64];
	struct 	pdata	*pptr;

	printf("FuncCount Cfg: tbl: 0x%08lx, size: 0x%x\n",
		(ulong)prof_FuncTbl, prof_FuncTot);
	printf("TidCount  Cfg: tbl: 0x%08lx, size: 0x%x\n",
		(ulong)prof_TidTbl, prof_TidTot);
	printf("PcCount   Cfg: tbl: 0x%08lx, size: 0x%x\n",
		(ulong)prof_PcTbl, prof_PcTot*prof_PcWidth);

	if (prof_CallCnt == 0) {
		printf("No data collected%s",
			prof_Enabled == 0 ? " (profiling disabled)\n" : "\n");
		return;
	}
	linecount = 0;
	tfd = prof_GetSymFile();
	if ((prof_FuncTbl) && (prof_FuncTot > 0)) {
		printf("\nFUNC_PROF stats:\n");
		pptr = prof_FuncTbl;
		for(i=0;i<prof_FuncTot;pptr++,i++) {
			if (pptr->pcount < minhit)
				continue;
			if ((tfd < 0) ||
				(AddrToSym(tfd,pptr->data,symname,&notused) == 0)) {
				printf(" %08lx    :  %d\n",pptr->data,pptr->pcount);
			}
			else {
				printf(" %-25s:  %d\n",symname,pptr->pcount);
			}
			if ((more) && (++linecount >= more)) {
				linecount = 0;
				if (More() == 0)
					goto showdone;
			}
		}
	}
	if ((prof_TidTbl) && (prof_TidTot > 0)) {
		printf("\nTID_PROF stats:\n");
		pptr = prof_TidTbl;
		for(i=0;i<prof_TidTot;pptr++,i++) {
			if (pptr->pcount < minhit)
				continue;
			printf(" %08lx    :  %d\n",pptr->data,pptr->pcount);
			if ((more) && (++linecount >= more)) {
				linecount = 0;
				if (More() == 0)
					goto showdone;
			}

⌨️ 快捷键说明

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