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

📄 monprof.c

📁 完整的Bell实验室的嵌入式文件系统TFS
💻 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];voidprofiler(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;}intprof_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);}voidprof_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(" %-12s:  %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 + -