diff --git a/mozilla/tools/trace-malloc/bloatblame.c b/mozilla/tools/trace-malloc/bloatblame.c index 32383b0a27f..5461b6b2ac9 100644 --- a/mozilla/tools/trace-malloc/bloatblame.c +++ b/mozilla/tools/trace-malloc/bloatblame.c @@ -62,45 +62,6 @@ static int unified_output = 0; static char *function_dump = NULL; static uint32 min_subtotal = 0; -static void connect_nodes(tmgraphnode *from, tmgraphnode *to, tmcallsite *site) -{ - tmgraphlink *link; - tmgraphedge *edge; - - for (link = from->out; link; link = link->next) { - if (link->node == to) { - /* - * Say the stack looks like this: ... => JS => js => JS => js. - * We must avoid overcounting JS=>js because the first edge total - * includes the second JS=>js edge's total (which is because the - * lower site's total includes all its kids' totals). - */ - edge = TM_LINK_TO_EDGE(link, TM_EDGE_OUT_LINK); - if (!to->low || to->low < from->low) { - /* Add the direct and total counts to edge->allocs. */ - edge->allocs.bytes.direct += site->allocs.bytes.direct; - edge->allocs.bytes.total += site->allocs.bytes.total; - edge->allocs.calls.direct += site->allocs.calls.direct; - edge->allocs.calls.total += site->allocs.calls.total; - } - return; - } - } - - edge = (tmgraphedge*) malloc(sizeof(tmgraphedge)); - if (!edge) { - perror(program); - exit(1); - } - edge->links[TM_EDGE_OUT_LINK].node = to; - edge->links[TM_EDGE_OUT_LINK].next = from->out; - from->out = &edge->links[TM_EDGE_OUT_LINK]; - edge->links[TM_EDGE_IN_LINK].node = from; - edge->links[TM_EDGE_IN_LINK].next = to->in; - to->in = &edge->links[TM_EDGE_IN_LINK]; - edge->allocs = site->allocs; -} - static void compute_callsite_totals(tmcallsite *site) { tmcallsite *kid; @@ -132,7 +93,8 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp meth->allocs.bytes.total += site->allocs.bytes.total; meth->allocs.calls.total += site->allocs.calls.total; } - connect_nodes(pmeth, meth, site); + if (!tmgraphnode_connect(pmeth, meth, site)) + goto bad; comp = meth->up; if (comp) { @@ -144,7 +106,8 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp comp->allocs.calls.total += site->allocs.calls.total; } - connect_nodes(pcomp, comp, site); + if (!tmgraphnode_connect(pcomp, comp, site)) + goto bad; lib = comp->up; if (lib) { @@ -156,7 +119,8 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp lib->allocs.calls.total += site->allocs.calls.total; } - connect_nodes(plib, lib, site); + if (!tmgraphnode_connect(plib, lib, site)) + goto bad; } old_lib_low = lib->low; if (!old_lib_low) @@ -200,6 +164,11 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp } } } + return; + +bad: + perror(program); + exit(1); } /* diff --git a/mozilla/tools/trace-malloc/tmreader.c b/mozilla/tools/trace-malloc/tmreader.c index e4ed543d008..5d97d5ce42c 100644 --- a/mozilla/tools/trace-malloc/tmreader.c +++ b/mozilla/tools/trace-malloc/tmreader.c @@ -653,3 +653,48 @@ tmcallsite *tmreader_callsite(tmreader *tmr, uint32 serial) hash = hash_serial(key); return (tmcallsite*) *PL_HashTableRawLookup(tmr->callsites, hash, key); } + +int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, tmcallsite *site) +{ + tmgraphlink *outlink; + tmgraphedge *edge; + + for (outlink = from->out; outlink; outlink = outlink->next) { + if (outlink->node == to) { + /* + * Say the stack looks like this: ... => JS => js => JS => js. + * We must avoid overcounting JS=>js because the first edge total + * includes the second JS=>js edge's total (which is because the + * lower site's total includes all its kids' totals). + */ + edge = TM_LINK_TO_EDGE(outlink, TM_EDGE_OUT_LINK); + if (!to->low || to->low < from->low) { + /* Add the direct and total counts to edge->allocs. */ + edge->allocs.bytes.direct += site->allocs.bytes.direct; + edge->allocs.bytes.total += site->allocs.bytes.total; + edge->allocs.calls.direct += site->allocs.calls.direct; + edge->allocs.calls.total += site->allocs.calls.total; + + /* Now update the free counts. */ + edge->frees.bytes.direct += site->frees.bytes.direct; + edge->frees.bytes.total += site->frees.bytes.total; + edge->frees.calls.direct += site->frees.calls.direct; + edge->frees.calls.total += site->frees.calls.total; + } + return 1; + } + } + + edge = (tmgraphedge*) malloc(sizeof(tmgraphedge)); + if (!edge) + return 0; + edge->links[TM_EDGE_OUT_LINK].node = to; + edge->links[TM_EDGE_OUT_LINK].next = from->out; + from->out = &edge->links[TM_EDGE_OUT_LINK]; + edge->links[TM_EDGE_IN_LINK].node = from; + edge->links[TM_EDGE_IN_LINK].next = to->in; + to->in = &edge->links[TM_EDGE_IN_LINK]; + edge->allocs = site->allocs; + edge->frees = site->frees; + return 1; +} diff --git a/mozilla/tools/trace-malloc/tmreader.h b/mozilla/tools/trace-malloc/tmreader.h index d33bc711819..a3c13436f81 100644 --- a/mozilla/tools/trace-malloc/tmreader.h +++ b/mozilla/tools/trace-malloc/tmreader.h @@ -169,6 +169,24 @@ extern tmgraphnode *tmreader_component(tmreader *tmr, const char *name); extern tmgraphnode *tmreader_method(tmreader *tmr, uint32 serial); extern tmcallsite *tmreader_callsite(tmreader *tmr, uint32 serial); +/* + * Connect node 'from' to node 'to' with an edge, if there isn't one already + * connecting the nodes. Add site's allocation stats to the edge only if we + * create the edge, or if we find that it exists, but that to->low is zero or + * less than from->low. + * + * If the callsite tree already totals allocation costs (tmcounts.total for + * each site includes tmcounts.direct for that site, plus tmcounts.total for + * all kid sites), then the node->low watermarks should be set from the tree + * level when walking the callsite tree, and should be set to non-zero values + * only if zero (the root is at level 0). A low watermark should be cleared + * when the tree walk unwinds past the level at which it was set non-zero. + * + * Return 0 on error (malloc failure) and 1 on success. + */ +extern int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, + tmcallsite *site); + PR_END_EXTERN_C #endif /* tmreader_h___ */ diff --git a/mozilla/xpcom/base/bloatblame.c b/mozilla/xpcom/base/bloatblame.c index 32383b0a27f..5461b6b2ac9 100644 --- a/mozilla/xpcom/base/bloatblame.c +++ b/mozilla/xpcom/base/bloatblame.c @@ -62,45 +62,6 @@ static int unified_output = 0; static char *function_dump = NULL; static uint32 min_subtotal = 0; -static void connect_nodes(tmgraphnode *from, tmgraphnode *to, tmcallsite *site) -{ - tmgraphlink *link; - tmgraphedge *edge; - - for (link = from->out; link; link = link->next) { - if (link->node == to) { - /* - * Say the stack looks like this: ... => JS => js => JS => js. - * We must avoid overcounting JS=>js because the first edge total - * includes the second JS=>js edge's total (which is because the - * lower site's total includes all its kids' totals). - */ - edge = TM_LINK_TO_EDGE(link, TM_EDGE_OUT_LINK); - if (!to->low || to->low < from->low) { - /* Add the direct and total counts to edge->allocs. */ - edge->allocs.bytes.direct += site->allocs.bytes.direct; - edge->allocs.bytes.total += site->allocs.bytes.total; - edge->allocs.calls.direct += site->allocs.calls.direct; - edge->allocs.calls.total += site->allocs.calls.total; - } - return; - } - } - - edge = (tmgraphedge*) malloc(sizeof(tmgraphedge)); - if (!edge) { - perror(program); - exit(1); - } - edge->links[TM_EDGE_OUT_LINK].node = to; - edge->links[TM_EDGE_OUT_LINK].next = from->out; - from->out = &edge->links[TM_EDGE_OUT_LINK]; - edge->links[TM_EDGE_IN_LINK].node = from; - edge->links[TM_EDGE_IN_LINK].next = to->in; - to->in = &edge->links[TM_EDGE_IN_LINK]; - edge->allocs = site->allocs; -} - static void compute_callsite_totals(tmcallsite *site) { tmcallsite *kid; @@ -132,7 +93,8 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp meth->allocs.bytes.total += site->allocs.bytes.total; meth->allocs.calls.total += site->allocs.calls.total; } - connect_nodes(pmeth, meth, site); + if (!tmgraphnode_connect(pmeth, meth, site)) + goto bad; comp = meth->up; if (comp) { @@ -144,7 +106,8 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp comp->allocs.calls.total += site->allocs.calls.total; } - connect_nodes(pcomp, comp, site); + if (!tmgraphnode_connect(pcomp, comp, site)) + goto bad; lib = comp->up; if (lib) { @@ -156,7 +119,8 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp lib->allocs.calls.total += site->allocs.calls.total; } - connect_nodes(plib, lib, site); + if (!tmgraphnode_connect(plib, lib, site)) + goto bad; } old_lib_low = lib->low; if (!old_lib_low) @@ -200,6 +164,11 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp } } } + return; + +bad: + perror(program); + exit(1); } /* diff --git a/mozilla/xpcom/base/tmreader.c b/mozilla/xpcom/base/tmreader.c index e4ed543d008..5d97d5ce42c 100644 --- a/mozilla/xpcom/base/tmreader.c +++ b/mozilla/xpcom/base/tmreader.c @@ -653,3 +653,48 @@ tmcallsite *tmreader_callsite(tmreader *tmr, uint32 serial) hash = hash_serial(key); return (tmcallsite*) *PL_HashTableRawLookup(tmr->callsites, hash, key); } + +int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, tmcallsite *site) +{ + tmgraphlink *outlink; + tmgraphedge *edge; + + for (outlink = from->out; outlink; outlink = outlink->next) { + if (outlink->node == to) { + /* + * Say the stack looks like this: ... => JS => js => JS => js. + * We must avoid overcounting JS=>js because the first edge total + * includes the second JS=>js edge's total (which is because the + * lower site's total includes all its kids' totals). + */ + edge = TM_LINK_TO_EDGE(outlink, TM_EDGE_OUT_LINK); + if (!to->low || to->low < from->low) { + /* Add the direct and total counts to edge->allocs. */ + edge->allocs.bytes.direct += site->allocs.bytes.direct; + edge->allocs.bytes.total += site->allocs.bytes.total; + edge->allocs.calls.direct += site->allocs.calls.direct; + edge->allocs.calls.total += site->allocs.calls.total; + + /* Now update the free counts. */ + edge->frees.bytes.direct += site->frees.bytes.direct; + edge->frees.bytes.total += site->frees.bytes.total; + edge->frees.calls.direct += site->frees.calls.direct; + edge->frees.calls.total += site->frees.calls.total; + } + return 1; + } + } + + edge = (tmgraphedge*) malloc(sizeof(tmgraphedge)); + if (!edge) + return 0; + edge->links[TM_EDGE_OUT_LINK].node = to; + edge->links[TM_EDGE_OUT_LINK].next = from->out; + from->out = &edge->links[TM_EDGE_OUT_LINK]; + edge->links[TM_EDGE_IN_LINK].node = from; + edge->links[TM_EDGE_IN_LINK].next = to->in; + to->in = &edge->links[TM_EDGE_IN_LINK]; + edge->allocs = site->allocs; + edge->frees = site->frees; + return 1; +} diff --git a/mozilla/xpcom/base/tmreader.h b/mozilla/xpcom/base/tmreader.h index d33bc711819..a3c13436f81 100644 --- a/mozilla/xpcom/base/tmreader.h +++ b/mozilla/xpcom/base/tmreader.h @@ -169,6 +169,24 @@ extern tmgraphnode *tmreader_component(tmreader *tmr, const char *name); extern tmgraphnode *tmreader_method(tmreader *tmr, uint32 serial); extern tmcallsite *tmreader_callsite(tmreader *tmr, uint32 serial); +/* + * Connect node 'from' to node 'to' with an edge, if there isn't one already + * connecting the nodes. Add site's allocation stats to the edge only if we + * create the edge, or if we find that it exists, but that to->low is zero or + * less than from->low. + * + * If the callsite tree already totals allocation costs (tmcounts.total for + * each site includes tmcounts.direct for that site, plus tmcounts.total for + * all kid sites), then the node->low watermarks should be set from the tree + * level when walking the callsite tree, and should be set to non-zero values + * only if zero (the root is at level 0). A low watermark should be cleared + * when the tree walk unwinds past the level at which it was set non-zero. + * + * Return 0 on error (malloc failure) and 1 on success. + */ +extern int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, + tmcallsite *site); + PR_END_EXTERN_C #endif /* tmreader_h___ */