Backed out 5 changesets (bug 1330185, bug 1330184) for leaking an nsTArray_base from the plugin process on Win8

Backed out changeset e6f368f2d874 (bug 1330185)
Backed out changeset 2b8d50fcb20f (bug 1330184)
Backed out changeset dbe452a9eebb (bug 1330184)
Backed out changeset e13b9e798e16 (bug 1330184)
Backed out changeset 52489c7eadaf (bug 1330184)

MozReview-Commit-ID: 8L20BZ5E3t2
This commit is contained in:
Phil Ringnalda 2017-05-22 19:45:35 -07:00
parent e6e35bafa1
commit 6368ef89e2
37 changed files with 734 additions and 878 deletions

View File

@ -74,10 +74,6 @@
#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
@ -1054,11 +1050,6 @@ ContentChild::InitXPCOM(const XPCOMInitData& aXPCOMInit,
nsCOMPtr<nsIURI> ucsURL = DeserializeURI(aXPCOMInit.userContentSheetURL());
nsLayoutStylesheetCache::SetUserContentCSSURL(ucsURL);
#ifdef MOZ_GECKO_PROFILER
mProfilerController = new ChildProfilerController();
Unused << SendInitProfiler(mProfilerController->SetUpEndpoints(OtherPid()));
#endif
// This will register cross-process observer.
mozilla::dom::time::InitializeDateCacheCleaner();
@ -2660,6 +2651,60 @@ ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
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)
@ -2826,12 +2871,11 @@ ContentChild::RecvShutdown()
GetIPCChannel()->SetAbortOnError(false);
#ifdef MOZ_GECKO_PROFILER
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);
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);
}
#endif

View File

