summaryrefslogtreecommitdiffstats
path: root/tools/jprof/leaky.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/jprof/leaky.cpp')
-rw-r--r--tools/jprof/leaky.cpp863
1 files changed, 0 insertions, 863 deletions
diff --git a/tools/jprof/leaky.cpp b/tools/jprof/leaky.cpp
deleted file mode 100644
index d8e5322f5..000000000
--- a/tools/jprof/leaky.cpp
+++ /dev/null
@@ -1,863 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "leaky.h"
-#include "intcnt.h"
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#ifndef NTO
-#include <getopt.h>
-#endif
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef NTO
-#include <mem.h>
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-static const u_int DefaultBuckets = 10007; // arbitrary, but prime
-static const u_int MaxBuckets = 1000003; // arbitrary, but prime
-
-//----------------------------------------------------------------------
-
-int main(int argc, char** argv)
-{
- leaky* l = new leaky;
-
- l->initialize(argc, argv);
- l->outputfd = stdout;
-
- for (int i = 0; i < l->numLogFiles; i++) {
- if (l->output_dir || l->numLogFiles > 1) {
- char name[2048]; // XXX fix
- if (l->output_dir)
- snprintf(name,sizeof(name),"%s/%s.html",l->output_dir,argv[l->logFileIndex + i]);
- else
- snprintf(name,sizeof(name),"%s.html",argv[l->logFileIndex + i]);
-
- fprintf(stderr,"opening %s\n",name);
- l->outputfd = fopen(name,"w");
- // if an error we won't process the file
- }
- if (l->outputfd) { // paranoia
- l->open(argv[l->logFileIndex + i]);
-
- if (l->outputfd != stderr) {
- fclose(l->outputfd);
- l->outputfd = nullptr;
- }
- }
- }
-
- return 0;
-}
-
-char *
-htmlify(const char *in)
-{
- const char *p = in;
- char *out, *q;
- int n = 0;
- size_t newlen;
-
- // Count the number of '<' and '>' in the input.
- while ((p = strpbrk(p, "<>")))
- {
- ++n;
- ++p;
- }
-
- // Knowing the number of '<' and '>', we can calculate the space
- // needed for the output string.
- newlen = strlen(in) + n * 3 + 1;
- out = new char[newlen];
-
- // Copy the input to the output, with substitutions.
- p = in;
- q = out;
- do
- {
- if (*p == '<')
- {
- strcpy(q, "&lt;");
- q += 4;
- }
- else if (*p == '>')
- {
- strcpy(q, "&gt;");
- q += 4;
- }
- else
- {
- *q++ = *p;
- }
- p++;
- } while (*p);
- *q = '\0';
-
- return out;
-}
-
-leaky::leaky()
-{
- applicationName = nullptr;
- progFile = nullptr;
-
- quiet = true;
- showAddress = false;
- showThreads = false;
- stackDepth = 100000;
- onlyThread = 0;
- cleo = false;
-
- mappedLogFile = -1;
- firstLogEntry = lastLogEntry = 0;
-
- sfd = -1;
- externalSymbols = 0;
- usefulSymbols = 0;
- numExternalSymbols = 0;
- lowestSymbolAddr = 0;
- highestSymbolAddr = 0;
-
- loadMap = nullptr;
-
- collect_last = false;
- collect_start = -1;
- collect_end = -1;
-}
-
-leaky::~leaky()
-{
-}
-
-void leaky::usageError()
-{
- fprintf(stderr, "Usage: %s [-v] [-t] [-e exclude] [-i include] [-s stackdepth] [--last] [--all] [--start n [--end m]] [--cleo] [--output-dir dir] prog log [log2 ...]\n", (char*) applicationName);
- fprintf(stderr,
- "\t-v: verbose\n"
- "\t-t | --threads: split threads\n"
- "\t--only-thread n: only profile thread N\n"
- "\t-i include-id: stack must include specified id\n"
- "\t-e exclude-id: stack must NOT include specified id\n"
- "\t-s stackdepth: Limit depth looked at from captured stack frames\n"
- "\t--last: only profile the last capture section\n"
- "\t--start n [--end m]: profile n to m (or end) capture sections\n"
- "\t--cleo: format output for 'cleopatra' display\n"
- "\t--output-dir dir: write output files to dir\n"
- "\tIf there's one log, output goes to stdout unless --output-dir is set\n"
- "\tIf there are more than one log, output files will be named with .html added\n"
- );
- exit(-1);
-}
-
-static struct option longopts[] = {
- { "threads", 0, nullptr, 't' },
- { "only-thread", 1, nullptr, 'T' },
- { "last", 0, nullptr, 'l' },
- { "start", 1, nullptr, 'x' },
- { "end", 1, nullptr, 'n' },
- { "cleo",0, nullptr, 'c' },
- { "output-dir", 1, nullptr, 'd' },
- { nullptr, 0, nullptr, 0 },
-};
-
-void leaky::initialize(int argc, char** argv)
-{
- applicationName = argv[0];
- applicationName = strrchr(applicationName, '/');
- if (!applicationName) {
- applicationName = argv[0];
- } else {
- applicationName++;
- }
-
- int arg;
- int errflg = 0;
- int longindex = 0;
-
- onlyThread = 0;
- output_dir = nullptr;
- cleo = false;
-
- // XXX tons of cruft here left over from tracemalloc
- // XXX The -- options shouldn't need short versions, or they should be documented
- while (((arg = getopt_long(argc, argv, "adEe:gh:i:r:Rs:tT:qvx:ln:",longopts,&longindex)) != -1)) {
- switch (arg) {
- case '?':
- default:
- fprintf(stderr,"error: unknown option %c\n",optopt);
- errflg++;
- break;
- case 'a':
- break;
- case 'A': // not implemented
- showAddress = true;
- break;
- case 'c':
- cleo = true;
- break;
- case 'd':
- output_dir = optarg; // reference to an argv pointer
- break;
- case 'R':
- break;
- case 'e':
- exclusions.add(optarg);
- break;
- case 'g':
- break;
- case 'r': // not implemented
- roots.add(optarg);
- if (!includes.IsEmpty()) {
- errflg++;
- }
- break;
- case 'i':
- includes.add(optarg);
- if (!roots.IsEmpty()) {
- errflg++;
- }
- break;
- case 'h':
- break;
- case 's':
- stackDepth = atoi(optarg);
- if (stackDepth < 2) {
- stackDepth = 2;
- }
- break;
- case 'x':
- // --start
- collect_start = atoi(optarg);
- break;
- case 'n':
- // --end
- collect_end = atoi(optarg);
- break;
- case 'l':
- // --last
- collect_last = true;
- break;
- case 'q':
- break;
- case 'v':
- quiet = !quiet;
- break;
- case 't':
- showThreads = true;
- break;
- case 'T':
- showThreads = true;
- onlyThread = atoi(optarg);
- break;
- }
- }
- if (errflg || ((argc - optind) < 2)) {
- usageError();
- }
- progFile = argv[optind++];
- logFileIndex = optind;
- numLogFiles = argc - optind;
- if (!quiet)
- fprintf(stderr,"numlogfiles = %d\n",numLogFiles);
-}
-
-static void* mapFile(int fd, u_int flags, off_t* sz)
-{
- struct stat sb;
- if (fstat(fd, &sb) < 0) {
- perror("fstat");
- exit(-1);
- }
- void* base = mmap(0, (int)sb.st_size, flags, MAP_PRIVATE, fd, 0);
- if (!base) {
- perror("mmap");
- exit(-1);
- }
- *sz = sb.st_size;
- return base;
-}
-
-void leaky::LoadMap()
-{
- malloc_map_entry mme;
- char name[1000];
-
- if (!loadMap) {
- // all files use the same map
- int fd = ::open(M_MAPFILE, O_RDONLY);
- if (fd < 0) {
- perror("open: " M_MAPFILE);
- exit(-1);
- }
- for (;;) {
- int nb = read(fd, &mme, sizeof(mme));
- if (nb != sizeof(mme)) break;
- nb = read(fd, name, mme.nameLen);
- if (nb != (int)mme.nameLen) break;
- name[mme.nameLen] = 0;
- if (!quiet) {
- fprintf(stderr,"%s @ %lx\n", name, mme.address);
- }
-
- LoadMapEntry* lme = new LoadMapEntry;
- lme->address = mme.address;
- lme->name = strdup(name);
- lme->next = loadMap;
- loadMap = lme;
- }
- close(fd);
- }
-}
-
-void leaky::open(char *logFile)
-{
- int threadArray[100]; // should auto-expand
- int last_thread = -1;
- int numThreads = 0;
- int section = -1;
- bool collecting = false;
-
- LoadMap();
-
- setupSymbols(progFile);
-
- // open up the log file
- if (mappedLogFile)
- ::close(mappedLogFile);
-
- mappedLogFile = ::open(logFile, O_RDONLY);
- if (mappedLogFile < 0) {
- perror("open");
- exit(-1);
- }
- off_t size;
- firstLogEntry = (malloc_log_entry*) mapFile(mappedLogFile, PROT_READ, &size);
- lastLogEntry = (malloc_log_entry*)((char*)firstLogEntry + size);
-
- if (!collect_last || collect_start < 0) {
- collecting = true;
- }
-
- // First, restrict it to the capture sections specified (all, last, start/end)
- // This loop walks through all the call stacks we recorded
- for (malloc_log_entry* lep=firstLogEntry;
- lep < lastLogEntry;
- lep = reinterpret_cast<malloc_log_entry*>(&lep->pcs[lep->numpcs])) {
-
- if (lep->flags & JP_FIRST_AFTER_PAUSE) {
- section++;
- if (collect_last) {
- firstLogEntry = lep;
- numThreads = 0;
- collecting = true;
- }
- if (collect_start == section) {
- collecting = true;
- firstLogEntry = lep;
- }
- if (collect_end == section) {
- collecting = false;
- lastLogEntry = lep;
- }
- if (!quiet)
- fprintf(stderr,"New section %d: first=%p, last=%p, collecting=%d\n",
- section,(void*)firstLogEntry,(void*)lastLogEntry,collecting);
- }
-
- // Capture thread info at the same time
-
- // Find all the threads captured
-
- // pthread/linux docs say the signal can be delivered to any thread in
- // the process. In practice, it appears in Linux that it's always
- // delivered to the thread that called setitimer(), and each thread can
- // have a separate itimer. There's a support library for gprof that
- // overlays pthread_create() to set timers in any threads you spawn.
- if (showThreads && collecting) {
- if (lep->thread != last_thread)
- {
- int i;
- for (i=0; i<numThreads; i++)
- {
- if (lep->thread == threadArray[i])
- break;
- }
- if (i == numThreads &&
- i < (int) (sizeof(threadArray)/sizeof(threadArray[0])))
- {
- threadArray[i] = lep->thread;
- numThreads++;
- if (!quiet)
- fprintf(stderr,"new thread %d\n",lep->thread);
- }
- }
- }
- }
- if (!quiet)
- fprintf(stderr,"Done collecting: sections %d: first=%p, last=%p, numThreads=%d\n",
- section,(void*)firstLogEntry,(void*)lastLogEntry,numThreads);
-
- if (!cleo) {
- fprintf(outputfd,"<html><head><title>Jprof Profile Report</title></head><body>\n");
- fprintf(outputfd,"<h1><center>Jprof Profile Report</center></h1>\n");
- }
-
- if (showThreads)
- {
- fprintf(stderr,"Num threads %d\n",numThreads);
-
- if (!cleo) {
- fprintf(outputfd,"<hr>Threads:<p><pre>\n");
- for (int i=0; i<numThreads; i++)
- {
- fprintf(outputfd," <a href=\"#thread_%d\">%d</a> ",
- threadArray[i],threadArray[i]);
- if ((i+1)%10 == 0)
- fprintf(outputfd,"<br>\n");
- }
- fprintf(outputfd,"</pre>");
- }
-
- for (int i=0; i<numThreads; i++)
- {
- if (!onlyThread || onlyThread == threadArray[i])
- analyze(threadArray[i]);
- }
- }
- else
- {
- analyze(0);
- }
-
- if (!cleo)
- fprintf(outputfd,"</pre></body></html>\n");
-}
-
-//----------------------------------------------------------------------
-
-
-static int symbolOrder(void const* a, void const* b)
-{
- Symbol const** ap = (Symbol const **)a;
- Symbol const** bp = (Symbol const **)b;
- return (*ap)->address == (*bp)->address ? 0 :
- ((*ap)->address > (*bp)->address ? 1 : -1);
-}
-
-void leaky::ReadSharedLibrarySymbols()
-{
- LoadMapEntry* lme = loadMap;
- while (nullptr != lme) {
- ReadSymbols(lme->name, lme->address);
- lme = lme->next;
- }
-}
-
-void leaky::setupSymbols(const char *fileName)
-{
- if (usefulSymbols == 0) {
- // only read once!
-
- // Read in symbols from the program
- ReadSymbols(fileName, 0);
-
- // Read in symbols from the .so's
- ReadSharedLibrarySymbols();
-
- if (!quiet) {
- fprintf(stderr,"A total of %d symbols were loaded\n", usefulSymbols);
- }
-
- // Now sort them
- qsort(externalSymbols, usefulSymbols, sizeof(Symbol *), symbolOrder);
- lowestSymbolAddr = externalSymbols[0]->address;
- highestSymbolAddr = externalSymbols[usefulSymbols-1]->address;
- }
-}
-
-// Binary search the table, looking for a symbol that covers this
-// address.
-int leaky::findSymbolIndex(u_long addr)
-{
- u_int base = 0;
- u_int limit = usefulSymbols - 1;
- Symbol** end = &externalSymbols[limit];
- while (base <= limit) {
- u_int midPoint = (base + limit)>>1;
- Symbol** sp = &externalSymbols[midPoint];
- if (addr < (*sp)->address) {
- if (midPoint == 0) {
- return -1;
- }
- limit = midPoint - 1;
- } else {
- if (sp+1 < end) {
- if (addr < (*(sp+1))->address) {
- return midPoint;
- }
- } else {
- return midPoint;
- }
- base = midPoint + 1;
- }
- }
- return -1;
-}
-
-Symbol* leaky::findSymbol(u_long addr)
-{
- int idx = findSymbolIndex(addr);
-
- if(idx<0) {
- return nullptr;
- } else {
- return externalSymbols[idx];
- }
-}
-
-//----------------------------------------------------------------------
-
-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 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;
-}
-
-//----------------------------------------------------------------------
-
-void leaky::displayStackTrace(FILE* out, malloc_log_entry* lep)
-{
- char** pcp = &lep->pcs[0];
- u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth;
- for (u_int i = 0; i < n; i++, pcp++) {
- u_long addr = (u_long) *pcp;
- Symbol* sp = findSymbol(addr);
- if (sp) {
- fputs(sp->name, out);
- if (showAddress) {
- fprintf(out, "[%p]", (char*)addr);
- }
- }
- else {
- fprintf(out, "<%p>", (char*)addr);
- }
- fputc(' ', out);
- }
- fputc('\n', out);
-}
-
-void leaky::dumpEntryToLog(malloc_log_entry* lep)
-{
- printf("%ld\t", lep->delTime);
- printf(" --> ");
- displayStackTrace(outputfd, lep);
-}
-
-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://dxr.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://dxr.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;
- }
-}
-
-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 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);
-}