Bug 1384688 - Add an aIsShuttingDown argument to profiler_get_profile() and to profiler_stream_json_for_this_process(). r=njn
☠☠ backed out by 6806dd90d02e ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Mon, 31 Jul 2017 13:11:19 -0400
changeset 420725 e9d92bc3be81366484f4929d1554c21e73a7ff59
parent 420724 ed86b892433b5c4049122b0561a8012a353c6ea1
child 420726 3ad8f1ba9de6ebe7fae8b41ea5c3e280b8b71b86
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1384688
milestone56.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 1384688 - Add an aIsShuttingDown argument to profiler_get_profile() and to profiler_stream_json_for_this_process(). r=njn When set to true, the resulting profile will have a non-null meta.shutdownTime field which is set to current time. Non-shutdown profiles also get that field, but it's null for them. MozReview-Commit-ID: 1vpmhBR8rC6
tools/profiler/core/platform.cpp
tools/profiler/public/GeckoProfiler.h
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -1437,29 +1437,39 @@ StreamTaskTracer(PSLockRef aLock, Splice
   aWriter.EndArray();
 
   aWriter.DoubleProperty(
     "start", static_cast<double>(tasktracer::GetStartTime()));
 #endif
 }
 
 static void
-StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter)
+StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter,
+                         const TimeStamp& aShutdownTime)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   aWriter.IntProperty("version", 7);
 
   // The "startTime" field holds the number of milliseconds since midnight
   // January 1, 1970 GMT. This grotty code computes (Now - (Now -
   // ProcessStartTime)) to convert CorePS::ProcessStartTime() into that form.
   TimeDuration delta = TimeStamp::Now() - CorePS::ProcessStartTime();
   aWriter.DoubleProperty(
     "startTime", static_cast<double>(PR_Now()/1000.0 - delta.ToMilliseconds()));
 
+  // Write the shutdownTime field. Unlike startTime, shutdownTime is not an
+  // absolute time stamp: It's relative to startTime. This is consistent with
+  // all other (non-"startTime") times anywhere in the profile JSON.
+  if (aShutdownTime) {
+    aWriter.DoubleProperty("shutdownTime", profiler_time());
+  } else {
+    aWriter.NullProperty("shutdownTime");
+  }
+
   if (!NS_IsMainThread()) {
     // Leave the rest of the properties out if we're not on the main thread.
     // At the moment, the only case in which this function is called on a
     // background thread is if we're in a content process and are going to
     // send this profile to the parent process. In that case, the parent
     // process profile's "meta" object already has the rest of the properties,
     // and the parent process profile is dumped on that process's main thread.
     return;
@@ -1581,31 +1591,33 @@ BuildJavaThreadJSObject(SpliceableJSONWr
   }
   aWriter.EndArray();
 }
 #endif
 
 static TimeStamp
 locked_profiler_stream_json_for_this_process(PSLockRef aLock,
                                              SpliceableJSONWriter& aWriter,
-                                             double aSinceTime)
+                                             double aSinceTime,
+                                             bool aIsShuttingDown)
 {
   LOG("locked_profiler_stream_json_for_this_process");
 
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   // Put shared library info
   aWriter.StartArrayProperty("libs");
   AppendSharedLibraries(aWriter);
   aWriter.EndArray();
 
   // Put meta data
   aWriter.StartObjectProperty("meta");
   {
-    StreamMetaJSCustomObject(aLock, aWriter);
+    StreamMetaJSCustomObject(aLock, aWriter,
+                             aIsShuttingDown ? TimeStamp::Now() : TimeStamp());
   }
   aWriter.EndObject();
 
   // Data of TaskTracer doesn't belong in the circular buffer.
   if (ActivePS::FeatureTaskTracer(aLock)) {
     aWriter.StartObjectProperty("tasktracer");
     StreamTaskTracer(aLock, aWriter);
     aWriter.EndObject();
@@ -1660,30 +1672,32 @@ locked_profiler_stream_json_for_this_pro
   }
 
   return TimeStamp();
 }
 
 bool
 profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter,
                                       double aSinceTime,
+                                      bool aIsShuttingDown,
                                       TimeStamp* aOutFirstSampleTime)
 {
   LOG("profiler_stream_json_for_this_process");
 
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   PSAutoLock lock(gPSMutex);
 
   if (!ActivePS::Exists(lock)) {
     return false;
   }
 
   TimeStamp firstSampleTime =
-    locked_profiler_stream_json_for_this_process(lock, aWriter, aSinceTime);
+    locked_profiler_stream_json_for_this_process(lock, aWriter, aSinceTime,
+                                                 aIsShuttingDown);
 
   if (aOutFirstSampleTime) {
     *aOutFirstSampleTime = firstSampleTime;
   }
 
   return true;
 }
 
@@ -2344,17 +2358,18 @@ profiler_init(void* aStackTop)
 
   // We do this with gPSMutex unlocked. The comment in profiler_stop() explains
   // why.
   NotifyProfilerStarted(entries, interval, features,
                         filters.Elements(), filters.Length());
 }
 
 static void
