Added -R flag and logic for managing refcnt dumping better

This commit is contained in:
kipp%netscape.com 1999-10-04 16:32:03 +00:00
parent bbe0ad61fd
commit 9a999cfdbe
2 changed files with 171 additions and 67 deletions

View File

@ -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("<html><head><title>Leaky Graph</title>\n");
printf("<style src=\"resource:/res/leaky/leaky.css\"></style>\n");
printf("<script src=\"resource:/res/leaky/leaky.js\"/></script>\n");
printf("<script src=\"resource:/res/leaky/leaky.js\"></script>\n");
printf("</head><body><div class=\"key\">\n");
printf("Key:<br>\n");
printf("<span class=b>Bytes directly leaked</span><br>\n");

View File

@ -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);
}