Bug 1146718 - Split the 'J' tag in the profiler into 'J' (JIT frames without opt info) and 'O' (with opt info). (r=djvj)
authorShu-yu Guo <shu@rfrn.org>
Tue, 24 Mar 2015 18:49:16 -0700
changeset 264322 b1d39f9d8c13d9817428e8c133b81fbd338558dd
parent 264321 43e18ef6680757fef26449194ad309ca9ad7616c
child 264323 bb0db528a2c4fb1d155ea108d30870bba86263c2
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs1146718
milestone39.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 1146718 - Split the 'J' tag in the profiler into 'J' (JIT frames without opt info) and 'O' (with opt info). (r=djvj)
js/public/ProfilingFrameIterator.h
js/src/vm/Stack.cpp
tools/profiler/ProfileEntry.cpp
tools/profiler/TableTicker.cpp
--- a/js/public/ProfilingFrameIterator.h
+++ b/js/public/ProfilingFrameIterator.h
@@ -104,17 +104,17 @@ class JS_PUBLIC_API(ProfilingFrameIterat
 
     struct Frame
     {
         FrameKind kind;
         void *stackAddress;
         void *returnAddress;
         void *activation;
         const char *label;
-        bool hasTrackedOptimizations;
+        bool mightHaveTrackedOptimizations;
     };
     uint32_t extractStack(Frame *frames, uint32_t offset, uint32_t end) const;
 
   private:
     void iteratorConstruct(const RegisterState &state);
     void iteratorConstruct();
     void iteratorDestroy();
     bool iteratorDone();
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1857,17 +1857,17 @@ JS::ProfilingFrameIterator::extractStack
     void *stackAddr = stackAddress();
 
     if (isAsmJS()) {
         frames[offset].kind = Frame_AsmJS;
         frames[offset].stackAddress = stackAddr;
         frames[offset].returnAddress = nullptr;
         frames[offset].activation = activation_;
         frames[offset].label = asmJSIter().label();
-        frames[offset].hasTrackedOptimizations = false;
+        frames[offset].mightHaveTrackedOptimizations = false;
         return 1;
     }
 
     MOZ_ASSERT(isJit());
     void *returnAddr = jitIter().returnAddressToFp();
 
     // Look up an entry for the return address.
     jit::JitcodeGlobalTable *table = rt_->jitRuntime()->getJitcodeGlobalTable();
@@ -1893,31 +1893,26 @@ JS::ProfilingFrameIterator::extractStack
     for (uint32_t i = 0; i < depth; i++) {
         if (offset + i >= end)
             return i;
         frames[offset + i].kind = kind;
         frames[offset + i].stackAddress = stackAddr;
         frames[offset + i].returnAddress = returnAddr;
         frames[offset + i].activation = activation_;
         frames[offset + i].label = labels[i];
-        frames[offset + i].hasTrackedOptimizations = false;
+        frames[offset + i].mightHaveTrackedOptimizations = false;
     }
 
-    // Extract the index into the side table of optimization information and
-    // store it on the youngest frame. All inlined frames will have the same
-    // optimization information by virtue of sharing the JitcodeGlobalEntry,
-    // but such information is only interpretable on the youngest frame.
+    // A particular return address might have tracked optimizations only if
+    // there are any optimizations at all.
     //
-    // FIXMEshu: disabled until we can ensure the optimization info is live
-    // when we write out the JSON stream of the profile.
-    if (false && entry.hasTrackedOptimizations()) {
-        uint32_t dummy;
-        mozilla::Maybe<uint8_t> index = entry.trackedOptimizationIndexAtAddr(returnAddr, &dummy);
-        frames[offset].hasTrackedOptimizations = index.isSome();
-    }
+    // All inlined Ion frames will have the same optimization information by
+    // virtue of sharing the JitcodeGlobalEntry, but such information is only
+    // interpretable on the youngest frame.
+    frames[offset].mightHaveTrackedOptimizations = entry.hasTrackedOptimizations();
 
     return depth;
 }
 
 bool
 JS::ProfilingFrameIterator::isAsmJS() const
 {
     MOZ_ASSERT(!done());
--- a/tools/profiler/ProfileEntry.cpp
+++ b/tools/profiler/ProfileEntry.cpp
@@ -338,17 +338,17 @@ void UniqueJITOptimizations::stream(JSSt
         b.NameValue("line", line);
         b.NameValue("column", column);
       b.EndObject();
     }
   b.EndArray();
 }
 
 void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JSRuntime* rt,