@ -35,7 +35,6 @@ struct LookAndFeelInt;
namespace mozilla {
class RemoteSpellcheckEngineChild;
class ChildProfilerController;
using mozilla::loader::PScriptCacheChild;
@ -453,6 +452,14 @@ public:
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;
@ -685,6 +692,8 @@ private:
virtual already_AddRefed<nsIEventTarget>
GetConstructedEventTarget(const Message& aMsg) override;
void GatherProfile(bool aIsExitProfile);
InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
RefPtr<ConsoleListener> mConsoleListener;
@ -729,10 +738,6 @@ private:
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

View File

@ -24,6 +24,9 @@
#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"
@ -185,7 +188,6 @@
#include "nsHostObjectProtocolHandler.h"
#include "nsICaptivePortalService.h"
#include "nsIObjectLoadingContent.h"
#include "ProfilerParent.h"
#include "nsIBidiKeyboard.h"
@ -253,10 +255,6 @@
#include "nsAccessibilityService.h"
#endif
#ifdef MOZ_GECKO_PROFILER
#include "nsIProfiler.h"
#endif
// For VP9Benchmark::sBenchmarkFpsPref
#include "Benchmark.h"
@ -1069,6 +1067,38 @@ ContentParent::RecvRemovePermission(const IPC::Principal& aPrincipal,
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,
@ -1322,6 +1352,10 @@ ContentParent::Init()
}
#endif
#ifdef MOZ_GECKO_PROFILER
mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
#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());
@ -1716,6 +1750,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
mConsoleService = nullptr;
#ifdef MOZ_GECKO_PROFILER
mProfilerController = nullptr;
#endif
if (obs) {
RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
@ -2754,15 +2792,6 @@ ContentParent::RecvInitBackground(Endpoint<PBackgroundParent>&& aEndpoint)
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvInitProfiler(Endpoint<PProfilerParent>&& aEndpoint)
{
if (!ProfilerParent::Alloc(Move(aEndpoint))) {
NS_WARNING("ProfilerParent::Alloc failed");
}
return IPC_OK();
}
mozilla::jsipc::PJavaScriptParent *
ContentParent::AllocPJavaScriptParent()
{
@ -4669,11 +4698,12 @@ ContentParent::RecvCreateWindowInDifferentProcess(
}
mozilla::ipc::IPCResult
ContentParent::RecvShutdownProfile(const nsCString& aProfile)
ContentParent::RecvProfile(const nsCString& aProfile, const bool& aIsExitProfile)
{
#ifdef MOZ_GECKO_PROFILER
nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
profiler->ReceiveShutdownProfile(aProfile);
if (mProfilerController) {
mProfilerController->RecvProfile(aProfile, aIsExitProfile);
}
#endif
return IPC_OK();
}

View File

@ -30,6 +30,7 @@
#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")
@ -55,6 +56,9 @@ class nsIWidget;
namespace mozilla {
class PRemoteSpellcheckEngineParent;
#ifdef MOZ_GECKO_PROFILER
class CrossProcessProfilerController;
#endif
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
class SandboxBroker;
@ -110,6 +114,7 @@ class ContentParent final : public PContentParent
, public mozilla::LinkedListElement<ContentParent>
, public gfx::GPUProcessListener
, public mozilla::MemoryReportingProcess
, public mozilla::ProfilerControllingProcess
{
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
@ -307,6 +312,11 @@ public:
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
@ -815,7 +825,6 @@ private:
static nsTArray<ContentParent*>& GetOrCreatePool(const nsAString& aContentProcessType);
virtual mozilla::ipc::IPCResult RecvInitBackground(Endpoint<mozilla::ipc::PBackgroundParent>&& aEndpoint) override;
virtual mozilla::ipc::IPCResult RecvInitProfiler(Endpoint<mozilla::PProfilerParent>&& aEndpoint) override;
mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport) override;
mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration) override;
@ -1122,7 +1131,8 @@ private:
virtual mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect) override;
virtual mozilla::ipc::IPCResult RecvShutdownProfile(const nsCString& aProfile) override;
virtual mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile,
const bool& aIsExitProfile) override;
virtual mozilla::ipc::IPCResult RecvGetGraphicsDeviceInitData(ContentDeviceData* aOut) override;
@ -1239,6 +1249,10 @@ private:
PProcessHangMonitorParent* mHangMonitorActor;
#ifdef MOZ_GECKO_PROFILER
UniquePtr<mozilla::CrossProcessProfilerController> mProfilerController;
#endif
UniquePtr<gfx::DriverCrashGuard> mDriverCrashGuard;
UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;

View File

@ -45,7 +45,6 @@ include protocol PURLClassifierLocal;
include protocol PVRManager;
include protocol PVideoDecoderManager;
include protocol PFlyWebPublishedServer;
include protocol PProfiler;
include protocol PScriptCache;
include DOMTypes;
include JavaScriptTypes;
@ -59,6 +58,7 @@ include PBackgroundSharedTypes;
include PContentPermission;
include ServiceWorkerConfiguration;
include GraphicsMessages;
include ProfilerTypes;
include MemoryReportTypes;
// Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp
@ -511,6 +511,15 @@ child:
*/
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,
@ -620,7 +629,6 @@ child:
parent:
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
async InitProfiler(Endpoint<PProfilerParent> aEndpoint);
sync CreateChildProcess(IPCTabContext context,
ProcessPriority priority,
@ -987,7 +995,7 @@ parent:
async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
TabId tabId);
async ShutdownProfile(nsCString aProfile);
async Profile(nsCString aProfile, bool aIsExitProfile);
/**
* Request graphics initialization information from the parent.

View File

@ -6,7 +6,7 @@
include protocol PPluginInstance;
include protocol PPluginScriptableObject;
include protocol PContent;
include protocol PProfiler;
include ProfilerTypes;
using NPError from "npapi.h";
using NPNVariable from "npapi.h";
@ -95,6 +95,14 @@ 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);
@ -104,8 +112,6 @@ child:
parent:
async NP_InitializeResult(NPError aError);
async InitProfiler(Endpoint<PProfilerParent> aEndPoint);
/**
* This message is only used on X11 platforms.
*
@ -147,6 +153,8 @@ parent:
// 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);

View File

@ -53,9 +53,7 @@
#include "mozilla/ipc/CrashReporterClient.h"
#endif
#ifdef MOZ_GECKO_PROFILER
#include "ChildProfilerController.h"
#endif
#include "GeckoProfiler.h"
using namespace mozilla;
using namespace mozilla::ipc;
@ -286,11 +284,6 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
GetIPCChannel()->SetAbortOnError(true);
#ifdef MOZ_GECKO_PROFILER
mProfilerController = new ChildProfilerController();
Unused << SendInitProfiler(mProfilerController->SetUpEndpoints(OtherPid()));
#endif
// TODO: use PluginPRLibrary here
#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
@ -753,13 +746,6 @@ PluginModuleChild::AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeT
void
PluginModuleChild::ActorDestroy(ActorDestroyReason why)
{
#ifdef MOZ_GECKO_PROFILER
if (mProfilerController) {
mProfilerController->Shutdown();
mProfilerController = nullptr;
}
#endif
if (!mIsChrome) {
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
@ -2679,6 +2665,54 @@ PluginModuleChild::ProcessNativeEvents() {
}
#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,

View File

@ -46,9 +46,6 @@ typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFun
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
namespace mozilla {
class ChildProfilerController;
namespace plugins {
class PluginInstanceChild;
@ -128,6 +125,11 @@ protected:
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:
@ -253,10 +255,6 @@ private:
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)

View File

@ -33,8 +33,10 @@
#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"
@ -56,6 +58,9 @@
using base::KillProcess;
using mozilla::PluginLibrary;
#ifdef MOZ_GECKO_PROFILER
using mozilla::CrossProcessProfilerController;
#endif
using mozilla::ipc::MessageChannel;
using mozilla::ipc::GeckoChildProcessHost;
@ -631,6 +636,10 @@ PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
}
#endif
}
#ifdef MOZ_GECKO_PROFILER
mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
#endif
}
bool
@ -770,6 +779,10 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
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,
@ -3120,15 +3133,6 @@ PluginModuleParent::RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
return IPC_OK();
}
mozilla::ipc::IPCResult
PluginModuleParent::RecvInitProfiler(Endpoint<PProfilerParent>&& aEndpoint)
{
if (!ProfilerParent::Alloc(Move(aEndpoint))) {
NS_WARNING("ProfilerParent::Alloc failed");
}
return IPC_OK();
}
layers::TextureClientRecycleAllocator*
PluginModuleParent::EnsureTextureAllocatorForDirectBitmap()
{
@ -3259,6 +3263,18 @@ PluginModuleChromeParent::OnCrash(DWORD processID)
#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)
{

View File

@ -29,6 +29,7 @@
#include "sandboxPermissions.h"
#endif
#endif
#include "ProfilerControllingProcess.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
@ -38,6 +39,11 @@ class nsPluginTag;
namespace mozilla {
#ifdef MOZ_GECKO_PROFILER
class CrossProcessProfilerController;
#endif
namespace ipc {
class CrashReporterHost;
} // namespace ipc
@ -79,6 +85,7 @@ class FinishInjectorInitTask;
class PluginModuleParent
: public PPluginModuleParent
, public PluginLibrary
, public mozilla::ProfilerControllingProcess
#ifdef MOZ_CRASHREPORTER_INJECTOR
, public CrashReporter::InjectorCrashCallback
#endif
@ -140,6 +147,23 @@ public:
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,
@ -209,6 +233,8 @@ protected:
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,
@ -217,8 +243,6 @@ protected:
virtual mozilla::ipc::IPCResult RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
const uint64_t& aCallbackId) override;
virtual mozilla::ipc::IPCResult RecvInitProfiler(Endpoint<mozilla::PProfilerParent>&& aEndpoint) override;
void SetPluginFuncs(NPPluginFuncs* aFuncs);
nsresult NPP_NewInternal(NPMIMEType pluginType, NPP instance,
@ -502,6 +526,9 @@ class PluginModuleChromeParent
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;
@ -653,6 +680,9 @@ private:
// 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)

View File

@ -20,7 +20,9 @@
#include "mozilla/ipc/CrashReporterHost.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/Unused.h"
#include "ProfilerParent.h"
#ifdef MOZ_GECKO_PROFILER
#include "CrossProcessProfilerController.h"
#endif
namespace mozilla {
namespace gfx {
@ -74,6 +76,10 @@ GPUChild::Init()
SendInit(prefs, updates, devicePrefs, mappings);
gfxVars::AddReceiver(this);
#ifdef MOZ_GECKO_PROFILER
mProfilerController = MakeUnique<CrossProcessProfilerController>(this);
#endif
}
void
@ -199,6 +205,17 @@ GPUChild::RecvNotifyDeviceReset(const GPUDeviceData& aData)
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,
@ -214,16 +231,6 @@ GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
return true;
}
mozilla::ipc::IPCResult
GPUChild::RecvInitProfiler(Endpoint<PProfilerParent>&& aEndpoint)
{
if (!ProfilerParent::Alloc(Move(aEndpoint))) {
return IPC_FAIL(this, "ProfilerParent::Alloc failed");
}
return IPC_OK();
}
mozilla::ipc::IPCResult
GPUChild::RecvAddMemoryReport(const MemoryReport& aReport)
{
@ -243,6 +250,30 @@ GPUChild::RecvFinishMemoryReport(const uint32_t& aGeneration)
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)
{
@ -264,6 +295,10 @@ GPUChild::ActorDestroy(ActorDestroyReason aWhy)
}
#ifdef MOZ_GECKO_PROFILER
mProfilerController = nullptr;
#endif
gfxVars::RemoveReceiver(this);
mHost->OnChannelClosed();
}

View File

@ -10,9 +10,14 @@
#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
@ -26,6 +31,7 @@ class GPUProcessHost;
class GPUChild final
: public PGPUChild
, public gfxVarReceiver
, public ProfilerControllingProcess
{
typedef mozilla::dom::MemoryReportRequestHost MemoryReportRequestHost;
@ -55,10 +61,15 @@ public:
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 RecvInitProfiler(Endpoint<mozilla::PProfilerParent>&& aEndpoint) 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,
@ -71,6 +82,9 @@ private:
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
bool mGPUReady;
#ifdef MOZ_GECKO_PROFILER
UniquePtr<CrossProcessProfilerController> mProfilerController;
#endif
};
} // namespace gfx

View File

@ -7,6 +7,7 @@
#include "WMF.h"
#endif
#include "GPUParent.h"
#include "GeckoProfiler.h"
#include "gfxConfig.h"
#include "gfxPlatform.h"
#include "gfxPrefs.h"
@ -44,9 +45,6 @@
#ifdef MOZ_WIDGET_GTK
# include <gtk/gtk.h>
#endif
#ifdef MOZ_GECKO_PROFILER
#include "ChildProfilerController.h"
#endif
namespace mozilla {
namespace gfx {
@ -118,10 +116,6 @@ GPUParent::Init(base::ProcessId aParentPid,
mozilla::ipc::SetThisProcessName("GPU Process");
#ifdef XP_WIN
wmf::MFStartup();
#endif
#ifdef MOZ_GECKO_PROFILER
mProfilerController = new ChildProfilerController();
Unused << SendInitProfiler(mProfilerController->SetUpEndpoints(OtherPid()));
#endif
return true;
}
@ -388,6 +382,51 @@ GPUParent::RecvNotifyGpuObservers(const nsCString& aTopic)
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,
@ -419,13 +458,6 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
ProcessChild::QuickExit();
#endif
#ifdef MOZ_GECKO_PROFILER
if (mProfilerController) {
mProfilerController->Shutdown();
mProfilerController = nullptr;
}
#endif
if (mVsyncBridge) {
mVsyncBridge->Shutdown();
mVsyncBridge = nullptr;

View File

@ -12,7 +12,6 @@
namespace mozilla {
class TimeStamp;
class ChildProfilerController;
namespace gfx {
@ -56,6 +55,10 @@ public:
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,
@ -67,9 +70,6 @@ public:
private:
const TimeStamp mLaunchTime;
RefPtr<VsyncBridgeParent> mVsyncBridge;
#ifdef MOZ_GECKO_PROFILER
RefPtr<ChildProfilerController> mProfilerController;
#endif
};
} // namespace gfx

View File

@ -4,10 +4,10 @@
* 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;
@ -90,6 +90,12 @@ parent:
// 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,
@ -100,9 +106,6 @@ child:
// Init().
async InitComplete(GPUDeviceData data);
// Sent to the UI process to register the GPU process's profiler.
async InitProfiler(Endpoint<PProfilerParent> endpoint);
// Sent when APZ detects checkerboarding and apz checkerboard reporting is enabled.
async ReportCheckerboard(uint32_t severity, nsCString log);
@ -124,6 +127,8 @@ child:
async NotifyDeviceReset(GPUDeviceData status);
// Called in response to GatherProfile.
async Profile(nsCString aProfile, bool aIsExitProfile);
async AddMemoryReport(MemoryReport aReport);
async FinishMemoryReport(uint32_t aGeneration);
};

View File

@ -265,6 +265,8 @@ SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
// mSamplerTid to a dummy value and fill it in for real in ThreadEntry().
, mSamplerTid(-1)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
#if defined(USE_EHABI_STACKWALK)
mozilla::EHABIStackWalkInit();
#elif defined(USE_LUL_STACKWALK)
@ -319,6 +321,8 @@ SamplerThread::~SamplerThread()
void
SamplerThread::Stop(PSLockRef aLock)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
// Restore old signal handler. This is global state so it's important that
// we do it now, while gPSMutex is locked. It's safe to do this now even
// though this SamplerThread is still alive, because the next time the main

View File

@ -78,6 +78,8 @@ SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
, mIntervalMicroseconds(
std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5))))
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
pthread_attr_t* attr_ptr = nullptr;
if (pthread_create(&mThread, attr_ptr, ThreadEntry, this) != 0) {
MOZ_CRASH("pthread_create failed");
@ -92,6 +94,7 @@ SamplerThread::~SamplerThread()
void
SamplerThread::Stop(PSLockRef aLock)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
}
void

View File

@ -95,6 +95,8 @@ SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
, mIntervalMicroseconds(
std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5))))
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
// By default we'll not adjust the timer resolution which tends to be
// around 16ms. However, if the requested interval is sufficiently low
// we'll try to adjust the resolution to match.
@ -130,6 +132,8 @@ SamplerThread::~SamplerThread()
void
SamplerThread::Stop(PSLockRef aLock)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
// Disable any timer resolution changes we've made. Do it now while
// gPSMutex is locked, i.e. before any other SamplerThread can be created
// and call ::timeBeginPeriod().

View File

@ -35,7 +35,6 @@
#include "nsMemoryReporterManager.h"
#include "nsXULAppAPI.h"
#include "nsProfilerStartParams.h"
#include "ProfilerParent.h"
#include "mozilla/Services.h"
#include "nsThreadUtils.h"
#include "ProfilerMarkerPayload.h"
@ -299,32 +298,16 @@ private:
}
if (mInterposeObserver) {
// We need to register the observer on the main thread, because we want
// to observe IO that happens on the main thread.
if (NS_IsMainThread()) {
IOInterposer::Register(IOInterposeObserver::OpAll, mInterposeObserver);
} else {
RefPtr<ProfilerIOInterposeObserver> observer = mInterposeObserver;
NS_DispatchToMainThread(NS_NewRunnableFunction([=]() {
IOInterposer::Register(IOInterposeObserver::OpAll, observer);
}));
}
mozilla::IOInterposer::Register(mozilla::IOInterposeObserver::OpAll,
mInterposeObserver.get());
}
}
~ActivePS()
{
if (mInterposeObserver) {
// We need to unregister the observer on the main thread, because that's
// where we've registered it.
if (NS_IsMainThread()) {
IOInterposer::Unregister(IOInterposeObserver::OpAll, mInterposeObserver);
} else {
RefPtr<ProfilerIOInterposeObserver> observer = mInterposeObserver;
NS_DispatchToMainThread(NS_NewRunnableFunction([=]() {
IOInterposer::Unregister(IOInterposeObserver::OpAll, observer);
}));
}
mozilla::IOInterposer::Unregister(mozilla::IOInterposeObserver::OpAll,
mInterposeObserver.get());
}
}
@ -467,7 +450,7 @@ private:
SamplerThread* const mSamplerThread;
// The interposer that records main thread I/O.
const RefPtr<mozilla::ProfilerIOInterposeObserver> mInterposeObserver;
const UniquePtr<mozilla::ProfilerIOInterposeObserver> mInterposeObserver;
// Is the profiler paused?
bool mIsPaused;
@ -549,6 +532,19 @@ MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
// The name of the main thread.
static const char* const kMainThreadName = "GeckoMain";
static bool
CanNotifyObservers()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
#if defined(GP_OS_android)
// Android ANR reporter uses the profiler off the main thread.
return NS_IsMainThread();
#else
return true;
#endif
}
////////////////////////////////////////////////////////////////////////
// BEGIN tick/unwinding code
@ -1384,6 +1380,7 @@ static void
StreamTaskTracer(PSLockRef aLock, SpliceableJSONWriter& aWriter)
{
#ifdef MOZ_TASK_TRACER
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
aWriter.StartArrayProperty("data");
@ -1420,28 +1417,10 @@ StreamTaskTracer(PSLockRef aLock, SpliceableJSONWriter& aWriter)
static void
StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
aWriter.IntProperty("version", 6);
// The "startTime" field holds the number of milliseconds since midnight
// January 1, 1970 GMT. This grotty code computes (Now - (Now -
// ProcessStartTime)) to convert CorePS::ProcessStartTime() into that form.
mozilla::TimeDuration delta =
mozilla::TimeStamp::Now() - CorePS::ProcessStartTime(aLock);
aWriter.DoubleProperty(
"startTime", static_cast<double>(PR_Now()/1000.0 - delta.ToMilliseconds()));
if (!NS_IsMainThread()) {
// Leave the rest of the properties out if we're not on the main thread.
// At the moment, the only case in which this function is called on a
// background thread is if we're in a content process and are going to
// send this profile to the parent process. In that case, the parent
// process profile's "meta" object already has all this information, and
// the parent process profile is dumped on its main thread.
return;
}
aWriter.DoubleProperty("interval", ActivePS::Interval(aLock));
aWriter.IntProperty("stackwalk", ActivePS::FeatureStackWalk(aLock));
@ -1456,6 +1435,14 @@ StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter)
bool asyncStacks = Preferences::GetBool("javascript.options.asyncstack");
aWriter.IntProperty("asyncstack", asyncStacks);
// The "startTime" field holds the number of milliseconds since midnight
// January 1, 1970 GMT. This grotty code computes (Now - (Now -
// ProcessStartTime)) to convert CorePS::ProcessStartTime() into that form.
mozilla::TimeDuration delta =
mozilla::TimeStamp::Now() - CorePS::ProcessStartTime(aLock);
aWriter.DoubleProperty(
"startTime", static_cast<double>(PR_Now()/1000.0 - delta.ToMilliseconds()));
aWriter.IntProperty("processType", XRE_GetProcessType());
nsresult res;
@ -1567,6 +1554,7 @@ locked_profiler_stream_json_for_this_process(PSLockRef aLock,
{
LOG("locked_profiler_stream_json_for_this_process");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
// Put shared library info
@ -1631,6 +1619,7 @@ profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter, double aSin
{
LOG("profiler_stream_json_for_this_process");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
@ -2002,24 +1991,19 @@ locked_register_thread(PSLockRef aLock, const char* aName, void* stackTop)
CorePS::LiveThreads(aLock).push_back(info);
}
static void
NotifyObservers(const char* aTopic, nsISupports* aSubject = nullptr)
{
if (!NS_IsMainThread()) {
nsCOMPtr<nsISupports> subject = aSubject;
NS_DispatchToMainThread(NS_NewRunnableFunction([=] { NotifyObservers(aTopic, subject); }));
return;
}
if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
os->NotifyObservers(aSubject, aTopic, nullptr);
}
}
static void
NotifyProfilerStarted(const int aEntries, double aInterval, uint32_t aFeatures,
const char** aFilters, uint32_t aFilterCount)
{
if (!CanNotifyObservers()) {
return;
}
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (!os) {
return;
}
nsTArray<nsCString> filtersArray;
for (size_t i = 0; i < aFilterCount; ++i) {
filtersArray.AppendElement(aFilters[i]);
@ -2028,8 +2012,22 @@ NotifyProfilerStarted(const int aEntries, double aInterval, uint32_t aFeatures,
nsCOMPtr<nsIProfilerStartParams> params =
new nsProfilerStartParams(aEntries, aInterval, aFeatures, filtersArray);
ProfilerParent::ProfilerStarted(params);
NotifyObservers("profiler-started", params);
os->NotifyObservers(params, "profiler-started", nullptr);
}
static void
NotifyObservers(const char* aTopic)
{
if (!CanNotifyObservers()) {
return;
}
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (!os) {
return;
}
os->NotifyObservers(nullptr, aTopic, nullptr);
}
static void
@ -2174,7 +2172,6 @@ profiler_shutdown()
// We do these operations with gPSMutex unlocked. The comments in
// profiler_stop() explain why.
if (samplerThread) {
ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
delete samplerThread;
}
@ -2185,6 +2182,7 @@ profiler_get_profile(double aSinceTime)
{
LOG("profiler_get_profile");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
SpliceableChunkedJSONWriter b;
@ -2208,6 +2206,7 @@ void
profiler_get_start_params(int* aEntries, double* aInterval, uint32_t* aFeatures,
mozilla::Vector<const char*>* aFilters)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
if (NS_WARN_IF(!aEntries) || NS_WARN_IF(!aInterval) ||
@ -2283,6 +2282,7 @@ profiler_save_profile_to_file(const char* aFilename)
uint32_t
profiler_get_available_features()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
uint32_t features = 0;
@ -2354,6 +2354,7 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
}
}
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists() && !ActivePS::Exists(aLock));
// Fall back to the default values if the passed-in values are unreasonable.
@ -2410,6 +2411,7 @@ profiler_start(int aEntries, double aInterval, uint32_t aFeatures,
{
LOG("profiler_start");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
SamplerThread* samplerThread = nullptr;
{
@ -2432,7 +2434,6 @@ profiler_start(int aEntries, double aInterval, uint32_t aFeatures,
// We do these operations with gPSMutex unlocked. The comments in
// profiler_stop() explain why.
if (samplerThread) {
ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
delete samplerThread;
}
@ -2445,6 +2446,7 @@ locked_profiler_stop(PSLockRef aLock)
{
LOG("locked_profiler_stop");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
#ifdef MOZ_TASK_TRACER
@ -2492,6 +2494,7 @@ profiler_stop()
{
LOG("profiler_stop");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
SamplerThread* samplerThread;
@ -2508,7 +2511,6 @@ profiler_stop()
// We notify observers with gPSMutex unlocked. Otherwise we might get a
// deadlock, if code run by the observer calls a profiler function that locks
// gPSMutex. (This has been seen in practise in bug 1346356.)
ProfilerParent::ProfilerStopped();
NotifyObservers("profiler-stopped");
// We delete with gPSMutex unlocked. Otherwise we would get a deadlock: we
@ -2526,6 +2528,7 @@ profiler_stop()
bool
profiler_is_paused()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
@ -2542,6 +2545,7 @@ profiler_pause()
{
LOG("profiler_pause");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
{
@ -2555,7 +2559,6 @@ profiler_pause()
}
// gPSMutex must be unlocked when we notify, to avoid potential deadlocks.
ProfilerParent::ProfilerPaused();
NotifyObservers("profiler-paused");
}
@ -2564,6 +2567,7 @@ profiler_resume()
{
LOG("profiler_resume");
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
{
@ -2577,7 +2581,6 @@ profiler_resume()
}
// gPSMutex must be unlocked when we notify, to avoid potential deadlocks.
ProfilerParent::ProfilerResumed();
NotifyObservers("profiler-resumed");
}

View File

@ -1,107 +0,0 @@
/* -*- 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 {
ChildProfilerController::ChildProfilerController()
{
MOZ_COUNT_CTOR(ChildProfilerController);
MOZ_RELEASE_ASSERT(NS_IsMainThread());
}
Endpoint<PProfilerParent>
ChildProfilerController::SetUpEndpoints(base::ProcessId aOtherPid)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
Endpoint<PProfilerParent> parent;
Endpoint<PProfilerChild> child;
nsresult rv = PProfiler::CreateEndpoints(aOtherPid,
base::GetCurrentProcId(),
&parent, &child);
if (NS_FAILED(rv)) {
MOZ_CRASH("Failed to create top level actor for PProfiler!");
}
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(child)),
NS_DISPATCH_NORMAL);
}
return parent;
}
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

View File

@ -0,0 +1,157 @@
/* 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

View File

@ -1,32 +0,0 @@
/* -*- 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();
parent:
async Profile(nsCString aProfile);
};
} // namespace mozilla

View File

@ -60,6 +60,12 @@ ProfileGatherer::GatheredOOPProfile(const nsACString& aProfile)
}
}
void
ProfileGatherer::WillGatherOOPProfile()
{
mPendingProfiles++;
}
RefPtr<ProfileGatherer::ProfileGatherPromise>
ProfileGatherer::Start(double aSinceTime)
{
@ -72,14 +78,20 @@ ProfileGatherer::Start(double aSinceTime)
}
mGathering = true;
mPendingProfiles = 0;
// Request profiles from the other processes. This will trigger
// asynchronous calls to ProfileGatherer::GatheredOOPProfile as the
// profiles arrive.
// Send a notification to request profiles from other processes. The
// observers of this notification will call WillGatherOOPProfile() which
// increments mPendingProfiles.
// 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.
mPendingProfiles = ProfilerParent::GatherProfiles();
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");
}
mWriter.emplace();

View File

@ -20,6 +20,7 @@ public:
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);

View File

@ -1,104 +0,0 @@
/* -*- 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()
{
if (!mDestroyed) {
Unused << SendProfile(CollectProfileOrEmptyString());
}
return IPC_OK();
}
void
ProfilerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
{
mDestroyed = true;
}
void
ProfilerChild::Destroy()
{
if (!mDestroyed) {
Close();
}
}
nsCString
ProfilerChild::GrabShutdownProfile()
{
return CollectProfileOrEmptyString();
}
} // namespace mozilla

View File

@ -8,7 +8,6 @@
#ifdef MOZ_GECKO_PROFILER
#include "mozilla/IOInterposer.h"
#include "nsISupportsImpl.h"
namespace mozilla {
@ -18,13 +17,8 @@ namespace mozilla {
*/
class ProfilerIOInterposeObserver final : public IOInterposeObserver
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProfilerIOInterposeObserver)
public:
virtual void Observe(Observation& aObservation);
protected:
virtual ~ProfilerIOInterposeObserver() {}
};
} // namespace mozilla

