mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 1193838 - Allow ProfileGatherer to gather profiles from exiting processes. r=BenWa
--HG-- extra : commitid : IhyN838vNVU extra : rebase_source : a91c87e3f9a087cd789bdb678651ab351357092a
This commit is contained in:
parent
9811d5b26c
commit
51d7f5de3d
@ -2965,6 +2965,15 @@ ContentChild::RecvShutdown()
|
||||
|
||||
GetIPCChannel()->SetAbortOnError(false);
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
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.
|
||||
Unused << RecvGatherProfile();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ignore errors here. If this fails, the parent will kill us after a
|
||||
// timeout.
|
||||
Unused << SendFinishShutdown();
|
||||
|
@ -2094,6 +2094,12 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
|
||||
mConsoleService = nullptr;
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
if (mGatherer && !mProfile.IsEmpty()) {
|
||||
mGatherer->OOPExitProfile(mProfile);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (obs) {
|
||||
RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
|
||||
|
||||
|
@ -3185,8 +3185,7 @@ PluginProfilerObserver::Observe(nsISupports *aSubject,
|
||||
} else if (!strcmp(aTopic, "profiler-stopped")) {
|
||||
mPmp->StopProfiler();
|
||||
} else if (!strcmp(aTopic, "profiler-subprocess-gather")) {
|
||||
RefPtr<ProfileGatherer> gatherer = static_cast<ProfileGatherer*>(aSubject);
|
||||
mPmp->GatherAsyncProfile(gatherer);
|
||||
mPmp->GatherAsyncProfile();
|
||||
} else if (!strcmp(aTopic, "profiler-subprocess")) {
|
||||
nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
|
||||
mPmp->GatheredAsyncProfile(pse);
|
||||
|
@ -12,7 +12,16 @@ using mozilla::dom::Promise;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS0(ProfileGatherer)
|
||||
/**
|
||||
* When a subprocess exits before we've gathered profiles, we'll
|
||||
* store profiles for those processes until gathering starts. We'll
|
||||
* only store up to MAX_SUBPROCESS_EXIT_PROFILES. The buffer is
|
||||
* circular, so as soon as we receive another exit profile, we'll
|
||||
* bump the oldest one out of the buffer.
|
||||
*/
|
||||
static const uint32_t MAX_SUBPROCESS_EXIT_PROFILES = 5;
|
||||
|
||||
NS_IMPL_ISUPPORTS(ProfileGatherer, nsIObserver)
|
||||
|
||||
ProfileGatherer::ProfileGatherer(GeckoSampler* aTicker)
|
||||
: mTicker(aTicker)
|
||||
@ -26,6 +35,13 @@ void
|
||||
ProfileGatherer::GatheredOOPProfile()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mGathering) {
|
||||
// If we're not actively gathering, then we don't actually
|
||||
// care that we gathered a profile here. This can happen for
|
||||
// processes that exit while profiling.
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mPromise)) {
|
||||
// If we're not holding on to a Promise, then someone is
|
||||
// calling us erroneously.
|
||||
@ -68,7 +84,9 @@ ProfileGatherer::Start(double aSinceTime,
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
nsresult rv = os->NotifyObservers(this, "profiler-subprocess-gather", nullptr);
|
||||
nsresult rv = os->AddObserver(this, "profiler-subprocess", false);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
rv = os->NotifyObservers(this, "profiler-subprocess-gather", nullptr);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
@ -90,6 +108,12 @@ ProfileGatherer::Finish()
|
||||
|
||||
UniquePtr<char[]> buf = mTicker->ToJSON(mSinceTime);
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
nsresult rv = os->RemoveObserver(this, "profiler-subprocess");
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mPromise->GlobalJSObject()))) {
|
||||
// We're really hosed if we can't get a JS context for some reason.
|
||||
@ -145,4 +169,38 @@ ProfileGatherer::Cancel()
|
||||
mTicker = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ProfileGatherer::OOPExitProfile(const nsCString& aProfile)
|
||||
{
|
||||
if (mExitProfiles.Length() >= MAX_SUBPROCESS_EXIT_PROFILES) {
|
||||
mExitProfiles.RemoveElementAt(0);
|
||||
}
|
||||
mExitProfiles.AppendElement(aProfile);
|
||||
|
||||
// If a process exited while gathering, we need to make
|
||||
// sure we decrement the counter.
|
||||
if (mGathering) {
|
||||
GatheredOOPProfile();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ProfileGatherer::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t *someData)
|
||||
{
|
||||
if (!strcmp(aTopic, "profiler-subprocess")) {
|
||||
nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
|
||||
if (pse) {
|
||||
for (size_t i = 0; i < mExitProfiles.Length(); ++i) {
|
||||
if (!mExitProfiles[i].IsEmpty()) {
|
||||
pse->AddSubProfile(mExitProfiles[i].get());
|
||||
}
|
||||
}
|
||||
mExitProfiles.Clear();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -11,22 +11,25 @@ class GeckoSampler;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ProfileGatherer final : public nsISupports
|
||||
class ProfileGatherer final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
explicit ProfileGatherer(GeckoSampler* aTicker);
|
||||
void WillGatherOOPProfile();
|
||||
void GatheredOOPProfile();
|
||||
void Start(double aSinceTime, mozilla::dom::Promise* aPromise);
|
||||
void Cancel();
|
||||
void OOPExitProfile(const nsCString& aProfile);
|
||||
|
||||
private:
|
||||
~ProfileGatherer() {};
|
||||
void Finish();
|
||||
void Reset();
|
||||
|
||||
nsTArray<nsCString> mExitProfiles;
|
||||
RefPtr<mozilla::dom::Promise> mPromise;
|
||||
GeckoSampler* mTicker;
|
||||
double mSinceTime;
|
||||
|
Loading…
Reference in New Issue
Block a user