-                                            UniqueJITOptimizations &aUniqueOpts)
+                                            UniqueJITOptimizations& aUniqueOpts)
 {
   b.BeginArray();
 
     bool sample = false;
     int readPos = mReadPos;
     int currentThreadID = -1;
     while (readPos != mWritePos) {
       ProfileEntry entry = mEntries[readPos];
@@ -463,17 +463,18 @@ void ProfileBuffer::StreamSamplesToJSObj
                       readAheadPos = (framePos + incBy) % mEntrySize;
                       if (readAheadPos != mWritePos &&
                           mEntries[readAheadPos].mTagName == 'y') {
                         b.NameValue("category", mEntries[readAheadPos].mTagInt);
                         incBy++;
                       }
                       readAheadPos = (framePos + incBy) % mEntrySize;
                       if (readAheadPos != mWritePos &&
-                          mEntries[readAheadPos].mTagName == 'J') {
+                          (mEntries[readAheadPos].mTagName == 'J' ||
+                           mEntries[readAheadPos].mTagName == 'O')) {
                         void* pc = mEntries[readAheadPos].mTagPtr;
 
                         // TODOshu: cannot stream tracked optimization info if
                         // the JS engine has already shut down when streaming.
                         if (rt) {
                           JS::ProfilingFrameIterator::FrameKind frameKind =
                             JS::GetProfilingFrameKindFromNativeAddr(rt, pc);
                           MOZ_ASSERT(frameKind == JS::ProfilingFrameIterator::Frame_Ion ||
@@ -481,21 +482,26 @@ void ProfileBuffer::StreamSamplesToJSObj
                           const char* jitLevelString =
                             (frameKind == JS::ProfilingFrameIterator::Frame_Ion) ? "ion"
                                                                                  : "baseline";
                           b.NameValue("implementation", jitLevelString);
 
                           // Sampled JIT optimizations are deduplicated by
                           // aUniqueOpts to save space. Stream an index that
                           // references into the optimizations array.
-                          Maybe<unsigned> optsIndex = aUniqueOpts.getIndex(pc, rt);
-                          if (optsIndex.isSome()) {
-                            b.NameValue("optsIndex", optsIndex.value());
+                          bool mightHaveTrackedOpts = mEntries[readAheadPos].mTagName == 'O';
+                          if (mightHaveTrackedOpts) {
+                            Maybe<unsigned> optsIndex = aUniqueOpts.getIndex(pc, rt);
+                            if (optsIndex.isSome()) {
+                              b.NameValue("optsIndex", optsIndex.value());
+                            }
                           }
                         }
+
+                        incBy++;
                       }
                     b.EndObject();
                   }
                   framePos = (framePos + incBy) % mEntrySize;
                 }
               b.EndArray();
             }
             break;
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -591,37 +591,41 @@ void mergeStacksIntoProfile(ThreadProfil
       addPseudoEntry(pseudoFrame, aProfile, pseudoStack, nullptr);
       pseudoIndex++;
       continue;
     }
 
     // Check to see if JS jit stack frame is top-most
     if (jsStackAddr > nativeStackAddr) {
       MOZ_ASSERT(jsIndex >= 0);
-      addDynamicTag(aProfile, 'c', jsFrames[jsIndex].label);
+      const JS::ProfilingFrameIterator::Frame& jsFrame = jsFrames[jsIndex];
+      addDynamicTag(aProfile, 'c', jsFrame.label);
 
-      // Stringifying optimization information is delayed until streaming
-      // time. To re-lookup the entry in the JitcodeGlobalTable, we need to
-      // store the JIT code address ('J') in the circular buffer.
+      // Stringifying optimization information and the JIT tier is delayed
+      // until streaming time. To re-lookup the entry in the
+      // JitcodeGlobalTable, we need to store the JIT code address in the
+      // circular buffer.
+      //
+      // Frames which may have optimization information are tagged by an 'O'
+      // entry. Otherwise they are tagged by a 'J' entry.
       //
       // Note that we cannot do this when we are sychronously sampling the
       // current thread; that is, when called from profiler_get_backtrace. The
       // captured backtrace is usually externally stored for an indeterminate
       // amount of time, such as in nsRefreshDriver. Problematically, the
       // stored backtrace may be alive across a GC during which the profiler
       // itself is disabled. In that case, the JS engine is free to discard
       // its JIT code. This means that if we inserted such 'J' entries into
       // the buffer, nsRefreshDriver would now be holding on to a backtrace
       // with stale JIT code return addresses.
-      MOZ_ASSERT_IF(jsFrames[jsIndex].hasTrackedOptimizations,
-                    jsFrames[jsIndex].kind == JS::ProfilingFrameIterator::Frame_Ion);
       if (!aSample->isSamplingCurrentThread &&
-          (jsFrames[jsIndex].kind == JS::ProfilingFrameIterator::Frame_Ion ||
-           jsFrames[jsIndex].kind == JS::ProfilingFrameIterator::Frame_Baseline)) {
-        aProfile.addTag(ProfileEntry('J', jsFrames[jsIndex].returnAddress));
+          (jsFrame.kind == JS::ProfilingFrameIterator::Frame_Ion ||
+           jsFrame.kind == JS::ProfilingFrameIterator::Frame_Baseline)) {
+        char entryTag = jsFrame.mightHaveTrackedOptimizations ? 'O' : 'J';
+        aProfile.addTag(ProfileEntry(entryTag, jsFrames[jsIndex].returnAddress));
       }
 
       jsIndex--;
       continue;
     }
 
     // If we reach here, there must be a native stack entry and it must be the
     // greatest entry.