Bug 1008435 - Let the Gecko Profiler work with child processes. r=BenWa,smaug.

We now allow profiling the content process for e10s, and plugin processes.

--HG--
extra : rebase_source : 1f2e35d4d55b33b56160132893dbf7d4787925fa
extra : amend_source : d03465d4318f8e50c7624ad0eeb681b30c068b11
This commit is contained in:
Mike Conley 2014-11-18 12:50:25 -05:00
parent cae77eaed3
commit df420b6488
14 changed files with 307 additions and 14 deletions

View File

@ -16,6 +16,7 @@
#include "BlobChild.h"
#include "CrashReporterChild.h"
#include "GeckoProfiler.h"
#include "TabChild.h"
#include "mozilla/Attributes.h"
@ -2385,6 +2386,48 @@ ContentChild::RecvOnAppThemeChanged()
return true;
}
bool
ContentChild::RecvStartProfiler(const uint32_t& aEntries,
const double& aInterval,
const nsTArray<nsCString>& aFeatures,
const nsTArray<nsCString>& aThreadNameFilters)
{
nsTArray<const char*> featureArray;
for (size_t i = 0; i < aFeatures.Length(); ++i) {
featureArray.AppendElement(aFeatures[i].get());
}
nsTArray<const char*> threadNameFilterArray;
for (size_t i = 0; i < aThreadNameFilters.Length(); ++i) {
threadNameFilterArray.AppendElement(aThreadNameFilters[i].get());
}
profiler_start(aEntries, aInterval, featureArray.Elements(), featureArray.Length(),
threadNameFilterArray.Elements(), threadNameFilterArray.Length());
return true;
}
bool
ContentChild::RecvStopProfiler()
{
profiler_stop();
return true;
}
bool
ContentChild::AnswerGetProfile(nsCString* aProfile)
{
char* profile = profiler_get_profile();
if (profile) {
*aProfile = nsCString(profile, strlen(profile));
free(profile);
} else {
*aProfile = EmptyCString();
}
return true;
}
PBrowserOrId
ContentChild::GetBrowserOrId(TabChild* aTabChild)
{

View File

@ -358,6 +358,13 @@ public:
virtual bool RecvOnAppThemeChanged() MOZ_OVERRIDE;
virtual bool RecvStartProfiler(const uint32_t& aEntries,
const double& aInterval,
const nsTArray<nsCString>& aFeatures,
const nsTArray<nsCString>& aThreadNameFilters) MOZ_OVERRIDE;
virtual bool RecvStopProfiler() MOZ_OVERRIDE;
virtual bool AnswerGetProfile(nsCString* aProfile) MOZ_OVERRIDE;
#ifdef ANDROID
gfxIntSize GetScreenSize() { return mScreenSize; }
#endif

View File

@ -201,6 +201,11 @@ using namespace mozilla::system;
#include "nsIBrowserSearchService.h"
#endif
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "nsIProfiler.h"
#include "nsIProfileSaveEvent.h"
#endif
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static const char* sClipboardTextFlavors[] = { kUnicodeMime };
@ -590,6 +595,11 @@ static const char* sObserverTopics[] = {
"a11y-init-or-shutdown",
#endif
"app-theme-changed",
#ifdef MOZ_ENABLE_PROFILER_SPS
"profiler-started",
"profiler-stopped",
"profiler-subprocess",
#endif
};
/* static */ already_AddRefed<ContentParent>
@ -2795,6 +2805,31 @@ ContentParent::Observe(nsISupports* aSubject,
else if (!strcmp(aTopic, "app-theme-changed")) {
unused << SendOnAppThemeChanged();
}
#ifdef MOZ_ENABLE_PROFILER_SPS
else if (!strcmp(aTopic, "profiler-started")) {
nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject));
uint32_t entries;
double interval;
params->GetEntries(&entries);
params->GetInterval(&interval);
const nsTArray<nsCString>& features = params->GetFeatures();
const nsTArray<nsCString>& threadFilterNames = params->GetThreadFilterNames();
unused << SendStartProfiler(entries, interval, features, threadFilterNames);
}
else if (!strcmp(aTopic, "profiler-stopped")) {
unused << SendStopProfiler();
}
else if (!strcmp(aTopic, "profiler-subprocess")) {
nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
if (pse) {
nsCString result;
unused << CallGetProfile(&result);
if (!result.IsEmpty()) {
pse->AddSubProfile(result.get());
}
}
}
#endif
return NS_OK;
}

View File

@ -509,6 +509,15 @@ child:
*/
OnAppThemeChanged();
/**
* Control the Gecko Profiler in the child process.
*/
async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures,
nsCString[] aThreadNameFilters);
async StopProfiler();
intr GetProfile()
returns (nsCString aProfile);
parent:
/**
* Tell the parent process a new accessible document has been created.

View File

@ -81,7 +81,13 @@ child:
intr PCrashReporter()
returns (NativeThreadId tid, uint32_t processType);
intr GeckoGetProfile()
/**
* Control the Gecko Profiler in the plugin process.
*/
async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures,
nsCString[] aThreadNameFilters);
async StopProfiler();
intr GetProfile()
returns (nsCString aProfile);
async SettingChanged(PluginSettings settings);

