Bug 1382910 - Propagate the current profiler state to a newly-launched child process using environment variables. r?njn draft
authorMarkus Stange <mstange@themasta.com>
Mon, 24 Jul 2017 18:16:33 -0400
changeset 614734 6e02c8969b98be9dcf3e0e3b601b782bcd9c5118
parent 614590 508f22f3910a16d81f01ca454908550104801812
child 614735 bfb28d33e32b5690dc7012203248c57f9a1c54bd
push id70096
push userbmo:mstange@themasta.com
push dateMon, 24 Jul 2017 22:17:43 +0000
reviewersnjn
bugs1382910
milestone56.0a1
Bug 1382910 - Propagate the current profiler state to a newly-launched child process using environment variables. r?njn This also fixes the bug where we would always profile child processes if the parent process had been launched with MOZ_PROFILER_STARTUP=1, regardless of whether the profiler was still running in the parent process. MozReview-Commit-ID: LkIpYmKJOJ1
ipc/glue/GeckoChildProcessHost.cpp
tools/profiler/core/platform.cpp
tools/profiler/gecko/ProfilerParent.cpp
tools/profiler/public/GeckoProfiler.h
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -536,16 +536,18 @@ GeckoChildProcessHost::SetChildLogName(c
   // for the time we launch the sub-process.  It's copied to the new
   // environment.
   PR_SetEnv(buffer.BeginReading());
 }
 
 bool
 GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
 {
+  AutoSetProfilerEnvVarsForChildProcess profilerEnvironment;
+
   // If NSPR log files are not requested, we're done.
   const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
   const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
   if (!origNSPRLogName && !origMozLogName) {
     return PerformAsyncLaunchInternal(aExtraOpts, arch);
   }
 
   // - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2366,16 +2366,70 @@ profiler_get_start_params(int* aEntries,
 
   const Vector<std::string>& filters = ActivePS::Filters(lock);
   MOZ_ALWAYS_TRUE(aFilters->resize(filters.length()));
   for (uint32_t i = 0; i < filters.length(); ++i) {
     (*aFilters)[i] = filters[i].c_str();
   }
 }
 
+AutoSetProfilerEnvVarsForChildProcess::AutoSetProfilerEnvVarsForChildProcess(
+  MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
+{
+  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+
+  MOZ_RELEASE_ASSERT(CorePS::Exists());
+
+  PSAutoLock lock(gPSMutex);
+
+  if (!ActivePS::Exists(lock)) {
+    PR_SetEnv("MOZ_PROFILER_STARTUP=");
+    return;
+  }
+
+  PR_SetEnv("MOZ_PROFILER_STARTUP=1");
+  SprintfLiteral(mSetEntries, "MOZ_PROFILER_STARTUP_ENTRIES=%d",
+                 ActivePS::Entries(lock));
+  PR_SetEnv(mSetEntries);
+
+  SprintfLiteral(mSetInterval, "MOZ_PROFILER_STARTUP_INTERVAL=%f",
+                 ActivePS::Interval(lock));
+  PR_SetEnv(mSetInterval);
+
+  SprintfLiteral(mSetFeaturesBitfield,
+                 "MOZ_PROFILER_STARTUP_FEATURES_BITFIELD=%d",
+                 ActivePS::Features(lock));
+  PR_SetEnv(mSetFeaturesBitfield);
+
+  std::string filtersString;
+  const Vector<std::string>& filters = ActivePS::Filters(lock);
+  for (uint32_t i = 0; i < filters.length(); ++i) {
+    filtersString += filters[i];
+    if (i != filters.length() - 1) {
+      filtersString += ",";
+    }
+  }
+  SprintfLiteral(mSetFilters, "MOZ_PROFILER_STARTUP_FILTERS=%s",
+                 filtersString.c_str());
+  PR_SetEnv(mSetFilters);
+}
+
+AutoSetProfilerEnvVarsForChildProcess::~AutoSetProfilerEnvVarsForChildProcess()
+{
+  // Our current process doesn't look at these variables after startup, so we
+  // can just unset all the variables. This allows us to use literal strings,
+  // which will be valid for the whole life time of the program and can be
+  // passed to PR_SetEnv without problems.
+  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)
 {
   LOG("locked_profiler_save_profile_to_file(%s)", aFilename);
 
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   std::ofstream stream;
--- a/tools/profiler/gecko/ProfilerParent.cpp
+++ b/tools/profiler/gecko/ProfilerParent.cpp
@@ -124,38 +124,16 @@ ProfilerParent::ProfilerParent()
 }
 
 void
 ProfilerParent::Init()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   ProfilerParentTracker::StartTracking(this);
-
-  if (profiler_is_active()) {
-    // If the profiler is already running in this process, start it in the
-    // child process immediately.
-    int entries = 0;
-    double interval = 0;
-    mozilla::Vector<const char*> filters;
-    uint32_t features;
-    profiler_get_start_params(&entries, &interval, &features, &filters);
-
-    ProfilerInitParams ipcParams;
-    ipcParams.enabled() = true;
-    ipcParams.entries() = entries;
-    ipcParams.interval() = interval;
-    ipcParams.features() = features;
-
-    for (uint32_t i = 0; i < filters.length(); ++i) {
-      ipcParams.filters().AppendElement(filters[i]);
-    }
-
-    Unused << SendStart(ipcParams);
-  }
 }
 
 ProfilerParent::~ProfilerParent()
 {
   MOZ_COUNT_DTOR(ProfilerParent);
 
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   ProfilerParentTracker::StopTracking(this);
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -584,11 +584,34 @@ public:
   }
 
 protected:
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   const char* mCategory;
   const char* mMarkerName;
 };
 
+// Set MOZ_PROFILER_STARTUP* environment variables that will be inherited into
+// a child process that is about to be launched, in order to make that child
+// process start with the same profiler settings as in the current process.
+#ifdef MOZ_GECKO_PROFILER
+class MOZ_RAII AutoSetProfilerEnvVarsForChildProcess
+{
+public:
+  explicit AutoSetProfilerEnvVarsForChildProcess(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
+  ~AutoSetProfilerEnvVarsForChildProcess();
+
+private:
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+  char mSetEntries[64];
+  char mSetInterval[64];
+  char mSetFeaturesBitfield[64];
+  char mSetFilters[1024];
+};
+#else
+class AutoSetProfilerEnvVarsForChildProcess
+{
+};
+#endif
+
 } // namespace mozilla
 
 #endif  // GeckoProfiler_h