--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -20,16 +20,20 @@
#include <sys/types.h>
#include <sys/wait.h>
#endif
#include "chrome/common/process_watcher.h"
#include "mozilla/a11y/PDocAccessible.h"
#include "AudioChannelService.h"
+#ifdef MOZ_GECKO_PROFILER
+#include "CrossProcessProfilerController.h"
+#endif
+#include "GeckoProfiler.h"
#include "GMPServiceParent.h"
#include "HandlerServiceParent.h"
#include "IHistory.h"
#include "imgIContainer.h"
#if defined(XP_WIN) && defined(ACCESSIBILITY)
#include "mozilla/a11y/AccessibleWrap.h"
#endif
#include "mozilla/ClearOnShutdown.h"
@@ -82,17 +86,16 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/media/MediaParent.h"
#include "mozilla/Move.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/plugins/PluginBridge.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/ProcessHangMonitorIPC.h"
-#include "GeckoProfiler.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TelemetryIPC.h"
#include "mozilla/WebBrowserPersistDocumentParent.h"
#include "mozilla/Unused.h"
#include "nsAnonymousTemporaryFile.h"
@@ -230,21 +233,16 @@
#include "mozilla/SandboxBroker.h"
#include "mozilla/SandboxBrokerPolicyFactory.h"
#endif
#ifdef MOZ_TOOLKIT_SEARCH
#include "nsIBrowserSearchService.h"
#endif
-#ifdef MOZ_GECKO_PROFILER
-#include "nsIProfiler.h"
-#include "nsIProfileSaveEvent.h"
-#endif
-
#ifdef XP_WIN
#include "mozilla/widget/AudioSession.h"
#endif
#ifdef MOZ_CRASHREPORTER
#include "nsThread.h"
#include "mozilla/ipc/CrashReporterHost.h"
#endif
@@ -558,24 +556,16 @@ static const char* sObserverTopics[] = {
"child-gc-request",
"child-cc-request",
"child-mmu-request",
"last-pb-context-exited",
"file-watcher-update",
#ifdef ACCESSIBILITY
"a11y-init-or-shutdown",
#endif
-#ifdef MOZ_GECKO_PROFILER
- "profiler-started",
- "profiler-stopped",
- "profiler-paused",
- "profiler-resumed",
- "profiler-subprocess-gather",
- "profiler-subprocess",
-#endif
"cacheservice:empty-cache",
};
// PreallocateProcess is called by the PreallocatedProcessManager.
// ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
/*static*/ already_AddRefed<ContentParent>
ContentParent::PreallocateProcess()
{
@@ -1065,16 +1055,48 @@ ContentParent::RecvUngrabPointer(const u
mozilla::ipc::IPCResult
ContentParent::RecvRemovePermission(const IPC::Principal& aPrincipal,
const nsCString& aPermissionType,
nsresult* aRv) {
*aRv = Permissions::RemovePermission(aPrincipal, aPermissionType.get());
return IPC_OK();
}
+void
+ContentParent::SendStartProfiler(const ProfilerInitParams& aParams)
+{
+ if (mSubprocess && mIsAlive) {
+ Unused << PContentParent::SendStartProfiler(aParams);
+ }
+}
+
+void
+ContentParent::SendStopProfiler()
+{
+ if (mSubprocess && mIsAlive) {
+ Unused << PContentParent::SendStopProfiler();
+ }
+}
+
+void
+ContentParent::SendPauseProfiler(const bool& aPause)
+{
+ if (mSubprocess && mIsAlive) {
+ Unused << PContentParent::SendPauseProfiler(aPause);
+ }
+}
+
+void
+ContentParent::SendGatherProfile()
+{
+ if (mSubprocess && mIsAlive) {
+ Unused << PContentParent::SendGatherProfile();
+ }
+}
+
mozilla::ipc::IPCResult
ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId,
nsresult* aRv,
Endpoint<PPluginModuleParent>* aEndpoint)
{
*aRv = NS_OK;
// We don't need to get the run ID for the plugin, since we already got it
// in the first call to SetupBridge in RecvLoadPlugin, so we pass in a dummy
@@ -1309,30 +1331,17 @@ ContentParent::Init()
SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
#else
Unused << SendActivateA11y(0);
#endif
}
#endif
#ifdef MOZ_GECKO_PROFILER
- nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
- bool profilerActive = false;
- DebugOnly<nsresult> rv = profiler->IsActive(&profilerActive);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- if (profilerActive) {
- nsCOMPtr<nsIProfilerStartParams> currentProfilerParams;
- rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams));
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- mIsProfilerActive = true;
-
- StartProfiler(currentProfilerParams);
- }
+ mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
#endif
RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
gmps->UpdateContentProcessGMPCapabilities();
mScriptableHelper = new ScriptableCPInfo(this);
}
@@ -1716,19 +1725,17 @@ ContentParent::ActorDestroy(ActorDestroy
gpu->RemoveListener(this);
}
RecvRemoveGeolocationListener();
mConsoleService = nullptr;
#ifdef MOZ_GECKO_PROFILER
- if (mIsProfilerActive && !mProfile.IsEmpty()) {
- profiler_OOP_exit_profile(mProfile);
- }
+ mProfilerController = nullptr;
#endif
if (obs) {
RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
if (AbnormalShutdown == why) {
@@ -2064,19 +2071,16 @@ ContentParent::ContentParent(ContentPare
, mSendPermissionUpdates(false)
, mIsForBrowser(!mRemoteType.IsEmpty())
, mCalledClose(false)
, mCalledKillHard(false)
, mCreatedPairedMinidumps(false)
, mShutdownPending(false)
, mIPCOpen(true)
, mHangMonitorActor(nullptr)
-#ifdef MOZ_GECKO_PROFILER
- , mIsProfilerActive(false)
-#endif
{
// Insert ourselves into the global linked list of ContentParent objects.
if (!sContentParents) {
sContentParents = new LinkedList<ContentParent>();
}
sContentParents->insertBack(this);
// From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
@@ -2711,37 +2715,16 @@ ContentParent::Observe(nsISupports* aSub
// data (e.g. telemetry) from the child before we quit.
// This loop terminate prematurely based on mForceKillTimer.
while (mIPCOpen && !mCalledKillHard) {
NS_ProcessNextEvent(nullptr, true);
}
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
}
-#ifdef MOZ_GECKO_PROFILER
- // Need to do this before the mIsAlive check to avoid missing profiles.
- if (!strcmp(aTopic, "profiler-subprocess-gather")) {
- if (mIsProfilerActive) {
- profiler_will_gather_OOP_profile();
- if (mIsAlive && mSubprocess) {
- Unused << SendGatherProfile();
- }
- }
- }
- else if (!strcmp(aTopic, "profiler-subprocess")) {
- nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
- if (pse) {
- if (!mProfile.IsEmpty()) {
- pse->AddSubProfile(mProfile.get());
- mProfile.Truncate();
- }
- }
- }
-#endif
-
if (!mIsAlive || !mSubprocess)
return NS_OK;
// listening for memory pressure event
if (!strcmp(aTopic, "memory-pressure") &&
!StringEndsWith(nsDependentString(aData),
NS_LITERAL_STRING("-no-forward"))) {
Unused << SendFlushMemory(nsDependentString(aData));
@@ -2815,32 +2798,16 @@ ContentParent::Observe(nsISupports* aSub
#endif
} else {
// If possible, shut down accessibility in content process when
// accessibility gets shutdown in chrome process.
Unused << SendShutdownA11y();
}
}
#endif
-#ifdef MOZ_GECKO_PROFILER
- else if (!strcmp(aTopic, "profiler-started")) {
- nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject));
- StartProfiler(params);
- }
- else if (!strcmp(aTopic, "profiler-stopped")) {
- mIsProfilerActive = false;
- Unused << SendStopProfiler();
- }
- else if (!strcmp(aTopic, "profiler-paused")) {
- Unused << SendPauseProfiler(true);
- }
- else if (!strcmp(aTopic, "profiler-resumed")) {
- Unused << SendPauseProfiler(false);
- }
-#endif
else if (!strcmp(aTopic, "cacheservice:empty-cache")) {
Unused << SendNotifyEmptyHTTPCache();
}
return NS_OK;
}
mozilla::ipc::IPCResult
ContentParent::RecvInitBackground(Endpoint<PBackgroundParent>&& aEndpoint)
@@ -4759,21 +4726,19 @@ ContentParent::RecvCreateWindowInDiffere
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvProfile(const nsCString& aProfile)
{
#ifdef MOZ_GECKO_PROFILER
- if (NS_WARN_IF(!mIsProfilerActive)) {
- return IPC_OK();
- }
- mProfile = aProfile;
- profiler_gathered_OOP_profile();
+ if (mProfilerController) {
+ mProfilerController->RecvProfile(aProfile);
+ }
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvGetGraphicsDeviceInitData(ContentDeviceData* aOut)
{
gfxPlatform::GetPlatform()->BuildContentDeviceData(aOut);
@@ -4854,42 +4819,16 @@ ContentParent::RecvNotifyBenchmarkResult
if (aCodecName.EqualsLiteral("VP9")) {
Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck,
VP9Benchmark::sBenchmarkVersionID);
}
return IPC_OK();
}
-void
-ContentParent::StartProfiler(nsIProfilerStartParams* aParams)
-{
-#ifdef MOZ_GECKO_PROFILER
- if (NS_WARN_IF(!aParams)) {
- return;
- }
-
- ProfilerInitParams ipcParams;
-
- ipcParams.enabled() = true;
- aParams->GetEntries(&ipcParams.entries());
- aParams->GetInterval(&ipcParams.interval());
- ipcParams.features() = aParams->GetFeatures();
- ipcParams.threadFilters() = aParams->GetThreadFilterNames();
-
- Unused << SendStartProfiler(ipcParams);
-
- nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
- if (NS_WARN_IF(!profiler)) {
- return;
- }
- mIsProfilerActive = true;
-#endif
-}
-
mozilla::ipc::IPCResult
ContentParent::RecvNotifyPushObservers(const nsCString& aScope,
const IPC::Principal& aPrincipal,
const nsString& aMessageId)
{
PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
return IPC_OK();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -25,16 +25,17 @@
#include "nsFrameMessageManager.h"
#include "nsHashKeys.h"
#include "nsIObserver.h"
#include "nsIThreadInternal.h"
#include "nsIDOMGeoPositionCallback.h"
#include "nsIDOMGeoPositionErrorCallback.h"
#include "nsRefPtrHashtable.h"
#include "PermissionMessageUtils.h"
+#include "ProfilerControllingProcess.h"
#include "DriverCrashGuard.h"
#define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
#define NO_REMOTE_TYPE ""
// These must match the similar ones in E10SUtils.jsm.
#define DEFAULT_REMOTE_TYPE "web"
@@ -50,16 +51,19 @@ class nsICycleCollectorLogSink;
class nsIDumpGCAndCCLogsCallback;
class nsITabParent;
class nsITimer;
class ParentIdleListener;
class nsIWidget;
namespace mozilla {
class PRemoteSpellcheckEngineParent;
+#ifdef MOZ_GECKO_PROFILER
+class CrossProcessProfilerController;
+#endif
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
class SandboxBroker;
class SandboxBrokerPolicyFactory;
#endif
class PreallocatedProcessManagerImpl;
@@ -103,16 +107,17 @@ class ContentParent final : public PCont
, public nsIContentParent
, public nsIObserver
, public nsIDOMGeoPositionCallback
, public nsIDOMGeoPositionErrorCallback
, public gfx::gfxVarReceiver
, public mozilla::LinkedListElement<ContentParent>
, public gfx::GPUProcessListener
, public mozilla::MemoryReportingProcess
+ , public mozilla::ProfilerControllingProcess
{
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
typedef mozilla::ipc::PFileDescriptorSetParent PFileDescriptorSetParent;
typedef mozilla::ipc::TestShellParent TestShellParent;
typedef mozilla::ipc::URIParams URIParams;
typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@@ -298,16 +303,21 @@ public:
uint32_t* aNewPluginEpoch) override;
virtual mozilla::ipc::IPCResult RecvUngrabPointer(const uint32_t& aTime) override;
virtual mozilla::ipc::IPCResult RecvRemovePermission(const IPC::Principal& aPrincipal,
const nsCString& aPermissionType,
nsresult* aRv) override;
+ void SendStartProfiler(const ProfilerInitParams& aParams) override;
+ void SendStopProfiler() override;
+ void SendPauseProfiler(const bool& aPause) override;
+ void SendGatherProfile() override;
+
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMGEOPOSITIONCALLBACK
NS_DECL_NSIDOMGEOPOSITIONERRORCALLBACK
/**
@@ -1085,18 +1095,16 @@ private:
virtual mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect) override;
virtual mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile) override;
virtual mozilla::ipc::IPCResult RecvGetGraphicsDeviceInitData(ContentDeviceData* aOut) override;
- void StartProfiler(nsIProfilerStartParams* aParams);
-
virtual mozilla::ipc::IPCResult RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo) override;
virtual mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsString& aCodecName,
const uint32_t& aDecodeFPS) override;
virtual mozilla::ipc::IPCResult RecvNotifyPushObservers(const nsCString& aScope,
const IPC::Principal& aPrincipal,
const nsString& aMessageId) override;
@@ -1202,19 +1210,18 @@ private:
// Dup of child's X socket, used to scope its resources to this
// object instead of the child process's lifetime.
ScopedClose mChildXSocketFdDup;
#endif
PProcessHangMonitorParent* mHangMonitorActor;
#ifdef MOZ_GECKO_PROFILER
- bool mIsProfilerActive;
+ UniquePtr<mozilla::CrossProcessProfilerController> mProfilerController;
#endif
- nsCString mProfile;
UniquePtr<gfx::DriverCrashGuard> mDriverCrashGuard;
UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
mozilla::UniquePtr<SandboxBroker> mSandboxBroker;
static mozilla::UniquePtr<SandboxBrokerPolicyFactory>
sSandboxBrokerPolicyFactory;
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -95,17 +95,17 @@ child:
intr InitCrashReporter(Shmem shmem)
returns (NativeThreadId tid);
/**
* Control the Gecko Profiler in the plugin process.
*/
async StartProfiler(ProfilerInitParams params);
async StopProfiler();
-
+ async PauseProfiler(bool aPause);
async GatherProfile();
async SettingChanged(PluginSettings settings);
async NPP_SetValue_NPNVaudioDeviceChangeDetails(NPAudioDeviceChangeDetailsIPC changeDetails);
async InitPluginModuleChild(Endpoint<PPluginModuleChild> endpoint);
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -2714,16 +2714,28 @@ PluginModuleChild::RecvStartProfiler(con
mozilla::ipc::IPCResult
PluginModuleChild::RecvStopProfiler()
{
profiler_stop();
return IPC_OK();
}
mozilla::ipc::IPCResult
+PluginModuleChild::RecvPauseProfiler(const bool& aPause)
+{
+ if (aPause) {
+ profiler_pause();
+ } else {
+ profiler_resume();
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
PluginModuleChild::RecvGatherProfile()
{
nsCString profileCString;
UniquePtr<char[]> profile = profiler_get_profile();
if (profile != nullptr) {
profileCString = nsCString(profile.get(), strlen(profile.get()));
} else {
profileCString = nsCString("", 0);
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -122,16 +122,17 @@ protected:
virtual void
ActorDestroy(ActorDestroyReason why) override;
virtual mozilla::ipc::IPCResult
RecvProcessNativeEventsInInterruptCall() override;
virtual mozilla::ipc::IPCResult RecvStartProfiler(const ProfilerInitParams& params) override;
virtual mozilla::ipc::IPCResult RecvStopProfiler() override;
+ virtual mozilla::ipc::IPCResult RecvPauseProfiler(const bool& aPause) override;
virtual mozilla::ipc::IPCResult RecvGatherProfile() override;
virtual mozilla::ipc::IPCResult
AnswerModuleSupportsAsyncRender(bool* aResult) override;
public:
explicit PluginModuleChild(bool aIsChrome);
virtual ~PluginModuleChild();
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -26,43 +26,44 @@
#include "nsCRT.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsIXULRuntime.h"
#include "nsNPAPIPlugin.h"
#include "nsPrintfCString.h"
#include "prsystem.h"
#include "PluginQuirks.h"
+#ifdef MOZ_GECKO_PROFILER
+#include "CrossProcessProfilerController.h"
+#endif
#include "GeckoProfiler.h"
#include "nsPluginTags.h"
#include "nsUnicharUtils.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#ifdef XP_WIN
#include "mozilla/plugins/PluginSurfaceParent.h"
#include "mozilla/widget/AudioSession.h"
#include "PluginHangUIParent.h"
#include "PluginUtilsWin.h"
#endif
-#ifdef MOZ_GECKO_PROFILER
-#include "nsIProfiler.h"
-#include "nsIProfileSaveEvent.h"
-#endif
-
#ifdef MOZ_WIDGET_GTK
#include <glib.h>
#elif XP_MACOSX
#include "PluginInterposeOSX.h"
#include "PluginUtilsOSX.h"
#endif
using base::KillProcess;
using mozilla::PluginLibrary;
+#ifdef MOZ_GECKO_PROFILER
+using mozilla::CrossProcessProfilerController;
+#endif
using mozilla::ipc::MessageChannel;
using mozilla::ipc::GeckoChildProcessHost;
using namespace mozilla;
using namespace mozilla::plugins;
using namespace mozilla::plugins::parent;
#ifdef MOZ_CRASHREPORTER
@@ -629,29 +630,17 @@ PluginModuleChromeParent::OnProcessLaunc
if (NS_SUCCEEDED(mAsyncInitRv)) {
mAsyncInitRv = NP_GetEntryPoints(mNPPIface,
&mAsyncInitError);
}
#endif
}
#ifdef MOZ_GECKO_PROFILER
- nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
- bool profilerActive = false;
- DebugOnly<nsresult> rv = profiler->IsActive(&profilerActive);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
- if (profilerActive) {
- nsCOMPtr<nsIProfilerStartParams> currentProfilerParams;
- rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams));
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- mIsProfilerActive = true;
-
- StartProfiler(currentProfilerParams);
- }
+ mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
#endif
}
bool
PluginModuleChromeParent::WaitForIPCConnection()
{
PluginProcessParent* process = Process();
MOZ_ASSERT(process);
@@ -767,40 +756,33 @@ PluginModuleChromeParent::PluginModuleCh
, mFlashProcess1(0)
, mFlashProcess2(0)
, mFinishInitTask(nullptr)
#endif
, mInitOnAsyncConnect(false)
, mAsyncInitRv(NS_ERROR_NOT_INITIALIZED)
, mAsyncInitError(NPERR_NO_ERROR)
, mContentParent(nullptr)
-#ifdef MOZ_GECKO_PROFILER
- , mIsProfilerActive(false)
-#endif
{
NS_ASSERTION(mSubprocess, "Out of memory!");
sInstantiated = true;
mSandboxLevel = aSandboxLevel;
mRunID = GeckoChildProcessHost::GetUniqueID();
-#ifdef MOZ_GECKO_PROFILER
- InitPluginProfiling();
-#endif
-
mozilla::HangMonitor::RegisterAnnotator(*this);
}
PluginModuleChromeParent::~PluginModuleChromeParent()
{
if (!OkToCleanup()) {
MOZ_CRASH("unsafe destruction");
}
#ifdef MOZ_GECKO_PROFILER
- ShutdownPluginProfiling();
+ mProfilerController = nullptr;
#endif
#ifdef XP_WIN
// If we registered for audio notifications, stop.
mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
false);
#endif
@@ -3277,140 +3259,23 @@ PluginModuleChromeParent::OnCrash(DWORD
} else {
NS_ERROR("Failed to open child process when attempting kill.");
}
}
}
#endif // MOZ_CRASHREPORTER_INJECTOR
-#ifdef MOZ_GECKO_PROFILER
-class PluginProfilerObserver final : public nsIObserver,
- public nsSupportsWeakReference
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIOBSERVER
-
- explicit PluginProfilerObserver(PluginModuleChromeParent* pmp)
- : mPmp(pmp)
- {}
-
-private:
- ~PluginProfilerObserver() {}
- PluginModuleChromeParent* mPmp;
-};
-
-NS_IMPL_ISUPPORTS(PluginProfilerObserver, nsIObserver, nsISupportsWeakReference)
-
-NS_IMETHODIMP
-PluginProfilerObserver::Observe(nsISupports *aSubject,
- const char *aTopic,
- const char16_t *aData)
-{
- if (!strcmp(aTopic, "profiler-started")) {
- nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject));
- mPmp->StartProfiler(params);
- } else if (!strcmp(aTopic, "profiler-stopped")) {
- mPmp->StopProfiler();
- } else if (!strcmp(aTopic, "profiler-subprocess-gather")) {
- mPmp->GatherAsyncProfile();
- } else if (!strcmp(aTopic, "profiler-subprocess")) {
- nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
- mPmp->GatheredAsyncProfile(pse);
- }
- return NS_OK;
-}
-
-void
-PluginModuleChromeParent::InitPluginProfiling()
-{
- nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
- if (observerService) {
- mProfilerObserver = new PluginProfilerObserver(this);
- observerService->AddObserver(mProfilerObserver, "profiler-started", false);
- observerService->AddObserver(mProfilerObserver, "profiler-stopped", false);
- observerService->AddObserver(mProfilerObserver, "profiler-subprocess-gather", false);
- observerService->AddObserver(mProfilerObserver, "profiler-subprocess", false);
- }
-}
-
-void
-PluginModuleChromeParent::ShutdownPluginProfiling()
-{
- nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
- if (observerService) {
- observerService->RemoveObserver(mProfilerObserver, "profiler-started");
- observerService->RemoveObserver(mProfilerObserver, "profiler-stopped");
- observerService->RemoveObserver(mProfilerObserver, "profiler-subprocess-gather");
- observerService->RemoveObserver(mProfilerObserver, "profiler-subprocess");
- }
-}
-
-void
-PluginModuleChromeParent::StartProfiler(nsIProfilerStartParams* aParams)
-{
- if (NS_WARN_IF(!aParams)) {
- return;
- }
-
- ProfilerInitParams ipcParams;
-
- ipcParams.enabled() = true;
- aParams->GetEntries(&ipcParams.entries());
- aParams->GetInterval(&ipcParams.interval());
- ipcParams.features() = aParams->GetFeatures();
- ipcParams.threadFilters() = aParams->GetThreadFilterNames();
-
- Unused << SendStartProfiler(ipcParams);
-
- nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
- if (NS_WARN_IF(!profiler)) {
- return;
- }
- mIsProfilerActive = true;
-}
-
-void
-PluginModuleChromeParent::StopProfiler()
-{
- mIsProfilerActive = false;
- Unused << SendStopProfiler();
-}
-
-void
-PluginModuleChromeParent::GatherAsyncProfile()
-{
- if (NS_WARN_IF(!mIsProfilerActive)) {
- return;
- }
- profiler_will_gather_OOP_profile();
- Unused << SendGatherProfile();
-}
-
-void
-PluginModuleChromeParent::GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent)
-{
- if (aSaveEvent && !mProfile.IsEmpty()) {
- aSaveEvent->AddSubProfile(mProfile.get());
- mProfile.Truncate();
- }
-}
-#endif // MOZ_GECKO_PROFILER
-
mozilla::ipc::IPCResult
PluginModuleChromeParent::RecvProfile(const nsCString& aProfile)
{
#ifdef MOZ_GECKO_PROFILER
- if (NS_WARN_IF(!mIsProfilerActive)) {
- return IPC_OK();
+ if (mProfilerController) {
+ mProfilerController->RecvProfile(aProfile);
}
-
- mProfile = aProfile;
- profiler_gathered_OOP_profile();
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult
PluginModuleParent::AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet)
{
return IPC_FAIL_NO_REASON(this);
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -12,37 +12,43 @@
#include "mozilla/HangAnnotations.h"
#include "mozilla/PluginLibrary.h"
#include "mozilla/plugins/PluginProcessParent.h"
#include "mozilla/plugins/PPluginModuleParent.h"
#include "mozilla/plugins/PluginMessageUtils.h"
#include "mozilla/plugins/PluginTypes.h"
#include "mozilla/ipc/TaskFactory.h"
#include "mozilla/TimeStamp.h"
+#include "mozilla/Unused.h"
#include "npapi.h"
#include "npfunctions.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsIObserver.h"
#ifdef XP_WIN
#include "nsWindowsHelpers.h"
#if defined(MOZ_SANDBOX)
#include "sandboxPermissions.h"
#endif
#endif
+#include "ProfilerControllingProcess.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
-class nsIProfileSaveEvent;
class nsPluginTag;
namespace mozilla {
+#ifdef MOZ_GECKO_PROFILER
+class CrossProcessProfilerController;
+#endif
+
+
namespace ipc {
class CrashReporterHost;
} // namespace ipc
namespace layers {
class TextureClientRecycleAllocator;
} // namespace layers
namespace plugins {
@@ -74,16 +80,17 @@ class FinishInjectorInitTask;
* the chrome process. In addition, any content process using the plugin will
* have its own PluginModuleParent. The subclasses PluginModuleChromeParent and
* PluginModuleContentParent implement functionality that is specific to one
* case or the other.
*/
class PluginModuleParent
: public PPluginModuleParent
, public PluginLibrary
+ , public mozilla::ProfilerControllingProcess
#ifdef MOZ_CRASHREPORTER_INJECTOR
, public CrashReporter::InjectorCrashCallback
#endif
{
protected:
typedef mozilla::PluginLibrary PluginLibrary;
PPluginInstanceParent*
@@ -135,16 +142,33 @@ public:
virtual nsresult GetRunID(uint32_t* aRunID) override;
virtual void SetHasLocalInstance() override {
mHadLocalInstance = true;
}
int GetQuirks() { return mQuirks; }
+ void SendStartProfiler(const ProfilerInitParams& aParams) override
+ {
+ Unused << PPluginModuleParent::SendStartProfiler(aParams);
+ }
+ void SendStopProfiler() override
+ {
+ Unused << PPluginModuleParent::SendStopProfiler();
+ }
+ void SendPauseProfiler(const bool& aPause) override
+ {
+ Unused << PPluginModuleParent::SendPauseProfiler(aPause);
+ }
+ void SendGatherProfile() override
+ {
+ Unused << PPluginModuleParent::SendGatherProfile();
+ }
+
protected:
virtual mozilla::ipc::RacyInterruptPolicy
MediateInterruptRace(const MessageInfo& parent,
const MessageInfo& child) override
{
return MediateRace(parent, child);
}
@@ -333,17 +357,16 @@ protected:
bool mHadLocalInstance;
bool mClearSiteDataSupported;
bool mGetSitesWithDataSupported;
NPNetscapeFuncs* mNPNIface;
NPPluginFuncs* mNPPIface;
nsNPAPIPlugin* mPlugin;
ipc::TaskFactory<PluginModuleParent> mTaskFactory;
nsString mHangID;
- RefPtr<nsIObserver> mProfilerObserver;
TimeDuration mTimeBlocked;
nsCString mPluginName;
nsCString mPluginVersion;
int32_t mSandboxLevel;
bool mIsFlashPlugin;
#ifdef MOZ_X11
// Dup of plugin's X socket, used to scope its resources to this
@@ -498,23 +521,16 @@ class PluginModuleChromeParent
void
SetContentParent(dom::ContentParent* aContentParent);
bool
SendAssociatePluginId();
void CachedSettingChanged();
-#ifdef MOZ_GECKO_PROFILER
- void GatherAsyncProfile();
- void GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent);
- void StartProfiler(nsIProfilerStartParams* aParams);
- void StopProfiler();
-#endif
-
virtual mozilla::ipc::IPCResult
RecvProfile(const nsCString& aProfile) override;
virtual mozilla::ipc::IPCResult
AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
// Proxy GetOpenFileName/GetSaveFileName on Windows.
virtual mozilla::ipc::IPCResult
@@ -561,21 +577,16 @@ private:
explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId,
int32_t aSandboxLevel,
bool aAllowAsyncInit);
void CleanupFromTimeout(const bool aByHangUI);
virtual void UpdatePluginTimeout() override;
-#ifdef MOZ_GECKO_PROFILER
- void InitPluginProfiling();
- void ShutdownPluginProfiling();
-#endif
-
void RegisterSettingsCallbacks();
void UnregisterSettingsCallbacks();
bool InitCrashReporter();
virtual mozilla::ipc::IPCResult RecvNotifyContentModuleDestroyed() override;
static void CachedSettingChanged(const char* aPref, void* aModule);
@@ -665,19 +676,18 @@ private:
NPError mAsyncInitError;
// mContentParent is to be used ONLY during the IPC dance that occurs
// when ContentParent::RecvLoadPlugin is called under async plugin init!
// In other contexts it is *unsafe*, as there might be multiple content
// processes in existence!
dom::ContentParent* mContentParent;
nsCOMPtr<nsIObserver> mPluginOfflineObserver;
#ifdef MOZ_GECKO_PROFILER
- bool mIsProfilerActive;
+ UniquePtr<CrossProcessProfilerController> mProfilerController;
#endif
- nsCString mProfile;
bool mIsBlocklisted;
static bool sInstantiated;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mozilla::SandboxPermissions mSandboxPermissions;
#endif
};
} // namespace plugins
new file mode 100644
--- /dev/null
+++ b/tools/profiler/gecko/CrossProcessProfilerController.cpp
@@ -0,0 +1,186 @@
+/* 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/. */
+
+#include "CrossProcessProfilerController.h"
+
+#include "mozilla/Move.h"
+#include "mozilla/ProfilerTypes.h"
+#include "nsIProfiler.h"
+#include "nsIProfileSaveEvent.h"
+#include "nsISupports.h"
+#include "nsIObserver.h"
+#include "ProfilerControllingProcess.h"
+
+namespace mozilla {
+
+static const char* sObserverTopics[] = {
+ "profiler-started",
+ "profiler-stopped",
+ "profiler-paused",
+ "profiler-resumed",
+ "profiler-subprocess-gather",
+ "profiler-subprocess",
+};
+
+// ProfilerObserver is a refcounted class that gets registered with the
+// observer service and just forwards Observe() calls to mController.
+// This indirection makes the CrossProcessProfilerController API nicer because
+// it doesn't require a separate Init() method to register with the observer
+// service, and because not being refcounted allows CPPC to be managed with a
+// UniquePtr.
+// The life time of ProfilerObserver is bounded by the life time of CPPC: CPPC
+// unregisters the ProfilerObserver from the observer service in its
+// destructor, and then it drops its reference to the ProfilerObserver, which
+// destroys the ProfilerObserver.
+class ProfilerObserver final : public nsIObserver
+{
+public:
+ explicit ProfilerObserver(CrossProcessProfilerController& aController)
+ : mController(aController)
+ {}
+
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData) override
+ {
+ mController.Observe(aSubject, aTopic);
+ return NS_OK;
+ }
+
+private:
+ ~ProfilerObserver() {}
+
+ CrossProcessProfilerController& mController;
+};
+
+NS_IMPL_ISUPPORTS(ProfilerObserver, nsIObserver)
+
+CrossProcessProfilerController::CrossProcessProfilerController(
+ ProfilerControllingProcess* aProcess)
+ : mProcess(aProcess)
+ , mObserver(new ProfilerObserver(*this))
+ , mIsProfilerActive(false)
+{
+ nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
+ bool profilerActive = false;
+ DebugOnly<nsresult> rv = profiler->IsActive(&profilerActive);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+ if (profilerActive) {
+ nsCOMPtr<nsIProfilerStartParams> currentProfilerParams;
+ rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams));
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+ StartProfiler(currentProfilerParams);
+ }
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ size_t length = ArrayLength(sObserverTopics);
+ for (size_t i = 0; i < length; ++i) {
+ obs->AddObserver(mObserver, sObserverTopics[i], false);
+ }
+ }
+}
+
+CrossProcessProfilerController::~CrossProcessProfilerController()
+{
+ if (mIsProfilerActive && !mProfile.IsEmpty()) {
+ profiler_OOP_exit_profile(mProfile);
+ }
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ size_t length = ArrayLength(sObserverTopics);
+ for (size_t i = 0; i < length; ++i) {
+ obs->RemoveObserver(mObserver, sObserverTopics[i]);
+ }
+ }
+}
+
+void
+CrossProcessProfilerController::StartProfiler(nsIProfilerStartParams* aParams)
+{
+ if (NS_WARN_IF(!aParams)) {
+ return;
+ }
+
+ ProfilerInitParams ipcParams;
+
+ ipcParams.enabled() = true;
+ aParams->GetEntries(&ipcParams.entries());
+ aParams->GetInterval(&ipcParams.interval());
+ ipcParams.features() = aParams->GetFeatures();
+ ipcParams.threadFilters() = aParams->GetThreadFilterNames();
+
+ mProcess->SendStartProfiler(ipcParams);
+
+ mIsProfilerActive = true;
+}
+
+void
+CrossProcessProfilerController::Observe(nsISupports* aSubject,
+ const char* aTopic)
+{
+ if (!strcmp(aTopic, "profiler-subprocess-gather")) {
+ // profiler-subprocess-gather is the request to capture the profile. We
+ // need to tell the other process that we're interested in its profile,
+ // and we tell the gatherer that we've forwarded the request, so that it
+ // can keep track of the number of pending profiles.
+ if (mIsProfilerActive) {
+ profiler_will_gather_OOP_profile();
+ mProcess->SendGatherProfile();
+ }
+ }
+ else if (!strcmp(aTopic, "profiler-subprocess")) {
+ // profiler-subprocess is sent once the gatherer knows that all other
+ // processes have replied with their profiles. It's sent during the final
+ // assembly of the parent process profile, and this is where we pass the
+ // subprocess profile along.
+ nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
+ if (pse) {
+ if (!mProfile.IsEmpty()) {
+ pse->AddSubProfile(mProfile.get());
+ mProfile.Truncate();
+ }
+ }
+ }
+ // These four notifications are sent by the profiler when its corresponding
+ // methods are called inside this process. These state changes just need to
+ // be forwarded to the other process.
+ else if (!strcmp(aTopic, "profiler-started")) {
+ nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject));
+ StartProfiler(params);
+ }
+ else if (!strcmp(aTopic, "profiler-stopped")) {
+ mIsProfilerActive = false;
+ mProcess->SendStopProfiler();
+ }
+ else if (!strcmp(aTopic, "profiler-paused")) {
+ mProcess->SendPauseProfiler(true);
+ }
+ else if (!strcmp(aTopic, "profiler-resumed")) {
+ mProcess->SendPauseProfiler(false);
+ }
+}
+
+// This is called in response to a SendGatherProfile request, or when the
+// other process exits while the profiler is running.
+void
+CrossProcessProfilerController::RecvProfile(const nsCString& aProfile)
+{
+ if (NS_WARN_IF(!mIsProfilerActive)) {
+ return;
+ }
+ // Store the profile on this object.
+ mProfile = aProfile;
+ // Tell the gatherer that we've received the profile from this process, but
+ // don't actually give it the profile. It will request the profile once all
+ // processes have replied, through the "profiler-subprocess" observer
+ // notification.
+ profiler_gathered_OOP_profile();
+}
+
+} // namespace mozilla
--- a/tools/profiler/moz.build
+++ b/tools/profiler/moz.build
@@ -1,140 +1,143 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-if CONFIG['MOZ_GECKO_PROFILER']:
- XPIDL_MODULE = 'profiler'
- XPIDL_SOURCES += [
- 'gecko/nsIProfiler.idl',
- 'gecko/nsIProfileSaveEvent.idl',
- ]
- EXPORTS += [
- 'public/ProfilerMarkers.h',
- 'public/PseudoStack.h',
- 'public/shared-libraries.h',
- ]
- EXTRA_JS_MODULES += [
- 'gecko/Profiler.jsm',
- ]
- UNIFIED_SOURCES += [
- 'core/platform.cpp',
- 'core/ProfileBuffer.cpp',
- 'core/ProfileBufferEntry.cpp',
- 'core/ProfileJSONWriter.cpp',
- 'core/ProfilerBacktrace.cpp',
- 'core/ProfilerMarkers.cpp',
- 'core/StackTop.cpp',
- 'core/ThreadInfo.cpp',
- 'gecko/nsProfiler.cpp',
- 'gecko/nsProfilerFactory.cpp',
- 'gecko/nsProfilerStartParams.cpp',
- 'gecko/ProfilerIOInterposeObserver.cpp',
- 'gecko/ThreadResponsiveness.cpp',
- ]
- if CONFIG['OS_TARGET'] == 'Darwin':
- SOURCES += [
- 'gecko/ProfileGatherer.cpp',
- ]
- else:
- UNIFIED_SOURCES += [
- 'gecko/ProfileGatherer.cpp',
- ]
-
- if CONFIG['OS_TARGET'] in ('Android', 'Linux'):
- UNIFIED_SOURCES += [
- 'lul/AutoObjectMapper.cpp',
- 'lul/LulCommon.cpp',
- 'lul/LulDwarf.cpp',
- 'lul/LulDwarfSummariser.cpp',
- 'lul/LulElf.cpp',
- 'lul/LulMain.cpp',
- 'lul/platform-linux-lul.cpp',
- ]
- # These files cannot be built in unified mode because of name clashes with mozglue headers on Android.
- SOURCES += [
- 'core/shared-libraries-linux.cc',
- ]
- if not CONFIG['MOZ_CRASHREPORTER']:
- SOURCES += [
- '/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc',
- '/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc',
- '/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc',
- '/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc',
- ]
- if CONFIG['CPU_ARCH'] == 'arm':
- SOURCES += [
- 'core/EHABIStackWalk.cpp',
- ]
- elif CONFIG['OS_TARGET'] == 'Darwin':
- UNIFIED_SOURCES += [
- 'core/shared-libraries-macos.cc',
- ]
- elif CONFIG['OS_TARGET'] == 'WINNT':
- SOURCES += [
- 'core/shared-libraries-win32.cc',
- ]
-
- LOCAL_INCLUDES += [
- '/docshell/base',
- '/ipc/chromium/src',
- '/mozglue/linker',
- '/toolkit/crashreporter/google-breakpad/src',
- '/tools/profiler/core/',
- '/tools/profiler/gecko/',
- '/xpcom/base',
- ]
-
- if CONFIG['OS_TARGET'] == 'Android':
- LOCAL_INCLUDES += [
- # We need access to Breakpad's getcontext(3) which is suitable for Android
- '/toolkit/crashreporter/google-breakpad/src/common/android/include',
- ]
-
- if not CONFIG['MOZ_CRASHREPORTER'] and CONFIG['OS_TARGET'] == 'Android':
- SOURCES += ['/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S']
-
- if CONFIG['ANDROID_CPU_ARCH'] == 'armeabi':
- DEFINES['ARCH_ARMV6'] = True
-
- if CONFIG['ENABLE_TESTS']:
- DIRS += ['tests/gtest']
-
- if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and (CONFIG['ANDROID_VERSION'] <= '17' or CONFIG['ANDROID_VERSION'] >= '21'):
- DEFINES['ELFSIZE'] = 32
-
- FINAL_LIBRARY = 'xul'
-
-IPDL_SOURCES += [
- 'gecko/ProfilerTypes.ipdlh',
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-EXPORTS += [
- 'public/GeckoProfiler.h',
-]
-
-if CONFIG['MOZ_TASK_TRACER']:
- EXPORTS += [
- 'tasktracer/GeckoTaskTracer.h',
- 'tasktracer/GeckoTaskTracerImpl.h',
- 'tasktracer/SourceEventTypeMap.h',
- 'tasktracer/TracedTaskCommon.h',
- ]
- UNIFIED_SOURCES += [
- 'tasktracer/GeckoTaskTracer.cpp',
- 'tasktracer/TracedTaskCommon.cpp',
- ]
-
-XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
-
-if CONFIG['GNU_CXX']:
- CXXFLAGS += [
- '-Wno-error=shadow',
- '-Wno-ignored-qualifiers', # due to use of breakpad headers
- ]
-
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+if CONFIG['MOZ_GECKO_PROFILER']:
+ XPIDL_MODULE = 'profiler'
+ XPIDL_SOURCES += [
+ 'gecko/nsIProfiler.idl',
+ 'gecko/nsIProfileSaveEvent.idl',
+ ]
+ EXPORTS += [
+ 'public/CrossProcessProfilerController.h',
+ 'public/ProfilerMarkers.h',
+ 'public/PseudoStack.h',
+ 'public/shared-libraries.h',
+ ]
+ EXTRA_JS_MODULES += [
+ 'gecko/Profiler.jsm',
+ ]
+ UNIFIED_SOURCES += [
+ 'core/platform.cpp',
+ 'core/ProfileBuffer.cpp',
+ 'core/ProfileBufferEntry.cpp',
+ 'core/ProfileJSONWriter.cpp',
+ 'core/ProfilerBacktrace.cpp',
+ 'core/ProfilerMarkers.cpp',
+ 'core/StackTop.cpp',
+ 'core/ThreadInfo.cpp',
+ 'gecko/CrossProcessProfilerController.cpp',
+ 'gecko/nsProfiler.cpp',
+ 'gecko/nsProfilerFactory.cpp',
+ 'gecko/nsProfilerStartParams.cpp',
+ 'gecko/ProfilerIOInterposeObserver.cpp',
+ 'gecko/ThreadResponsiveness.cpp',
+ ]
+ if CONFIG['OS_TARGET'] == 'Darwin':
+ SOURCES += [
+ 'gecko/ProfileGatherer.cpp',
+ ]
+ else:
+ UNIFIED_SOURCES += [
+ 'gecko/ProfileGatherer.cpp',
+ ]
+
+ if CONFIG['OS_TARGET'] in ('Android', 'Linux'):
+ UNIFIED_SOURCES += [
+ 'lul/AutoObjectMapper.cpp',
+ 'lul/LulCommon.cpp',
+ 'lul/LulDwarf.cpp',
+ 'lul/LulDwarfSummariser.cpp',
+ 'lul/LulElf.cpp',
+ 'lul/LulMain.cpp',
+ 'lul/platform-linux-lul.cpp',
+ ]
+ # These files cannot be built in unified mode because of name clashes with mozglue headers on Android.
+ SOURCES += [
+ 'core/shared-libraries-linux.cc',
+ ]
+ if not CONFIG['MOZ_CRASHREPORTER']:
+ SOURCES += [
+ '/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc',
+ '/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc',
+ '/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc',
+ '/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc',
+ ]
+ if CONFIG['CPU_ARCH'] == 'arm':
+ SOURCES += [
+ 'core/EHABIStackWalk.cpp',
+ ]
+ elif CONFIG['OS_TARGET'] == 'Darwin':
+ UNIFIED_SOURCES += [
+ 'core/shared-libraries-macos.cc',
+ ]
+ elif CONFIG['OS_TARGET'] == 'WINNT':
+ SOURCES += [
+ 'core/shared-libraries-win32.cc',
+ ]
+
+ LOCAL_INCLUDES += [
+ '/docshell/base',
+ '/ipc/chromium/src',
+ '/mozglue/linker',
+ '/toolkit/crashreporter/google-breakpad/src',
+ '/tools/profiler/core/',
+ '/tools/profiler/gecko/',
+ '/xpcom/base',
+ ]
+
+ if CONFIG['OS_TARGET'] == 'Android':
+ LOCAL_INCLUDES += [
+ # We need access to Breakpad's getcontext(3) which is suitable for Android
+ '/toolkit/crashreporter/google-breakpad/src/common/android/include',
+ ]
+
+ if not CONFIG['MOZ_CRASHREPORTER'] and CONFIG['OS_TARGET'] == 'Android':
+ SOURCES += ['/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S']
+
+ if CONFIG['ANDROID_CPU_ARCH'] == 'armeabi':
+ DEFINES['ARCH_ARMV6'] = True
+
+ if CONFIG['ENABLE_TESTS']:
+ DIRS += ['tests/gtest']
+
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and (CONFIG['ANDROID_VERSION'] <= '17' or CONFIG['ANDROID_VERSION'] >= '21'):
+ DEFINES['ELFSIZE'] = 32
+
+ FINAL_LIBRARY = 'xul'
+
+IPDL_SOURCES += [
+ 'gecko/ProfilerTypes.ipdlh',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+EXPORTS += [
+ 'public/GeckoProfiler.h',
+ 'public/ProfilerControllingProcess.h',
+]
+
+if CONFIG['MOZ_TASK_TRACER']:
+ EXPORTS += [
+ 'tasktracer/GeckoTaskTracer.h',
+ 'tasktracer/GeckoTaskTracerImpl.h',
+ 'tasktracer/SourceEventTypeMap.h',
+ 'tasktracer/TracedTaskCommon.h',
+ ]
+ UNIFIED_SOURCES += [
+ 'tasktracer/GeckoTaskTracer.cpp',
+ 'tasktracer/TracedTaskCommon.cpp',
+ ]
+
+XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
+
+if CONFIG['GNU_CXX']:
+ CXXFLAGS += [
+ '-Wno-error=shadow',
+ '-Wno-ignored-qualifiers', # due to use of breakpad headers
+ ]
+
with Files('**'):
BUG_COMPONENT = ('Core', 'Gecko Profiler')
new file mode 100644
--- /dev/null
+++ b/tools/profiler/public/CrossProcessProfilerController.h
@@ -0,0 +1,44 @@
+/* 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 CrossProcessProfilerController_h
+#define CrossProcessProfilerController_h
+
+#include "nsString.h"
+
+class nsIProfilerStartParams;
+
+namespace mozilla {
+
+class ProfilerObserver;
+class ProfilerControllingProcess;
+
+// A class that calls methods on aProcess to coordinate the profiler in other
+// processes. aProcess needs to implement a number of calls that trigger calls
+// to the relevant profiler_* functions in the other process.
+// RecvProfile needs to be called when the other process replies with its
+// profile.
+class CrossProcessProfilerController final
+{
+public:
+ // aProcess is expected to outlast this CrossProcessProfilerController object.
+ explicit CrossProcessProfilerController(ProfilerControllingProcess* aProcess);
+ ~CrossProcessProfilerController();
+ void RecvProfile(const nsCString& aProfile);
+
+private:
+ void StartProfiler(nsIProfilerStartParams* aParams);
+ void Observe(nsISupports* aSubject, const char* aTopic);
+
+ friend class ProfilerObserver;
+
+ ProfilerControllingProcess* mProcess;
+ RefPtr<ProfilerObserver> mObserver;
+ nsCString mProfile;
+ bool mIsProfilerActive;
+};
+
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/tools/profiler/public/ProfilerControllingProcess.h
@@ -0,0 +1,26 @@
+/* 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 ProfilerControllingProcess_h
+#define ProfilerControllingProcess_h
+
+namespace mozilla {
+
+class ProfilerInitParams;
+
+// Top-level process actors should implement this to integrate with
+// CrossProcessProfilerController.
+class ProfilerControllingProcess {
+public:
+ virtual void SendStartProfiler(const ProfilerInitParams& aParams) = 0;
+ virtual void SendPauseProfiler(const bool& aPause) = 0;
+ virtual void SendStopProfiler() = 0;
+ virtual void SendGatherProfile() = 0;
+
+ virtual ~ProfilerControllingProcess() {}
+};
+
+} // namespace mozilla
+
+#endif