-locked_profiler_save_profile_to_file(PSLockRef aLock, const char* aFilename);
+locked_profiler_save_profile_to_file(PSLockRef aLock, const char* aFilename,
+                                     bool aIsShuttingDown);
 
 static SamplerThread*
 locked_profiler_stop(PSLockRef aLock);
 
 void
 profiler_shutdown()
 {
   LOG("profiler_shutdown");
@@ -2367,17 +2382,18 @@ profiler_shutdown()
   SamplerThread* samplerThread = nullptr;
   {
     PSAutoLock lock(gPSMutex);
 
     // Save the profile on shutdown if requested.
     if (ActivePS::Exists(lock)) {
       const char* filename = getenv("MOZ_PROFILER_SHUTDOWN");
       if (filename) {
-        locked_profiler_save_profile_to_file(lock, filename);
+        locked_profiler_save_profile_to_file(lock, filename,
+                                             /* aIsShuttingDown */ true);
       }
 
       samplerThread = locked_profiler_stop(lock);
     }
 
     CorePS::Destroy(lock);
 
     // We just destroyed CorePS and the ThreadInfos it contains, so we can
@@ -2394,26 +2410,27 @@ profiler_shutdown()
   if (samplerThread) {
     ProfilerParent::ProfilerStopped();
     NotifyObservers("profiler-stopped");
     delete samplerThread;
   }
 }
 
 UniquePtr<char[]>
-profiler_get_profile(double aSinceTime)
+profiler_get_profile(double aSinceTime, bool aIsShuttingDown)
 {
   LOG("profiler_get_profile");
 
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   SpliceableChunkedJSONWriter b;
   b.Start(SpliceableJSONWriter::SingleLineStyle);
   {
-    if (!profiler_stream_json_for_this_process(b, aSinceTime)) {
+    if (!profiler_stream_json_for_this_process(b, aSinceTime,
+                                               aIsShuttingDown)) {
       return nullptr;
     }
 
     // Don't include profiles from other processes because this is a
     // synchronous function.
     b.StartArrayProperty("processes");
     b.EndArray();
   }
@@ -2504,29 +2521,31 @@ AutoSetProfilerEnvVarsForChildProcess::~
   PR_SetEnv("MOZ_PROFILER_STARTUP=");
   PR_SetEnv("MOZ_PROFILER_STARTUP_ENTRIES=");
   PR_SetEnv("MOZ_PROFILER_STARTUP_INTERVAL=");
   PR_SetEnv("MOZ_PROFILER_STARTUP_FEATURES_BITFIELD=");
   PR_SetEnv("MOZ_PROFILER_STARTUP_FILTERS=");
 }
 
 static void
-locked_profiler_save_profile_to_file(PSLockRef aLock, const char* aFilename)
+locked_profiler_save_profile_to_file(PSLockRef aLock, const char* aFilename,
+                                     bool aIsShuttingDown = false)
 {
   LOG("locked_profiler_save_profile_to_file(%s)", aFilename);
 
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   std::ofstream stream;
   stream.open(aFilename);
   if (stream.is_open()) {
     SpliceableJSONWriter w(MakeUnique<OStreamJSONWriteFunc>(stream));
     w.Start(SpliceableJSONWriter::SingleLineStyle);
     {
-      locked_profiler_stream_json_for_this_process(aLock, w, /* sinceTime */ 0);
+      locked_profiler_stream_json_for_this_process(aLock, w, /* sinceTime */ 0,
+                                                   aIsShuttingDown);
 
       // Don't include profiles from other processes because this is a
       // synchronous function.
       w.StartArrayProperty("processes");
       w.EndArray();
     }
     w.End();
 
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -448,25 +448,29 @@ PROFILER_FUNC_VOID(profiler_tracing(cons
                                     TracingKind aKind = TRACING_EVENT))
 
 //---------------------------------------------------------------------------
 // Output profiles
 //---------------------------------------------------------------------------
 
 // Get the profile encoded as a JSON string. A no-op (returning nullptr) if the
 // profiler is inactive.
+// If aIsShuttingDown is true, the current time is included as the process
+// shutdown time in the JSON's "meta" object.
 PROFILER_FUNC(
-  mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0),
+  mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0,
+                                                  bool aIsShuttingDown = false),
   nullptr)
 
 // Write the profile for this process (excluding subprocesses) into aWriter.
 // Returns false if the profiler is inactive.
 PROFILER_FUNC(
   bool profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter,
                                              double aSinceTime = 0,
+                                             bool aIsShuttingDown = false,
                                              mozilla::TimeStamp* aOutFirstSampleTime = nullptr),
   false)
 
 // Get the profile and write it into a file. A no-op if the profile is
 // inactive.
 //
 // This function is 'extern "C"' so that it is easily callable from a debugger
 // in a build without debugging information (a workaround for