📄 mprof.c
字号:
staticvoidleaktable(void){ profiledata *d; profilenode *n, *p; treenode *t; size_t i; unsigned long a, b, j, k; double e, f, g; printchar(' ', 34); fputs("MEMORY LEAKS\n\n", stdout); printchar(' ', 28); fprintf(stdout, "(maximum stack depth: %lu)\n\n", maxstack); printchar(' ', 16); fputs("unfreed", stdout); printchar(' ', 22); fputs("allocated\n", stdout); printchar('-', 40); fputs(" ", stdout); printchar('-', 16); if (showcounts) fputs("\n % count % bytes % " "count bytes function\n\n", stdout); else fputs("\n % bytes % count % " "bytes count function\n\n", stdout); for (n = (profilenode *) __mp_minimum(proftree.root); n != NULL; n = p) { p = (profilenode *) __mp_successor(&n->node); if ((n->data != 0) && !n->flags) { d = &n->tdata; sumdata(d, &data[n->data - 1]); while ((p != NULL) && ((p->addr == n->addr) || (!useaddresses && (p->symbol != 0) && (p->symbol == n->symbol)))) { if ((p->data != 0) && !p->flags && comparestack(n, p, 0)) { sumdata(d, &data[p->data - 1]); p->flags = 1; } p = (profilenode *) __mp_successor(&p->node); } p = (profilenode *) __mp_successor(&n->node); a = 0; for (i = 0; i < 4; i++) if (showcounts) a += d->acount[i] - d->dcount[i]; else a += d->atotal[i] - d->dtotal[i]; if (a > 0) __mp_treeinsert(&temptree, &n->tnode, a); } } for (n = (profilenode *) __mp_minimum(proftree.root); n != NULL; n = (profilenode *) __mp_successor(&n->node)) n->flags = 0; for (t = __mp_maximum(temptree.root); t != NULL; t = __mp_predecessor(t)) { n = (profilenode *) ((char *) t - offsetof(profilenode, tnode)); d = &n->tdata; a = t->key; b = j = k = 0; for (i = 0; i < 4; i++) if (showcounts) { b += d->dtotal[i]; j += d->acount[i]; k += d->atotal[i]; } else { b += d->dcount[i]; j += d->atotal[i]; k += d->acount[i]; } b = k - b; e = ((double) a / (double) j) * 100.0; f = ((double) b / (double) k) * 100.0; if (showcounts) { g = ((double) a / (double) (acount - dcount)) * 100.0; fprintf(stdout, "%6.2f %6lu %6.2f %8lu %6.2f %6lu %8lu ", g, a, e, b, f, j, k); } else { g = ((double) a / (double) (atotal - dtotal)) * 100.0; fprintf(stdout, "%6.2f %8lu %6.2f %6lu %6.2f %8lu %6lu ", g, a, e, b, f, j, k); } printsymbol(stdout, n); fputc('\n', stdout); p = n; for (i = 1; (maxstack == 0) || (i < maxstack); i++) { if (p->parent == 0) break; p = &nodes[p->parent - 1]; printchar(' ', 60); printsymbol(stdout, p); fputc('\n', stdout); } cleardata(d); } if (acount != 0) e = ((double) (acount - dcount) / (double) acount) * 100.0; else e = 0.0; if (atotal != 0) f = ((double) (atotal - dtotal) / (double) atotal) * 100.0; else f = 0.0; if (temptree.size != 0) fputc('\n', stdout); if (showcounts) fprintf(stdout, " %6lu %6.2f %8lu %6.2f %6lu %8lu total\n", acount - dcount, e, atotal - dtotal, f, acount, atotal); else fprintf(stdout, " %8lu %6.2f %6lu %6.2f %8lu %6lu total\n", atotal - dtotal, f, acount - dcount, e, atotal, acount); __mp_newtree(&temptree);}/* Display the allocation call graph. */staticvoidcallgraph(void){ size_t d[4]; listnode *l; vertex *u, *v; edge *e; graphedge *g; size_t i, s, t; i = 1; printchar(' ', 29); fputs("ALLOCATION CALL GRAPH\n\n", stdout); printchar(' ', 28); fprintf(stdout, "(number of vertices: %lu)\n\n", temptree.size); if (showcounts) { printchar(' ', 10); fputs("allocated", stdout); printchar(' ', 13); fputs("unfreed\n", stdout); printchar(' ', 5); printchar('-', 19); fputs(" ", stdout); printchar('-', 19); fputs("\nindex count s m l x count s m l x function\n", stdout); } else { printchar(' ', 11); fputs("allocated", stdout); printchar(' ', 15); fputs("unfreed\n", stdout); printchar(' ', 5); printchar('-', 21); fputs(" ", stdout); printchar('-', 21); fputs("\nindex bytes s m l x bytes s m l x function\n", stdout); } /* Compute the index for each vertex in the graph. This is currently * done after the graph has been completely constructed so that the * ordering can be done by code address. It has to be done before we * start displaying the graph since each vertex will contain forward * references to its parents and children. */ for (v = (vertex *) __mp_minimum(temptree.root); v != NULL; v = (vertex *) __mp_successor(&v->node)) v->index = i++; for (v = (vertex *) __mp_minimum(temptree.root); v != NULL; v = (vertex *) __mp_successor(&v->node)) { if (showcounts) printchar('-', 45); else printchar('-', 49); fputc('\n', stdout); /* Calculate the details of the parents. */ for (l = v->gnode.parents.head; l->next != NULL; l = l->next) { /* The following three lines are a bit excessive and result from * using class-based programming in C. These conversions would be * automatically calculated by the compiler if we were using C++ * classes. */ g = (graphedge *) ((char *) l - offsetof(graphedge, pnode)); e = (edge *) ((char *) g - offsetof(edge, gnode)); u = (vertex *) ((char *) e->gnode.parent - offsetof(vertex, gnode)); if (&u->gnode != &graph.start) { for (i = s = t = 0; i < 4; i++) { if (showcounts) { t += e->data.acount[i]; d[i] = e->data.acount[i] - e->data.dcount[i]; } else { t += e->data.atotal[i]; d[i] = e->data.atotal[i] - e->data.dtotal[i]; } s += d[i]; } if (e->flags & 2) fputs(" (*) ", stdout); else printchar(' ', 5); if (showcounts) { fprintf(stdout, "%6lu ", t); printdata(e->data.acount, t); fprintf(stdout, " %6lu ", s); } else { fprintf(stdout, "%8lu ", t); printdata(e->data.atotal, t); fprintf(stdout, " %8lu ", s); } printdata(d, s); printchar(' ', 6); printsymbol(stdout, u->pnode); fprintf(stdout, " [%lu]\n", u->index); } } fprintf(stdout, "[%lu] ", v->index); if (showcounts) printchar(' ', 44 - countdigits(v->index)); else printchar(' ', 48 - countdigits(v->index)); printsymbol(stdout, v->pnode); fprintf(stdout, " [%lu]\n", v->index); /* Calculate the details of the children. */ for (l = v->gnode.children.head; l->next != NULL; l = l->next) { /* The following three lines are a bit excessive and result from * using class-based programming in C. These conversions would be * automatically calculated by the compiler if we were using C++ * classes. */ g = (graphedge *) ((char *) l - offsetof(graphedge, cnode)); e = (edge *) ((char *) g - offsetof(edge, gnode)); u = (vertex *) ((char *) e->gnode.child - offsetof(vertex, gnode)); if (&u->gnode != &graph.end) { for (i = s = t = 0; i < 4; i++) { if (showcounts) { t += e->data.acount[i]; d[i] = e->data.acount[i] - e->data.dcount[i]; } else { t += e->data.atotal[i]; d[i] = e->data.atotal[i] - e->data.dtotal[i]; } s += d[i]; } if (e->flags & 2) fputs(" (*) ", stdout); else printchar(' ', 5); if (showcounts) { fprintf(stdout, "%6lu ", t); printdata(e->data.acount, t); fprintf(stdout, " %6lu ", s); } else { fprintf(stdout, "%8lu ", t); printdata(e->data.atotal, t); fprintf(stdout, " %8lu ", s); } printdata(d, s); printchar(' ', 6); printsymbol(stdout, u->pnode); fprintf(stdout, " [%lu]\n", u->index); } } }}/* Write out the graph specification file in dot format. */staticvoidwritegraph(profilenode *p, graphnode *n){ listnode *l; vertex *v; edge *e; graphedge *g; size_t i, t; for (l = n->children.head; l->next != NULL; l = l->next) { /* The following three lines are a bit excessive and result from * using class-based programming in C. These conversions would be * automatically calculated by the compiler if we were using C++ * classes. */ g = (graphedge *) ((char *) l - offsetof(graphedge, cnode)); e = (edge *) ((char *) g - offsetof(edge, gnode)); v = (vertex *) ((char *) e->gnode.child - offsetof(vertex, gnode)); if (!(e->flags & 1)) { e->flags |= 1; for (i = t = 0; i < 4; i++) if (showcounts) { t += e->data.acount[i]; if (showleaks) t -= e->data.dcount[i]; } else { t += e->data.atotal[i]; if (showleaks) t -= e->data.dtotal[i]; } if ((t > 0) || !showleaks) { fputs(" \"", graphfile); if (p == NULL) fputs("START", graphfile); else printsymbol(graphfile, p); fputs("\" -> \"", graphfile); if (&v->gnode == &graph.end) fputs("ALLOC", graphfile); else printsymbol(graphfile, v->pnode); fprintf(graphfile, "\" [label = \"%lu\"", t); if (e->flags & 2) fputs(", style = dotted", graphfile); fputs("];\n", graphfile); } writegraph(v->pnode, &v->gnode); } } if (p == NULL) for (e = (edge *) edgelist.head; e->node.next != NULL; e = (edge *) e->node.next) e->flags &= ~1;}/* Read the profiling output file and display all specified information. */intmain(int argc, char **argv){ char b[256]; char *f, *g; int c, e, h, r, v; g = NULL; e = h = v = 0; r = EXIT_SUCCESS; maxstack = 1; progname = __mp_basename(argv[0]); while ((c = __mp_getopt(argc, argv, __mp_shortopts(b, options_table), options_table)) != EOF) switch (c) { case OF_ADDRESSES: useaddresses = 1; break; case OF_CALLGRAPH: showgraph = 1; break; case OF_COUNTS: showcounts = 1; break; case OF_GRAPHFILE: g = __mp_optarg; break; case OF_HELP: h = 1; break; case OF_LEAKS: showleaks = 1; break; case OF_STACKDEPTH: if (!__mp_getnum(progname, __mp_optarg, (long *) &maxstack, 1)) e = 1; break; case OF_VERSION: v = 1; break; default: e = 1; break; } argc -= __mp_optindex; argv += __mp_optindex; if (v == 1) { fprintf(stdout, "%s %s\n%s %s\n\n", progname, PROGVERSION, __mp_copyright, __mp_author); fputs("This is free software, and you are welcome to redistribute it " "under certain\n", stdout); fputs("conditions; see the GNU Library General Public License for " "details.\n\n", stdout); fputs("For the latest mpatrol release and documentation,\n", stdout); fprintf(stdout, "visit %s.\n\n", __mp_homepage); } if (argc > 1) e = 1; if ((e == 1) || (h == 1)) { fprintf(stdout, "Usage: %s [options] [file]\n\n", progname); if (h == 0) fprintf(stdout, "Type `%s --help' for a complete list of " "options.\n", progname); else __mp_showopts(options_table); if (e == 1) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); } if (argc == 1) f = argv[0]; else f = MP_PROFFILE; acount = dcount = 0; atotal = dtotal = 0; acounts = dcounts = NULL; atotals = dtotals = 0; binsize = 0; data = NULL; datasize = 0; nodes = NULL; nodesize = 0; addrs = NULL; symbols = NULL; sbound = mbound = lbound = 0; __mp_newtree(&proftree); __mp_newtree(&temptree); __mp_newlist(&edgelist); __mp_newgraph(&graph); if (strcmp(f, "-") == 0) proffile = stdin; else if ((proffile = fopen(f, "rb")) == NULL) { fprintf(stderr, "%s: Cannot open file `%s'\n", progname, f); exit(EXIT_FAILURE); } readfile(); fclose(proffile); bintable(); fputs("\n\n", stdout); directtable(); fputs("\n\n", stdout); leaktable(); /* The reason that the allocation call graph is not used for the direct * allocation and memory leak tables is that the code to build and display * the allocation call graph was added much later. Rather than convert * these tables to use the new call graph, I decided to keep the code that * already worked and only use the call graph for any new tables. */ buildgraph(); if (showgraph) { fputs("\n\n", stdout); callgraph(); } if (g != NULL) { if (strcmp(g, "stdout") == 0) graphfile = stdout; else if (strcmp(g, "stderr") == 0) graphfile = stderr; else if ((graphfile = fopen(g, "w")) == NULL) { fprintf(stderr, "%s: Cannot open file `%s'\n", progname, g); r = EXIT_FAILURE; } if (r == EXIT_SUCCESS) { fprintf(graphfile, "/* produced by %s %s from %s */\n\n", progname, PROGVERSION, f); if (showleaks) fputs("digraph \"memory leak call graph\"\n{\n", graphfile); else fputs("digraph \"allocation call graph\"\n{\n", graphfile); writegraph(NULL, &graph.start); fputs("}\n", graphfile); if ((graphfile != stdout) && (graphfile != stderr)) fclose(graphfile); } } deletegraph(); if (acounts != NULL) free(acounts); if (dcounts != NULL) free(dcounts); if (data != NULL) free(data); if (nodes != NULL) free(nodes); if (addrs != NULL) free(addrs); if (symbols != NULL) free(symbols); return r;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -