00001 #include <assert.h>
00002 #include <ctype.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <string.h>
00006
00007
00008
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 {
00020 int x, y;
00021 int count;
00022 };
00023
00024 char *progname;
00025 int number;
00026 char *dirs[20];
00027 int fcount;
00028
00029 struct file {
00030 struct file *link;
00031 char *name;
00032 int size;
00033 int count;
00034 struct count *counts;
00035 struct func {
00036 struct func *link;
00037 char *name;
00038 struct count count;
00039 struct caller {
00040 struct caller *link;
00041 char *name;
00042 char *file;
00043 int x, y;
00044 int count;
00045 } *callers;
00046 } *funcs;
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
00062 void *alloc(unsigned n) {
00063 void *new = malloc(n);
00064
00065 assert(new);
00066 return new;
00067 }
00068
00069
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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