Bug 1384688 - Add thread register and unregister time. r?njn draft
authorMarkus Stange <mstange@themasta.com>
Fri, 28 Jul 2017 15:43:19 -0400
changeset 618525 49f522ac16556fb172425736b8b8322b13cb7ca2
parent 618502 1be0c1da06076f85c69cd8a9d244e0164ec544d9
child 618526 0311111377b5bc588c42cd432897b82cb997abbd
child 618568 983d412b7d802ad58fb47cee3e4dcc0f1aecfadb
push id71371
push userbmo:mstange@themasta.com
push dateMon, 31 Jul 2017 17:30:53 +0000
reviewersnjn
bugs1384688
milestone56.0a1
Bug 1384688 - Add thread register and unregister time. r?njn MozReview-Commit-ID: JDRP8m7QrE1
tools/profiler/core/ProfilerBacktrace.cpp
tools/profiler/core/ThreadInfo.cpp
tools/profiler/core/ThreadInfo.h
tools/profiler/core/platform.cpp
--- a/tools/profiler/core/ProfilerBacktrace.cpp
+++ b/tools/profiler/core/ProfilerBacktrace.cpp
@@ -30,15 +30,17 @@ ProfilerBacktrace::StreamJSON(Spliceable
 {
   // This call to StreamSamplesAndMarkers() can safely pass in a non-null
   // JSContext. That's because StreamSamplesAndMarkers() only accesses the
   // JSContext when streaming JitReturnAddress entries, and such entries
   // never appear in synchronous samples.
   double firstSampleTimeIgnored;
   StreamSamplesAndMarkers(mName.get(), mThreadId,
                           *mBuffer.get(), aWriter, aProcessStartTime,
+                          /* aRegisterTime */ TimeStamp(),
+                          /* aUnregisterTime */ TimeStamp(),
                           /* aSinceTime */ 0, &firstSampleTimeIgnored,
                           /* aContext */ nullptr,
                           /* aSavedStreamedSamples */ nullptr,
                           /* aFirstSavedStreamedSampleTime */ 0.0,
                           /* aSavedStreamedMarkers */ nullptr,
                           aUniqueStacks);
 }
--- a/tools/profiler/core/ThreadInfo.cpp
+++ b/tools/profiler/core/ThreadInfo.cpp
@@ -17,16 +17,17 @@
 #define getpid _getpid
 #else
 #include <unistd.h> // for getpid()
 #endif
 
 ThreadInfo::ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread,
                        void* aStackTop)
   : mName(strdup(aName))
+  , mRegisterTime(TimeStamp::Now())
   , mThreadId(aThreadId)
   , mIsMainThread(aIsMainThread)
   , mRacyInfo(mozilla::WrapNotNull(new RacyThreadInfo()))
   , mPlatformData(AllocPlatformData(aThreadId))
   , mStackTop(aStackTop)
   , mIsBeingProfiled(false)
   , mContext(nullptr)
   , mJSSampling(INACTIVE)
@@ -79,17 +80,19 @@ ThreadInfo::StreamJSON(const ProfileBuff
     mUniqueStacks.emplace(mContext);
   }
 
   double firstSampleTime = 0.0;
 
   aWriter.Start(SpliceableJSONWriter::SingleLineStyle);
   {
     StreamSamplesAndMarkers(Name(), ThreadId(), aBuffer, aWriter,
-                            aProcessStartTime, aSinceTime, &firstSampleTime,
+                            aProcessStartTime,
+                            mRegisterTime, mUnregisterTime,
+                            aSinceTime, &firstSampleTime,
                             mContext,
                             mSavedStreamedSamples.get(),
                             mFirstSavedStreamedSampleTime,
                             mSavedStreamedMarkers.get(),
                             *mUniqueStacks);
     mSavedStreamedSamples.reset();
     mFirstSavedStreamedSampleTime = 0.0;
     mSavedStreamedMarkers.reset();
@@ -143,31 +146,47 @@ ThreadInfo::StreamJSON(const ProfileBuff
 }
 
 void
 StreamSamplesAndMarkers(const char* aName,
                         int aThreadId,
                         const ProfileBuffer& aBuffer,
                         SpliceableJSONWriter& aWriter,
                         const TimeStamp& aProcessStartTime,
+                        const TimeStamp& aRegisterTime,
+                        const TimeStamp& aUnregisterTime,
                         double aSinceTime,
                         double* aOutFirstSampleTime,
                         JSContext* aContext,
                         char* aSavedStreamedSamples,
                         double aFirstSavedStreamedSampleTime,
                         char* aSavedStreamedMarkers,
                         UniqueStacks& aUniqueStacks)
 {
   aWriter.StringProperty("processType",
                          XRE_ChildProcessTypeToString(XRE_GetProcessType()));
 
   aWriter.StringProperty("name", aName);
   aWriter.IntProperty("tid", static_cast<int64_t>(aThreadId));
   aWriter.IntProperty("pid", static_cast<int64_t>(getpid()));
 
+  if (aRegisterTime) {
+    aWriter.DoubleProperty("registerTime",
+      (aRegisterTime - aProcessStartTime).ToMilliseconds());
+  } else {
+    aWriter.NullProperty("registerTime");
+  }
+
+  if (aUnregisterTime) {
+    aWriter.DoubleProperty("unregisterTime",
+      (aUnregisterTime - aProcessStartTime).ToMilliseconds());
+  } else {
+    aWriter.NullProperty("unregisterTime");
+  }
+
   aWriter.StartObjectProperty("samples");
   {
     {
       JSONSchemaWriter schema(aWriter);
       schema.WriteField("stack");
       schema.WriteField("time");
       schema.WriteField("responsiveness");
       schema.WriteField("rss");
--- a/tools/profiler/core/ThreadInfo.h
+++ b/tools/profiler/core/ThreadInfo.h
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #ifndef ThreadInfo_h
 #define ThreadInfo_h
 
 #include "mozilla/NotNull.h"
+#include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtrExtensions.h"
 
 #include "platform.h"
 #include "ProfileBuffer.h"
 #include "js/ProfilingStack.h"
 
 // This class contains the info for a single thread that is accessible without
 // protection from gPSMutex in platform.cpp. Because there is no external
@@ -177,25 +178,29 @@ public:
   bool IsMainThread() const { return mIsMainThread; }
 
   mozilla::NotNull<RacyThreadInfo*> RacyInfo() const { return mRacyInfo; }
 
   void StartProfiling();
   void StopProfiling();
   bool IsBeingProfiled() { return mIsBeingProfiled; }
 
+  void NotifyUnregistered() { mUnregisterTime = TimeStamp::Now(); }
+
   PlatformData* GetPlatformData() const { return mPlatformData.get(); }
   void* StackTop() const { return mStackTop; }
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   ProfileBuffer::LastSample& LastSample() { return mLastSample; }
 
 private:
   mozilla::UniqueFreePtr<char> mName;
+  mozilla::TimeStamp mRegisterTime;
+  mozilla::TimeStamp mUnregisterTime;
   int mThreadId;
   const bool mIsMainThread;
 
   // The thread's RacyThreadInfo. This is an owning pointer. It could be an
   // inline member, but we don't do that because RacyThreadInfo is quite large
   // (due to the PseudoStack within it), and we have ThreadInfo vectors and so
   // we'd end up wasting a lot of space in those vectors for excess elements.
   mozilla::NotNull<RacyThreadInfo*> mRacyInfo;
@@ -370,16 +375,18 @@ private:
   ProfileBuffer::LastSample mLastSample;
 };
 
 void
 StreamSamplesAndMarkers(const char* aName, int aThreadId,
                         const ProfileBuffer& aBuffer,
                         SpliceableJSONWriter& aWriter,
                         const mozilla::TimeStamp& aProcessStartTime,
+                        const TimeStamp& aRegisterTime,
+                        const TimeStamp& aUnregisterTime,
                         double aSinceTime,
                         double* aOutFirstSampleTime,
                         JSContext* aContext,
                         char* aSavedStreamedSamples,
                         double aFirstSavedStreamedSampleTime,
                         char* aSavedStreamedMarkers,
                         UniqueStacks& aUniqueStacks);
 
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2957,16 +2957,17 @@ profiler_unregister_thread()
   // that for a JS thread that is in the process of disappearing.
 
   int i;
   ThreadInfo* info = FindLiveThreadInfo(lock, &i);
   MOZ_RELEASE_ASSERT(info == TLSInfo::Info(lock));
   if (info) {
     DEBUG_LOG("profiler_unregister_thread: %s", info->Name());
     if (ActivePS::Exists(lock) && info->IsBeingProfiled()) {
+      info->NotifyUnregistered();
       CorePS::DeadThreads(lock).push_back(info);
     } else {
       delete info;
     }
     CorePS::ThreadVector& liveThreads = CorePS::LiveThreads(lock);
     liveThreads.erase(liveThreads.begin() + i);
 
     // Whether or not we just destroyed the ThreadInfo or transferred it to the