--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -68,16 +68,20 @@
#include "mozilla/widget/WidgetMessageUtils.h"
#include "nsBaseDragService.h"
#include "mozilla/media/MediaChild.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/WebBrowserPersistDocumentChild.h"
#include "imgLoader.h"
#include "GMPServiceChild.h"
+#ifdef MOZ_GECKO_PROFILER
+#include "ChildProfilerController.h"
+#endif
+
#if defined(MOZ_CONTENT_SANDBOX)
#if defined(XP_WIN)
#define TARGET_SANDBOX_EXPORTS
#include "mozilla/sandboxTarget.h"
#elif defined(XP_LINUX)
#include "mozilla/Sandbox.h"
#include "mozilla/SandboxInfo.h"
@@ -1122,16 +1126,25 @@ ContentChild::RecvInitGMPService(Endpoin
{
if (!GMPServiceChild::Create(Move(aGMPService))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
+ContentChild::RecvInitProfiler(Endpoint<PProfilerChild>&& aEndpoint)
+{
+#ifdef MOZ_GECKO_PROFILER
+ mProfilerController = ChildProfilerController::Create(Move(aEndpoint));
+#endif
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
ContentChild::RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities)
{
GeckoMediaPluginServiceChild::UpdateGMPCapabilities(Move(capabilities));
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvInitProcessHangMonitor(Endpoint<PProcessHangMonitorChild>&& aHangMonitor)
@@ -2603,70 +2616,16 @@ ContentChild::DeallocPOfflineCacheUpdate
{
OfflineCacheUpdateChild* offlineCacheUpdate =
static_cast<OfflineCacheUpdateChild*>(actor);
NS_RELEASE(offlineCacheUpdate);
return true;
}
mozilla::ipc::IPCResult
-ContentChild::RecvStartProfiler(const ProfilerInitParams& params)
-{
- nsTArray<const char*> filterArray;
- for (size_t i = 0; i < params.filters().Length(); ++i) {
- filterArray.AppendElement(params.filters()[i].get());
- }
-
- profiler_start(params.entries(), params.interval(), params.features(),
- filterArray.Elements(), filterArray.Length());
-
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-ContentChild::RecvStopProfiler()
-{
- profiler_stop();
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-ContentChild::RecvPauseProfiler(const bool& aPause)
-{
- if (aPause) {
- profiler_pause();
- } else {
- profiler_resume();
- }
-
- return IPC_OK();
-}
-
-void
-ContentChild::GatherProfile(bool aIsExitProfile)
-{
- nsCString profileCString;
- UniquePtr<char[]> profile = profiler_get_profile();
- if (profile) {
- profileCString = nsCString(profile.get(), strlen(profile.get()));
- } else {
- profileCString = EmptyCString();
- }
-
- Unused << SendProfile(profileCString, aIsExitProfile);
-}
-
-mozilla::ipc::IPCResult
-ContentChild::RecvGatherProfile()
-{
- GatherProfile(false);
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
ContentChild::RecvLoadPluginResult(const uint32_t& aPluginId,
const bool& aResult)
{
nsresult rv;
Endpoint<PPluginModuleParent> endpoint;
bool finalResult = aResult &&
SendConnectPluginBridge(aPluginId, &rv, &endpoint) &&
NS_SUCCEEDED(rv);
@@ -2822,21 +2781,22 @@ ContentChild::RecvShutdown()
#if defined(XP_WIN)
mozilla::widget::StopAudioSession();
#endif
GetIPCChannel()->SetAbortOnError(false);
#ifdef MOZ_GECKO_PROFILER
- if (profiler_is_active()) {
- // We're shutting down while we were profiling. Send the
- // profile up to the parent so that we don't lose this
- // information.
- GatherProfile(true);
+ if (mProfilerController) {
+ nsCString shutdownProfile = mProfilerController->GrabShutdownProfileAndShutdown();
+ mProfilerController = nullptr;
+ // Send the shutdown profile to the parent process through our own
+ // message channel, which we know will survive for long enough.
+ Unused << SendShutdownProfile(shutdownProfile);
}
#endif
// Start a timer that will insure we quickly exit after a reasonable
// period of time. Prevents shutdown hangs after our connection to the
// parent closes.
StartForceKillTimer();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -30,16 +30,17 @@ class nsIObserver;
struct SubstitutionMapping;
struct OverrideMapping;
class nsIDomainPolicy;
class nsIURIClassifierCallback;
struct LookAndFeelInt;
namespace mozilla {
class RemoteSpellcheckEngineChild;
+class ChildProfilerController;
using mozilla::loader::PScriptCacheChild;
namespace ipc {
class OptionalURIParams;
class URIParams;
}// namespace ipc
@@ -145,16 +146,19 @@ public:
mozilla::ipc::IPCResult
RecvInitContentBridgeChild(Endpoint<PContentBridgeChild>&& aEndpoint) override;
mozilla::ipc::IPCResult
RecvInitGMPService(Endpoint<PGMPServiceChild>&& aGMPService) override;
mozilla::ipc::IPCResult
+ RecvInitProfiler(Endpoint<PProfilerChild>&& aEndpoint) override;
+
+ mozilla::ipc::IPCResult
RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities) override;
mozilla::ipc::IPCResult
RecvInitProcessHangMonitor(Endpoint<PProcessHangMonitorChild>&& aHangMonitor) override;
mozilla::ipc::IPCResult
RecvInitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
@@ -436,24 +440,16 @@ public:
virtual mozilla::ipc::IPCResult RecvAssociatePluginId(const uint32_t& aPluginId,
const base::ProcessId& aProcessId) override;
virtual mozilla::ipc::IPCResult RecvLoadPluginResult(const uint32_t& aPluginId,
const bool& aResult) override;
virtual mozilla::ipc::IPCResult RecvUpdateWindow(const uintptr_t& aChildId) override;
- virtual mozilla::ipc::IPCResult RecvStartProfiler(const ProfilerInitParams& params) override;
-
- virtual mozilla::ipc::IPCResult RecvPauseProfiler(const bool& aPause) override;
-
- virtual mozilla::ipc::IPCResult RecvStopProfiler() override;
-
- virtual mozilla::ipc::IPCResult RecvGatherProfile() override;
-
virtual mozilla::ipc::IPCResult RecvDomainSetChanged(const uint32_t& aSetType,
const uint32_t& aChangeType,
const OptionalURIParams& aDomain) override;
virtual mozilla::ipc::IPCResult RecvShutdown() override;
virtual mozilla::ipc::IPCResult
RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
@@ -669,18 +665,16 @@ private:
virtual void ActorDestroy(ActorDestroyReason why) override;
virtual void ProcessingError(Result aCode, const char* aReason) override;
virtual already_AddRefed<nsIEventTarget>
GetConstructedEventTarget(const Message& aMsg) override;
- void GatherProfile(bool aIsExitProfile);
-
InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
RefPtr<ConsoleListener> mConsoleListener;
nsTHashtable<nsPtrHashKey<nsIObserver>> mIdleObservers;
InfallibleTArray<nsString> mAvailableDictionaries;
// Temporary storage for a list of available font families, passed from the
@@ -715,16 +709,20 @@ private:
bool mIsAlive;
nsString mProcessName;
static ContentChild* sSingleton;
nsCOMPtr<nsIDomainPolicy> mPolicy;
nsCOMPtr<nsITimer> mForceKillTimer;
+#ifdef MOZ_GECKO_PROFILER
+ RefPtr<ChildProfilerController> mProfilerController;
+#endif
+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
nsCOMPtr<nsIFile> mProfileDir;
#endif
// Hashtable to keep track of the pending GetFilesHelper objects.
// This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
// received.
nsRefPtrHashtable<nsIDHashKey, GetFilesHelperChild> mGetFilesPendingRequests;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -19,19 +19,16 @@
#ifdef MOZ_WIDGET_GONK
#include <sys/types.h>
#include <sys/wait.h>
#endif
#include "chrome/common/process_watcher.h"
#include "mozilla/a11y/PDocAccessible.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
@@ -182,16 +179,17 @@
#include "nsPluginHost.h"
#include "nsPluginTags.h"
#include "nsIBlocklistService.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsICaptivePortalService.h"
#include "nsIObjectLoadingContent.h"
+#include "ProfilerParent.h"
#include "nsIBidiKeyboard.h"
#include "nsLayoutStylesheetCache.h"
#include "ContentPrefs.h"
#include "mozilla/Sprintf.h"
@@ -249,16 +247,20 @@
#include "nsThread.h"
#include "mozilla/ipc/CrashReporterHost.h"
#endif
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
#endif
+#ifdef MOZ_GECKO_PROFILER
+#include "nsIProfiler.h"
+#endif
+
// For VP9Benchmark::sBenchmarkFpsPref
#include "Benchmark.h"
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
#if defined(XP_WIN)
// e10s forced enable pref, defined in nsAppRunner.cpp
extern const char* kForceEnableE10sPref;
@@ -1070,48 +1072,16 @@ 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
@@ -1356,17 +1326,17 @@ ContentParent::Init()
SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
#else
Unused << SendActivateA11y(0);
#endif
}
#endif
#ifdef MOZ_GECKO_PROFILER
- mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
+ Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
#endif
// Ensure that the default set of permissions are avaliable in the content
// process before we try to load any URIs in it.
EnsurePermissionsByKey(EmptyCString());
RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
gmps->UpdateContentProcessGMPCapabilities();
@@ -1753,20 +1723,16 @@ ContentParent::ActorDestroy(ActorDestroy
// Note: the manager could have shutdown already.
gpu->RemoveListener(this);
}
RecvRemoveGeolocationListener();
mConsoleService = nullptr;
-#ifdef MOZ_GECKO_PROFILER
- mProfilerController = nullptr;
-#endif
-
if (obs) {
RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID);
if (AbnormalShutdown == why) {
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
NS_LITERAL_CSTRING("content"), 1);
@@ -4642,22 +4608,21 @@ ContentParent::RecvCreateWindowInDiffere
if (NS_FAILED(rv)) {
NS_WARNING("Call to CommonCreateWindow failed.");
}
return IPC_OK();
}
mozilla::ipc::IPCResult
-ContentParent::RecvProfile(const nsCString& aProfile, const bool& aIsExitProfile)
+ContentParent::RecvShutdownProfile(const nsCString& aProfile)
{
#ifdef MOZ_GECKO_PROFILER
- if (mProfilerController) {
- mProfilerController->RecvProfile(aProfile, aIsExitProfile);
- }
+ nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
+ profiler->ReceiveShutdownProfile(aProfile);
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvGetGraphicsDeviceInitData(ContentDeviceData* aOut)
{
gfxPlatform::GetPlatform()->BuildContentDeviceData(aOut);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -25,17 +25,16 @@
#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"
@@ -51,19 +50,16 @@ 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;
@@ -109,17 +105,16 @@ 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;
@@ -307,21 +302,16 @@ 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
/**
@@ -1104,18 +1094,17 @@ private:
virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override;
virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override;
virtual mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect) override;
- virtual mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile,
- const bool& aIsExitProfile) override;
+ virtual mozilla::ipc::IPCResult RecvShutdownProfile(const nsCString& aProfile) override;
virtual mozilla::ipc::IPCResult RecvGetGraphicsDeviceInitData(ContentDeviceData* aOut) override;
virtual mozilla::ipc::IPCResult RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo) override;
virtual mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsString& aCodecName,
const uint32_t& aDecodeFPS) override;
@@ -1222,20 +1211,16 @@ private:
#ifdef MOZ_X11
// 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
- UniquePtr<mozilla::CrossProcessProfilerController> mProfilerController;
-#endif
-
UniquePtr<gfx::DriverCrashGuard> mDriverCrashGuard;
UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
mozilla::UniquePtr<SandboxBroker> mSandboxBroker;
static mozilla::UniquePtr<SandboxBrokerPolicyFactory>
sSandboxBrokerPolicyFactory;
#endif
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -38,30 +38,30 @@ include protocol PRemoteSpellcheckEngine
include protocol PWebBrowserPersistDocument;
include protocol PWebrtcGlobal;
include protocol PPresentation;
include protocol PURLClassifier;
include protocol PURLClassifierLocal;
include protocol PVRManager;
include protocol PVideoDecoderManager;
include protocol PFlyWebPublishedServer;
+include protocol PProfiler;
include protocol PScriptCache;
include DOMTypes;
include JavaScriptTypes;
include IPCBlob;
include IPCStream;
include PTabContext;
include URIParams;
include PluginTypes;
include ProtocolTypes;
include PBackgroundSharedTypes;
include PContentPermission;
include ServiceWorkerConfiguration;
include GraphicsMessages;
-include ProfilerTypes;
include MemoryReportTypes;
// Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp
// are put into different UnifiedProtocolsXX.cpp files.
// XXX Remove this once bug 1069073 is fixed
include "mozilla/dom/PContentBridgeParent.h";
using GeoPosition from "nsGeoPositionIPCSerialiser.h";
@@ -343,16 +343,17 @@ both:
// ignored and should be null/zero.
async PWebBrowserPersistDocument(nullable PBrowser aBrowser,
uint64_t aOuterWindowID);
child:
async InitGMPService(Endpoint<PGMPServiceChild> service);
async InitProcessHangMonitor(Endpoint<PProcessHangMonitorChild> hangMonitor);
async InitContentBridgeChild(Endpoint<PContentBridgeChild> endpoint);
+ async InitProfiler(Endpoint<PProfilerChild> aEndpoint);
// Give the content process its endpoints to the compositor.
async InitRendering(
Endpoint<PCompositorBridgeChild> compositor,
Endpoint<PImageBridgeChild> imageBridge,
Endpoint<PVRManagerChild> vr,
Endpoint<PVideoDecoderManagerChild> video,
uint32_t[] namespaces);
@@ -498,25 +499,16 @@ child:
/**
* This call is used by async plugin initialization to notify the
* PluginModuleContentParent that the PluginModuleChromeParent's async
* init has completed.
*/
async LoadPluginResult(uint32_t aPluginId, bool aResult);
- /**
- * Control the Gecko Profiler in the child process.
- */
- async StartProfiler(ProfilerInitParams params);
- async StopProfiler();
- async PauseProfiler(bool aPause);
-
- async GatherProfile();
-
async InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action);
async EndDragSession(bool aDoneDrag, bool aUserCancelled,
LayoutDeviceIntPoint aDragEndPoint,
uint32_t aKeyModifiers);
async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, OptionalURIParams aDomain);
@@ -977,17 +969,17 @@ parent:
*
* NOTE: The principal is untrusted in the parent process. Only
* principals that can live in the content process should
* provided.
*/
async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
TabId tabId);
- async Profile(nsCString aProfile, bool aIsExitProfile);
+ async ShutdownProfile(nsCString aProfile);
/**
* Request graphics initialization information from the parent.
*/
sync GetGraphicsDeviceInitData()
returns (ContentDeviceData aData);
sync CreateWindow(nullable PBrowser aThisTab,
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -1,17 +1,17 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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 protocol PPluginInstance;
include protocol PPluginScriptableObject;
include protocol PContent;
-include ProfilerTypes;
+include protocol PProfiler;
using NPError from "npapi.h";
using NPNVariable from "npapi.h";
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
using struct nsID from "nsID.h";
using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.h";
using mozilla::plugins::GetFileNameFunc from "mozilla/plugins/PluginMessageUtils.h";
@@ -41,16 +41,18 @@ intr protocol PPluginModule
manages PPluginInstance;
both:
// Window-specific message which instructs the interrupt mechanism to enter
// a nested event loop for the current interrupt call.
async ProcessNativeEventsInInterruptCall();
child:
+ async InitProfiler(Endpoint<PProfilerChild> aEndPoint);
+
async DisableFlashProtectedMode();
// Sync query to check if a Flash library indicates it
// supports async rendering mode.
intr ModuleSupportsAsyncRender()
returns (bool result);
// Forces the child process to update its plugin function table.
@@ -90,24 +92,16 @@ child:
nsString aDisplayName,
nsString aIconPath);
async SetParentHangTimeout(uint32_t seconds);
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);
parent:
async NP_InitializeResult(NPError aError);
@@ -148,18 +142,16 @@ parent:
async NPN_ReloadPlugins(bool aReloadPages);
// Notifies the chrome process that a PluginModuleChild linked to a content
// process was destroyed. The chrome process may choose to asynchronously shut
// down the plugin process in response.
async NotifyContentModuleDestroyed();
- async Profile(nsCString aProfile, bool aIsExitProfile);
-
// Answers to request about site data
async ReturnClearSiteData(NPError aRv, uint64_t aCallbackId);
async ReturnSitesWithData(nsCString[] aSites, uint64_t aCallbackId);
intr GetKeyState(int32_t aVirtKey)
returns (int16_t aState);
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -48,17 +48,19 @@
#include "PluginInterposeOSX.h"
#include "PluginUtilsOSX.h"
#endif
#ifdef MOZ_CRASHREPORTER
#include "mozilla/ipc/CrashReporterClient.h"
#endif
-#include "GeckoProfiler.h"
+#ifdef MOZ_GECKO_PROFILER
+#include "ChildProfilerController.h"
+#endif
using namespace mozilla;
using namespace mozilla::ipc;
using namespace mozilla::plugins;
using namespace mozilla::widget;
#if defined(XP_WIN)
const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
@@ -206,16 +208,25 @@ PluginModuleChild::InitForContent(Endpoi
mLibrary = GetChrome()->mLibrary;
mFunctions = GetChrome()->mFunctions;
return true;
}
mozilla::ipc::IPCResult
+PluginModuleChild::RecvInitProfiler(Endpoint<mozilla::PProfilerChild>&& aEndpoint)
+{
+#ifdef MOZ_GECKO_PROFILER
+ mProfilerController = ChildProfilerController::Create(Move(aEndpoint));
+#endif
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
PluginModuleChild::RecvDisableFlashProtectedMode()
{
MOZ_ASSERT(mIsChrome);
#ifdef XP_WIN
HookProtectedMode();
#else
MOZ_ASSERT(false, "Should not be called");
#endif
@@ -745,16 +756,23 @@ PluginModuleChild::AnswerInitCrashReport
*aOutId = CrashReporter::CurrentThreadId();
#endif
return IPC_OK();
}
void
PluginModuleChild::ActorDestroy(ActorDestroyReason why)
{
+#ifdef MOZ_GECKO_PROFILER
+ if (mProfilerController) {
+ mProfilerController->Shutdown();
+ mProfilerController = nullptr;
+ }
+#endif
+
if (!mIsChrome) {
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
chromeInstance->SendNotifyContentModuleDestroyed();
}
// Destroy ourselves once we finish other teardown activities.
RefPtr<DeleteTask<PluginModuleChild>> task =
@@ -2719,64 +2737,16 @@ PluginModuleChild::RecvProcessNativeEven
#ifdef MOZ_WIDGET_COCOA
void
PluginModuleChild::ProcessNativeEvents() {
CallProcessSomeEvents();
}
#endif
-mozilla::ipc::IPCResult
-PluginModuleChild::RecvStartProfiler(const ProfilerInitParams& params)
-{
- nsTArray<const char*> filterArray;
- for (size_t i = 0; i < params.filters().Length(); ++i) {
- filterArray.AppendElement(params.filters()[i].get());
- }
-
- profiler_start(params.entries(), params.interval(), params.features(),
- filterArray.Elements(), filterArray.Length());
-
- return IPC_OK();
-}
-
-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);
- }
-
- Unused << SendProfile(profileCString, false);
- return IPC_OK();
-}
-
NPError
PluginModuleChild::PluginRequiresAudioDeviceChanges(
PluginInstanceChild* aInstance,
NPBool aShouldRegister)
{
#ifdef XP_WIN
// Maintain a set of PluginInstanceChildren that we need to tell when the
// default audio device has changed.
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -41,16 +41,19 @@
#endif
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks);
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
namespace mozilla {
+
+class ChildProfilerController;
+
namespace plugins {
class PluginInstanceChild;
class PluginModuleChild : public PPluginModuleChild
{
protected:
virtual mozilla::ipc::RacyInterruptPolicy
@@ -60,16 +63,17 @@ protected:
return MediateRace(parent, child);
}
virtual bool ShouldContinueFromReplyTimeout() override;
virtual mozilla::ipc::IPCResult RecvSettingChanged(const PluginSettings& aSettings) override;
// Implement the PPluginModuleChild interface
+ virtual mozilla::ipc::IPCResult RecvInitProfiler(Endpoint<mozilla::PProfilerChild>&& aEndpoint) override;
virtual mozilla::ipc::IPCResult RecvDisableFlashProtectedMode() override;
virtual mozilla::ipc::IPCResult AnswerNP_GetEntryPoints(NPError* rv) override;
virtual mozilla::ipc::IPCResult AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv) override;
virtual mozilla::ipc::IPCResult RecvAsyncNP_Initialize(const PluginSettings& aSettings) override;
virtual mozilla::ipc::IPCResult AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
override;
virtual mozilla::ipc::IPCResult RecvAsyncNPP_New(PPluginInstanceChild* aActor) override;
@@ -120,21 +124,16 @@ protected:
AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeThreadId* aId) override;
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();
void CommonInit();
@@ -250,16 +249,20 @@ private:
PRLibrary* mLibrary;
nsCString mPluginFilename; // UTF8
int mQuirks;
bool mIsChrome;
bool mHasShutdown; // true if NP_Shutdown has run
+#ifdef MOZ_GECKO_PROFILER
+ RefPtr<ChildProfilerController> mProfilerController;
+#endif
+
// we get this from the plugin
NP_PLUGINSHUTDOWN mShutdownFunc;
#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
NP_PLUGINUNIXINIT mInitializeFunc;
#elif defined(OS_WIN) || defined(OS_MACOSX)
NP_PLUGININIT mInitializeFunc;
NP_GETENTRYPOINTS mGetEntryPointsFunc;
#endif
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -28,20 +28,18 @@
#include "nsIObserverService.h"
#include "nsIXULRuntime.h"
#include "nsNPAPIPlugin.h"
#include "nsPrintfCString.h"
#include "prsystem.h"
#include "prclist.h"
#include "PluginQuirks.h"
#include "gfxPlatform.h"
-#ifdef MOZ_GECKO_PROFILER
-#include "CrossProcessProfilerController.h"
-#endif
#include "GeckoProfiler.h"
+#include "ProfilerParent.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"
@@ -53,19 +51,16 @@
#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
@@ -633,17 +628,17 @@ PluginModuleChromeParent::OnProcessLaunc
if (NS_SUCCEEDED(mAsyncInitRv)) {
mAsyncInitRv = NP_GetEntryPoints(mNPPIface,
&mAsyncInitError);
}
#endif
}
#ifdef MOZ_GECKO_PROFILER
- mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
+ Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
#endif
}
bool
PluginModuleChromeParent::WaitForIPCConnection()
{
PluginProcessParent* process = Process();
MOZ_ASSERT(process);
@@ -774,20 +769,16 @@ PluginModuleChromeParent::PluginModuleCh
}
PluginModuleChromeParent::~PluginModuleChromeParent()
{
if (!OkToCleanup()) {
MOZ_CRASH("unsafe destruction");
}
-#ifdef MOZ_GECKO_PROFILER
- mProfilerController = nullptr;
-#endif
-
#ifdef XP_WIN
// If we registered for audio notifications, stop.
mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
false);
#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mSandboxPermissions.RemovePermissionsForProcess(OtherPid());
@@ -3259,28 +3250,16 @@ PluginModuleChromeParent::OnCrash(DWORD
NS_ERROR("Failed to open child process when attempting kill.");
}
}
}
#endif // MOZ_CRASHREPORTER_INJECTOR
mozilla::ipc::IPCResult
-PluginModuleChromeParent::RecvProfile(const nsCString& aProfile,
- const bool& aIsExitProfile)
-{
-#ifdef MOZ_GECKO_PROFILER
- if (mProfilerController) {
- mProfilerController->RecvProfile(aProfile, aIsExitProfile);
- }
-#endif
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
PluginModuleParent::AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet)
{
return IPC_FAIL_NO_REASON(this);
}
mozilla::ipc::IPCResult
PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
int16_t* aRet)
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -24,31 +24,25 @@
#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 nsPluginTag;
namespace mozilla {
-#ifdef MOZ_GECKO_PROFILER
-class CrossProcessProfilerController;
-#endif
-
-
namespace ipc {
class CrashReporterHost;
} // namespace ipc
namespace layers {
class TextureClientRecycleAllocator;
} // namespace layers
namespace plugins {
@@ -80,17 +74,16 @@ 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*
@@ -142,33 +135,16 @@ 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);
}
@@ -234,18 +210,16 @@ protected:
protected:
void SetChildTimeout(const int32_t aChildTimeout);
static void TimeoutChanged(const char* aPref, void* aModule);
virtual void UpdatePluginTimeout() {}
virtual mozilla::ipc::IPCResult RecvNotifyContentModuleDestroyed() override { return IPC_OK(); }
- virtual mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile, const bool& aIsExitProfile) override { return IPC_OK(); }
-
virtual mozilla::ipc::IPCResult AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
virtual mozilla::ipc::IPCResult RecvReturnClearSiteData(const NPError& aRv,
const uint64_t& aCallbackId) override;
virtual mozilla::ipc::IPCResult RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
const uint64_t& aCallbackId) override;
@@ -528,19 +502,16 @@ class PluginModuleChromeParent
SetContentParent(dom::ContentParent* aContentParent);
bool
SendAssociatePluginId();
void CachedSettingChanged();
virtual mozilla::ipc::IPCResult
- RecvProfile(const nsCString& aProfile, const bool& aIsExitProfile) override;
-
- virtual mozilla::ipc::IPCResult
AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
// Proxy GetOpenFileName/GetSaveFileName on Windows.
virtual mozilla::ipc::IPCResult
AnswerGetFileName(const GetFileNameFunc& aFunc,
const OpenFileNameIPC& aOfnIn,
OpenFileNameRetIPC* aOfnOut, bool* aResult) override;
@@ -685,19 +656,16 @@ private:
nsresult mAsyncInitRv;
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
- UniquePtr<CrossProcessProfilerController> mProfilerController;
-#endif
bool mIsBlocklisted;
static bool sInstantiated;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mozilla::SandboxPermissions mSandboxPermissions;
#endif
};
} // namespace plugins
--- a/gfx/ipc/GPUChild.cpp
+++ b/gfx/ipc/GPUChild.cpp
@@ -15,19 +15,17 @@
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/gfx/gfxVars.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerDx.h"
#endif
#include "mozilla/ipc/CrashReporterHost.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/Unused.h"
-#ifdef MOZ_GECKO_PROFILER
-#include "CrossProcessProfilerController.h"
-#endif
+#include "ProfilerParent.h"
namespace mozilla {
namespace gfx {
using namespace layers;
GPUChild::GPUChild(GPUProcessHost* aHost)
: mHost(aHost),
@@ -73,17 +71,17 @@ GPUChild::Init()
mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
});
SendInit(prefs, updates, devicePrefs, mappings);
gfxVars::AddReceiver(this);
#ifdef MOZ_GECKO_PROFILER
- mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
+ Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
#endif
}
void
GPUChild::OnVarChanged(const GfxVarUpdate& aVar)
{
SendUpdateVar(aVar);
}
@@ -200,27 +198,16 @@ GPUChild::RecvRecordChildEvents(nsTArray
mozilla::ipc::IPCResult
GPUChild::RecvNotifyDeviceReset(const GPUDeviceData& aData)
{
gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
mHost->mListener->OnProcessDeviceReset(mHost);
return IPC_OK();
}
-mozilla::ipc::IPCResult
-GPUChild::RecvProfile(const nsCString& aProfile, const bool& aIsExitProfile)
-{
-#ifdef MOZ_GECKO_PROFILER
- if (mProfilerController) {
- mProfilerController->RecvProfile(aProfile, aIsExitProfile);
- }
-#endif
- return IPC_OK();
-}
-
bool
GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile)
{
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
Unused << PGPUChild::SendRequestMemoryReport(
@@ -246,40 +233,16 @@ GPUChild::RecvFinishMemoryReport(const u
if (mMemoryReportRequest) {
mMemoryReportRequest->Finish(aGeneration);
mMemoryReportRequest = nullptr;
}
return IPC_OK();
}
void
-GPUChild::SendStartProfiler(const ProfilerInitParams& aParams)
-{
- Unused << PGPUChild::SendStartProfiler(aParams);
-}
-
-void
-GPUChild::SendStopProfiler()
-{
- Unused << PGPUChild::SendStopProfiler();
-}
-
-void
-GPUChild::SendPauseProfiler(const bool& aPause)
-{
- Unused << PGPUChild::SendPauseProfiler(aPause);
-}
-
-void
-GPUChild::SendGatherProfile()
-{
- Unused << PGPUChild::SendGatherProfile();
-}
-
-void
GPUChild::ActorDestroy(ActorDestroyReason aWhy)
{
if (aWhy == AbnormalShutdown) {
#ifdef MOZ_CRASHREPORTER
if (mCrashReporter) {
mCrashReporter->GenerateCrashReport(OtherPid());
mCrashReporter = nullptr;
}
@@ -290,20 +253,16 @@ GPUChild::ActorDestroy(ActorDestroyReaso
// Notify the Telemetry environment so that we can refresh and do a subsession split
if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
obsvc->NotifyObservers(nullptr, "compositor:process-aborted", nullptr);
}
}
-#ifdef MOZ_GECKO_PROFILER
- mProfilerController = nullptr;
-#endif
-
gfxVars::RemoveReceiver(this);
mHost->OnChannelClosed();
}
class DeferredDeleteGPUChild : public Runnable
{
public:
explicit DeferredDeleteGPUChild(UniquePtr<GPUChild>&& aChild)
--- a/gfx/ipc/GPUChild.h
+++ b/gfx/ipc/GPUChild.h
@@ -5,38 +5,32 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _include_mozilla_gfx_ipc_GPUChild_h_
#define _include_mozilla_gfx_ipc_GPUChild_h_
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/PGPUChild.h"
#include "mozilla/gfx/gfxVarReceiver.h"
-#include "ProfilerControllingProcess.h"
namespace mozilla {
-#ifdef MOZ_GECKO_PROFILER
-class CrossProcessProfilerController;
-#endif
-
namespace ipc {
class CrashReporterHost;
} // namespace ipc
namespace dom {
class MemoryReportRequestHost;
} // namespace dom
namespace gfx {
class GPUProcessHost;
class GPUChild final
: public PGPUChild
, public gfxVarReceiver
- , public ProfilerControllingProcess
{
typedef mozilla::dom::MemoryReportRequestHost MemoryReportRequestHost;
public:
explicit GPUChild(GPUProcessHost* aHost);
~GPUChild();
void Init();
@@ -56,38 +50,29 @@ public:
mozilla::ipc::IPCResult RecvUpdateChildScalars(InfallibleTArray<ScalarAction>&& aScalarActions) override;
mozilla::ipc::IPCResult RecvUpdateChildKeyedScalars(InfallibleTArray<KeyedScalarAction>&& aScalarActions) override;
mozilla::ipc::IPCResult RecvRecordChildEvents(nsTArray<ChildEventData>&& events) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override;
mozilla::ipc::IPCResult RecvNotifyUiObservers(const nsCString& aTopic) override;
mozilla::ipc::IPCResult RecvNotifyDeviceReset(const GPUDeviceData& aData) override;
- mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile, const bool& aIsExitProfile) override;
mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport) override;
mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration) override;
- void SendStartProfiler(const ProfilerInitParams& aParams) override;
- void SendStopProfiler() override;
- void SendPauseProfiler(const bool& aPause) override;
- void SendGatherProfile() override;
-
bool SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile);
static void Destroy(UniquePtr<GPUChild>&& aChild);
private:
GPUProcessHost* mHost;
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
bool mGPUReady;
-#ifdef MOZ_GECKO_PROFILER
- UniquePtr<CrossProcessProfilerController> mProfilerController;
-#endif
};
} // namespace gfx
} // namespace mozilla
#endif // _include_mozilla_gfx_ipc_GPUChild_h_
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -2,17 +2,16 @@
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* 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/. */
#ifdef XP_WIN
#include "WMF.h"
#endif
#include "GPUParent.h"
-#include "GeckoProfiler.h"
#include "gfxConfig.h"
#include "gfxPlatform.h"
#include "gfxPrefs.h"
#include "GPUProcessHost.h"
#include "mozilla/Assertions.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/MemoryReportRequest.h"
@@ -40,16 +39,19 @@
#include "VsyncBridgeParent.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerDx.h"
# include <process.h>
#endif
#ifdef MOZ_WIDGET_GTK
# include <gtk/gtk.h>
#endif
+#ifdef MOZ_GECKO_PROFILER
+#include "ChildProfilerController.h"
+#endif
namespace mozilla {
namespace gfx {
using namespace ipc;
using namespace layers;
static GPUParent* sGPUParent;
@@ -236,16 +238,25 @@ GPUParent::RecvInitVRManager(Endpoint<PV
mozilla::ipc::IPCResult
GPUParent::RecvInitUiCompositorController(const uint64_t& aRootLayerTreeId, Endpoint<PUiCompositorControllerParent>&& aEndpoint)
{
UiCompositorControllerParent::Start(aRootLayerTreeId, Move(aEndpoint));
return IPC_OK();
}
mozilla::ipc::IPCResult
+GPUParent::RecvInitProfiler(Endpoint<PProfilerChild>&& aEndpoint)
+{
+#ifdef MOZ_GECKO_PROFILER
+ mProfilerController = ChildProfilerController::Create(Move(aEndpoint));
+#endif
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
GPUParent::RecvUpdatePref(const GfxPrefSetting& setting)
{
gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()];
pref->SetCachedValue(setting.value());
return IPC_OK();
}
mozilla::ipc::IPCResult
@@ -378,61 +389,16 @@ GPUParent::RecvNotifyGpuObservers(const
MOZ_ASSERT(obsSvc);
if (obsSvc) {
obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
-GPUParent::RecvStartProfiler(const ProfilerInitParams& params)
-{
- nsTArray<const char*> filterArray;
- for (size_t i = 0; i < params.filters().Length(); ++i) {
- filterArray.AppendElement(params.filters()[i].get());
- }
- profiler_start(params.entries(), params.interval(), params.features(),
- filterArray.Elements(), filterArray.Length());
-
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-GPUParent::RecvStopProfiler()
-{
- profiler_stop();
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-GPUParent::RecvPauseProfiler(const bool& aPause)
-{
- if (aPause) {
- profiler_pause();
- } else {
- profiler_resume();
- }
-
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-GPUParent::RecvGatherProfile()
-{
- nsCString profileCString;
- UniquePtr<char[]> profile = profiler_get_profile();
- if (profile) {
- profileCString = nsDependentCString(profile.get());
- }
-
- Unused << SendProfile(profileCString, false /* aIsExitProfile */);
- return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
GPUParent::RecvRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile)
{
nsPrintfCString processName("GPU (pid %u)", (unsigned)getpid());
mozilla::dom::MemoryReportRequestClient::Start(
@@ -453,16 +419,23 @@ GPUParent::ActorDestroy(ActorDestroyReas
#endif
#ifndef NS_FREE_PERMANENT_DATA
// No point in going through XPCOM shutdown because we don't keep persistent
// state.
ProcessChild::QuickExit();
#endif
+#ifdef MOZ_GECKO_PROFILER
+ if (mProfilerController) {
+ mProfilerController->Shutdown();
+ mProfilerController = nullptr;
+ }
+#endif
+
if (mVsyncBridge) {
mVsyncBridge->Shutdown();
mVsyncBridge = nullptr;
}
dom::VideoDecoderManagerParent::ShutdownVideoBridge();
CompositorThreadHolder::Shutdown();
if (gfxVars::UseWebRender()) {
wr::RenderThread::ShutDown();
--- a/gfx/ipc/GPUParent.h
+++ b/gfx/ipc/GPUParent.h
@@ -7,16 +7,17 @@
#define _include_gfx_ipc_GPUParent_h__
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/PGPUParent.h"
namespace mozilla {
class TimeStamp;
+class ChildProfilerController;
namespace gfx {
class VsyncBridgeParent;
class GPUParent final : public PGPUParent
{
public:
@@ -33,16 +34,17 @@ public:
mozilla::ipc::IPCResult RecvInit(nsTArray<GfxPrefSetting>&& prefs,
nsTArray<GfxVarUpdate>&& vars,
const DevicePrefs& devicePrefs,
nsTArray<LayerTreeIdMapping>&& mappings) override;
mozilla::ipc::IPCResult RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override;
mozilla::ipc::IPCResult RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvInitUiCompositorController(const uint64_t& aRootLayerTreeId, Endpoint<PUiCompositorControllerParent>&& aEndpoint) override;
+ mozilla::ipc::IPCResult RecvInitProfiler(Endpoint<PProfilerChild>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvUpdatePref(const GfxPrefSetting& pref) override;
mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref) override;
mozilla::ipc::IPCResult RecvNewWidgetCompositor(
Endpoint<PCompositorBridgeParent>&& aEndpoint,
const CSSToLayoutDeviceScale& aScale,
const TimeDuration& aVsyncRate,
const CompositorOptions& aOptions,
const bool& aUseExternalSurface,
@@ -50,29 +52,28 @@ public:
mozilla::ipc::IPCResult RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvGetDeviceStatus(GPUDeviceData* aOutStatus) override;
mozilla::ipc::IPCResult RecvAddLayerTreeIdMapping(const LayerTreeIdMapping& aMapping) override;
mozilla::ipc::IPCResult RecvRemoveLayerTreeIdMapping(const LayerTreeIdMapping& aMapping) override;
mozilla::ipc::IPCResult RecvNotifyGpuObservers(const nsCString& aTopic) override;
- mozilla::ipc::IPCResult RecvStartProfiler(const ProfilerInitParams& params) override;
- mozilla::ipc::IPCResult RecvPauseProfiler(const bool& aPause) override;
- mozilla::ipc::IPCResult RecvStopProfiler() override;
- mozilla::ipc::IPCResult RecvGatherProfile() override;
mozilla::ipc::IPCResult RecvRequestMemoryReport(
const uint32_t& generation,
const bool& anonymize,
const bool& minimizeMemoryUsage,
const MaybeFileDesc& DMDFile) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
const TimeStamp mLaunchTime;
RefPtr<VsyncBridgeParent> mVsyncBridge;
+#ifdef MOZ_GECKO_PROFILER
+ RefPtr<ChildProfilerController> mProfilerController;
+#endif
};
} // namespace gfx
} // namespace mozilla
#endif // _include_gfx_ipc_GPUParent_h__
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -1,18 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 GraphicsMessages;
-include ProfilerTypes;
include MemoryReportTypes;
include protocol PCompositorBridge;
include protocol PImageBridge;
+include protocol PProfiler;
include protocol PVRManager;
include protocol PVsyncBridge;
include protocol PUiCompositorController;
include protocol PVideoDecoderManager;
using base::ProcessId from "base/process.h";
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
using mozilla::CSSToLayoutDeviceScale from "Units.h";
@@ -54,16 +54,17 @@ parent:
GfxVarUpdate[] vars,
DevicePrefs devicePrefs,
LayerTreeIdMapping[] mapping);
async InitVsyncBridge(Endpoint<PVsyncBridgeParent> endpoint);
async InitImageBridge(Endpoint<PImageBridgeParent> endpoint);
async InitVRManager(Endpoint<PVRManagerParent> endpoint);
async InitUiCompositorController(uint64_t rootLayerTreeId, Endpoint<PUiCompositorControllerParent> endpoint);
+ async InitProfiler(Endpoint<PProfilerChild> endpoint);
// Called to update a gfx preference or variable.
async UpdatePref(GfxPrefSetting pref);
async UpdateVar(GfxVarUpdate var);
// Create a new top-level compositor.
async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint,
CSSToLayoutDeviceScale scale,
@@ -85,22 +86,16 @@ parent:
// Request the current DeviceStatus from the GPU process. This blocks until
// one is available (i.e., Init has completed).
sync GetDeviceStatus() returns (GPUDeviceData status);
// Have a message be broadcasted to the GPU process by the GPU process
// observer service.
async NotifyGpuObservers(nsCString aTopic);
- // Control the Gecko Profiler in the GPU process.
- async StartProfiler(ProfilerInitParams params);
- async StopProfiler();
- async PauseProfiler(bool aPause);
- async GatherProfile();
-
async RequestMemoryReport(uint32_t generation,
bool anonymize,
bool minimizeMemoryUsage,
MaybeFileDesc DMDFile);
child:
// Sent when the GPU process has initialized devices. This occurs once, after
// Init().
@@ -122,16 +117,14 @@ child:
async AccumulateChildHistograms(Accumulation[] accumulations);
async AccumulateChildKeyedHistograms(KeyedAccumulation[] accumulations);
async UpdateChildScalars(ScalarAction[] actions);
async UpdateChildKeyedScalars(KeyedScalarAction[] actions);
async RecordChildEvents(ChildEventData[] events);
async NotifyDeviceReset(GPUDeviceData status);
- // Called in response to GatherProfile.
- async Profile(nsCString aProfile, bool aIsExitProfile);
async AddMemoryReport(MemoryReport aReport);
async FinishMemoryReport(uint32_t aGeneration);
};
} // namespace gfx
} // namespace mozilla
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -29,16 +29,17 @@
#include "nsIObserverService.h"
#include "nsIXULAppInfo.h"
#include "nsIXULRuntime.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsMemoryReporterManager.h"
#include "nsXULAppAPI.h"
#include "nsProfilerStartParams.h"
+#include "ProfilerParent.h"
#include "mozilla/Services.h"
#include "nsThreadUtils.h"
#include "ProfilerMarkerPayload.h"
#include "shared-libraries.h"
#include "prdtoa.h"
#include "prtime.h"
#ifdef MOZ_TASK_TRACER
@@ -2025,16 +2026,17 @@ NotifyProfilerStarted(const int aEntries
nsTArray<nsCString> filtersArray;
for (size_t i = 0; i < aFilterCount; ++i) {
filtersArray.AppendElement(aFilters[i]);
}
nsCOMPtr<nsIProfilerStartParams> params =
new nsProfilerStartParams(aEntries, aInterval, aFeatures, filtersArray);
+ ProfilerParent::ProfilerStarted(params);
NotifyObservers("profiler-started", params);
}
static void
locked_profiler_start(PSLockRef aLock, const int aEntries, double aInterval,
uint32_t aFeatures,
const char** aFilters, uint32_t aFilterCount);
@@ -2170,16 +2172,17 @@ profiler_shutdown()
#ifdef MOZ_TASK_TRACER
mozilla::tasktracer::ShutdownTaskTracer();
#endif
}
// We do these operations with gPSMutex unlocked. The comments in
// profiler_stop() explain why.
if (samplerThread) {
+ ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
delete samplerThread;
}
}
UniquePtr<char[]>
profiler_get_profile(double aSinceTime)
{
@@ -2424,16 +2427,17 @@ profiler_start(int aEntries, double aInt
locked_profiler_start(lock, aEntries, aInterval, aFeatures,
aFilters, aFilterCount);
}
// We do these operations with gPSMutex unlocked. The comments in
// profiler_stop() explain why.
if (samplerThread) {
+ ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
delete samplerThread;
}
NotifyProfilerStarted(aEntries, aInterval, aFeatures,
aFilters, aFilterCount);
}
static MOZ_MUST_USE SamplerThread*
@@ -2501,16 +2505,17 @@ profiler_stop()
samplerThread = locked_profiler_stop(lock);
}
// We notify observers with gPSMutex unlocked. Otherwise we might get a
// deadlock, if code run by these functions calls a profiler function that
// locks gPSMutex, for example when it wants to insert a marker.
// (This has been seen in practise in bug 1346356, when we were still firing
// these notifications synchronously.)
+ ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
// We delete with gPSMutex unlocked. Otherwise we would get a deadlock: we
// would be waiting here with gPSMutex locked for SamplerThread::Run() to
// return so the join operation within the destructor can complete, but Run()
// needs to lock gPSMutex to return.
//
// Because this call occurs with gPSMutex unlocked, it -- including the final
@@ -2547,16 +2552,17 @@ profiler_pause()
if (!ActivePS::Exists(lock)) {
return;
}
ActivePS::SetIsPaused(lock, true);
}
// gPSMutex must be unlocked when we notify, to avoid potential deadlocks.
+ ProfilerParent::ProfilerPaused();
NotifyObservers("profiler-paused");
}
void
profiler_resume()
{
LOG("profiler_resume");
@@ -2568,16 +2574,17 @@ profiler_resume()
if (!ActivePS::Exists(lock)) {
return;
}
ActivePS::SetIsPaused(lock, false);
}
// gPSMutex must be unlocked when we notify, to avoid potential deadlocks.
+ ProfilerParent::ProfilerResumed();
NotifyObservers("profiler-resumed");
}
bool
profiler_feature_active(uint32_t aFeature)
{
// This function runs both on and off the main thread.
new file mode 100644
--- /dev/null
+++ b/tools/profiler/gecko/ChildProfilerController.cpp
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "ChildProfilerController.h"
+#include "nsThreadUtils.h"
+#include "ProfilerChild.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+
+/* static */ already_AddRefed<ChildProfilerController>
+ChildProfilerController::Create(mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint)
+{
+ MOZ_RELEASE_ASSERT(NS_IsMainThread());
+ RefPtr<ChildProfilerController> cpc = new ChildProfilerController();
+ cpc->Init(Move(aEndpoint));
+ return cpc.forget();
+}
+
+ChildProfilerController::ChildProfilerController()
+{
+ MOZ_COUNT_CTOR(ChildProfilerController);
+}
+
+void
+ChildProfilerController::Init(Endpoint<PProfilerChild>&& aEndpoint)
+{
+ if (NS_SUCCEEDED(NS_NewNamedThread("ProfilerChild", getter_AddRefs(mThread)))) {
+ // Now that mThread has been set, run SetupProfilerChild on the thread.
+ mThread->Dispatch(NewRunnableMethod<Endpoint<PProfilerChild>&&>(
+ this, &ChildProfilerController::SetupProfilerChild, Move(aEndpoint)),
+ NS_DISPATCH_NORMAL);
+ }
+}
+
+nsCString
+ChildProfilerController::GrabShutdownProfileAndShutdown()
+{
+ nsCString shutdownProfile;
+ ShutdownAndMaybeGrabShutdownProfileFirst(&shutdownProfile);
+ return shutdownProfile;
+}
+
+void
+ChildProfilerController::Shutdown()
+{
+ ShutdownAndMaybeGrabShutdownProfileFirst(nullptr);
+}
+
+void
+ChildProfilerController::ShutdownAndMaybeGrabShutdownProfileFirst(nsCString* aOutShutdownProfile)
+{
+ if (mThread) {
+ mThread->Dispatch(NewRunnableMethod<nsCString*>(
+ this, &ChildProfilerController::ShutdownProfilerChild, aOutShutdownProfile),
+ NS_DISPATCH_NORMAL);
+ // Shut down the thread. This call will spin until all runnables (including
+ // the ShutdownProfilerChild runnable) have been processed.
+ mThread->Shutdown();
+ mThread = nullptr;
+ }
+}
+
+ChildProfilerController::~ChildProfilerController()
+{
+ MOZ_COUNT_DTOR(ChildProfilerController);
+
+ MOZ_ASSERT(!mThread, "Please call Shutdown before destroying ChildProfilerController");
+ MOZ_ASSERT(!mProfilerChild);
+}
+
+void
+ChildProfilerController::SetupProfilerChild(Endpoint<PProfilerChild>&& aEndpoint)
+{
+ MOZ_RELEASE_ASSERT(mThread == NS_GetCurrentThread());
+ MOZ_ASSERT(aEndpoint.IsValid());
+
+ mProfilerChild = new ProfilerChild();
+ Endpoint<PProfilerChild> endpoint = Move(aEndpoint);
+
+ if (!endpoint.Bind(mProfilerChild)) {
+ MOZ_CRASH("Failed to bind ProfilerChild!");
+ }
+}
+
+void
+ChildProfilerController::ShutdownProfilerChild(nsCString* aOutShutdownProfile)
+{
+ MOZ_RELEASE_ASSERT(mThread == NS_GetCurrentThread());
+
+ if (aOutShutdownProfile) {
+ *aOutShutdownProfile = mProfilerChild->GrabShutdownProfile();
+ }
+ mProfilerChild->Destroy();
+ mProfilerChild = nullptr;
+}
+
+} // namespace mozilla
deleted file mode 100644
--- a/tools/profiler/gecko/CrossProcessProfilerController.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/* 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 "nsISupports.h"
-#include "nsIObserver.h"
-#include "nsProfiler.h"
-#include "ProfilerControllingProcess.h"
-
-namespace mozilla {
-
-static const char* sObserverTopics[] = {
- "profiler-started",
- "profiler-stopped",
- "profiler-paused",
- "profiler-resumed",
- "profiler-subprocess-gather",
-};
-
-// 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))
-{
- if (profiler_is_active()) {
- // If the profiler is already running in this process, start it in the
- // child process immediately.
- nsCOMPtr<nsIProfilerStartParams> currentProfilerParams;
- nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
- DebugOnly<nsresult> 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()
-{
- 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());
- aParams->GetFeatures(&ipcParams.features());
- ipcParams.filters() = aParams->GetFilters();
-
- mProcess->SendStartProfiler(ipcParams);
-}
-
-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.
- nsProfiler::GetOrCreate()->WillGatherOOPProfile();
- mProcess->SendGatherProfile();
- }
- // 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")) {
- 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,
- bool aIsExitProfile)
-{
- // Pass our process's profile along to nsProfiler.
- if (aIsExitProfile) {
- nsProfiler::GetOrCreate()->OOPExitProfile(aProfile);
- } else {
- nsProfiler::GetOrCreate()->GatheredOOPProfile(aProfile);
- }
-}
-
-} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/tools/profiler/gecko/PProfiler.ipdl
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 ProfilerTypes;
+
+namespace mozilla {
+
+// PProfiler is a top-level protocol. It is used to let the main process
+// control the Gecko Profiler in other processes, and request profiles from
+// those processes.
+// It is a top-level protocol so that its child endpoint can be on a
+// background thread, so that profiles can be gathered even if the main thread
+// is unresponsive.
+async protocol PProfiler
+{
+child:
+ async Start(ProfilerInitParams params);
+ async Stop();
+ async Pause();
+ async Resume();
+
+ async GatherProfile() returns (nsCString profile);
+};
+
+} // namespace mozilla
+
--- a/tools/profiler/gecko/ProfileGatherer.cpp
+++ b/tools/profiler/gecko/ProfileGatherer.cpp
@@ -55,48 +55,37 @@ ProfileGatherer::GatheredOOPProfile(cons
if (mPendingProfiles == 0) {
// We've got all of the async profiles now. Let's
// finish off the profile and resolve the Promise.
Finish();
}
}
-void
-ProfileGatherer::WillGatherOOPProfile()
-{
- mPendingProfiles++;
-}
-
RefPtr<ProfileGatherer::ProfileGatherPromise>
ProfileGatherer::Start(double aSinceTime)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (mGathering) {
// If we're already gathering, return a rejected promise - this isn't
// going to end well.
return ProfileGatherPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
}
mGathering = true;
- mPendingProfiles = 0;
- // Send a notification to request profiles from other processes. The
- // observers of this notification will call WillGatherOOPProfile() which
- // increments mPendingProfiles.
+ // Request profiles from the other processes. This will trigger
+ // asynchronous calls to ProfileGatherer::GatheredOOPProfile as the
+ // profiles arrive.
// Do this before the call to profiler_stream_json_for_this_process because
// that call is slow and we want to let the other processes grab their
// profiles as soon as possible.
- nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
- if (os) {
- DebugOnly<nsresult> rv =
- os->NotifyObservers(this, "profiler-subprocess-gather", nullptr);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NotifyObservers failed");
- }
+ nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>> profiles =
+ ProfilerParent::GatherProfiles();
mWriter.emplace();
// Start building up the JSON result and grab the profile from this process.
mWriter->Start(SpliceableJSONWriter::SingleLineStyle);
if (!profiler_stream_json_for_this_process(*mWriter, aSinceTime)) {
// The profiler is inactive. This either means that it was inactive even
// at the time that ProfileGatherer::Start() was called, or that it was
@@ -119,16 +108,27 @@ ProfileGatherer::Start(double aSinceTime
mPromiseHolder.emplace();
RefPtr<ProfileGatherPromise> promise = mPromiseHolder->Ensure(__func__);
// Keep the array property "processes" and the root object in mWriter open
// until Finish() is called. As profiles from the other processes come in,
// they will be inserted and end up in the right spot. Finish() will close
// the array and the root object.
+ mPendingProfiles = profiles.Length();
+ RefPtr<ProfileGatherer> self = this;
+ for (auto profile : profiles) {
+ profile->Then(AbstractThread::MainThread(), __func__,
+ [self](const nsCString& aResult) {
+ self->GatheredOOPProfile(aResult);
+ },
+ [self](PromiseRejectReason aReason) {
+ self->GatheredOOPProfile(NS_LITERAL_CSTRING(""));
+ });
+ }
if (!mPendingProfiles) {
Finish();
}
return promise;
}
void
--- a/tools/profiler/gecko/ProfileGatherer.h
+++ b/tools/profiler/gecko/ProfileGatherer.h
@@ -15,17 +15,16 @@ namespace mozilla {
class ProfileGatherer final : public nsISupports
{
public:
NS_DECL_ISUPPORTS
typedef MozPromise<nsCString, nsresult, false> ProfileGatherPromise;
explicit ProfileGatherer();
- void WillGatherOOPProfile();
void GatheredOOPProfile(const nsACString& aProfile);
RefPtr<ProfileGatherPromise> Start(double aSinceTime);
void OOPExitProfile(const nsACString& aProfile);
private:
~ProfileGatherer();
void Cancel();
void Finish();
new file mode 100644
--- /dev/null
+++ b/tools/profiler/gecko/ProfilerChild.cpp
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "GeckoProfiler.h"
+#include "ProfilerChild.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+
+ProfilerChild::ProfilerChild()
+ : mThread(NS_GetCurrentThread())
+ , mDestroyed(false)
+{
+ MOZ_COUNT_CTOR(ProfilerChild);
+}
+
+ProfilerChild::~ProfilerChild()
+{
+ MOZ_COUNT_DTOR(ProfilerChild);
+}
+
+mozilla::ipc::IPCResult
+ProfilerChild::RecvStart(const ProfilerInitParams& params)
+{
+ nsTArray<const char*> filterArray;
+ for (size_t i = 0; i < params.filters().Length(); ++i) {
+ filterArray.AppendElement(params.filters()[i].get());
+ }
+
+ profiler_start(params.entries(), params.interval(),
+ params.features(),
+ filterArray.Elements(),
+ filterArray.Length());
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ProfilerChild::RecvStop()
+{
+ profiler_stop();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ProfilerChild::RecvPause()
+{
+ profiler_pause();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ProfilerChild::RecvResume()
+{
+ profiler_resume();
+ return IPC_OK();
+}
+
+static nsCString
+CollectProfileOrEmptyString()
+{
+ nsCString profileCString;
+ UniquePtr<char[]> profile = profiler_get_profile();
+ if (profile) {
+ profileCString = nsCString(profile.get(), strlen(profile.get()));
+ } else {
+ profileCString = EmptyCString();
+ }
+ return profileCString;
+}
+
+mozilla::ipc::IPCResult
+ProfilerChild::RecvGatherProfile(RefPtr<GatherProfilePromise>&& aPromise)
+{
+ aPromise->Resolve(CollectProfileOrEmptyString(), __func__);
+ return IPC_OK();
+}
+
+void
+ProfilerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
+{
+ mDestroyed = true;
+}
+
+void
+ProfilerChild::Destroy()
+{
+ if (!mDestroyed) {
+ Close();
+ }
+}
+
+nsCString
+ProfilerChild::GrabShutdownProfile()
+{
+ return CollectProfileOrEmptyString();
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/tools/profiler/gecko/ProfilerParent.cpp
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "ProfilerParent.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Unused.h"
+
+#include "nsProfiler.h"
+#include "nsTArray.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+class ProfilerParentTracker final {
+public:
+ static void StartTracking(ProfilerParent* aParent);
+ static void StopTracking(ProfilerParent* aParent);
+
+ template<typename FuncType>
+ static void Enumerate(FuncType aIterFunc);
+
+ ProfilerParentTracker();
+ ~ProfilerParentTracker();
+
+private:
+ nsTArray<ProfilerParent*> mProfilerParents;
+ static UniquePtr<ProfilerParentTracker> sInstance;
+};
+
+UniquePtr<ProfilerParentTracker> ProfilerParentTracker::sInstance;
+
+/* static */ void
+ProfilerParentTracker::StartTracking(ProfilerParent* aProfilerParent)
+{
+ if (!sInstance) {
+ sInstance = MakeUnique<ProfilerParentTracker>();
+ ClearOnShutdown(&sInstance);
+ }
+ sInstance->mProfilerParents.AppendElement(aProfilerParent);
+}
+
+/* static */ void
+ProfilerParentTracker::StopTracking(ProfilerParent* aParent)
+{
+ if (sInstance) {
+ sInstance->mProfilerParents.RemoveElement(aParent);
+ }
+}
+
+template<typename FuncType>
+/* static */ void
+ProfilerParentTracker::Enumerate(FuncType aIterFunc)
+{
+ if (sInstance) {
+ for (ProfilerParent* profilerParent : sInstance->mProfilerParents) {
+ if (!profilerParent->mDestroyed) {
+ aIterFunc(profilerParent);
+ }
+ }
+ }
+}
+
+ProfilerParentTracker::ProfilerParentTracker()
+{
+ MOZ_COUNT_CTOR(ProfilerParentTracker);
+}
+
+ProfilerParentTracker::~ProfilerParentTracker()
+{
+ MOZ_COUNT_DTOR(ProfilerParentTracker);
+
+ nsTArray<ProfilerParent*> parents;
+ parents = mProfilerParents;
+ // Close the channels of any profiler parents that haven't been destroyed.
+ for (ProfilerParent* profilerParent : parents) {
+ if (!profilerParent->mDestroyed) {
+ // Keep the object alive until the call to Close() has completed.
+ // Close() will trigger a call to DeallocPProfilerParent.
+ RefPtr<ProfilerParent> actor = profilerParent;
+ actor->Close();
+ }
+ }
+}
+
+/* static */ Endpoint<PProfilerChild>
+ProfilerParent::CreateForProcess(base::ProcessId aOtherPid)
+{
+ MOZ_RELEASE_ASSERT(NS_IsMainThread());
+ Endpoint<PProfilerParent> parent;
+ Endpoint<PProfilerChild> child;
+ nsresult rv = PProfiler::CreateEndpoints(base::GetCurrentProcId(),
+ aOtherPid,
+ &parent, &child);
+
+ if (NS_FAILED(rv)) {
+ MOZ_CRASH("Failed to create top level actor for PProfiler!");
+ }
+
+ RefPtr<ProfilerParent> actor = new ProfilerParent();
+ if (!parent.Bind(actor)) {
+ MOZ_CRASH("Failed to bind parent actor for PProfiler!");
+ }
+
+ // mSelfRef will be cleared in DeallocPProfilerParent.
+ actor->mSelfRef = actor;
+ actor->Init();
+
+ return child;
+}
+
+ProfilerParent::ProfilerParent()
+ : mDestroyed(false)
+{
+ MOZ_COUNT_CTOR(ProfilerParent);
+
+ MOZ_RELEASE_ASSERT(NS_IsMainThread());
+}
+
+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);
+}
+
+/* static */ nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>>
+ProfilerParent::GatherProfiles()
+{
+ if (!NS_IsMainThread()) {
+ return nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>>();
+ }
+
+ nsTArray<RefPtr<SingleProcessProfilePromise>> results;
+ ProfilerParentTracker::Enumerate([&](ProfilerParent* profilerParent) {
+ results.AppendElement(profilerParent->SendGatherProfile());
+ });
+ return results;
+}
+
+/* static */ void
+ProfilerParent::ProfilerStarted(nsIProfilerStartParams* aParams)
+{
+ if (!NS_IsMainThread()) {
+ return;
+ }
+
+ ProfilerInitParams ipcParams;
+ ipcParams.enabled() = true;
+ aParams->GetEntries(&ipcParams.entries());
+ aParams->GetInterval(&ipcParams.interval());
+ aParams->GetFeatures(&ipcParams.features());
+ ipcParams.filters() = aParams->GetFilters();
+
+ ProfilerParentTracker::Enumerate([&](ProfilerParent* profilerParent) {
+ Unused << profilerParent->SendStart(ipcParams);
+ });
+}
+
+/* static */ void
+ProfilerParent::ProfilerStopped()
+{
+ if (!NS_IsMainThread()) {
+ return;
+ }
+
+ ProfilerParentTracker::Enumerate([](ProfilerParent* profilerParent) {
+ Unused << profilerParent->SendStop();
+ });
+}
+
+/* static */ void
+ProfilerParent::ProfilerPaused()
+{
+ if (!NS_IsMainThread()) {
+ return;
+ }
+
+ ProfilerParentTracker::Enumerate([](ProfilerParent* profilerParent) {
+ Unused << profilerParent->SendPause();
+ });
+}
+
+/* static */ void
+ProfilerParent::ProfilerResumed()
+{
+ if (!NS_IsMainThread()) {
+ return;
+ }
+
+ ProfilerParentTracker::Enumerate([](ProfilerParent* profilerParent) {
+ Unused << profilerParent->SendResume();
+ });
+}
+
+void
+ProfilerParent::ActorDestroy(ActorDestroyReason aActorDestroyReason)
+{
+ MOZ_RELEASE_ASSERT(NS_IsMainThread());
+ mDestroyed = true;
+}
+
+void
+ProfilerParent::DeallocPProfilerParent()
+{
+ mSelfRef = nullptr;
+}
+
+} // namespace mozilla
--- a/tools/profiler/gecko/nsIProfiler.idl
+++ b/tools/profiler/gecko/nsIProfiler.idl
@@ -5,16 +5,17 @@
#include "nsISupports.idl"
%{C++
#include "nsTArrayForwardDeclare.h"
class nsCString;
%}
+[ref] native nsCString(const nsCString);
[ref] native StringArrayRef(const nsTArray<nsCString>);
/**
* Start-up parameters for subprocesses are passed through nsIObserverService,
* which, unfortunately, means we need to implement nsISupports in order to
* go through it.
*/
[builtinclass, uuid(0a175ba7-8fcf-4ce9-9c4b-ccc6272f4425)]
@@ -105,9 +106,12 @@ interface nsIProfiler : nsISupports
*/
[implicit_jscontext]
readonly attribute jsval sharedLibraries;
/**
* Dump the collected profile to a file.
*/
void dumpProfileToFile(in string aFilename);
+
+ [noscript, notxpcom, nostdcall]
+ void receiveShutdownProfile(in nsCString aProfile);
};
--- a/tools/profiler/gecko/nsProfiler.cpp
+++ b/tools/profiler/gecko/nsProfiler.cpp
@@ -487,43 +487,30 @@ nsProfiler::GetBufferInfo(uint32_t* aCur
MOZ_ASSERT(aCurrentPosition);
MOZ_ASSERT(aTotalSize);
MOZ_ASSERT(aGeneration);
profiler_get_buffer_info(aCurrentPosition, aTotalSize, aGeneration);
return NS_OK;
}
void
-nsProfiler::WillGatherOOPProfile()
-{
- MOZ_RELEASE_ASSERT(NS_IsMainThread());
-
- if (!mGatherer) {
- return;
- }
-
- mGatherer->WillGatherOOPProfile();
-}
-
-void
nsProfiler::GatheredOOPProfile(const nsACString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!mGatherer) {
return;
}
mGatherer->GatheredOOPProfile(aProfile);
}
void
-nsProfiler::OOPExitProfile(const nsACString& aProfile)
+nsProfiler::ReceiveShutdownProfile(const nsCString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!mGatherer) {
return;
}
mGatherer->OOPExitProfile(aProfile);
}
-
--- a/tools/profiler/gecko/nsProfiler.h
+++ b/tools/profiler/gecko/nsProfiler.h
@@ -28,19 +28,17 @@ public:
static nsProfiler* GetOrCreate()
{
nsCOMPtr<nsIProfiler> iprofiler =
do_GetService("@mozilla.org/tools/profiler;1");
return static_cast<nsProfiler*>(iprofiler.get());
}
- void WillGatherOOPProfile();
void GatheredOOPProfile(const nsACString& aProfile);
- void OOPExitProfile(const nsACString& aProfile);
private:
~nsProfiler();
RefPtr<mozilla::ProfileGatherer> mGatherer;
bool mLockedForPrivateBrowsing;
};
--- a/tools/profiler/moz.build
+++ b/tools/profiler/moz.build
@@ -5,34 +5,38 @@
# 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',
]
EXPORTS += [
- 'public/CrossProcessProfilerController.h',
+ 'public/ChildProfilerController.h',
+ 'public/ProfilerChild.h',
'public/ProfilerMarkerPayload.h',
+ 'public/ProfilerParent.h',
'public/shared-libraries.h',
]
UNIFIED_SOURCES += [
'core/platform.cpp',
'core/ProfileBuffer.cpp',
'core/ProfileBufferEntry.cpp',
'core/ProfileJSONWriter.cpp',
'core/ProfilerBacktrace.cpp',
'core/ProfilerMarkerPayload.cpp',
'core/StackTop.cpp',
'core/ThreadInfo.cpp',
- 'gecko/CrossProcessProfilerController.cpp',
+ 'gecko/ChildProfilerController.cpp',
'gecko/nsProfilerFactory.cpp',
'gecko/nsProfilerStartParams.cpp',
'gecko/ProfileGatherer.cpp',
+ 'gecko/ProfilerChild.cpp',
'gecko/ProfilerIOInterposeObserver.cpp',
+ 'gecko/ProfilerParent.cpp',
'gecko/ThreadResponsiveness.cpp',
]
if CONFIG['OS_TARGET'] == 'Darwin':
# This file cannot be built in unified mode because it includes
# "nsLocalFile.h", which pulls in a system header which uses a type
# called TextRange, which conflicts with mozilla::TextRange due to
# a "using namespace mozilla;" declaration from a different file.
SOURCES += [
@@ -103,25 +107,25 @@ if CONFIG['MOZ_GECKO_PROFILER']:
DEFINES['ARCH_ARMV6'] = True
if CONFIG['ENABLE_TESTS']:
DIRS += ['tests/gtest']
FINAL_LIBRARY = 'xul'
IPDL_SOURCES += [
+ 'gecko/PProfiler.ipdl',
'gecko/ProfilerTypes.ipdlh',
]
include('/ipc/chromium/chromium-config.mozbuild')
EXPORTS += [
'public/GeckoProfiler.h',
'public/GeckoProfilerReporter.h',
- 'public/ProfilerControllingProcess.h',
]
if CONFIG['MOZ_TASK_TRACER']:
EXPORTS += [
'tasktracer/GeckoTaskTracer.h',
'tasktracer/GeckoTaskTracerImpl.h',
'tasktracer/SourceEventTypeMap.h',
'tasktracer/TracedTaskCommon.h',
new file mode 100644
--- /dev/null
+++ b/tools/profiler/public/ChildProfilerController.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 ChildProfilerController_h
+#define ChildProfilerController_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/RefPtr.h"
+#include "base/process.h"
+
+class nsCString;
+
+namespace mozilla {
+
+class ProfilerChild;
+class PProfilerChild;
+class PProfilerParent;
+
+// ChildProfilerController manages the setup and teardown of ProfilerChild.
+// It's used on the main thread.
+// It manages a background thread that ProfilerChild runs on.
+class ChildProfilerController final
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChildProfilerController)
+
+ static already_AddRefed<ChildProfilerController>
+ Create(mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint);
+
+ MOZ_MUST_USE nsCString GrabShutdownProfileAndShutdown();
+ void Shutdown();
+
+private:
+ ChildProfilerController();
+ ~ChildProfilerController();
+ void Init(mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint);
+ void ShutdownAndMaybeGrabShutdownProfileFirst(nsCString* aOutShutdownProfile);
+
+ // Called on mThread:
+ void SetupProfilerChild(mozilla::ipc::Endpoint<PProfilerChild>&& aEndpoint);
+ void ShutdownProfilerChild(nsCString* aOutShutdownProfile);
+
+ RefPtr<ProfilerChild> mProfilerChild; // only accessed on mThread
+ RefPtr<nsIThread> mThread;
+};
+
+} // namespace mozilla
+
+#endif // ChildProfilerController_h
deleted file mode 100644
--- a/tools/profiler/public/CrossProcessProfilerController.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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, bool aIsExitProfile);
-
-private:
- void StartProfiler(nsIProfilerStartParams* aParams);
- void Observe(nsISupports* aSubject, const char* aTopic);
-
- friend class ProfilerObserver;
-
- ProfilerControllingProcess* mProcess;
- RefPtr<ProfilerObserver> mObserver;
-};
-
-} // namespace mozilla
-
-#endif
new file mode 100644
--- /dev/null
+++ b/tools/profiler/public/ProfilerChild.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 ProfilerChild_h
+#define ProfilerChild_h
+
+#include "mozilla/PProfilerChild.h"
+#include "mozilla/RefPtr.h"
+
+class nsIThread;
+
+namespace mozilla {
+
+// The ProfilerChild actor is created in all processes except for the main
+// process. The corresponding ProfilerParent actor is created in the main
+// process, and it will notify us about profiler state changes and request
+// profiles from us.
+class ProfilerChild final : public PProfilerChild
+{
+ NS_INLINE_DECL_REFCOUNTING(ProfilerChild)
+
+ ProfilerChild();
+
+ // Collects and returns a profile.
+ // This method can be used to grab a profile just before PProfiler is torn
+ // down. The collected profile should then be sent through a different
+ // message channel that is guaranteed to stay open long enough.
+ nsCString GrabShutdownProfile();
+
+ void Destroy();
+
+private:
+ virtual ~ProfilerChild();
+
+ mozilla::ipc::IPCResult RecvStart(const ProfilerInitParams& params) override;
+ mozilla::ipc::IPCResult RecvStop() override;
+ mozilla::ipc::IPCResult RecvPause() override;
+ mozilla::ipc::IPCResult RecvResume() override;
+ mozilla::ipc::IPCResult RecvGatherProfile(RefPtr<GatherProfilePromise>&& aPromise) override;
+
+ void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
+
+ nsCOMPtr<nsIThread> mThread;
+ bool mDestroyed;
+};
+
+} // namespace mozilla
+
+#endif // ProfilerChild_h
deleted file mode 100644
--- a/tools/profiler/public/ProfilerControllingProcess.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* 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
new file mode 100644
--- /dev/null
+++ b/tools/profiler/public/ProfilerParent.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 ProfilerParent_h
+#define ProfilerParent_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/PProfilerParent.h"
+
+namespace mozilla {
+
+class ProfilerParentTracker;
+
+// This is the main process side of the PProfiler protocol.
+// ProfilerParent instances only exist on the main thread of the main process.
+// The other side (ProfilerChild) lives on a background thread in the other
+// process.
+// The creation of PProfiler actors is initiated from the main process, after
+// the other process has been launched.
+// ProfilerParent instances are destroyed once the message channel closes,
+// which can be triggered by either process, depending on which one shuts down
+// first.
+// All ProfilerParent instances are registered with a manager class called
+// ProfilerParentTracker, which has the list of living ProfilerParent instances
+// and handles shutdown.
+class ProfilerParent final : public PProfilerParent
+{
+public:
+ NS_INLINE_DECL_REFCOUNTING(ProfilerParent)
+
+ static mozilla::ipc::Endpoint<PProfilerChild> CreateForProcess(base::ProcessId aOtherPid);
+
+ typedef MozPromise<nsCString, PromiseRejectReason, false> SingleProcessProfilePromise;
+
+ // The following static methods can be called on any thread, but they are
+ // no-ops on anything other than the main thread.
+ // If called on the main thread, the call will be broadcast to all
+ // registered processes (all processes for which we have a ProfilerParent
+ // object).
+ // At the moment, the main process always calls these methods on the main
+ // thread, and that's the only process in which we need to forward these
+ // calls to other processes. The other processes will call these methods on
+ // the ProfilerChild background thread, but those processes don't need to
+ // forward these calls any further.
+
+ // Returns the number of profiles to expect. The gathered profiles will be
+ // provided asynchronously with a call to ProfileGatherer::ReceiveGatheredProfile.
+ static nsTArray<RefPtr<SingleProcessProfilePromise>> GatherProfiles();
+
+ static void ProfilerStarted(nsIProfilerStartParams* aParams);
+ static void ProfilerStopped();
+ static void ProfilerPaused();
+ static void ProfilerResumed();
+
+private:
+ friend class ProfilerParentTracker;
+
+ ProfilerParent();
+ virtual ~ProfilerParent();
+
+ void Init();
+ void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
+ void DeallocPProfilerParent() override;
+
+ RefPtr<ProfilerParent> mSelfRef;
+ nsTArray<MozPromiseHolder<SingleProcessProfilePromise>> mPendingRequestedProfiles;
+ bool mDestroyed;
+};
+
+} // namespace mozilla
+
+#endif // ProfilerParent_h