From ca37059e302b9e676fd564195701ec2bc3e60cb1 Mon Sep 17 00:00:00 2001 From: "brendan%mozilla.org" Date: Wed, 28 Jun 2000 06:42:29 +0000 Subject: [PATCH] Interim checkin: -u option for unified (-f and standard) output, down/next links for sorted subgraph navigation, some -j (js-mode) support. --- tools/trace-malloc/bloatblame.c | 462 +++++++++++++++++++++----------- xpcom/base/bloatblame.c | 462 +++++++++++++++++++++----------- 2 files changed, 618 insertions(+), 306 deletions(-) diff --git a/tools/trace-malloc/bloatblame.c b/tools/trace-malloc/bloatblame.c index 6f465d0a74e7..b49efd741784 100644 --- a/tools/trace-malloc/bloatblame.c +++ b/tools/trace-malloc/bloatblame.c @@ -39,6 +39,10 @@ #include #ifdef HAVE_GETOPT_H #include +#else +extern int getopt(int argc, char *const *argv, const char *shortopts); +extern char *optarg; +extern int optind; #endif #include #include @@ -52,7 +56,9 @@ static char *program; static int sort_by_direct = 0; +static int js_mode = 0; static int do_tree_dump = 0; +static int unified_output = 0; static char *function_dump = NULL; static int32 min_subtotal = 0; @@ -156,7 +162,7 @@ typedef struct logevent { uint32 size; } alloc; struct { - struct nsTMStats tmstats; + nsTMStats tmstats; uint32 calltree_maxkids_parent; uint32 calltree_maxstack_top; } stats; @@ -256,11 +262,14 @@ struct graphnode { PLHashEntry entry; /* key is serial or name, value must be name */ graphedge *in; graphedge *out; - graphnode *up; + graphnode *up; /* parent in supergraph, e.g., JS for JS_*() */ + graphnode *down; /* subgraph kids, declining bytes.total order */ + graphnode *next; /* next kid in supergraph node's down list */ int low; /* 0 or lowest current tree walk level */ counts bytes; /* bytes (direct and total) allocated */ counts allocs; /* number of allocations */ double sqsum; /* sum of squared bytes.direct */ + int sort; /* sorted index in node table, -1 if no table */ }; #define graphnode_name(node) ((char*) (node)->entry.value) @@ -343,11 +352,12 @@ static PLHashEntry *graphnode_allocentry(void *pool, const void *key) graphnode *node = (graphnode*) malloc(sizeof(graphnode)); if (node) { node->in = node->out = NULL; - node->up = NULL; + node->up = node->down = node->next = NULL; node->low = 0; node->bytes.direct = node->bytes.total = 0; node->allocs.direct = node->allocs.total = 0; node->sqsum = 0; + node->sort = -1; } return &node->entry; } @@ -495,11 +505,46 @@ static void walk_callsite_tree(callsite *site, int level, int kidnum, FILE *fp) } } +/* Linked list bubble-sort (waterson and brendan went bald hacking this). */ +#define BUBBLE_SORT_LINKED_LIST(listp, nodetype) \ + PR_BEGIN_MACRO \ + nodetype *curr, **currp, *next, **nextp, *tmp; \ + \ + currp = listp; \ + while ((curr = *currp) != NULL && curr->next) { \ + nextp = &curr->next; \ + while ((next = *nextp) != NULL) { \ + if (curr->bytes.total < next->bytes.total) { \ + tmp = curr->next; \ + *currp = tmp; \ + if (tmp == next) { \ + PR_ASSERT(nextp == &curr->next); \ + curr->next = next->next; \ + next->next = curr; \ + } else { \ + *nextp = next->next; \ + curr->next = next->next; \ + next->next = tmp; \ + *currp = next; \ + *nextp = curr; \ + nextp = &curr->next; \ + } \ + curr = next; \ + continue; \ + } \ + nextp = &next->next; \ + } \ + currp = &curr->next; \ + } \ + PR_END_MACRO + static PRIntn tabulate_node(PLHashEntry *he, PRIntn i, void *arg) { + graphnode *node = (graphnode*) he; graphnode **table = (graphnode**) arg; - table[i] = (graphnode*) he; + table[i] = node; + BUBBLE_SORT_LINKED_LIST(&node->down, graphnode); return HT_ENUMERATE_NEXT; } @@ -561,58 +606,50 @@ static double percent(int32 num, int32 total) return ((double) num * 100) / (double) total; } -/* Linked list bubble-sort (waterson and brendan went bald hacking this). */ -static void sort_graphedge_list(graphedge **currp) +static void sort_graphedge_list(graphedge **listp) { - graphedge *curr, *next, **nextp, *tmp; - - while ((curr = *currp) != NULL && curr->next) { - nextp = &curr->next; - while ((next = *nextp) != NULL) { - if (curr->bytes.total < next->bytes.total) { - tmp = curr->next; - *currp = tmp; - if (tmp == next) { - PR_ASSERT(nextp == &curr->next); - curr->next = next->next; - next->next = curr; - } else { - *nextp = next->next; - curr->next = next->next; - next->next = tmp; - *currp = next; - *nextp = curr; - nextp = &curr->next; - } - curr = next; - continue; - } - nextp = &next->next; - } - currp = &curr->next; - } + BUBBLE_SORT_LINKED_LIST(listp, graphedge); } -static void dump_graphedge_list(graphedge *list, FILE *fp) +static void dump_graphedge_list(graphedge *list, const char *name, FILE *fp) { - int32 total; + counts bytes; graphedge *edge; char buf[16]; - fputs("", fp); - total = 0; - for (edge = list; edge; edge = edge->next) - total += edge->bytes.total; + bytes.direct = bytes.total = 0; for (edge = list; edge; edge = edge->next) { - fprintf(fp, "%s (%1.2f%%)\n", - graphnode_name(edge->node), - prettybig(edge->bytes.total, buf, sizeof buf), - percent(edge->bytes.total, total)); + bytes.direct += edge->bytes.direct; + bytes.total += edge->bytes.total; + } + + if (js_mode) { + fprintf(fp, + " %s:{dbytes:%ld, tbytes:%ld, edges:[\n", + name, (long) bytes.direct, (long) bytes.total); + for (edge = list; edge; edge = edge->next) { + fprintf(fp, + " {node:%d, dbytes:%ld, tbytes:%ld},\n", + edge->node->sort, + (long) edge->bytes.direct, + (long) edge->bytes.total); + } + fputs(" ]},\n", fp); + } else { + fputs("", fp); + for (edge = list; edge; edge = edge->next) { + fprintf(fp, + "%s (%1.2f%%)\n", + graphnode_name(edge->node), + prettybig(edge->bytes.total, buf, sizeof buf), + percent(edge->bytes.total, bytes.total)); + } + fputs("", fp); } - fputs("", fp); } -static void dump_graph(PLHashTable *hashtbl, const char *title, FILE *fp) +static void dump_graph(PLHashTable *hashtbl, const char *varname, + const char *title, FILE *fp) { uint32 i, count; graphnode **table, *node; @@ -629,17 +666,27 @@ static void dump_graph(PLHashTable *hashtbl, const char *title, FILE *fp) } PL_HashTableEnumerateEntries(hashtbl, tabulate_node, table); qsort(table, count, sizeof(graphnode*), node_table_compare); + for (i = 0; i < count; i++) + table[i]->sort = i; - fprintf(fp, - "\n" - "" - "" - "" - "" - "" - "" - "\n", - title); + if (js_mode) { + fprintf(fp, + "var %s = {\n name:'%s', title:'%s', nodes:[\n", + varname, varname, title); + } else { + fprintf(fp, + "
%sTotal/Direct (percents)AllocationsFan-inFan-out
\n" + "" + "" + "" + "" + "" + "" + "" + "" + "\n", + title); + } for (i = 0; i < count; i++) { /* Don't bother with truly puny nodes. */ @@ -648,82 +695,113 @@ static void dump_graph(PLHashTable *hashtbl, const char *title, FILE *fp) break; name = graphnode_name(node); - namelen = strlen(name); - fprintf(fp, - "" - "" - "" - "", - name, - (namelen > 45) ? 45 : (int)namelen, name, - (namelen > 45) ? "..." : "", - prettybig(node->bytes.total, buf1, sizeof buf1), - prettybig(node->bytes.direct, buf2, sizeof buf2), - percent(node->bytes.total, calltree_root.bytes.total), - percent(node->bytes.direct, calltree_root.bytes.total), - prettybig(node->allocs.total, buf3, sizeof buf3), - prettybig(node->allocs.direct, buf4, sizeof buf4), - percent(node->allocs.total, calltree_root.allocs.total), - percent(node->allocs.direct, calltree_root.allocs.total)); + if (js_mode) { + fprintf(fp, + " {name:'%s', dbytes:%ld, tbytes:%ld," + " dallocs:%ld, tallocs:%ld,\n", + name, + (long) node->bytes.direct, (long) node->bytes.total, + (long) node->allocs.direct, (long) node->allocs.total); + } else { + namelen = strlen(name); + fprintf(fp, + "" + "", + name, + (namelen > 45) ? 45 : (int)namelen, name, + (namelen > 45) ? "..." : ""); + if (node->down) { + fprintf(fp, + "", + graphnode_name(node->down)); + } else { + fputs("", fp); + } + if (node->next) { + fprintf(fp, + "", + graphnode_name(node->next)); + } else { + fputs("", fp); + } + fprintf(fp, + "" + "", + prettybig(node->bytes.total, buf1, sizeof buf1), + prettybig(node->bytes.direct, buf2, sizeof buf2), + percent(node->bytes.total, calltree_root.bytes.total), + percent(node->bytes.direct, calltree_root.bytes.total), + prettybig(node->allocs.total, buf3, sizeof buf3), + prettybig(node->allocs.direct, buf4, sizeof buf4), + percent(node->allocs.total, calltree_root.allocs.total), + percent(node->allocs.direct, calltree_root.allocs.total)); + } sort_graphedge_list(&node->in); - dump_graphedge_list(node->in, fp); + dump_graphedge_list(node->in, "fin", fp); /* 'in' is a JS keyword! */ sort_graphedge_list(&node->out); - dump_graphedge_list(node->out, fp); + dump_graphedge_list(node->out, "out", fp); - fputs("\n", fp); - } - - fputs("
%sDownNextTotal/Direct (percents)AllocationsFan-inFan-out
%.*s%s%s/%s (%1.2f%%/%1.2f%%)%s/%s (%1.2f%%/%1.2f%%)
%.*s%sdownnext%s/%s (%1.2f%%/%1.2f%%)%s/%s (%1.2f%%/%1.2f%%)
\n
\n", fp); - - qsort(table, count, sizeof(graphnode*), mean_size_compare); - - fprintf(fp, - "\n" - "\n" - "" - "" - "" - "" - "\n", - title); - - for (i = 0; i < count; i++) { - double allocs, bytes, mean, variance, sigma; - - node = table[i]; - allocs = (double)node->allocs.direct; - if (!allocs) - continue; - - /* Compute direct-size mean and standard deviation. */ - bytes = (double)node->bytes.direct; - mean = bytes / allocs; - variance = allocs * node->sqsum - bytes * bytes; - if (variance < 0 || allocs == 1) - variance = 0; + if (js_mode) + fputs(" },\n", fp); else - variance /= allocs * (allocs - 1); - sigma = sqrt(variance); - - name = graphnode_name(node); - namelen = strlen(name); - fprintf(fp, - "" - "" - "" - "" - "" - "\n", - (namelen > 65) ? 45 : (int)namelen, name, - (namelen > 65) ? "..." : "", - prettybig((uint32)mean, buf1, sizeof buf1), - prettybig((uint32)sigma, buf2, sizeof buf2), - prettybig(node->allocs.direct, buf3, sizeof buf3)); + fputs("\n", fp); + } + + if (js_mode) { + fputs("]};\n", fp); + } else { + fputs("
Direct Allocators
%sMean SizeStdDevAllocations" - "
%.*s%s%s%s%s
\n
\n", fp); + + qsort(table, count, sizeof(graphnode*), mean_size_compare); + + fprintf(fp, + "\n" + "\n" + "" + "" + "" + "" + "\n", + title); + + for (i = 0; i < count; i++) { + double allocs, bytes, mean, variance, sigma; + + node = table[i]; + allocs = (double)node->allocs.direct; + if (!allocs) + continue; + + /* Compute direct-size mean and standard deviation. */ + bytes = (double)node->bytes.direct; + mean = bytes / allocs; + variance = allocs * node->sqsum - bytes * bytes; + if (variance < 0 || allocs == 1) + variance = 0; + else + variance /= allocs * (allocs - 1); + sigma = sqrt(variance); + + name = graphnode_name(node); + namelen = strlen(name); + fprintf(fp, + "" + "" + "" + "" + "" + "\n", + (namelen > 65) ? 45 : (int)namelen, name, + (namelen > 65) ? "..." : "", + prettybig((uint32)mean, buf1, sizeof buf1), + prettybig((uint32)sigma, buf2, sizeof buf2), + prettybig(node->allocs.direct, buf3, sizeof buf3)); + } + fputs("
Direct Allocators
%sMean SizeStdDevAllocations" + "
%.*s%s%s%s%s
\n", fp); } - fputs("\n", fp); free((void*) table); } @@ -820,11 +898,17 @@ static void process(const char *filename, FILE *fp) key = (const void*) event.u.method.library; hash = hash_serial(key); lib = (graphnode*) *PL_HashTableRawLookup(libraries, hash, key); - comp->up = lib; + if (lib) { + comp->up = lib; + comp->next = lib->down; + lib->down = comp; + } } *mark = save; meth->up = comp; + meth->next = comp->down; + comp->down = meth; break; } @@ -944,6 +1028,8 @@ static void process(const char *filename, FILE *fp) break; case 'Z': + if (js_mode) + break; fprintf(stdout, "

