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
--- 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