Bug 1145924 - Ensure JSRuntime is kept in sync with the profiler. (r=djvj)
authorShu-yu Guo <shu@rfrn.org>
Mon, 23 Mar 2015 20:33:01 -0700
changeset 265544 1d410fe6bf992bc69daf3dac318ecf023ef3bacd
parent 265543 f687743cc499b25eeca008639abc506640de3eaf
child 265545 3824a459106770770fb3f6275263e83382256948
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs1145924
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 1145924 - Ensure JSRuntime is kept in sync with the profiler. (r=djvj)
js/src/jit/JitcodeMap.cpp
js/src/jit/JitcodeMap.h
js/src/vm/Runtime.h
js/src/vm/SPSProfiler.cpp
tools/profiler/TableTicker.cpp
--- a/js/src/jit/JitcodeMap.cpp
+++ b/js/src/jit/JitcodeMap.cpp
@@ -713,16 +713,24 @@ JitcodeGlobalTable::verifySkiplist()
         }
         curEntry = curEntry->tower_->next(0);
     }
 
     MOZ_ASSERT(count == skiplistSize_);
 }
 #endif // DEBUG
 
+void
+JitcodeGlobalTable::setAllEntriesAsExpired(JSRuntime *rt)
+{
+    AutoSuppressProfilerSampling suppressSampling(rt);
+    for (Range r(*this); !r.empty(); r.popFront())
+        r.front()->setAsExpired();
+}
+
 bool
 JitcodeGlobalTable::markIteratively(JSTracer *trc)
 {
     // JitcodeGlobalTable must keep entries that are in the sampler buffer
     // alive. This conditionality is akin to holding the entries weakly.
     //
     // If this table were marked at the beginning of the mark phase, then
     // sampling would require a read barrier for sampling in between
@@ -757,17 +765,17 @@ JitcodeGlobalTable::markIteratively(JSTr
         // If an entry is not sampled, reset its generation to the invalid
         // generation, and conditionally mark the rest of the entry if its
         // JitCode is not already marked. This conditional marking ensures
         // that so long as the JitCode *may* be sampled, we keep any
         // information that may be handed out to the sampler, like tracked
         // types used by optimizations and scripts used for pc to line number
         // mapping, alive as well.
         if (!entry->isSampled(gen, lapCount)) {
-            entry->setGeneration(UINT32_MAX);
+            entry->setAsExpired();
             if (!entry->baseEntry().isJitcodeMarkedFromAnyThread())
                 continue;
         }
 
         // The table is runtime-wide. Not all zones may be participating in
         // the GC.
         if (!entry->zone()->isCollecting() || entry->zone()->isGCFinished())
             continue;
--- a/js/src/jit/JitcodeMap.h
+++ b/js/src/jit/JitcodeMap.h
@@ -596,16 +596,19 @@ class JitcodeGlobalEntry
     }
 
     uint32_t generation() const {
         return baseEntry().generation();
     }
     void setGeneration(uint32_t gen) {
         baseEntry().setGeneration(gen);
     }
+    void setAsExpired() {
+        baseEntry().setGeneration(UINT32_MAX);
+    }
     bool isSampled(uint32_t currentGen, uint32_t lapCount) {
         return baseEntry().isSampled(currentGen, lapCount);
     }
 
     bool startsBelowPointer(void *ptr) const {
         return base_.startsBelowPointer(ptr);
     }
     bool endsAbovePointer(void *ptr) const {
@@ -948,16 +951,17 @@ class JitcodeGlobalTable
     }
     bool addEntry(const JitcodeGlobalEntry::DummyEntry &entry, JSRuntime *rt) {
         return addEntry(JitcodeGlobalEntry(entry), rt);
     }
 
     void removeEntry(JitcodeGlobalEntry &entry, JitcodeGlobalEntry **prevTower, JSRuntime *rt);
     void releaseEntry(JitcodeGlobalEntry &entry, JitcodeGlobalEntry **prevTower, JSRuntime *rt);
 
+    void setAllEntriesAsExpired(JSRuntime *rt);
     bool markIteratively(JSTracer *trc);
     void sweep(JSRuntime *rt);
 
   private:
     bool addEntry(const JitcodeGlobalEntry &entry, JSRuntime *rt);
 
     JitcodeGlobalEntry *lookupInternal(void *ptr);
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -691,28 +691,44 @@ struct JSRuntime : public JS::shadow::Ru
     }
     static unsigned offsetOfProfilingActivation() {
         return offsetof(JSRuntime, profilingActivation_);
     }
 
     uint32_t profilerSampleBufferGen() {
         return profilerSampleBufferGen_;
     }
