Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

bprint.c

Go to the documentation of this file.
00001 #include <assert.h>
00002 #include <ctype.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <string.h>
00006 
00007 /* bprint [ -c | -Idir... | -f | -b | -n ] [ file... ]
00008  * annotate listings of files with prof.out data
00009  */
00010 
00011 
00012 #define NDIRS (sizeof dirs/sizeof dirs[0] - 1)
00013 #define NEW(p,a) ((p) = alloc(sizeof *(p)))
00014 #define newarray(m,n,a) alloc((m)*(n))
00015 #define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0])))
00016 
00017 #define MAXTOKEN 64
00018 
00019 struct count {          /* count data: */
00020     int x, y;           /* source coordinate */
00021     int count;          /* associated execution count */
00022 };
00023 
00024 char *progname;
00025 int number;
00026 char *dirs[20];
00027 int fcount;
00028 
00029 struct file {           /* per-file prof.out data: */
00030     struct file *link;      /* link to next file */
00031     char *name;         /* file name */
00032     int size;           /* size of counts[] */
00033     int count;          /* counts[0..count-1] hold valid data */
00034     struct count *counts;       /* count data */
00035     struct func {           /* function data: */
00036         struct func *link;      /* link to next function */
00037         char *name;         /* function name */
00038         struct count count;     /* total number of calls */
00039         struct caller {     /* caller data: */
00040             struct caller *link;    /* link to next caller */
00041             char *name;     /* caller's name */
00042             char *file;     /* call site: file, x, y */
00043             int x, y;
00044             int count;      /* number of calls from this site */
00045         } *callers;
00046     } *funcs;           /* list of functions */
00047 } *filelist;
00048 FILE *fp;
00049 
00050 extern int process(char *);
00051 extern int findfunc(char *, char *);
00052 extern int findcount(char *, int, int);
00053 
00054 void *alloc(unsigned);
00055 char *string(char *);
00056 int process(char *);
00057 void emitdata(char *);
00058 void printfile(struct file *, int);
00059 void printfuncs(struct file *, int);
00060 
00061 /* alloc - allocate n bytes or die */
00062 void *alloc(unsigned n) {
00063     void *new = malloc(n);
00064 
00065     assert(new);
00066     return new;
00067 }
00068 
00069 /* emitdata - write prof.out data to file */
00070 void emitdata(char *file) {
00071     FILE *fp;
00072 
00073     if (fp = fopen(file, "w")) {
00074         struct file *p;
00075         for (p = filelist; p; p = p->link) {
00076             int i;
00077             struct func *q;
00078             struct caller *r;
00079             fprintf(fp, "1\n%s\n", p->name);
00080             for (i = 0, q = p->funcs; q; i++, q = q->link)
00081                 if (r = q->callers)
00082                     for (i--; r; r = r->link)
00083                         i++;
00084             fprintf(fp, "%d\n", i);
00085             for (q = p->funcs; q; q = q->link)
00086                 if (q->count.count == 0 || !q->callers)
00087                     fprintf(fp, "%s 1 %d %d %d ? ? 0 0\n", q->name, q->count.x,
00088                         q->count.y, q->count.count);
00089                 else
00090                     for (r = q->callers; r; r = r->link)
00091                         fprintf(fp, "%s 1 %d %d %d %s %s %d %d\n", q->name, q->count.x,
00092                             q->count.y, r->count, r->name, r->file, r->x, r->y);
00093             fprintf(fp, "%d\n", p->count);
00094             for (i = 0; i < p->count; i++)
00095                 fprintf(fp, "1 %d %d %d\n", p->counts[i].x,
00096                     p->counts[i].y, p->counts[i].count);
00097         }
00098         fclose(fp);
00099     } else
00100         fprintf(stderr, "%s: can't create `%s'\n", progname, file);
00101 }
00102 
00103 /* openfile - open name for reading, searching -I directories */
00104 FILE *openfile(char *name) {
00105     int i;
00106     FILE *fp;
00107 
00108     if (*name != '/')   
00109         for (i = 0; dirs[i]; i++) {
00110             char buf[200];
00111             sprintf(buf, "%s/%s", dirs[i], name);
00112             if (fp = fopen(buf, "r"))
00113                 return fp;
00114         }
00115     return fopen(name, "r");
00116 }
00117 
00118 /* printfile - print annotated listing for p */
00119 void printfile(struct file *p, int nf) {
00120     int lineno;
00121     FILE *fp;
00122     char *s, buf[512];
00123     struct count *u = p->counts, *r, *uend;
00124 
00125     if (u == 0 || p->count <= 0)
00126         return;
00127     uend = &p->counts[p->count];
00128     if ((fp = openfile(p->name)) == NULL) {
00129         fprintf(stderr, "%s: can't open `%s'\n", progname, p->name);
00130         return;
00131     }
00132     if (nf)
00133         printf("%s%s:\n\n", nf == 1 ? "" : "\f", p->name);
00134     for (lineno = 1; fgets(buf, sizeof buf, fp); lineno++) {
00135         if (number)
00136             printf("%d\t", lineno);
00137         while (u < uend && u->y < lineno)
00138             u++;
00139         for (s = buf; *s; ) {
00140             char *t = s + 1;
00141             while (u < uend && u->y == lineno && u->x < s - buf)
00142                 u++;
00143             if (isalnum(*s) || *s == '_')
00144                 while (isalnum(*t) || *t == '_')
00145                     t++;
00146             while (u < uend && u->y == lineno && u->x < t - buf) {
00147                 printf("<%d>", u->count);
00148                 for (r = u++; u < uend && u->x == r->x && u->y == r->y && u->count == r->count; u++)
00149                     ;
00150             }
00151             while (s < t)
00152                 putchar(*s++);
00153         }
00154         if (*s)
00155             printf("%s", s);
00156     }
00157     fclose(fp);
00158 }
00159 
00160 /* printfuncs - summarize data for functions in p */
00161 void printfuncs(struct file *p, int nf) {
00162     struct func *q;
00163 
00164     if (nf)
00165         printf("%s:\n", p->name);
00166     for (q = p->funcs; q; q = q->link)
00167         if (fcount <= 1 || q->count.count == 0 || !q->callers)
00168             printf("%d\t%s\n", q->count.count, q->name);
00169         else {
00170             struct caller *r;
00171             for (r = q->callers; r; r = r->link)
00172                 printf("%d\t%s\tfrom %s\tin %s:%d.%d\n", r->count, q->name, r->name,
00173                     r->file, r->y, r->x + 1);
00174         }
00175         
00176 }
00177 
00178 /* string - save a copy of str, if necessary */
00179 char *string(char *str) {
00180     static struct string { struct string *link; char str[1]; } *list;
00181     struct string *p;
00182 
00183     for (p = list; p; p = p->link)
00184         if (strcmp(p->str, str) == 0)
00185             return p->str;
00186     p = (struct string *)alloc(strlen(str) + sizeof *p);
00187     strcpy(p->str, str);
00188     p->link = list;
00189     list = p;
00190     return p->str;
00191 }
00192 /* acaller - add caller and site (file,x,y) to callee's callers list */
00193 static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) {
00194     struct caller *q;
00195 
00196     assert(callee);
00197     for (q = callee->callers; q && (caller != q->name
00198         || file != q->file || x != q->x || y != q->y); q = q->link)
00199         ;
00200     if (!q) {
00201         struct caller **r;
00202         NEW(q, PERM);
00203         q->name = caller;
00204         q->file = file;
00205         q->x = x;
00206         q->y = y;
00207         q->count = 0;
00208         for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0
00209             || strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link)
00210             ;
00211         q->link = *r;
00212         *r = q;
00213     }
00214     q->count += count;
00215 }
00216 
00217 /* compare - return <0, 0, >0 if a<b, a==b, a>b, resp. */
00218 static int compare(struct count *a, struct count *b) {
00219     if (a->y == b->y)
00220         return a->x - b->x;
00221     return a->y - b->y;
00222 }
00223 
00224 /* findfile - return file name's file list entry, or 0 */
00225 static struct file *findfile(char *name) {
00226     struct file *p;
00227 
00228     for (p = filelist; p; p = p->link)
00229         if (p->name == name)
00230             return p;
00231     return 0;
00232 }
00233 
00234 /* afunction - add function name and its data to file's function list */
00235 static struct func *afunction(char *name, char *file, int x, int y, int count) {
00236     struct file *p = findfile(file);
00237     struct func *q;
00238 
00239     assert(p);
00240     for (q = p->funcs; q && name != q->name; q = q->link)
00241         ;
00242     if (!q) {
00243         struct func **r;
00244         NEW(q, PERM);
00245         q->name = name;
00246         q->count.x = x;
00247         q->count.y = y;
00248         q->count.count = 0;
00249         q->callers = 0;
00250         for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link)
00251             ;
00252         q->link = *r;
00253         *r = q;
00254     }
00255     q->count.count += count;
00256     return q;
00257 }
00258 
00259 /* apoint - append execution point i to file's data */ 
00260 static void apoint(int i, char *file, int x, int y, int count) {
00261     struct file *p = findfile(file);
00262 
00263     assert(p);
00264     if (i >= p->size) {
00265         int j;
00266         if (p->size == 0) {
00267             p->size = i >= 200 ? 2*i : 200;
00268             p->counts = newarray(p->size, sizeof *p->counts, PERM);
00269         } else {
00270             struct count *new;
00271             p->size = 2*i;
00272             new = newarray(p->size, sizeof *new, PERM);
00273             for (j = 0; j < p->count; j++)
00274                 new[j] = p->counts[j];
00275             p->counts = new;
00276         }
00277         for (j = p->count; j < p->size; j++) {
00278             static struct count z;
00279             p->counts[j] = z;
00280         }
00281     }
00282     p->counts[i].x = x;
00283     p->counts[i].y = y;
00284     p->counts[i].count += count;
00285     if (i >= p->count)
00286         p->count = i + 1;
00287 }
00288 
00289 /* findcount - return count associated with (file,x,y) or -1 */
00290 int findcount(char *file, int x, int y) {
00291     static struct file *cursor;
00292 
00293     if (cursor == 0 || cursor->name != file)
00294         cursor = findfile(file);
00295     if (cursor) {
00296         int l, u;
00297         struct count *c = cursor->counts;
00298         for (l = 0, u = cursor->count - 1; l <= u; ) {
00299             int k = (l + u)/2;
00300             if (c[k].y > y || c[k].y == y && c[k].x > x)
00301                 u = k - 1;
00302             else if (c[k].y < y || c[k].y == y && c[k].x < x)
00303                 l = k + 1;
00304             else
00305                 return c[k].count;
00306         }
00307     }
00308     return -1;
00309 }
00310 
00311 /* findfunc - return count associated with function name in file or -1 */
00312 int findfunc(char *name, char *file) {
00313     static struct file *cursor;
00314 
00315     if (cursor == 0 || cursor->name != file)
00316         cursor = findfile(file);
00317     if (cursor) {
00318         struct func *p;
00319         for (p = cursor->funcs; p; p = p->link)
00320             if (p->name == name)
00321                 return p->count.count;
00322     }
00323     return -1;
00324 }
00325 
00326 /* getd - read a nonnegative number */
00327 static int getd(void) {
00328     int c, n = 0;
00329 
00330     while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t'))
00331         ;
00332     if (c >= '0' && c <= '9') {
00333         do
00334             n = 10*n + (c - '0');
00335         while ((c = getc(fp)) >= '0' && c <= '9');
00336         return n;
00337     }
00338     return -1;
00339 }
00340 
00341 /* getstr - read a string */
00342 static char *getstr(void) {
00343     int c;
00344     char buf[MAXTOKEN], *s = buf;
00345 
00346     while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t')
00347         if (s - buf < (int)sizeof buf - 2)
00348             *s++ = c;
00349     *s = 0;
00350     return s == buf ? (char *)0 : string(buf);
00351 }
00352 
00353 /* gather - read prof.out data from fd */
00354 static int gather(void) {
00355     int i, nfiles, nfuncs, npoints;
00356     char *files[64];
00357 
00358     if ((nfiles = getd()) < 0)
00359         return 0;
00360     assert(nfiles < NELEMS(files));
00361     for (i = 0; i < nfiles; i++) {
00362         if ((files[i] = getstr()) == 0)
00363             return -1;
00364         if (!findfile(files[i])) {
00365             struct file *new;
00366             NEW(new, PERM);
00367             new->name = files[i];
00368             new->size = new->count = 0;
00369             new->counts = 0;
00370             new->funcs = 0;
00371             new->link = filelist;
00372             filelist = new;
00373         }
00374     }
00375     if ((nfuncs = getd()) < 0)
00376         return -1;
00377     for (i = 0; i < nfuncs; i++) {
00378         struct func *q;
00379         char *name, *file;
00380         int f, x, y, count;
00381         if ((name = getstr()) == 0 || (f = getd()) <= 0
00382         || (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0)
00383             return -1;
00384         q = afunction(name, files[f-1], x, y, count);
00385         if ((name = getstr()) == 0 || (file = getstr()) == 0
00386         || (x = getd()) < 0 || (y = getd()) < 0)
00387             return -1;
00388         if (*name != '?')
00389             acaller(name, file, x, y, count, q);
00390     }
00391     if ((npoints = getd()) < 0)
00392         return -1;
00393     for (i = 0; i < npoints; i++) {
00394         int f, x, y, count;
00395         if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0
00396         || (count = getd()) < 0)
00397             return -1;
00398         if (f)
00399             apoint(i, files[f-1], x, y, count);
00400     }
00401     return 1;
00402 }
00403 
00404 /* process - read prof.out data from file */
00405 int process(char *file) {
00406     int more;
00407 
00408     if ((fp = fopen(file, "r")) != NULL) {
00409         struct file *p;
00410         while ((more = gather()) > 0)
00411             ;
00412         fclose(fp);
00413         if (more < 0)
00414             return more;
00415         for (p = filelist; p; p = p->link)
00416             qsort(p->counts, p->count, sizeof *p->counts,
00417                 (int (*)(const void *, const void *))
00418                 compare);
00419         
00420         return 1;
00421     }
00422     return 0;
00423 }
00424 int main(int argc, char *argv[]) {
00425     int i;
00426     struct file *p;
00427     void (*f)(struct file *, int) = printfile;
00428 
00429     progname = argv[0];
00430     if ((i = process("prof.out")) <= 0) {
00431         fprintf(stderr, "%s: can't %s `%s'\n", progname,
00432             i == 0 ? "open" : "interpret", "prof.out");
00433         exit(1);
00434     }
00435     for (i = 1; i < argc && *argv[i] == '-'; i++)
00436         if (strcmp(argv[i], "-c") == 0) {
00437             emitdata("prof.out"); 
00438             exit(0);
00439         } else if (strcmp(argv[i], "-b") == 0)
00440             f = printfile;
00441         else if (strcmp(argv[i], "-f") == 0) {
00442             fcount++;
00443             f = printfuncs;
00444         } else if (strcmp(argv[i], "-n") == 0)
00445             number++;
00446         else if (strncmp(argv[i], "-I", 2) == 0) {
00447             int j;
00448             for (j = 0; j < NDIRS && dirs[j]; j++)
00449                 ;
00450             if (j < NDIRS)
00451                 dirs[j] = &argv[i][2];
00452             else
00453                 fprintf(stderr, "%s: too many -I options\n", progname);
00454         } else {
00455             fprintf(stderr, "usage: %s [ -c | -b | -n | -f | -Idir... ] [ file... ]\n", progname);
00456             exit(1);
00457         }
00458     for (p = filelist; p; p = p->link)
00459         qsort(p->counts, p->count, sizeof *p->counts,
00460             (int (*)(const void *, const void *))compare);
00461     if (i < argc) {
00462         int nf = i < argc - 1 ? 1 : 0;
00463         for ( ; i < argc; i++, nf ? nf++ : 0)
00464             if (p = findfile(string(argv[i])))
00465                 (*f)(p, nf);
00466             else
00467                 fprintf(stderr, "%s: no data for `%s'\n", progname, argv[i]);
00468     } else {
00469         int nf = filelist && filelist->link ? 1 : 0;
00470         for (p = filelist; p; p = p->link, nf ? nf++ : 0)
00471             (*f)(p, nf);
00472     }
00473     return 0;
00474 }
00475 

Generated on Thu Aug 25 12:38:09 2005 for Quake III Arena by  doxygen 1.3.9.1