View File

@ -1,250 +0,0 @@
/* -*- 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, ShutdownPhase::Shutdown);
}
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()
{
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 */ bool
ProfilerParent::Alloc(Endpoint<PProfilerParent>&& aEndpoint)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
Endpoint<PProfilerParent> endpoint = Move(aEndpoint);
RefPtr<ProfilerParent> actor = new ProfilerParent();
if (!endpoint.Bind(actor)) {
return false;
}
// mSelfRef will be cleared in DeallocPProfilerParent.
actor->mSelfRef = actor;
actor->Init();
return true;
}
ProfilerParent::ProfilerParent()
: mPendingRequestedProfilesCount(0)
, 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 */ uint32_t
ProfilerParent::GatherProfiles()
{
if (!NS_IsMainThread()) {
return 0;
}
uint32_t count = 0;
ProfilerParentTracker::Enumerate([&](ProfilerParent* profilerParent) {
profilerParent->mPendingRequestedProfilesCount++;
Unused << profilerParent->SendGatherProfile();
count++;
});
return count;
}
/* 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();
});
}
mozilla::ipc::IPCResult
ProfilerParent::RecvProfile(const nsCString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mPendingRequestedProfilesCount > 0);
mPendingRequestedProfilesCount--;
nsProfiler::GetOrCreate()->GatheredOOPProfile(aProfile);
return IPC_OK();
}
void
ProfilerParent::ActorDestroy(ActorDestroyReason aActorDestroyReason)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
RefPtr<nsProfiler> profiler = nsProfiler::GetOrCreate();
while (mPendingRequestedProfilesCount > 0) {
profiler->GatheredOOPProfile(NS_LITERAL_CSTRING(""));
mPendingRequestedProfilesCount--;
}
mDestroyed = true;
}
void
ProfilerParent::DeallocPProfilerParent()
{
mSelfRef = nullptr;
}
} // namespace mozilla

View File

@ -10,7 +10,6 @@
class nsCString;
%}
[ref] native nsCString(const nsCString);
[ref] native StringArrayRef(const nsTArray<nsCString>);
/**
@ -111,7 +110,4 @@ interface nsIProfiler : nsISupports
* Dump the collected profile to a file.
*/
void dumpProfileToFile(in string aFilename);
[noscript, notxpcom, nostdcall]
void receiveShutdownProfile(in nsCString aProfile);
};

