MP_GLOBAL void __mp_deleteallocs(allochead *h) { /* We don't need to explicitly free any memory as this is dealt with * at a lower level by the heap manager. */ __mp_deleteheap(&h->heap); h->table.free = NULL; h->table.size = 0; __mp_newlist(&h->list); __mp_newlist(&h->flist); __mp_newtree(&h->itree); __mp_newtree(&h->atree); __mp_newtree(&h->gtree); __mp_newtree(&h->ftree); h->isize = h->asize = h->gsize = h->fsize = 0; h->prot = MA_NOACCESS; h->protrecur = 0; }
MP_GLOBAL void __mp_newheap(heaphead *h) { struct { char x; heapnode y; } z; long n; __mp_newmemory(&h->memory); /* Determine the minimum alignment for a heap node on this system * and force the alignment to be a power of two. This information * is used when initialising the slot table. */ n = (char *) &z.y - &z.x; __mp_newslots(&h->table, sizeof(heapnode), __mp_poweroftwo(n)); __mp_newtree(&h->itree); __mp_newtree(&h->dtree); h->isize = h->dsize = 0; h->prot = MA_NOACCESS; h->protrecur = 0; h->tracing = 0; }
MP_GLOBAL void __mp_newallocs(allochead *h, size_t m, size_t s, unsigned char o, unsigned char a, unsigned char f, unsigned long u) { struct { char x; allocnode y; } z; long n; __mp_newheap(&h->heap); /* Determine the minimum alignment for an allocation node on this * system and force the alignment to be a power of two. This * information is used when initialising the slot table. */ n = (char *) &z.y - &z.x; __mp_newslots(&h->table, sizeof(allocnode), __mp_poweroftwo(n)); __mp_newlist(&h->list); __mp_newlist(&h->flist); __mp_newtree(&h->itree); __mp_newtree(&h->atree); __mp_newtree(&h->gtree); __mp_newtree(&h->ftree); h->isize = h->asize = h->gsize = h->fsize = 0; h->fmax = m; h->oflow = __mp_poweroftwo(s); h->obyte = o; h->abyte = a; h->fbyte = f; h->flags = u; if (h->flags & FLG_PAGEALLOC) { if (h->oflow == 0) h->oflow = 1; h->oflow = __mp_roundup(h->oflow, h->heap.memory.page); } h->prot = MA_NOACCESS; h->protrecur = 0; }
static void directtable(void) { profiledata *d; profilenode *n, *p; treenode *t; profiledata m; size_t i; unsigned long a, b, c; double e, f; cleardata(&m); printchar(' ', 31); fputs("DIRECT ALLOCATIONS\n\n", stdout); printchar(' ', 20); fprintf(stdout, "(0 < s <= %lu < m <= %lu < l <= %lu < x)\n\n", sbound, mbound, lbound); if (showcounts) { printchar(' ', 9); fputs("allocated", stdout); printchar(' ', 21); fputs("unfreed\n", stdout); printchar('-', 27); fputs(" ", stdout); printchar('-', 27); fputs("\n count % s m l x " "count % s m l x bytes function\n\n", stdout); } else { printchar(' ', 10); fputs("allocated", stdout); printchar(' ', 23); fputs("unfreed\n", stdout); printchar('-', 29); fputs(" ", stdout); printchar('-', 29); fputs("\n bytes % s m l x " "bytes % s m l x 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) { 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) sumdata(d, &data[p->data - 1]); p = (profilenode *) __mp_successor(&p->node); } a = 0; for (i = 0; i < 4; i++) if (showcounts) a += d->acount[i]; else a += d->atotal[i]; __mp_treeinsert(&temptree, &n->tnode, a); sumdata(&m, d); } } 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 = c = 0; for (i = 0; i < 4; i++) { if (showcounts) { b += d->dcount[i]; c += d->atotal[i]; } else { b += d->dtotal[i]; c += d->acount[i]; } d->dcount[i] = d->acount[i] - d->dcount[i]; d->dtotal[i] = d->atotal[i] - d->dtotal[i]; } b = a - b; if (showcounts) { e = ((double) a / (double) acount) * 100.0; if (acount != dcount) f = ((double) b / (double) (acount - dcount)) * 100.0; else f = 0.0; fprintf(stdout, "%6lu %6.2f ", a, e); printdata(d->acount, acount); fprintf(stdout, " %6lu %6.2f ", b, f); printdata(d->dcount, acount - dcount); fprintf(stdout, " %8lu ", c); } else { e = ((double) a / (double) atotal) * 100.0; if (atotal != dtotal) f = ((double) b / (double) (atotal - dtotal)) * 100.0; else f = 0.0; fprintf(stdout, "%8lu %6.2f ", a, e); printdata(d->atotal, atotal); fprintf(stdout, " %8lu %6.2f ", b, f); printdata(d->dtotal, atotal - dtotal); fprintf(stdout, " %6lu ", c); } printsymbol(stdout, n); fputc('\n', stdout); cleardata(d); } for (i = 0; i < 4; i++) { m.dcount[i] = m.acount[i] - m.dcount[i]; m.dtotal[i] = m.atotal[i] - m.dtotal[i]; } if (temptree.size != 0) fputc('\n', stdout); if (showcounts) { fprintf(stdout, "%6lu ", acount); printdata(m.acount, acount); fprintf(stdout, " %6lu ", acount - dcount); printdata(m.dcount, acount - dcount); fprintf(stdout, " %8lu total\n", atotal); } else { fprintf(stdout, "%8lu ", atotal); printdata(m.atotal, atotal); fprintf(stdout, " %8lu ", atotal - dtotal); printdata(m.dtotal, atotal - dtotal); fprintf(stdout, " %6lu total\n", acount); } __mp_newtree(&temptree); }
int main(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 Lesser 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; }
static void leaktable(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); }
int main(int argc, char **argv) { struct { char x; void *y; } z; char b[256]; char *f, *s, *t; #if MP_GUI_SUPPORT XGCValues g; #endif /* MP_GUI_SUPPORT */ long n; int c, e, h, v; #if MP_GUI_SUPPORT appwidget = XtVaAppInitialize(&appcontext, "MPTrace", options, XtNumber(options), &argc, argv, NULL, NULL); XtVaGetApplicationResources(appwidget, NULL, resources, XtNumber(resources), NULL); #endif /* MP_GUI_SUPPORT */ s = t = NULL; e = h = v = 0; progname = __mp_basename(argv[0]); while ((c = __mp_getopt(argc, argv, __mp_shortopts(b, options_table), options_table)) != EOF) switch (c) { case OF_GUI: #if MP_GUI_SUPPORT usegui = 1; #endif /* MP_GUI_SUPPORT */ break; case OF_HATFFILE: t = __mp_optarg; break; case OF_HELP: h = 1; break; case OF_SIMFILE: s = __mp_optarg; break; case OF_SOURCE: displaysource = 1; break; case OF_VERBOSE: verbose = 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 Lesser 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_TRACEFILE; __mp_newtree(&alloctree); if (strcmp(f, "-") == 0) tracefile = stdin; else if ((tracefile = fopen(f, "rb")) == NULL) { fprintf(stderr, "%s: Cannot open file `%s'\n", progname, f); exit(EXIT_FAILURE); } currentevent = 0; bufferpos = buffer; bufferlen = 0; n = (char *) &z.y - &z.x; __mp_newslots(&table, sizeof(void *), __mp_poweroftwo(n)); __mp_initslots(&table, tableslots, sizeof(tableslots)); maxslots = 1; if (s != NULL) { if (strcmp(s, "stdout") == 0) simfile = stdout; else if (strcmp(s, "stderr") == 0) simfile = stderr; else if ((simfile = fopen(s, "w")) == NULL) { fprintf(stderr, "%s: Cannot open file `%s'\n", progname, s); exit(EXIT_FAILURE); } fprintf(simfile, "/* produced by %s %s from %s */\n\n\n", progname, PROGVERSION, f); fputs("#include <stdio.h>\n", simfile); fputs("#include <stdlib.h>\n\n\n", simfile); fputs("typedef struct event\n{\n", simfile); fputs(" unsigned long index;\n", simfile); fputs(" unsigned long size;\n", simfile); fputs(" char resize;\n", simfile); fputs("}\nevent;\n\n\n", simfile); fputs("static event events[] =\n{\n", simfile); } if (t != NULL) { if (strcmp(t, "stdout") == 0) hatffile = stdout; else if (strcmp(t, "stderr") == 0) hatffile = stderr; else if ((hatffile = fopen(t, "w")) == NULL) { fprintf(stderr, "%s: Cannot open file `%s'\n", progname, t); exit(EXIT_FAILURE); } fprintf(hatffile, "## Tracename: %s\n", t); fputs("## Author: Unknown\n", hatffile); fputs("## Date: Unknown\n", hatffile); fputs("## DTDURL: hatf.dtd\n", hatffile); fprintf(hatffile, "## Description: Converted to HATF by %s %s.\n\n", progname, PROGVERSION); } readfile(); #if MP_GUI_SUPPORT if (usegui) { appdisplay = XtDisplay(appwidget); appscreen = XtScreen(appwidget); addrscale = (((addrspace * 1048576) - 1) / (width * height)) + 1; /* Set up the main application window and scrollable drawing area. * Also set up a pixmap to backup the drawing area. */ mainwidget = XtVaCreateManagedWidget("main", xmScrolledWindowWidgetClass, appwidget, XmNwidth, vwidth, XmNheight, vheight, XmNscrollingPolicy, XmAUTOMATIC, XmNscrollBarDisplayPolicy, XmAS_NEEDED, NULL); drawwidget = XtVaCreateManagedWidget("draw", xmDrawingAreaWidgetClass, mainwidget, XmNwidth, width, XmNheight, height, NULL); pixmap = XCreatePixmap(appdisplay, RootWindowOfScreen(appscreen), width, height, DefaultDepthOfScreen(appscreen)); /* Set up the graphics contexts that are used for drawing in different * colours. */ g.foreground = uncol; ungc = XCreateGC(appdisplay, RootWindowOfScreen(appscreen), GCForeground, &g); g.foreground = incol; ingc = XCreateGC(appdisplay, RootWindowOfScreen(appscreen), GCForeground, &g); g.foreground = frcol; frgc = XCreateGC(appdisplay, RootWindowOfScreen(appscreen), GCForeground, &g); g.foreground = alcol; algc = XCreateGC(appdisplay, RootWindowOfScreen(appscreen), GCForeground, &g); /* Add a callback procedure to handle the refreshing of the drawing * area and also a work procedure to read events from the tracing * output file. Then initialise the drawing area and enter the main X * application loop. */ XtAddCallback(drawwidget, XmNexposeCallback, (XtCallbackProc) redrawmemory, NULL); XtAppAddWorkProc(appcontext, (XtWorkProc) readevent, NULL); XtRealizeWidget(appwidget); XFillRectangle(appdisplay, XtWindow(drawwidget), ungc, 0, 0, width - 1, height - 1); XFillRectangle(appdisplay, pixmap, ungc, 0, 0, width - 1, height - 1); XtAppMainLoop(appcontext); } #endif /* MP_GUI_SUPPORT */ return EXIT_SUCCESS; }