/* dump out a Paragraph in the desired manner */ static Paragraph* display(Paragraph *p, MMIOT *f) { if ( !p ) return 0; switch ( p->typ ) { case STYLE: case WHITESPACE: break; case HTML: printhtml(p->text, f); break; case CODE: printcode(p->text, f); break; case QUOTE: htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f); break; case UL: case OL: case AL: listdisplay(p->typ, p->down, f); break; #if DL_TAG_EXTENSION case DL: definitionlist(p->down, f); break; #endif case HR: Qstring("<hr />", f); break; case HDR: printheader(p, f); break; case TABLE: printtable(p, f); break; case SOURCE: htmlify(p->down, 0, 0, f); break; default: printblock(p, f); break; } return p->next; }
/* return a pointer to the compiled markdown * document. */ int mkd_document(Document *p, char **res, int easyNewLine) { int size; if ( p && p->compiled ) { if ( ! p->html ) { // MK HACK if (p->code) { p->code->easyNewline = easyNewLine; } htmlify(p->code, 0, 0, p->ctx); p->html = 1; } size = S(p->ctx->out); if ( (size == 0) || T(p->ctx->out)[size-1] ) EXPAND(p->ctx->out) = 0; *res = T(p->ctx->out); return size; } return EOF; }
void FunctionCount::printReport(FILE *fp, leaky *lk, int parent, int total) { const char *fmt = " <A href=\"#%d\">%8d (%3.1f%%)%s %s</A>%s\n"; int nmax, tmax=((~0U)>>1); do { nmax=0; for(int j=getSize(); --j>=0;) { int cnt = getCount(j); if(cnt==tmax) { int idx = getIndex(j); char *symname = htmlify(lk->indexToName(idx)); fprintf(fp, fmt, idx, getCount(j), getCount(j)*100.0/total, getCount(j)*100.0/total >= 10.0 ? "" : " ", symname, parent == idx ? " (self)" : ""); delete [] symname; } else if(cnt<tmax && cnt>nmax) { nmax=cnt; } } } while((tmax=nmax)>0); }
static void definitionlist(Paragraph *p, MMIOT *f) { Line *tag; if ( p ) { Qstring("<dl>\n", f); for ( ; p ; p = p->next) { for ( tag = p->text; tag; tag = tag->next ) { Qstring("<dt>", f); ___mkd_reparse(T(tag->text), S(tag->text), 0, f); Qstring("</dt>\n", f); } // MK HACK if (p->down) { p->down->easyNewline = p->easyNewline; } htmlify(p->down, "dd", p->ident, f); Qchar('\n', f); } Qstring("</dl>", f); } }
/* return a pointer to the compiled markdown * document. */ int mkd_document(Document *p, char **res) { if ( p && p->compiled ) { if ( ! p->html ) { htmlify(p->code, 0, 0, p->ctx); p->html = 1; } *res = T(p->ctx->out); return S(p->ctx->out); } return EOF; }
static void listdisplay(int typ, Paragraph *p, MMIOT* f) { if ( p ) { Qprintf(f, "<%cl>\n", (typ==UL)?'u':'o'); for ( ; p ; p = p->next ) { htmlify(p->down, "li", f); Qchar('\n', f); } Qprintf(f, "</%cl>\n", (typ==UL)?'u':'o'); } }
static void listdisplay(int typ, Paragraph *p, MMIOT* f) { if ( p ) { Qprintf(f, "<%cl", (typ==UL)?'u':'o'); if ( typ == AL ) Qprintf(f, " type=\"a\""); Qprintf(f, ">\n"); for ( ; p ; p = p->next ) { if (p->down) { p->down->easyNewline = p->easyNewline; } htmlify(p->down, "li", p->ident, f); Qchar('\n', f); } Qprintf(f, "</%cl>\n", (typ==UL)?'u':'o'); } }
static void definitionlist(Paragraph *p, MMIOT *f) { Line *tag; if ( p ) { Qstring("<dl>\n", f); for ( ; p ; p = p->next) { for ( tag = p->text; tag; tag = tag->next ) { Qstring("<dt>", f); reparse(T(tag->text), S(tag->text), 0, f); Qstring("</dt>\n", f); } htmlify(p->down, "dd", f); } Qstring("</dl>", f); } }
void leaky::analyze(int thread) { int *countArray = new int[usefulSymbols]; int *flagArray = new int[usefulSymbols]; //Zero our function call counter memset(countArray, 0, sizeof(countArray[0])*usefulSymbols); // reset hit counts for(int i=0; i<usefulSymbols; i++) { externalSymbols[i]->timerHit = 0; externalSymbols[i]->regClear(); } // The flag array is used to prevent counting symbols multiple times // if functions are called recursively. In order to keep from having // to zero it on each pass through the loop, we mark it with the value // of stacks on each trip through the loop. This means we can determine // if we have seen this symbol for this stack trace w/o having to reset // from the prior stacktrace. memset(flagArray, -1, sizeof(flagArray[0])*usefulSymbols); if (cleo) fprintf(outputfd,"m-Start\n"); // This loop walks through all the call stacks we recorded // --last, --start and --end can restrict it, as can excludes/includes stacks = 0; for(malloc_log_entry* lep=firstLogEntry; lep < lastLogEntry; lep = reinterpret_cast<malloc_log_entry*>(&lep->pcs[lep->numpcs])) { if ((thread != 0 && lep->thread != thread) || excluded(lep) || !included(lep)) { continue; } ++stacks; // How many stack frames did we collect u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; char** pcp = &lep->pcs[n-1]; int idx=-1, parrentIdx=-1; // Init idx incase n==0 if (cleo) { // This loop walks through every symbol in the call stack. By walking it // backwards we know who called the function when we get there. char type = 's'; for (int i=n-1; i>=0; --i, --pcp) { idx = findSymbolIndex(reinterpret_cast<u_long>(*pcp)); if(idx>=0) { // Skip over bogus __restore_rt frames that realtime profiling // can introduce. if (i > 0 && !strcmp(externalSymbols[idx]->name, "__restore_rt")) { --pcp; --i; idx = findSymbolIndex(reinterpret_cast<u_long>(*pcp)); if (idx < 0) { continue; } } Symbol **sp=&externalSymbols[idx]; char *symname = htmlify((*sp)->name); fprintf(outputfd,"%c-%s\n",type,symname); delete [] symname; } // else can't find symbol - ignore type = 'c'; } } else { // This loop walks through every symbol in the call stack. By walking it // backwards we know who called the function when we get there. for (int i=n-1; i>=0; --i, --pcp) { idx = findSymbolIndex(reinterpret_cast<u_long>(*pcp)); if(idx>=0) { // Skip over bogus __restore_rt frames that realtime profiling // can introduce. if (i > 0 && !strcmp(externalSymbols[idx]->name, "__restore_rt")) { --pcp; --i; idx = findSymbolIndex(reinterpret_cast<u_long>(*pcp)); if (idx < 0) { continue; } } // If we have not seen this symbol before count it and mark it as seen if(flagArray[idx]!=stacks && ((flagArray[idx]=stacks) || true)) { ++countArray[idx]; } // We know who we are and we know who our parrent is. Count this if(parrentIdx>=0) { externalSymbols[parrentIdx]->regChild(idx); externalSymbols[idx]->regParrent(parrentIdx); } // inside if() so an unknown in the middle of a stack won't break // the link! parrentIdx=idx; } } // idx should be the function that we were in when we received the signal. if(idx>=0) { ++externalSymbols[idx]->timerHit; } } } if (!cleo) generateReportHTML(outputfd, countArray, stacks, thread); }
void leaky::generateReportHTML(FILE *fp, int *countArray, int count, int thread) { fprintf(fp,"<center>"); if (showThreads) { fprintf(fp,"<hr><A NAME=thread_%d><b>Thread: %d</b></A><p>", thread,thread); } fprintf(fp,"<A href=#flat_%d>flat</A><b> | </b><A href=#hier_%d>hierarchical</A>", thread,thread); fprintf(fp,"</center><P><P><P>\n"); int totalTimerHits = count; int *rankingTable = new int[usefulSymbols]; for(int cnt=usefulSymbols; --cnt>=0; rankingTable[cnt]=cnt); // Drat. I would use ::qsort() but I would need a global variable and my // intro-pascal professor threatened to flunk anyone who used globals. // She damaged me for life :-) (That was 1986. See how much influence // she had. I don't remember her name but I always feel guilty about globals) // Shell Sort. 581130733 is the max 31 bit value of h = 3h+1 int mx, i, h; for(mx=usefulSymbols/9, h=581130733; h>0; h/=3) { if(h<mx) { for(i = h-1; i<usefulSymbols; i++) { int j, tmp=rankingTable[i], val = countArray[tmp]; for(j = i; (j>=h) && (countArray[rankingTable[j-h]]<val); j-=h) { rankingTable[j] = rankingTable[j-h]; } rankingTable[j] = tmp; } } } // Ok, We are sorted now. Let's go through the table until we get to // functions that were never called. Right now we don't do much inside // this loop. Later we can get callers and callees into it like gprof // does fprintf(fp, "<h2><A NAME=hier_%d></A><center><a href=\"http://mxr.mozilla.org/mozilla-central/source/tools/jprof/README.html#hier\">Hierarchical Profile</a></center></h2><hr>\n", thread); fprintf(fp, "<pre>\n"); fprintf(fp, "%6s %6s %4s %s\n", "index", "Count", "Hits", "Function Name"); for(i=0; i<usefulSymbols && countArray[rankingTable[i]]>0; i++) { Symbol **sp=&externalSymbols[rankingTable[i]]; (*sp)->cntP.printReport(fp, this, rankingTable[i], totalTimerHits); char *symname = htmlify((*sp)->name); fprintf(fp, "%6d %6d (%3.1f%%)%s <a name=%d>%8d (%3.1f%%)</a>%s <b>%s</b>\n", rankingTable[i], (*sp)->timerHit, ((*sp)->timerHit*1000/totalTimerHits)/10.0, ((*sp)->timerHit*1000/totalTimerHits)/10.0 >= 10.0 ? "" : " ", rankingTable[i], countArray[rankingTable[i]], (countArray[rankingTable[i]]*1000/totalTimerHits)/10.0, (countArray[rankingTable[i]]*1000/totalTimerHits)/10.0 >= 10.0 ? "" : " ", symname); delete [] symname; (*sp)->cntC.printReport(fp, this, rankingTable[i], totalTimerHits); fprintf(fp, "<hr>\n"); } fprintf(fp,"</pre>\n"); // OK, Now we want to print the flat profile. To do this we resort on // the hit count. // Cut-N-Paste Shell sort from above. The Ranking Table has already been // populated, so we do not have to reinitialize it. for(mx=usefulSymbols/9, h=581130733; h>0; h/=3) { if(h<mx) { for(i = h-1; i<usefulSymbols; i++) { int j, tmp=rankingTable[i], val = externalSymbols[tmp]->timerHit; for(j = i; (j>=h) && (externalSymbols[rankingTable[j-h]]->timerHit<val); j-=h) { rankingTable[j] = rankingTable[j-h]; } rankingTable[j] = tmp; } } } // Pre-count up total counter hits, to get a percentage. // I wanted the total before walking the list, if this // double-pass over externalSymbols gets slow we can // do single-pass and print this out after the loop finishes. totalTimerHits = 0; for(i=0; i<usefulSymbols && externalSymbols[rankingTable[i]]->timerHit>0; i++) { Symbol **sp=&externalSymbols[rankingTable[i]]; totalTimerHits += (*sp)->timerHit; } if (totalTimerHits == 0) totalTimerHits = 1; if (totalTimerHits != count) fprintf(stderr,"Hit count mismatch: count=%d; totalTimerHits=%d", count,totalTimerHits); fprintf(fp,"<h2><A NAME=flat_%d></A><center><a href=\"http://mxr.mozilla.org/mozilla-central/source/tools/jprof/README.html#flat\">Flat Profile</a></center></h2><br>\n", thread); fprintf(fp, "<pre>\n"); fprintf(fp, "Total hit count: %d\n", totalTimerHits); fprintf(fp, "Count %%Total Function Name\n"); // Now loop for as long as we have timer hits for(i=0; i<usefulSymbols && externalSymbols[rankingTable[i]]->timerHit>0; i++) { Symbol **sp=&externalSymbols[rankingTable[i]]; char *symname = htmlify((*sp)->name); fprintf(fp, "<a href=\"#%d\">%3d %-2.1f %s</a>\n", rankingTable[i], (*sp)->timerHit, ((float)(*sp)->timerHit/(float)totalTimerHits)*100.0, symname); delete [] symname; } }
/* dump out a Paragraph in the desired manner */ static Paragraph* display(Paragraph *p, MMIOT *f, int easyNewLine) { if ( !p ) return 0; switch ( p->typ ) { case STYLE: case WHITESPACE: break; case HTML: printhtml(p->text, f); break; case CODE: printcode(p->text, f); break; case QUOTE: if (p->down) { p->down->easyNewline = p->easyNewline; } htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f); break; case UL: case OL: case AL: listdisplay(p->typ, p->down, f); break; case DL: definitionlist(p->down, f); break; case HR: Qstring("<hr />", f); break; case HDR: printheader(p, f); break; case TABLE: printtable(p, f); break; case SOURCE: if (p->down) { p->down->easyNewline = p->easyNewline; } htmlify(p->down, 0, 0, f); break; default: printblock(p, f, easyNewLine); break; } // MK HACK, copy easyNewLine Paragraph *pNext = p->next; if (pNext) { pNext->easyNewline = p->easyNewline; } return pNext; }