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 87219 0673da2a834a2f128380f78788d2a4c45a5f518a
parent 87218 6eec3b4644bd983359ce9f0e92ca5de42278d9bc
child 87220 715e4b7e3b51fded840bec05b9294cc9b8506feb
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs712224
milestone12.0a1
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;