View File

@ -2370,7 +2370,37 @@ PluginModuleChild::ProcessNativeEvents() {
#endif
bool
PluginModuleChild::AnswerGeckoGetProfile(nsCString* aProfile) {
PluginModuleChild::RecvStartProfiler(const uint32_t& aEntries,
const double& aInterval,
const nsTArray<nsCString>& aFeatures,
const nsTArray<nsCString>& aThreadNameFilters)
{
nsTArray<const char*> featureArray;
for (size_t i = 0; i < aFeatures.Length(); ++i) {
featureArray.AppendElement(aFeatures[i].get());
}
nsTArray<const char*> threadNameFilterArray;
for (size_t i = 0; i < aThreadNameFilters.Length(); ++i) {
threadNameFilterArray.AppendElement(aThreadNameFilters[i].get());
}
profiler_start(aEntries, aInterval, featureArray.Elements(), featureArray.Length(),
threadNameFilterArray.Elements(), threadNameFilterArray.Length());
return true;
}
bool
PluginModuleChild::RecvStopProfiler()
{
profiler_stop();
return true;
}
bool
PluginModuleChild::AnswerGetProfile(nsCString* aProfile)
{
char* profile = profiler_get_profile();
if (profile != nullptr) {
*aProfile = nsCString(profile, strlen(profile));
@ -2380,4 +2410,3 @@ PluginModuleChild::AnswerGeckoGetProfile(nsCString* aProfile) {
}
return true;
}

View File

@ -142,8 +142,12 @@ protected:
virtual bool
RecvProcessNativeEventsInInterruptCall() MOZ_OVERRIDE;
virtual bool
AnswerGeckoGetProfile(nsCString* aProfile) MOZ_OVERRIDE;
virtual bool RecvStartProfiler(const uint32_t& aEntries,
const double& aInterval,
const nsTArray<nsCString>& aFeatures,
const nsTArray<nsCString>& aThreadNameFilters) MOZ_OVERRIDE;
virtual bool RecvStopProfiler() MOZ_OVERRIDE;
virtual bool AnswerGetProfile(nsCString* aProfile) MOZ_OVERRIDE;
public:
PluginModuleChild(bool aIsChrome);

View File

@ -40,6 +40,7 @@
#endif
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "nsIProfiler.h"
#include "nsIProfileSaveEvent.h"
#endif
@ -1968,13 +1969,26 @@ PluginProfilerObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
if (pse) {
nsCString result;
bool success = mPmp->CallGeckoGetProfile(&result);
if (success && !result.IsEmpty()) {
pse->AddSubProfile(result.get());
}
if (!strcmp(aTopic, "profiler-started")) {
nsCOMPtr<nsIProfilerStartParams> params(do_QueryInterface(aSubject));
uint32_t entries;
double interval;
params->GetEntries(&entries);
params->GetInterval(&interval);
const nsTArray<nsCString>& features = params->GetFeatures();
const nsTArray<nsCString>& threadFilterNames = params->GetThreadFilterNames();
unused << mPmp->SendStartProfiler(entries, interval, features, threadFilterNames);
} else if (!strcmp(aTopic, "profiler-stopped")) {
unused << mPmp->SendStopProfiler();
} else if (!strcmp(aTopic, "profiler-subprocess")) {
nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
if (pse) {
nsCString result;
bool success = mPmp->CallGetProfile(&result);
if (success && !result.IsEmpty()) {
pse->AddSubProfile(result.get());
}
}
}
return NS_OK;
}
@ -1985,6 +1999,8 @@ PluginModuleChromeParent::InitPluginProfiling()
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (observerService) {
mProfilerObserver = new PluginProfilerObserver(this);
observerService->AddObserver(mProfilerObserver, "profiler-started", false);
observerService->AddObserver(mProfilerObserver, "profiler-stopped", false);
observerService->AddObserver(mProfilerObserver, "profiler-subprocess", false);
}
}
@ -1994,6 +2010,8 @@ PluginModuleChromeParent::ShutdownPluginProfiling()
{
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(mProfilerObserver, "profiler-started");
observerService->RemoveObserver(mProfilerObserver, "profiler-stopped");
observerService->RemoveObserver(mProfilerObserver, "profiler-subprocess");
}
}

View File

@ -323,6 +323,10 @@ void ThreadProfile::StreamJSObject(JSStreamWriter& b)
if (XRE_GetProcessType() == GeckoProcessType_Plugin) {
// TODO Add the proper plugin name
b.NameValue("name", "Plugin");
} else if (XRE_GetProcessType() == GeckoProcessType_Content) {
// This isn't going to really help once we have multiple content
// processes, but it'll do for now.
b.NameValue("name", "Content");
} else {
b.NameValue("name", Name());
}

View File

@ -28,6 +28,7 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
'JSStreamWriter.cpp',
'nsProfiler.cpp',
'nsProfilerFactory.cpp',
'nsProfilerStartParams.cpp',
'platform.cpp',
'ProfileEntry.cpp',
'ProfilerBacktrace.cpp',

View File

@ -5,6 +5,13 @@
#include "nsISupports.idl"
%{C++
template<class T> class nsTArray;
class nsCString;
%}
[ref] native StringArrayRef(const nsTArray<nsCString>);
[scriptable, uuid(f7f3709c-04a9-45c6-8e34-40f762654a78)]
interface nsIProfiler : nsISupports
{
@ -37,3 +44,17 @@ interface nsIProfiler : nsISupports
AString getSharedLibraryInformation();
};
/**
* Start-up parameters for subprocesses are passed through nsIObserverService,
* which, unfortunately, means we need to implement nsISupports in order to
* go through it.
*/
[uuid(0a175ba7-8fcf-4ce9-9c4b-ccc6272f4425)]
interface nsIProfilerStartParams : nsISupports
{
attribute uint32_t entries;
attribute double interval;
[noscript, notxpcom, nostdcall] StringArrayRef getFeatures();
[noscript, notxpcom, nostdcall] StringArrayRef getThreadFilterNames();
};

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsProfilerStartParams.h"
NS_IMPL_ISUPPORTS(nsProfilerStartParams, nsIProfilerStartParams)
nsProfilerStartParams::nsProfilerStartParams(uint32_t aEntries,
double aInterval,
const nsTArray<nsCString>& aFeatures,
const nsTArray<nsCString>& aThreadFilterNames) :
mEntries(aEntries),
mInterval(aInterval),
mFeatures(aFeatures),
mThreadFilterNames(aThreadFilterNames)
{
}
nsProfilerStartParams::~nsProfilerStartParams()
{
}
NS_IMETHODIMP
nsProfilerStartParams::GetEntries(uint32_t* aEntries)
{
NS_ENSURE_ARG_POINTER(aEntries);
*aEntries = mEntries;
return NS_OK;
}
NS_IMETHODIMP
nsProfilerStartParams::SetEntries(uint32_t aEntries)
{
NS_ENSURE_ARG(aEntries);
mEntries = aEntries;
return NS_OK;
}
NS_IMETHODIMP
nsProfilerStartParams::GetInterval(double* aInterval)
{
NS_ENSURE_ARG_POINTER(aInterval);
*aInterval = mInterval;
return NS_OK;
}
NS_IMETHODIMP
nsProfilerStartParams::SetInterval(double aInterval)
{
NS_ENSURE_ARG(aInterval);
mInterval = aInterval;
return NS_OK;
}
const nsTArray<nsCString>&
nsProfilerStartParams::GetFeatures()
{
return mFeatures;
}
const nsTArray<nsCString>&
nsProfilerStartParams::GetThreadFilterNames()
{
return mThreadFilterNames;
}

View File

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 _NSPROFILERSTARTPARAMS_H_
#define _NSPROFILERSTARTPARAMS_H_
#include "nsIProfiler.h"
#include "nsString.h"
#include "nsTArray.h"
class nsProfilerStartParams : public nsIProfilerStartParams
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROFILERSTARTPARAMS
nsProfilerStartParams(uint32_t aEntries,
double aInterval,
const nsTArray<nsCString>& aFeatures,
const nsTArray<nsCString>& aThreadFilterNames);
private:
virtual ~nsProfilerStartParams();
uint32_t mEntries;
double mInterval;
nsTArray<nsCString> mFeatures;
nsTArray<nsCString> mThreadFilterNames;
};
#endif

View File

@ -19,6 +19,7 @@
#include "nsIObserverService.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsProfilerStartParams.h"
#include "mozilla/Services.h"
#include "nsThreadUtils.h"
#include "ProfilerMarkers.h"
@ -780,8 +781,24 @@ void mozilla_sampler_start(int aProfileEntries, double aInterval,
if (Sampler::CanNotifyObservers()) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os)
os->NotifyObservers(nullptr, "profiler-started", nullptr);
if (os) {
nsTArray<nsCString> featuresArray;
nsTArray<nsCString> threadNameFiltersArray;
for (size_t i = 0; i < aFeatureCount; ++i) {
featuresArray.AppendElement(aFeatures[i]);
}
for (size_t i = 0; i < aFilterCount; ++i) {
threadNameFiltersArray.AppendElement(aThreadNameFilters[i]);
}
nsCOMPtr<nsIProfilerStartParams> params =
new nsProfilerStartParams(aProfileEntries, aInterval, featuresArray,
threadNameFiltersArray);
os->NotifyObservers(params, "profiler-started", nullptr);
}
}
LOG("END mozilla_sampler_start");