View File

@ -480,6 +480,29 @@ nsProfiler::GetStartParams(nsIProfilerStartParams** aRetVal)
return NS_OK;
}
NS_IMETHODIMP
nsProfiler::GetBufferInfo(uint32_t* aCurrentPosition, uint32_t* aTotalSize,
uint32_t* aGeneration)
{
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)
{
@ -493,7 +516,7 @@ nsProfiler::GatheredOOPProfile(const nsACString& aProfile)
}
void
nsProfiler::ReceiveShutdownProfile(const nsCString& aProfile)
nsProfiler::OOPExitProfile(const nsACString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
@ -504,13 +527,3 @@ nsProfiler::ReceiveShutdownProfile(const nsCString& aProfile)
mGatherer->OOPExitProfile(aProfile);
}
NS_IMETHODIMP
nsProfiler::GetBufferInfo(uint32_t* aCurrentPosition, uint32_t* aTotalSize,
uint32_t* aGeneration)
{
MOZ_ASSERT(aCurrentPosition);
MOZ_ASSERT(aTotalSize);
MOZ_ASSERT(aGeneration);
profiler_get_buffer_info(aCurrentPosition, aTotalSize, aGeneration);
return NS_OK;
}

View File

@ -33,7 +33,9 @@ public:
return static_cast<nsProfiler*>(iprofiler.get());
}
void WillGatherOOPProfile();
void GatheredOOPProfile(const nsACString& aProfile);
void OOPExitProfile(const nsACString& aProfile);
private:
~nsProfiler();