" "\n" @@ -1031,22 +1117,10 @@ static void process(const char *filename, FILE *fp) int main(int argc, char **argv) { - time_t start; int c, i; FILE *fp; program = *argv; - start = time(NULL); - fprintf(stdout, - "\n"); - fprintf(stdout, "%s starting at %s", program, ctime(&start)); - fflush(stdout); libraries = PL_NewHashTable(100, hash_serial, PL_CompareValues, PL_CompareStrings, &graphnode_hashallocops, @@ -1067,14 +1141,20 @@ int main(int argc, char **argv) exit(1); } - while ((c = getopt(argc, argv, "dtf:m:")) != EOF) { + while ((c = getopt(argc, argv, "djtuf:m:")) != EOF) { switch (c) { case 'd': sort_by_direct = 1; break; + case 'j': + js_mode = 1; + break; case 't': do_tree_dump = 1; break; + case 'u': + unified_output = 1; + break; case 'f': function_dump = optarg; break; @@ -1089,6 +1169,21 @@ int main(int argc, char **argv) } } + if (!js_mode) { + time_t start = time(NULL); + + fprintf(stdout, + "\n"); + fprintf(stdout, "%s starting at %s", program, ctime(&start)); + fflush(stdout); + } + argc -= optind; argv += optind; if (argc == 0) { @@ -1109,28 +1204,89 @@ int main(int argc, char **argv) compute_callsite_totals(&calltree_root); walk_callsite_tree(&calltree_root, 0, 0, stdout); - dump_graph(libraries, "Library", stdout); - fputs("
\n", stdout); - dump_graph(components, "Class or Component", stdout); - if (function_dump) { - struct stat sb, fsb; + if (js_mode) { + fprintf(stdout, + "\n" + "\n" + " \n" + " \n" + "\n", + stdout); + } } exit(0); diff --git a/xpcom/base/bloatblame.c b/xpcom/base/bloatblame.c index 6f465d0a74e7..b49efd741784 100644 --- a/xpcom/base/bloatblame.c +++ b/xpcom/base/bloatblame.c @@ -39,6 +39,10 @@ #include #ifdef HAVE_GETOPT_H #include +#else +extern int getopt(int argc, char *const *argv, const char *shortopts); +extern char *optarg; +extern int optind; #endif #include #include @@ -52,7 +56,9 @@ static char *program; static int sort_by_direct = 0; +static int js_mode = 0; static int do_tree_dump = 0; +static int unified_output = 0; static char *function_dump = NULL; static int32 min_subtotal = 0; @@ -156,7 +162,7 @@ typedef struct logevent { uint32 size; } alloc; struct { - struct nsTMStats tmstats; + nsTMStats tmstats; uint32 calltree_maxkids_parent; uint32 calltree_maxstack_top; } stats; @@ -256,11 +262,14 @@ struct graphnode { PLHashEntry entry; /* key is serial or name, value must be name */ graphedge *in; graphedge *out; - graphnode *up; + graphnode *up; /* parent in supergraph, e.g., JS for JS_*() */ + graphnode *down; /* subgraph kids, declining bytes.total order */ + graphnode *next; /* next kid in supergraph node's down list */ int low; /* 0 or lowest current tree walk level */ counts bytes; /* bytes (direct and total) allocated */ counts allocs; /* number of allocations */ double sqsum; /* sum of squared bytes.direct */ + int sort; /* sorted index in node table, -1 if no table */ }; #define graphnode_name(node) ((char*) (node)->entry.value) @@ -343,11 +352,12 @@ static PLHashEntry *graphnode_allocentry(void *pool, const void *key) graphnode *node = (graphnode*) malloc(sizeof(graphnode)); if (node) { node->in = node->out = NULL; - node->up = NULL; + node->up = node->down = node->next = NULL; node->low = 0; node->bytes.direct = node->bytes.total = 0; node->allocs.direct = node->allocs.total = 0; node->sqsum = 0; + node->sort = -1; } return &node->entry; } @@ -495,11 +505,46 @@ static void walk_callsite_tree(callsite *site, int level, int kidnum, FILE *fp) } } +/* Linked list bubble-sort (waterson and brendan went bald hacking this). */ +#define BUBBLE_SORT_LINKED_LIST(listp, nodetype) \ + PR_BEGIN_MACRO \ + nodetype *curr, **currp, *next, **nextp, *tmp; \ + \ + currp = listp; \ + while ((curr = *currp) != NULL && curr->next) { \ + nextp = &curr->next; \ + while ((next = *nextp) != NULL) { \ + if (curr->bytes.total < next->bytes.total) { \ + tmp = curr->next; \ + *currp = tmp; \ + if (tmp == next) { \ + PR_ASSERT(nextp == &curr->next); \ + curr->next = next->next; \ + next->next = curr; \ + } else { \ + *nextp = next->next; \ + curr->next = next->next; \ + next->next = tmp; \ + *currp = next; \ + *nextp = curr; \ + nextp = &curr->next; \ + } \ + curr = next; \ + continue; \ + } \ + nextp = &next->next; \ + } \ + currp = &curr->next; \ + } \ + PR_END_MACRO + static PRIntn tabulate_node(PLHashEntry *he, PRIntn i, void *arg) { + graphnode *node = (graphnode*) he; graphnode **table = (graphnode**) arg; - table[i] = (graphnode*) he; + table[i] = node; + BUBBLE_SORT_LINKED_LIST(&node->down, graphnode); return HT_ENUMERATE_NEXT; } @@ -561,58 +606,50 @@ static double percent(int32 num, int32 total) return ((double) num * 100) / (double) total; } -/* Linked list bubble-sort (waterson and brendan went bald hacking this). */ -static void sort_graphedge_list(graphedge **currp) +static void sort_graphedge_list(graphedge **listp) { - graphedge *curr, *next, **nextp, *tmp; - - while ((curr = *currp) != NULL && curr->next) { - nextp = &curr->next; - while ((next = *nextp) != NULL) { - if (curr->bytes.total < next->bytes.total) { - tmp = curr->next; - *currp = tmp; - if (tmp == next) { - PR_ASSERT(nextp == &curr->next); - curr->next = next->next; - next->next = curr; - } else { - *nextp = next->next; - curr->next = next->next; - next->next = tmp; - *currp = next; - *nextp = curr; - nextp = &curr->next; - } - curr = next; - continue; - } - nextp = &next->next; - } - currp = &curr->next; - } + BUBBLE_SORT_LINKED_LIST(listp, graphedge); } -static void dump_graphedge_list(graphedge *list, FILE *fp) +static void dump_graphedge_list(graphedge *list, const char *name, FILE *fp) { - int32 total; + counts bytes; graphedge *edge; char buf[16]; - fputs("", fp); } - fputs("", fp); } -static void dump_graph(PLHashTable *hashtbl, const char *title, FILE *fp) +static void dump_graph(PLHashTable *hashtbl, const char *varname, + const char *title, FILE *fp) { uint32 i, count; graphnode **table, *node; @@ -629,17 +666,27 @@ static void dump_graph(PLHashTable *hashtbl, const char *title, FILE *fp) } PL_HashTableEnumerateEntries(hashtbl, tabulate_node, table); qsort(table, count, sizeof(graphnode*), node_table_compare); + for (i = 0; i < count; i++) + table[i]->sort = i; - fprintf(fp, - "
CounterValue
", fp); - total = 0; - for (edge = list; edge; edge = edge->next) - total += edge->bytes.total; + bytes.direct = bytes.total = 0; for (edge = list; edge; edge = edge->next) { - fprintf(fp, "%s (%1.2f%%)\n", - graphnode_name(edge->node), - prettybig(edge->bytes.total, buf, sizeof buf), - percent(edge->bytes.total, total)); + bytes.direct += edge->bytes.direct; + bytes.total += edge->bytes.total; + } + + if (js_mode) { + fprintf(fp, + " %s:{dbytes:%ld, tbytes:%ld, edges:[\n", + name, (long) bytes.direct, (long) bytes.total); + for (edge = list; edge; edge = edge->next) { + fprintf(fp, + " {node:%d, dbytes:%ld, tbytes:%ld},\n", + edge->node->sort, + (long) edge->bytes.direct, + (long) edge->bytes.total); + } + fputs(" ]},\n", fp); + } else { + fputs("", fp); + for (edge = list; edge; edge = edge->next) { + fprintf(fp, + "%s (%1.2f%%)\n", + graphnode_name(edge->node), + prettybig(edge->bytes.total, buf, sizeof buf), + percent(edge->bytes.total, bytes.total)); + } + fputs("
\n" - "" - "" - "" - "" - "" - "" - "\n", - title); + if (js_mode) { + fprintf(fp, + "var %s = {\n name:'%s', title:'%s', nodes:[\n", + varname, varname, title); + } else { + fprintf(fp, + "
%sTotal/Direct (percents)AllocationsFan-inFan-out
\n" + "" + "" + "" + "" + "" + "" + "" + "" + "\n", + title); + } for (i = 0; i < count; i++) { /* Don't bother with truly puny nodes. */ @@ -648,82 +695,113 @@ static void dump_graph(PLHashTable *hashtbl, const char *title, FILE *fp) break; name = graphnode_name(node); - namelen = strlen(name); - fprintf(fp, - "" - "" - "" - "", - name, - (namelen > 45) ? 45 : (int)namelen, name, - (namelen > 45) ? "..." : "", - prettybig(node->bytes.total, buf1, sizeof buf1), - prettybig(node->bytes.direct, buf2, sizeof buf2), - percent(node->bytes.total, calltree_root.bytes.total), - percent(node->bytes.direct, calltree_root.bytes.total), - prettybig(node->allocs.total, buf3, sizeof buf3), - prettybig(node->allocs.direct, buf4, sizeof buf4), - percent(node->allocs.total, calltree_root.allocs.total), - percent(node->allocs.direct, calltree_root.allocs.total)); + if (js_mode) { + fprintf(fp, + " {name:'%s', dbytes:%ld, tbytes:%ld," + " dallocs:%ld, tallocs:%ld,\n", + name, + (long) node->bytes.direct, (long) node->bytes.total, + (long) node->allocs.direct, (long) node->allocs.total); + } else { + namelen = strlen(name); + fprintf(fp, + "" + "", + name, + (namelen > 45) ? 45 : (int)namelen, name, + (namelen > 45) ? "..." : ""); + if (node->down) { + fprintf(fp, + "", + graphnode_name(node->down)); + } else { + fputs("", fp); + } + if (node->next) { + fprintf(fp, + "", + graphnode_name(node->next)); + } else { + fputs("", fp); + } + fprintf(fp, + "" + "", + prettybig(node->bytes.total, buf1, sizeof buf1), + prettybig(node->bytes.direct, buf2, sizeof buf2), + percent(node->bytes.total, calltree_root.bytes.total), + percent(node->bytes.direct, calltree_root.bytes.total), + prettybig(node->allocs.total, buf3, sizeof buf3), + prettybig(node->allocs.direct, buf4, sizeof buf4), + percent(node->allocs.total, calltree_root.allocs.total), + percent(node->allocs.direct, calltree_root.allocs.total)); + } sort_graphedge_list(&node->in); - dump_graphedge_list(node->in, fp); + dump_graphedge_list(node->in, "fin", fp); /* 'in' is a JS keyword! */ sort_graphedge_list(&node->out); - dump_graphedge_list(node->out, fp); + dump_graphedge_list(node->out, "out", fp); - fputs("\n", fp); - } - - fputs("
%sDownNextTotal/Direct (percents)AllocationsFan-inFan-out
%.*s%s%s/%s (%1.2f%%/%1.2f%%)%s/%s (%1.2f%%/%1.2f%%)
%.*s%sdownnext%s/%s (%1.2f%%/%1.2f%%)%s/%s (%1.2f%%/%1.2f%%)
\n


\n", fp); - - qsort(table, count, sizeof(graphnode*), mean_size_compare); - - fprintf(fp, - "\n" - "\n" - "" - "" - "" - "" - "\n", - title); - - for (i = 0; i < count; i++) { - double allocs, bytes, mean, variance, sigma; - - node = table[i]; - allocs = (double)node->allocs.direct; - if (!allocs) - continue; - - /* Compute direct-size mean and standard deviation. */ - bytes = (double)node->bytes.direct; - mean = bytes / allocs; - variance = allocs * node->sqsum - bytes * bytes; - if (variance < 0 || allocs == 1) - variance = 0; + if (js_mode) + fputs(" },\n", fp); else - variance /= allocs * (allocs - 1); - sigma = sqrt(variance); - - name = graphnode_name(node); - namelen = strlen(name); - fprintf(fp, - "" - "" - "" - "" - "" - "\n", - (namelen > 65) ? 45 : (int)namelen, name, - (namelen > 65) ? "..." : "", - prettybig((uint32)mean, buf1, sizeof buf1), - prettybig((uint32)sigma, buf2, sizeof buf2), - prettybig(node->allocs.direct, buf3, sizeof buf3)); + fputs("\n", fp); + } + + if (js_mode) { + fputs("]};\n", fp); + } else { + fputs("
Direct Allocators
%sMean SizeStdDevAllocations" - "
%.*s%s%s%s%s
\n
\n", fp); + + qsort(table, count, sizeof(graphnode*), mean_size_compare); + + fprintf(fp, + "\n" + "\n" + "" + "" + "" + "" + "\n", + title); + + for (i = 0; i < count; i++) { + double allocs, bytes, mean, variance, sigma; + + node = table[i]; + allocs = (double)node->allocs.direct; + if (!allocs) + continue; + + /* Compute direct-size mean and standard deviation. */ + bytes = (double)node->bytes.direct; + mean = bytes / allocs; + variance = allocs * node->sqsum - bytes * bytes; + if (variance < 0 || allocs == 1) + variance = 0; + else + variance /= allocs * (allocs - 1); + sigma = sqrt(variance); + + name = graphnode_name(node); + namelen = strlen(name); + fprintf(fp, + "" + "" + "" + "" + "" + "\n", + (namelen > 65) ? 45 : (int)namelen, name, + (namelen > 65) ? "..." : "", + prettybig((uint32)mean, buf1, sizeof buf1), + prettybig((uint32)sigma, buf2, sizeof buf2), + prettybig(node->allocs.direct, buf3, sizeof buf3)); + } + fputs("
Direct Allocators
%sMean SizeStdDevAllocations" + "
%.*s%s%s%s%s
\n", fp); } - fputs("\n", fp); free((void*) table); } @@ -820,11 +898,17 @@ static void process(const char *filename, FILE *fp) key = (const void*) event.u.method.library; hash = hash_serial(key); lib = (graphnode*) *PL_HashTableRawLookup(libraries, hash, key); - comp->up = lib; + if (lib) { + comp->up = lib; + comp->next = lib->down; + lib->down = comp; + } } *mark = save; meth->up = comp; + meth->next = comp->down; + comp->down = meth; break; } @@ -944,6 +1028,8 @@ static void process(const char *filename, FILE *fp) break; case 'Z': + if (js_mode) + break; fprintf(stdout, "

