📄 dbug_ana.c
字号:
/* * Analyze the profile file (cmon.out) written out by the dbug * routines with profiling enabled. * * Copyright June 1987, Binayak Banerjee * All rights reserved. * * This program may be freely distributed under the same terms and * conditions as Fred Fish's Dbug package. * * Compile with -- cc -O -s -o %s analyze.c * * Analyze will read an trace file created by the dbug package * (when run with traceing enabled). It will then produce a * summary on standard output listing the name of each traced * function, the number of times it was called, the percentage * of total calls, the time spent executing the function, the * proportion of the total time and the 'importance'. The last * is a metric which is obtained by multiplying the proportions * of calls and the proportions of time for each function. The * greater the importance, the more likely it is that a speedup * could be obtained by reducing the time taken by that function. * * Note that the timing values that you obtain are only rough * measures. The overhead of the dbug package is included * within. However, there is no need to link in special profiled * libraries and the like. * * CHANGES: * * 2-Mar-89: fnf * Changes to support tracking of stack usage. This required * reordering the fields in the profile log file to make * parsing of different record types easier. Corresponding * changes made in dbug runtime library. Also used this * opportunity to reformat the code more to my liking (my * apologies to Binayak Banerjee for "uglifying" his code). * * 24-Jul-87: fnf * Because I tend to use functions names like * "ExternalFunctionDoingSomething", I've rearranged the * printout to put the function name last in each line, so * long names don't screw up the formatting unless they are * *very* long and wrap around the screen width... * * 24-Jul-87: fnf * Modified to put out table very similar to Unix profiler * by default, but also puts out original verbose table * if invoked with -v flag. */#include <global.h>static char *my_name;static int verbose;/* * Structure of the stack. */#define PRO_FILE "dbugmon.out" /* Default output file name */#define STACKSIZ 100 /* Maximum function nesting */#define MAXPROCS 10000 /* Maximum number of function calls */# ifdef BSD# include <sysexits.h># else# define EX_SOFTWARE 1# define EX_DATAERR 1# define EX_USAGE 1# define EX_OSERR 1# define EX_IOERR 1# define EX_OK 0# endif#define __MERF_OO_ "%s: Malloc Failed in %s: %d\n"#define MALLOC(Ptr,Num,Typ) do /* Malloc w/error checking & exit */ \ if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \ {fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\ exit(EX_OSERR);} while(0)#define Malloc(Ptr,Num,Typ) do /* Weaker version of above */\ if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \ fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\ while(0)#define FILEOPEN(Fp,Fn,Mod) do /* File open with error exit */ \ if (!(Fp = fopen(Fn,Mod)))\ {fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\ exit(EX_IOERR);} while(0)#define Fileopen(Fp,Fn,Mod) do /* Weaker version of above */ \ if(!(Fp = fopen(Fn,Mod))) \ fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\ while(0)struct stack_t { unsigned int pos; /* which function? */ unsigned long time; /* Time that this was entered */ unsigned long children; /* Time spent in called funcs */};static struct stack_t fn_stack[STACKSIZ+1];static unsigned int stacktop = 0; /* Lowest stack position is a dummy */static unsigned long tot_time = 0;static unsigned long tot_calls = 0;static unsigned long highstack = 0;static unsigned long lowstack = (ulong) ~0;/* * top() returns a pointer to the top item on the stack. * (was a function, now a macro) */#define top() &fn_stack[stacktop]/* * Push - Push the given record on the stack. */void push (name_pos, time_entered)register unsigned int name_pos;register unsigned long time_entered;{ register struct stack_t *t; DBUG_ENTER("push"); if (++stacktop > STACKSIZ) { fprintf (DBUG_FILE,"%s: stack overflow (%s:%d)\n", my_name, __FILE__, __LINE__); exit (EX_SOFTWARE); } DBUG_PRINT ("push", ("%d %ld",name_pos,time_entered)); t = &fn_stack[stacktop]; t -> pos = name_pos; t -> time = time_entered; t -> children = 0; DBUG_VOID_RETURN;}/* * Pop - pop the top item off the stack, assigning the field values * to the arguments. Returns 0 on stack underflow, or on popping first * item off stack. */unsigned int pop (name_pos, time_entered, child_time)register unsigned int *name_pos;register unsigned long *time_entered;register unsigned long *child_time;{ register struct stack_t *temp; register unsigned int rtnval; DBUG_ENTER ("pop"); if (stacktop < 1) { rtnval = 0; } else { temp = &fn_stack[stacktop]; *name_pos = temp->pos; *time_entered = temp->time; *child_time = temp->children; DBUG_PRINT ("pop", ("%d %d %d",*name_pos,*time_entered,*child_time)); rtnval = stacktop--; } DBUG_RETURN (rtnval);}/* * We keep the function info in another array (serves as a simple * symbol table) */struct module_t { char *name; unsigned long m_time; unsigned long m_calls; unsigned long m_stkuse;};static struct module_t modules[MAXPROCS];/* * We keep a binary search tree in order to look up function names * quickly (and sort them at the end. */struct bnode { unsigned int lchild; /* Index of left subtree */ unsigned int rchild; /* Index of right subtree */ unsigned int pos; /* Index of module_name entry */};static struct bnode s_table[MAXPROCS];static unsigned int n_items = 0; /* No. of items in the array so far *//* * Need a function to allocate space for a string and squirrel it away. */char *strsave (s)char *s;{ register char *retval; register unsigned int len; DBUG_ENTER ("strsave"); DBUG_PRINT ("strsave", ("%s",s)); if (!s || (len = strlen (s)) == 0) { DBUG_RETURN (0); } MALLOC (retval, ++len, char); strcpy (retval, s); DBUG_RETURN (retval);}/* * add() - adds m_name to the table (if not already there), and returns * the index of its location in the table. Checks s_table (which is a * binary search tree) to see whether or not it should be added. */unsigned int add (m_name)char *m_name;{ register unsigned int ind = 0; register int cmp; DBUG_ENTER ("add"); if (n_items == 0) { /* First item to be added */ s_table[0].pos = ind; s_table[0].lchild = s_table[0].rchild = MAXPROCS; addit: modules[n_items].name = strsave (m_name); modules[n_items].m_time = 0; modules[n_items].m_calls = 0; modules[n_items].m_stkuse = 0; DBUG_RETURN (n_items++); } while (cmp = strcmp (m_name,modules[ind].name)) { if (cmp < 0) { /* In left subtree */ if (s_table[ind].lchild == MAXPROCS) { /* Add as left child */ if (n_items >= MAXPROCS) { fprintf (DBUG_FILE, "%s: Too many functions being profiled\n", my_name); exit (EX_SOFTWARE); } s_table[n_items].pos = s_table[ind].lchild = n_items; s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;#ifdef notdef modules[n_items].name = strsave (m_name); modules[n_items].m_time = modules[n_items].m_calls = 0; DBUG_RETURN (n_items++);#else goto addit;#endif } ind = s_table[ind].lchild; /* else traverse l-tree */ } else { if (s_table[ind].rchild == MAXPROCS) { /* Add as right child */ if (n_items >= MAXPROCS) { fprintf (DBUG_FILE, "%s: Too many functions being profiled\n", my_name); exit (EX_SOFTWARE); } s_table[n_items].pos = s_table[ind].rchild = n_items; s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;#ifdef notdef modules[n_items].name = strsave (m_name); modules[n_items].m_time = modules[n_items].m_calls = 0; DBUG_RETURN (n_items++);#else goto addit;#endif } ind = s_table[ind].rchild; /* else traverse r-tree */ } } DBUG_RETURN (ind);}/* * process() - process the input file, filling in the modules table. */void process (inf)FILE *inf;{ char buf[BUFSIZ]; char fn_name[64]; /* Max length of fn_name */ unsigned long fn_time; unsigned long fn_sbot; unsigned long fn_ssz; unsigned long lastuse; unsigned int pos; unsigned long time; unsigned int oldpos; unsigned long oldtime; unsigned long oldchild; struct stack_t *t; DBUG_ENTER ("process"); while (fgets (buf,BUFSIZ,inf) != NULL) { switch (buf[0]) { case 'E': sscanf (buf+2, "%ld %64s", &fn_time, fn_name); DBUG_PRINT ("erec", ("%ld %s", fn_time, fn_name)); pos = add (fn_name); push (pos, fn_time); break; case 'X': sscanf (buf+2, "%ld %64s", &fn_time, fn_name); DBUG_PRINT ("xrec", ("%ld %s", fn_time, fn_name)); pos = add (fn_name); /* * An exited function implies that all stacked * functions are also exited, until the matching * function is found on the stack. */ while (pop (&oldpos, &oldtime, &oldchild)) { DBUG_PRINT ("popped", ("%d %d", oldtime, oldchild)); time = fn_time - oldtime; t = top (); t -> children += time; DBUG_PRINT ("update", ("%s", modules[t -> pos].name)); DBUG_PRINT ("update", ("%d", t -> children)); time -= oldchild; modules[oldpos].m_time += time; modules[oldpos].m_calls++; tot_time += time; tot_calls++; if (pos == oldpos) { goto next_line; /* Should be a break2 */ } } /* * Assume that item seen started at time 0. * (True for function main). But initialize * it so that it works the next time too. */ t = top (); time = fn_time - t -> time - t -> children; t -> time = fn_time; t -> children = 0; modules[pos].m_time += time; modules[pos].m_calls++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -