From 9a999cfdbe913e90f0123c39b280c2dfffeface1 Mon Sep 17 00:00:00 2001 From: "kipp%netscape.com" Date: Mon, 4 Oct 1999 16:32:03 +0000 Subject: [PATCH] Added -R flag and logic for managing refcnt dumping better --- tools/leaky/leaky.cpp | 221 ++++++++++++++++++++++++++++++------------ tools/leaky/leaky.h | 17 +++- 2 files changed, 171 insertions(+), 67 deletions(-) diff --git a/tools/leaky/leaky.cpp b/tools/leaky/leaky.cpp index f7689f20369b..28a7f74d8ad3 100644 --- a/tools/leaky/leaky.cpp +++ b/tools/leaky/leaky.cpp @@ -52,18 +52,20 @@ leaky::leaky() progFile = NULL; sortByFrequency = FALSE; - dumpAll = FALSE; + dumpLeaks = FALSE; dumpGraph = FALSE; dumpHTML = FALSE; quiet = FALSE; - showAll = FALSE; + dumpEntireLog = FALSE; showAddress = FALSE; stackDepth = 100000; + dumpRefcnts = false; mappedLogFile = -1; firstLogEntry = lastLogEntry = 0; buckets = DefaultBuckets; - dict = 0; + dict = NULL; + refcntDict = NULL; mallocs = 0; reallocs = 0; @@ -90,7 +92,7 @@ leaky::~leaky() void leaky::usageError() { fprintf(stderr, - "Usage: %s [-aAEdfgqx] [-e name] [-s depth] [-h hash-buckets] [-r root] prog log\n", + "Usage: %s [-aAEdfgqxR] [-e name] [-s depth] [-h hash-buckets] [-r root|-i symbol] prog log\n", (char*) applicationName); exit(-1); } @@ -107,21 +109,24 @@ void leaky::initialize(int argc, char** argv) int arg; int errflg = 0; - while ((arg = getopt(argc, argv, "adEe:fgh:r:s:tqx")) != -1) { + while ((arg = getopt(argc, argv, "adEe:fgh:i:r:Rs:tqx")) != -1) { switch (arg) { case '?': errflg++; break; case 'a': - showAll = TRUE; + dumpEntireLog = TRUE; break; case 'A': showAddress = TRUE; break; case 'd': - dumpAll = TRUE; + dumpLeaks = TRUE; if (dumpGraph) errflg++; break; + case 'R': + dumpRefcnts = true; + break; case 'e': exclusions.add(optarg); break; @@ -130,10 +135,19 @@ void leaky::initialize(int argc, char** argv) break; case 'g': dumpGraph = TRUE; - if (dumpAll) errflg++; + if (dumpLeaks) errflg++; break; case 'r': roots.add(optarg); + if (!includes.IsEmpty()) { + errflg++; + } + break; + case 'i': + includes.add(optarg); + if (!roots.IsEmpty()) { + errflg++; + } break; case 'h': buckets = atoi(optarg); @@ -165,6 +179,9 @@ void leaky::initialize(int argc, char** argv) logFile = argv[optind]; dict = new MallocDict(buckets); + if (dumpRefcnts) { + refcntDict = new MallocDict(buckets); + } } static void* mapFile(int fd, u_int flags, off_t* sz) @@ -230,7 +247,7 @@ void leaky::open() analyze(); - if (dumpAll) { + if (dumpLeaks || dumpEntireLog || dumpRefcnts) { dumpLog(); } else if (dumpGraph) { @@ -308,17 +325,38 @@ Symbol* leaky::findSymbol(u_long addr) //---------------------------------------------------------------------- -int leaky::excluded(malloc_log_entry* lep) +bool leaky::excluded(malloc_log_entry* lep) { + if (exclusions.IsEmpty()) { + return false; + } + char** pcp = &lep->pcs[0]; u_int n = lep->numpcs; for (u_int i = 0; i < n; i++, pcp++) { Symbol* sp = findSymbol((u_long) *pcp); if (sp && exclusions.contains(sp->name)) { - return TRUE; + return true; } } - return FALSE; + return false; +} + +bool leaky::included(malloc_log_entry* lep) +{ + if (includes.IsEmpty()) { + return true; + } + + char** pcp = &lep->pcs[0]; + u_int n = lep->numpcs; + for (u_int i = 0; i < n; i++, pcp++) { + Symbol* sp = findSymbol((u_long) *pcp); + if (sp && includes.contains(sp->name)) { + return true; + } + } + return false; } //---------------------------------------------------------------------- @@ -368,20 +406,49 @@ void leaky::dumpEntryToLog(malloc_log_entry* lep) displayStackTrace(stdout, lep); } +bool leaky::ShowThisEntry(malloc_log_entry* lep) +{ + if ((!dumpRefcnts || IsRefcnt(lep)) && !excluded(lep) && included(lep)) { + return true; + } + return false; +} + void leaky::dumpLog() { - if (showAll) { - malloc_log_entry* lep = firstLogEntry; - while (lep < lastLogEntry) { - dumpEntryToLog(lep); - lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; - } - } else { - malloc_log_entry* lep; - dict->rewind(); - while (NULL != (lep = dict->next())) { - if (!excluded(lep)) { - dumpEntryToLog(lep); + if (dumpRefcnts) { + malloc_log_entry* lep; + refcntDict->rewind(); + while (NULL != (lep = refcntDict->next())) { + if (ShowThisEntry(lep)) { + // Now we get slow... + u_long addr = lep->address; + malloc_log_entry* lep2 = firstLogEntry; + while (lep2 < lastLogEntry) { + if (lep2->address == addr) { + dumpEntryToLog(lep2); + } + lep2 = (malloc_log_entry*) &lep2->pcs[lep2->numpcs]; + } + } + } + } + else { + if (dumpEntireLog) { + malloc_log_entry* lep = firstLogEntry; + while (lep < lastLogEntry) { + if (ShowThisEntry(lep)) { + dumpEntryToLog(lep); + } + lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; + } + } else { + malloc_log_entry* lep; + dict->rewind(); + while (NULL != (lep = dict->next())) { + if (ShowThisEntry(lep)) { + dumpEntryToLog(lep); + } } } } @@ -449,6 +516,30 @@ void leaky::analyze() } frees++; break; + case malloc_log_addref: + if (dumpRefcnts) { + if (lep->size == 0) { + // Initial addref + u_long addr = (u_long) lep->address; + malloc_log_entry** lepp = refcntDict->find(addr); + if (!lepp) { + refcntDict->add(addr, lep); + } + } + } + break; + case malloc_log_release: + if (dumpRefcnts) { + if (lep->oldaddress == 0) { + // Final release + u_long addr = (u_long) lep->address; + malloc_log_entry** lepp = refcntDict->find(addr); + if (lepp) { + refcntDict->remove(addr); + } + } + } + break; } lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; } @@ -476,52 +567,54 @@ void leaky::buildLeakGraph() malloc_log_entry* lep; dict->rewind(); while (NULL != (lep = dict->next())) { - char** basepcp = &lep->pcs[0]; - char** pcp = &lep->pcs[lep->numpcs - 1]; + if (ShowThisEntry(lep)) { + char** basepcp = &lep->pcs[0]; + char** pcp = &lep->pcs[lep->numpcs - 1]; - // Find root for this allocation - Symbol* sym = findSymbol((u_long) *pcp); - TreeNode* node = sym->root; - if (!node) { - sym->root = node = new TreeNode(sym); + // Find root for this allocation + Symbol* sym = findSymbol((u_long) *pcp); + TreeNode* node = sym->root; + if (!node) { + sym->root = node = new TreeNode(sym); - // Add root to list of roots - if (roots.IsEmpty()) { - node->nextRoot = rootList; - rootList = node; + // Add root to list of roots + if (roots.IsEmpty()) { + node->nextRoot = rootList; + rootList = node; + } } - } - pcp--; + pcp--; - // Build tree underneath the root - for (; pcp >= basepcp; pcp--) { - // Share nodes in the tree until there is a divergence - sym = findSymbol((u_long) *pcp); - if (!sym) { - break; - } - TreeNode* nextNode = node->GetDirectDescendant(sym); - if (!nextNode) { - // Make a new node at the point of divergence - nextNode = node->AddDescendant(sym); - } + // Build tree underneath the root + for (; pcp >= basepcp; pcp--) { + // Share nodes in the tree until there is a divergence + sym = findSymbol((u_long) *pcp); + if (!sym) { + break; + } + TreeNode* nextNode = node->GetDirectDescendant(sym); + if (!nextNode) { + // Make a new node at the point of divergence + nextNode = node->AddDescendant(sym); + } - // See if the symbol is to be a user specified root. If it is, - // and we haven't already stuck it on the root-list do so now. - if (!sym->root && !roots.IsEmpty() && roots.contains(sym->name)) { - sym->root = nextNode; - nextNode->nextRoot = rootList; - rootList = nextNode; - } + // See if the symbol is to be a user specified root. If it is, + // and we haven't already stuck it on the root-list do so now. + if (!sym->root && !roots.IsEmpty() && roots.contains(sym->name)) { + sym->root = nextNode; + nextNode->nextRoot = rootList; + rootList = nextNode; + } - if (pcp == basepcp) { - nextNode->bytesLeaked += lep->size; - } - else { - node->descendantBytesLeaked += lep->size; - } + if (pcp == basepcp) { + nextNode->bytesLeaked += lep->size; + } + else { + node->descendantBytesLeaked += lep->size; + } - node = nextNode; + node = nextNode; + } } } } @@ -542,7 +635,7 @@ void leaky::dumpLeakGraph() if (dumpHTML) { printf("Leaky Graph\n"); printf("\n"); - printf("\n"); + printf("\n"); printf("
\n"); printf("Key:
\n"); printf("Bytes directly leaked
\n"); diff --git a/tools/leaky/leaky.h b/tools/leaky/leaky.h index 608f55775adf..3bf4a27f2c60 100644 --- a/tools/leaky/leaky.h +++ b/tools/leaky/leaky.h @@ -84,12 +84,13 @@ struct leaky { char* progFile; int sortByFrequency; - int dumpAll; + int dumpLeaks; int dumpGraph; int dumpHTML; int quiet; - int showAll; + int dumpEntireLog; int showAddress; + bool dumpRefcnts; u_int stackDepth; int mappedLogFile; @@ -97,6 +98,7 @@ struct leaky { malloc_log_entry* lastLogEntry; u_int buckets; MallocDict* dict; + MallocDict* refcntDict; u_long mallocs; u_long reallocs; @@ -118,6 +120,7 @@ struct leaky { TreeNode* rootList; StrSet roots; + StrSet includes; void usageError(); @@ -142,13 +145,21 @@ struct leaky { void ReadSharedLibrarySymbols(); void setupSymbols(const char* fileName); Symbol* findSymbol(u_long address); - int excluded(malloc_log_entry* lep); + bool excluded(malloc_log_entry* lep); + bool included(malloc_log_entry* lep); void buildLeakGraph(); Symbol* findLeakGraphRoot(Symbol* aStart, Symbol* aEnd); void dumpLeakGraph(); void dumpLeakTree(TreeNode* aNode, int aIndent); + bool ShowThisEntry(malloc_log_entry* lep); + + bool IsRefcnt(malloc_log_entry* lep) const { + return (lep->type == malloc_log_addref) || + (lep->type == malloc_log_release); + } + static void indentBy(int aCount) { while (--aCount >= 0) fputs(" ", stdout); }