зеркало из https://github.com/mozilla/gecko-dev.git
253 строки
6.2 KiB
C++
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
|