Bug 712224: Make jprof generate output for 'cleopatra' backend. rs=dbaron DONTBUILD
authorRandell Jesup <rjesup@wgate.com>
Wed, 18 Jan 2012 00:11:00 -0500
changeset 87596 0673da2a834a2f128380f78788d2a4c45a5f518a
parent 87595 6eec3b4644bd983359ce9f0e92ca5de42278d9bc
child 87597 715e4b7e3b51fded840bec05b9294cc9b8506feb
push id129
push userffxbld
push dateFri, 20 Apr 2012 19:40:49 +0000
treeherdermozilla-release@5bcfa0da3be9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs712224
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 712224: Make jprof generate output for 'cleopatra' backend. rs=dbaron DONTBUILD
tools/jprof/leaky.cpp
tools/jprof/leaky.h
--- a/tools/jprof/leaky.cpp
+++ b/tools/jprof/leaky.cpp
@@ -150,16 +150,17 @@ leaky::leaky()
   applicationName = NULL;
   progFile = NULL;
 
   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;
@@ -174,39 +175,41 @@ leaky::leaky()
 }
 
 leaky::~leaky()
 {
 }
 
 void leaky::usageError()
 {
-  fprintf(stderr, "Usage: %s [-v] [-t] [-e exclude] [-i include] [-s stackdepth] [--last] [--all] [--start n [--end m]] [--output-dir dir] prog log [log2 ...]\n", (char*) applicationName);
+  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, NULL, 't' },
     { "only-thread", 1, NULL, 'T' },
     { "last", 0, NULL, 'l' },
     { "start", 1, NULL, 'x' },
     { "end", 1, NULL, 'n' },
+    { "cleo",0, NULL, 'c' },
     { "output-dir", 1, NULL, 'd' },
     { NULL, 0, NULL, 0 },
 };
 
 void leaky::initialize(int argc, char** argv)
 {
   applicationName = argv[0];
   applicationName = strrchr(applicationName, '/');
@@ -217,31 +220,35 @@ void leaky::initialize(int argc, char** 
   }
 
   int arg;
   int errflg = 0;
   int longindex = 0;
 
   onlyThread = 0;
   output_dir = NULL;
+  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;
@@ -434,43 +441,48 @@ void leaky::open(char *logFile)
         }
       }
     }
   }  
   if (!quiet)
     fprintf(stderr,"Done collecting: sections %d: first=%p, last=%p, numThreads=%d\n",
             section,(void*)firstLogEntry,(void*)lastLogEntry,numThreads);
 
-  fprintf(outputfd,"<html><head><title>Jprof Profile Report</title></head><body>\n");
-  fprintf(outputfd,"<h1><center>Jprof Profile Report</center></h1>\n");
+  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);
 
-    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 (!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]);
+      }
+      fprintf(outputfd,"</pre>");
     }
-    fprintf(outputfd,"</pre>");
 
     for (int i=0; i<numThreads; i++)
     {
       if (!onlyThread || onlyThread == threadArray[i])
         analyze(threadArray[i]);
     }
   }
   else
   {
     analyze(0);
   }
 
-  fprintf(outputfd,"</pre></body></html>\n");
+  if (!cleo)
+    fprintf(outputfd,"</pre></body></html>\n");
 }
 
 //----------------------------------------------------------------------
 
 
 static int symbolOrder(void const* a, void const* b)
 {
   Symbol const* ap = (Symbol const *)a;
@@ -757,74 +769,106 @@ void leaky::analyze(int thread)
   // 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
 
-    // This loop walks through every symbol in the call stack.  By walking it
-    // backwards we know who called the function when we get there.
     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
-    for (int i=n-1; i>=0; --i, --pcp) {
-      idx = findSymbolIndex(reinterpret_cast<u_long>(*pcp));
+    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;
-	  }
-	}
+        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];
-	}
+          // 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;
+          // 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;
+      // idx should be the function that we were in when we received the signal.
+      if(idx>=0) {
+        ++externalSymbols[idx].timerHit;
+      }
+
     }
   }
-
-  generateReportHTML(outputfd, countArray, stacks, thread);
+  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);
     
--- a/tools/jprof/leaky.h
+++ b/tools/jprof/leaky.h
@@ -89,16 +89,17 @@ struct leaky {
   int    logFileIndex;
   int    numLogFiles;
   char*  progFile;
   FILE*  outputfd;
 
   bool  quiet;
   bool  showAddress;
   bool  showThreads;
+  bool  cleo;
   u_int stackDepth;
   int   onlyThread;
   char* output_dir;
 
   int   mappedLogFile;
   malloc_log_entry* firstLogEntry;
   malloc_log_entry* lastLogEntry;