" "\n" @@ -1031,22 +1117,10 @@ static void process(const char *filename, FILE *fp) int main(int argc, char **argv) { - time_t start; int c, i; FILE *fp; program = *argv; - start = time(NULL); - fprintf(stdout, - "\n"); - fprintf(stdout, "%s starting at %s", program, ctime(&start)); - fflush(stdout); libraries = PL_NewHashTable(100, hash_serial, PL_CompareValues, PL_CompareStrings, &graphnode_hashallocops, @@ -1067,14 +1141,20 @@ int main(int argc, char **argv) exit(1); } - while ((c = getopt(argc, argv, "dtf:m:")) != EOF) { + while ((c = getopt(argc, argv, "djtuf:m:")) != EOF) { switch (c) { case 'd': sort_by_direct = 1; break; + case 'j': + js_mode = 1; + break; case 't': do_tree_dump = 1; break; + case 'u': + unified_output = 1; + break; case 'f': function_dump = optarg; break; @@ -1089,6 +1169,21 @@ int main(int argc, char **argv) } } + if (!js_mode) { + time_t start = time(NULL); + + fprintf(stdout, + "\n"); + fprintf(stdout, "%s starting at %s", program, ctime(&start)); + fflush(stdout); + } + argc -= optind; argv += optind; if (argc == 0) { @@ -1109,28 +1204,89 @@ int main(int argc, char **argv) compute_callsite_totals(&calltree_root); walk_callsite_tree(&calltree_root, 0, 0, stdout); - dump_graph(libraries, "Library", stdout); - fputs("
\n", stdout); - dump_graph(components, "Class or Component", stdout); - if (function_dump) { - struct stat sb, fsb; + if (js_mode) { + fprintf(stdout, + "\n" + "\n" + " \n" + " \n" + "\n", + stdout); + } } exit(0);
CounterValue