View File

@ -13,7 +13,7 @@
class nsProfilerStartParams : public nsIProfilerStartParams
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_ISUPPORTS
NS_DECL_NSIPROFILERSTARTPARAMS
nsProfilerStartParams(uint32_t aEntries,

View File

@ -10,7 +10,7 @@ if CONFIG['MOZ_GECKO_PROFILER']:
'gecko/nsIProfiler.idl',
]
EXPORTS += [
'public/ChildProfilerController.h',
'public/CrossProcessProfilerController.h',
'public/ProfilerMarkerPayload.h',
'public/PseudoStack.h',
'public/shared-libraries.h',
@ -24,7 +24,7 @@ if CONFIG['MOZ_GECKO_PROFILER']:
'core/ProfilerMarkerPayload.cpp',
'core/StackTop.cpp',
'core/ThreadInfo.cpp',
'gecko/ChildProfilerController.cpp',
'gecko/CrossProcessProfilerController.cpp',
'gecko/nsProfilerFactory.cpp',
'gecko/nsProfilerStartParams.cpp',
'gecko/ProfileGatherer.cpp',
@ -109,7 +109,6 @@ if CONFIG['MOZ_GECKO_PROFILER']:
FINAL_LIBRARY = 'xul'
IPDL_SOURCES += [
'gecko/PProfiler.ipdl',
'gecko/ProfilerTypes.ipdlh',
]
@ -118,13 +117,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
EXPORTS += [
'public/GeckoProfiler.h',
'public/GeckoProfilerReporter.h',
'public/ProfilerChild.h',
'public/ProfilerParent.h',
]
UNIFIED_SOURCES += [
'gecko/ProfilerChild.cpp',
'gecko/ProfilerParent.cpp',
'public/ProfilerControllingProcess.h',
]
if CONFIG['MOZ_TASK_TRACER']:

View File

@ -1,48 +0,0 @@
/* -*- 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)
ChildProfilerController();
mozilla::ipc::Endpoint<PProfilerParent> SetUpEndpoints(base::ProcessId aOtherPid);
MOZ_MUST_USE nsCString GrabShutdownProfileAndShutdown();
void Shutdown();
private:
virtual ~ChildProfilerController();
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

View File

@ -0,0 +1,42 @@
/* 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

View File

@ -1,52 +0,0 @@
/* -*- 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 will be 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() override;
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
nsCOMPtr<nsIThread> mThread;
bool mDestroyed;
};
} // namespace mozilla
#endif // ProfilerChild_h

View File

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

View File

@ -1,74 +0,0 @@
/* -*- 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 other process.
// 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_THREADSAFE_REFCOUNTING(ProfilerParent)
static bool Alloc(mozilla::ipc::Endpoint<PProfilerParent>&& aEndpoint);
// 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 uint32_t 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;
mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile) override;
RefPtr<ProfilerParent> mSelfRef;
uint32_t mPendingRequestedProfilesCount;
bool mDestroyed;
};
} // namespace mozilla
#endif // ProfilerParent_h