Bug 1287392 - Part 4: Expose a file writer API for GeckoProfiler. r=mstange

This commit is contained in:
Thinker K.F. Li 2016-11-19 02:48:00 +08:00
parent b8f15cf0fc
commit 6a49d378ba
7 changed files with 98 additions and 2 deletions

View File

@ -444,6 +444,15 @@ void GeckoSampler::ToJSObjectAsync(double aSinceTime,
mGatherer->Start(aSinceTime, aPromise);
}
void GeckoSampler::ToFileAsync(const nsACString& aFileName, double aSinceTime)
{
if (NS_WARN_IF(!mGatherer)) {
return;
}
mGatherer->Start(aSinceTime, aFileName);
}
struct SubprocessClosure {
explicit SubprocessClosure(SpliceableJSONWriter* aWriter)
: mWriter(aWriter)

View File

@ -112,6 +112,7 @@ class GeckoSampler: public Sampler {
#endif
mozilla::UniquePtr<char[]> ToJSON(double aSinceTime = 0);
virtual void ToJSObjectAsync(double aSinceTime = 0, mozilla::dom::Promise* aPromise = 0);
void ToFileAsync(const nsACString& aFileName, double aSinceTime = 0);
void StreamMetaJSCustomObject(SpliceableJSONWriter& aWriter);
void StreamTaskTracer(SpliceableJSONWriter& aWriter);
void FlushOnJSShutdown(JSContext* aContext);

View File

@ -624,6 +624,20 @@ void mozilla_sampler_get_profile_data_async(double aSinceTime,
t->ToJSObjectAsync(aSinceTime, aPromise);
}
void mozilla_sampler_save_profile_to_file_async(double aSinceTime,
const char* aFileName)
{
nsCString filename(aFileName);
NS_DispatchToMainThread(NS_NewRunnableFunction([=] () {
GeckoSampler *t = tlsTicker.get();
if (NS_WARN_IF(!t)) {
return;
}
t->ToFileAsync(filename, aSinceTime);
}));
}
void mozilla_sampler_get_profiler_start_params(int* aEntrySize,
double* aInterval,
mozilla::Vector<const char*>* aFilters,

View File

@ -1,11 +1,15 @@
/* 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 "mozilla/ProfileGatherer.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#include "nsIProfileSaveEvent.h"
#include "GeckoSampler.h"
#include "nsLocalFile.h"
#include "nsIFileStreams.h"
using mozilla::dom::AutoJSAPI;
using mozilla::dom::Promise;
@ -42,7 +46,7 @@ ProfileGatherer::GatheredOOPProfile()
return;
}
if (NS_WARN_IF(!mPromise)) {
if (NS_WARN_IF(!mPromise && !mFile)) {
// If we're not holding on to a Promise, then someone is
// calling us erroneously.
return;
@ -96,6 +100,46 @@ ProfileGatherer::Start(double aSinceTime,
}
}
void
ProfileGatherer::Start(double aSinceTime,
nsIFile* aFile)
{
MOZ_ASSERT(NS_IsMainThread());
if (mGathering) {
return;
}
mSinceTime = aSinceTime;
mFile = aFile;
mGathering = true;
mPendingProfiles = 0;
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
DebugOnly<nsresult> rv =
os->AddObserver(this, "profiler-subprocess", false);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddObserver failed");
rv = os->NotifyObservers(this, "profiler-subprocess-gather", nullptr);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NotifyObservers failed");
}
if (!mPendingProfiles) {
Finish();
}
}
void
ProfileGatherer::Start(double aSinceTime,
const nsACString& aFileName)
{
nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
nsresult rv = file->InitWithNativePath(aFileName);
if (NS_FAILED(rv)) {
MOZ_CRASH();
}
Start(aSinceTime, file);
}
void
ProfileGatherer::Finish()
{
@ -109,6 +153,17 @@ ProfileGatherer::Finish()
UniquePtr<char[]> buf = mTicker->ToJSON(mSinceTime);
if (mFile) {
nsCOMPtr<nsIFileOutputStream> of =
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
of->Init(mFile, -1, -1, 0);
uint32_t sz;
of->Write(buf.get(), strlen(buf.get()), &sz);
of->Close();
Reset();
return;
}
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
DebugOnly<nsresult> rv = os->RemoveObserver(this, "profiler-subprocess");
@ -153,6 +208,7 @@ ProfileGatherer::Reset()
{
mSinceTime = 0;
mPromise = nullptr;
mFile = nullptr;
mPendingProfiles = 0;
mGathering = false;
}
@ -165,6 +221,8 @@ ProfileGatherer::Cancel()
if (mPromise) {
mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
}
mPromise = nullptr;
mFile = nullptr;
// Clear out the GeckoSampler reference, since it's being destroyed.
mTicker = nullptr;

View File

@ -39,11 +39,18 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
'gecko/nsProfiler.cpp',
'gecko/nsProfilerFactory.cpp',
'gecko/nsProfilerStartParams.cpp',
'gecko/ProfileGatherer.cpp',
'gecko/ProfilerIOInterposeObserver.cpp',
'gecko/SaveProfileTask.cpp',
'gecko/ThreadResponsiveness.cpp',
]
if CONFIG['OS_TARGET'] == 'Darwin':
SOURCES += [
'gecko/ProfileGatherer.cpp',
]
else:
UNIFIED_SOURCES += [
'gecko/ProfileGatherer.cpp',
]
if CONFIG['OS_TARGET'] in ('Android', 'Linux'):
UNIFIED_SOURCES += [

View File

@ -71,6 +71,9 @@ mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(double aSinceTime);
JSObject *mozilla_sampler_get_profile_data(JSContext* aCx, double aSinceTime);
void mozilla_sampler_get_profile_data_async(double aSinceTime,
mozilla::dom::Promise* aPromise);
MOZ_EXPORT
void mozilla_sampler_save_profile_to_file_async(double aSinceTime,
const char* aFileName);
void mozilla_sampler_get_profiler_start_params(int* aEntrySize,
double* aInterval,
mozilla::Vector<const char*>* aFilters,

View File

@ -6,6 +6,7 @@
#define MOZ_PROFILE_GATHERER_H
#include "mozilla/dom/Promise.h"
#include "nsIFile.h"
class GeckoSampler;
@ -21,6 +22,8 @@ public:
void WillGatherOOPProfile();
void GatheredOOPProfile();
void Start(double aSinceTime, mozilla::dom::Promise* aPromise);
void Start(double aSinceTime, nsIFile* aFile);
void Start(double aSinceTime, const nsACString& aFileName);
void Cancel();
void OOPExitProfile(const nsCString& aProfile);
@ -31,6 +34,7 @@ private:
nsTArray<nsCString> mExitProfiles;
RefPtr<mozilla::dom::Promise> mPromise;
nsCOMPtr<nsIFile> mFile;
GeckoSampler* mTicker;
double mSinceTime;
uint32_t mPendingProfiles;