gecko-dev/tools/profiler/gecko/ProfilerParent.cpp

253 строки
6.2 KiB
C++

/* -*- 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);
// We propagated the profiler state from the parent process to the child
// process through MOZ_PROFILER_STARTUP* environment variables.
// However, the profiler state might have changed in this process since then,
// and now that an active communication channel has been established with the
// child process, it's a good time to sync up the two profilers again.
int entries = 0;
double interval = 0;
mozilla::Vector<const char*> filters;
uint32_t features;
profiler_get_start_params(&entries, &interval, &features, &filters);
if (entries != 0) {
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 << SendEnsureStarted(ipcParams);
} else {
Unused << SendStop();
}
}
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