+    void resetProfilerSampleBufferGen() {
+        profilerSampleBufferGen_ = 0;
+    }
     void setProfilerSampleBufferGen(uint32_t gen) {
-        profilerSampleBufferGen_ = gen;
+        // May be called from sampler thread or signal handler; use
+        // compareExchange to make sure we have monotonic increase.
+        for (;;) {
+            uint32_t curGen = profilerSampleBufferGen_;
+            if (curGen >= gen)
+                break;
+
+            if (profilerSampleBufferGen_.compareExchange(curGen, gen))
+                break;
+        }
     }
 
     uint32_t profilerSampleBufferLapCount() {
         MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
         return profilerSampleBufferLapCount_;
     }
+    void resetProfilerSampleBufferLapCount() {
+        profilerSampleBufferLapCount_ = 1;
+    }
     void updateProfilerSampleBufferLapCount(uint32_t lapCount) {
         MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
 
-        // Use compareExchange to make sure we have monotonic increase.
+        // May be called from sampler thread or signal handler; use
+        // compareExchange to make sure we have monotonic increase.
         for (;;) {
             uint32_t curLapCount = profilerSampleBufferLapCount_;
             if (curLapCount >= lapCount)
                 break;
 
             if (profilerSampleBufferLapCount_.compareExchange(curLapCount, lapCount))
                 break;
         }
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/DebugOnly.h"
 
 #include "jsnum.h"
 #include "jsprf.h"
 #include "jsscript.h"
 
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineJIT.h"
+#include "jit/JitcodeMap.h"
 #include "jit/JitFrameIterator.h"
 #include "jit/JitFrames.h"
 #include "vm/StringBuffer.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
 
@@ -82,16 +83,25 @@ SPSProfiler::enable(bool enabled)
         return;
 
     /*
      * Ensure all future generated code will be instrumented, or that all
      * currently instrumented code is discarded
      */
     ReleaseAllJITCode(rt->defaultFreeOp());
 
+    // This function is called when the Gecko profiler makes a new TableTicker
+    // (and thus, a new circular buffer). Set all current entries in the
+    // JitcodeGlobalTable as expired and reset the buffer generation and lap
+    // count.
+    if (rt->hasJitRuntime() && rt->jitRuntime()->hasJitcodeGlobalTable())
+        rt->jitRuntime()->getJitcodeGlobalTable()->setAllEntriesAsExpired(rt);
+    rt->resetProfilerSampleBufferGen();
+    rt->resetProfilerSampleBufferLapCount();
+
     // Ensure that lastProfilingFrame is null before 'enabled' becomes true.
     if (rt->jitActivation) {
         rt->jitActivation->setLastProfilingFrame(nullptr);
         rt->jitActivation->setLastProfilingCallSite(nullptr);
     }
 
     enabled_ = enabled;
 
@@ -461,18 +471,18 @@ AutoSuppressProfilerSampling::AutoSuppre
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     if (previouslyEnabled_)
         rt_->disableProfilerSampling();
 }
 
 AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
 {
-        if (previouslyEnabled_)
-            rt_->enableProfilerSampling();
+    if (previouslyEnabled_)
+        rt_->enableProfilerSampling();
 }
 
 void *
 js::GetTopProfilingJitFrame(uint8_t *exitFramePtr)
 {
     // For null exitFrame, there is no previous exit frame, just return.
     if (!exitFramePtr)
         return nullptr;
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -630,17 +630,20 @@ void mergeStacksIntoProfile(ThreadProfil
     aProfile.addTag(ProfileEntry('l', (void*)aNativeStack.pc_array[nativeIndex]));
     nativeIndex--;
   }
 
   MOZ_ASSERT(aProfile.bufferGeneration() >= startBufferGen);
   uint32_t lapCount = aProfile.bufferGeneration() - startBufferGen;
 
   // Update the JS runtime with the current profile sample buffer generation.
-  if (pseudoStack->mRuntime) {
+  //
+  // Do not do this for synchronous sampling, which create their own
+  // ProfileBuffers.
+  if (!aSample->isSamplingCurrentThread && pseudoStack->mRuntime) {
     JS::UpdateJSRuntimeProfilerSampleBufferGen(pseudoStack->mRuntime,
                                                aProfile.bufferGeneration(),
                                                lapCount);
   }
 }
 
 #ifdef USE_NS_STACKWALK
 static