Bug 1145824 - In nsProfiler, allow GetProfile and getProfileData to filter by a start time. (r=mstange)

This commit is contained in:
Shu-yu Guo 2015-04-24 17:30:58 -07:00
Родитель a145bf447c
Коммит 0fafc89798
12 изменённых файлов: 101 добавлений и 56 удалений

Просмотреть файл

@ -158,10 +158,13 @@ static inline void profiler_responsiveness(const mozilla::TimeStamp& aTime) {}
static inline void profiler_set_frame_number(int frameNumber) {}
// Get the profile encoded as a JSON string.
static inline char* profiler_get_profile() { return nullptr; }
static inline char* profiler_get_profile(float aSinceTime = 0) { return nullptr; }
// Get the profile encoded as a JSON object.
static inline JSObject* profiler_get_profile_jsobject(JSContext* aCx) { return nullptr; }
static inline JSObject* profiler_get_profile_jsobject(JSContext* aCx,
float aSinceTime = 0) {
return nullptr;
}
// Get the profile and write it into a file
static inline void profiler_save_profile_to_file(char* aFilename) { }

Просмотреть файл

@ -53,9 +53,9 @@ const double* mozilla_sampler_get_responsiveness();
void mozilla_sampler_save();
char* mozilla_sampler_get_profile();
char* mozilla_sampler_get_profile(float aSinceTime);
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx);
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime);
// Make this function easily callable from a debugger in a build without
// debugging information (work around http://llvm.org/bugs/show_bug.cgi?id=22211)

Просмотреть файл

@ -144,15 +144,15 @@ void profiler_set_frame_number(int frameNumber)
}
static inline
char* profiler_get_profile()
char* profiler_get_profile(float aSinceTime = 0)
{
return mozilla_sampler_get_profile();
return mozilla_sampler_get_profile(aSinceTime);
}
static inline
JSObject* profiler_get_profile_jsobject(JSContext* aCx)
JSObject* profiler_get_profile_jsobject(JSContext* aCx, float aSinceTime = 0)
{
return mozilla_sampler_get_profile_data(aCx);
return mozilla_sampler_get_profile_data(aCx, aSinceTime);
}
static inline

Просмотреть файл

@ -393,18 +393,30 @@ void UniqueJITOptimizations::stream(JSStreamWriter& b, JSRuntime* rt)
}
}
void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JSRuntime* rt,
void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId,
float aSinceTime, JSRuntime* rt,
UniqueJITOptimizations& aUniqueOpts)
{
bool sample = false;
int readPos = mReadPos;
int currentThreadID = -1;
float currentTime = 0;
bool hasCurrentTime = false;
while (readPos != mWritePos) {
ProfileEntry entry = mEntries[readPos];
if (entry.mTagName == 'T') {
currentThreadID = entry.mTagInt;
hasCurrentTime = false;
int readAheadPos = (readPos + 1) % mEntrySize;
if (readAheadPos != mWritePos) {
ProfileEntry readAheadEntry = mEntries[readAheadPos];
if (readAheadEntry.mTagName == 't') {
currentTime = readAheadEntry.mTagFloat;
hasCurrentTime = true;
}
}
}
if (currentThreadID == aThreadId) {
if (currentThreadID == aThreadId && (!hasCurrentTime || currentTime >= aSinceTime)) {
switch (entry.mTagName) {
case 'r':
{
@ -443,7 +455,13 @@ void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JS
break;
case 't':
{
if (sample) {
// FIXMEshu: this case is only needed because filtering by
// aSinceTime is broken if the unwinder thread is used, due to
// its placement of 't' tags.
//
// UnwinderTick is slated for removal in bug 1141712. Remove
// this case once it lands.
if (sample && (currentTime != entry.mTagFloat)) {
b.NameValue("time", entry.mTagFloat);
}
}
@ -459,6 +477,10 @@ void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JS
sample = true;
if (hasCurrentTime) {
b.NameValue("time", currentTime);
}
// Seek forward through the entire sample, looking for frames
// this is an easier approach to reason about than adding more
// control variables and cases to the loop that goes through the buffer once
@ -535,7 +557,7 @@ void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JS
}
}
void ProfileBuffer::StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId)
void ProfileBuffer::StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId, float aSinceTime)
{
int readPos = mReadPos;
int currentThreadID = -1;
@ -544,7 +566,10 @@ void ProfileBuffer::StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId)
if (entry.mTagName == 'T') {
currentThreadID = entry.mTagInt;
} else if (currentThreadID == aThreadId && entry.mTagName == 'm') {
entry.getMarker()->StreamJSObject(b);
const ProfilerMarker* marker = entry.getMarker();
if (marker->GetTime() >= aSinceTime) {
marker->StreamJSObject(b);
}
}
readPos = (readPos + 1) % mEntrySize;
}
@ -650,13 +675,13 @@ void ThreadProfile::IterateTags(IterateTagsCallback aCallback)
mBuffer->IterateTagsForThread(aCallback, mThreadId);
}
void ThreadProfile::ToStreamAsJSON(std::ostream& stream)
void ThreadProfile::ToStreamAsJSON(std::ostream& stream, float aSinceTime)
{
JSStreamWriter b(stream);
StreamJSObject(b);
StreamJSObject(b, aSinceTime);
}
void ThreadProfile::StreamJSObject(JSStreamWriter& b)
void ThreadProfile::StreamJSObject(JSStreamWriter& b, float aSinceTime)
{
b.BeginObject();
// Thread meta data
@ -677,16 +702,22 @@ void ThreadProfile::StreamJSObject(JSStreamWriter& b)
b.Name("samples");
b.BeginArray();
if (!mSavedStreamedSamples.empty()) {
// We would only have saved streamed samples during shutdown
// streaming, which cares about dumping the entire buffer, and thus
// should have passed in 0 for aSinceTime.
MOZ_ASSERT(aSinceTime == 0);
b.SpliceArrayElements(mSavedStreamedSamples.c_str());
mSavedStreamedSamples.clear();
}
mBuffer->StreamSamplesToJSObject(b, mThreadId, mPseudoStack->mRuntime, uniqueOpts);
mBuffer->StreamSamplesToJSObject(b, mThreadId, aSinceTime, mPseudoStack->mRuntime,
uniqueOpts);
b.EndArray();
// Having saved streamed optimizations implies the JS engine has
// shutdown. If the JS engine is gone, we shouldn't have any new JS
// samples, and thus no optimizations.
if (!mSavedStreamedOptimizations.empty()) {
MOZ_ASSERT(aSinceTime == 0);
MOZ_ASSERT(uniqueOpts.empty());
b.Name("optimizations");
b.BeginArray();
@ -703,10 +734,11 @@ void ThreadProfile::StreamJSObject(JSStreamWriter& b)
b.Name("markers");
b.BeginArray();
if (!mSavedStreamedMarkers.empty()) {
MOZ_ASSERT(aSinceTime == 0);
b.SpliceArrayElements(mSavedStreamedMarkers.c_str());
mSavedStreamedMarkers.clear();
}
mBuffer->StreamMarkersToJSObject(b, mThreadId);
mBuffer->StreamMarkersToJSObject(b, mThreadId, aSinceTime);
b.EndArray();
b.EndObject();
}
@ -725,7 +757,7 @@ void ThreadProfile::FlushSamplesAndMarkers()
JSStreamWriter b(ss);
UniqueJITOptimizations uniqueOpts;
b.BeginBareList();
mBuffer->StreamSamplesToJSObject(b, mThreadId, mPseudoStack->mRuntime, uniqueOpts);
mBuffer->StreamSamplesToJSObject(b, mThreadId, 0, mPseudoStack->mRuntime, uniqueOpts);
b.EndBareList();
mSavedStreamedSamples = ss.str();
@ -745,7 +777,7 @@ void ThreadProfile::FlushSamplesAndMarkers()
ss.clear();
b.BeginBareList();
mBuffer->StreamMarkersToJSObject(b, mThreadId);
mBuffer->StreamMarkersToJSObject(b, mThreadId, 0);
b.EndBareList();
mSavedStreamedMarkers = ss.str();
@ -754,7 +786,7 @@ void ThreadProfile::FlushSamplesAndMarkers()
mBuffer->reset();
}
JSObject* ThreadProfile::ToJSObject(JSContext *aCx)
JSObject* ThreadProfile::ToJSObject(JSContext *aCx, float aSinceTime)
{
JS::RootedValue val(aCx);
std::stringstream ss;
@ -762,7 +794,7 @@ JSObject* ThreadProfile::ToJSObject(JSContext *aCx)
// Define a scope to prevent a moving GC during ~JSStreamWriter from
// trashing the return value.
JSStreamWriter b(ss);
StreamJSObject(b);
StreamJSObject(b, aSinceTime);
NS_ConvertUTF8toUTF16 js_string(nsDependentCString(ss.str().c_str()));
JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()),
js_string.Length(), &val);

Просмотреть файл

@ -102,9 +102,9 @@ public:
void addTag(const ProfileEntry& aTag);
void IterateTagsForThread(IterateTagsCallback aCallback, int aThreadId);
void StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JSRuntime* rt,
UniqueJITOptimizations& aUniqueOpts);
void StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId);
void StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, float aSinceTime,
JSRuntime* rt, UniqueJITOptimizations& aUniqueOpts);
void StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId, float aSinceTime);
void DuplicateLastSample(int aThreadId);
void addStoredMarker(ProfilerMarker* aStoredMarker);
@ -155,11 +155,11 @@ public:
void addStoredMarker(ProfilerMarker *aStoredMarker);
void IterateTags(IterateTagsCallback aCallback);
void ToStreamAsJSON(std::ostream& stream);
JSObject *ToJSObject(JSContext *aCx);
void ToStreamAsJSON(std::ostream& stream, float aSinceTime = 0);
JSObject *ToJSObject(JSContext *aCx, float aSinceTime = 0);
PseudoStack* GetPseudoStack();
mozilla::Mutex* GetMutex();
void StreamJSObject(JSStreamWriter& b);
void StreamJSObject(JSStreamWriter& b, float aSinceTime = 0);
/**
* Call this method when the JS entries inside the buffer are about to

Просмотреть файл

@ -30,7 +30,7 @@ ProfilerMarkerPayload::~ProfilerMarkerPayload()
void
ProfilerMarkerPayload::streamCommonProps(const char* aMarkerType,
JSStreamWriter& b)
JSStreamWriter& b)
{
MOZ_ASSERT(aMarkerType);
b.NameValue("type", aMarkerType);

Просмотреть файл

@ -97,7 +97,7 @@ public:
return mGenID + 2 <= aGenID;
}
float GetTime();
float GetTime() const;
private:
char* mMarkerName;

Просмотреть файл

@ -218,13 +218,13 @@ void TableTicker::StreamMetaJSCustomObject(JSStreamWriter& b)
b.EndObject();
}
void TableTicker::ToStreamAsJSON(std::ostream& stream)
void TableTicker::ToStreamAsJSON(std::ostream& stream, float aSinceTime)
{
JSStreamWriter b(stream);
StreamJSObject(b);
StreamJSObject(b, aSinceTime);
}
JSObject* TableTicker::ToJSObject(JSContext *aCx)
JSObject* TableTicker::ToJSObject(JSContext *aCx, float aSinceTime)
{
JS::RootedValue val(aCx);
std::stringstream ss;
@ -232,7 +232,7 @@ JSObject* TableTicker::ToJSObject(JSContext *aCx)
// Define a scope to prevent a moving GC during ~JSStreamWriter from
// trashing the return value.
JSStreamWriter b(ss);
StreamJSObject(b);
StreamJSObject(b, aSinceTime);
NS_ConvertUTF8toUTF16 js_string(nsDependentCString(ss.str().c_str()));
JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()),
js_string.Length(), &val);
@ -316,7 +316,7 @@ void BuildJavaThreadJSObject(JSStreamWriter& b)
}
#endif
void TableTicker::StreamJSObject(JSStreamWriter& b)
void TableTicker::StreamJSObject(JSStreamWriter& b, float aSinceTime)
{
b.BeginObject();
// Put shared library info
@ -351,7 +351,7 @@ void TableTicker::StreamJSObject(JSStreamWriter& b)
MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());
sRegisteredThreads->at(i)->Profile()->StreamJSObject(b);
sRegisteredThreads->at(i)->Profile()->StreamJSObject(b, aSinceTime);
}
}
@ -979,6 +979,11 @@ void TableTicker::InplaceTick(TickSample* sample)
currThreadProfile.addTag(ProfileEntry('T', currThreadProfile.ThreadId()));
if (sample) {
mozilla::TimeDuration delta = sample->timestamp - sStartTime;
currThreadProfile.addTag(ProfileEntry('t', static_cast<float>(delta.ToMilliseconds())));
}
PseudoStack* stack = currThreadProfile.GetPseudoStack();
#if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK) || \
@ -1008,11 +1013,6 @@ void TableTicker::InplaceTick(TickSample* sample)
currThreadProfile.addTag(ProfileEntry('r', static_cast<float>(delta.ToMilliseconds())));
}
if (sample) {
mozilla::TimeDuration delta = sample->timestamp - sStartTime;
currThreadProfile.addTag(ProfileEntry('t', static_cast<float>(delta.ToMilliseconds())));
}
// rssMemory is equal to 0 when we are not recording.
if (sample && sample->rssMemory != 0) {
currThreadProfile.addTag(ProfileEntry('R', static_cast<float>(sample->rssMemory)));

Просмотреть файл

@ -192,8 +192,8 @@ class TableTicker: public Sampler {
return mPrimaryThreadProfile;
}
void ToStreamAsJSON(std::ostream& stream);
virtual JSObject *ToJSObject(JSContext *aCx);
void ToStreamAsJSON(std::ostream& stream, float aSinceTime = 0);
virtual JSObject *ToJSObject(JSContext *aCx, float aSinceTime = 0);
void StreamMetaJSCustomObject(JSStreamWriter& b);
void StreamTaskTracer(JSStreamWriter& b);
void FlushOnJSShutdown(JSRuntime* aRuntime);
@ -219,7 +219,7 @@ protected:
// Not implemented on platforms which do not support backtracing
void doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample);
void StreamJSObject(JSStreamWriter& b);
void StreamJSObject(JSStreamWriter& b, float aSinceTime);
// This represent the application's main thread (SAMPLER_INIT)
ThreadProfile* mPrimaryThreadProfile;

Просмотреть файл

@ -12,7 +12,7 @@ class nsCString;
[ref] native StringArrayRef(const nsTArray<nsCString>);
[scriptable, uuid(9c3c0534-ef4b-4a6e-a1a6-4522d4824ac8)]
[scriptable, uuid(9f3e7c97-abcf-425c-83fd-34d354eb95e8)]
interface nsIProfiler : nsISupports
{
void StartProfiler(in uint32_t aEntries, in double aInterval,
@ -25,9 +25,19 @@ interface nsIProfiler : nsISupports
void PauseSampling();
void ResumeSampling();
void AddMarker(in string aMarker);
string GetProfile();
/*
* Returns the JSON string of the profile. If aSinceTime is passed, only
* report samples taken at >= aSinceTime.
*/
string GetProfile([optional] in float aSinceTime);
/*
* Returns a JS object of the profile. If aSinceTime is passed, only report
* samples taken at >= aSinceTime.
*/
[implicit_jscontext]
jsval getProfileData();
jsval getProfileData([optional] in float aSinceTime);
boolean IsActive();
void GetFeatures(out uint32_t aCount, [retval, array, size_is(aCount)] out string aFeatures);

Просмотреть файл

@ -117,9 +117,9 @@ nsProfiler::AddMarker(const char *aMarker)
}
NS_IMETHODIMP
nsProfiler::GetProfile(char **aProfile)
nsProfiler::GetProfile(float aSinceTime, char **aProfile)
{
char *profile = profiler_get_profile();
char *profile = profiler_get_profile(aSinceTime);
if (profile) {
size_t len = strlen(profile);
char *profileStr = static_cast<char *>
@ -202,10 +202,10 @@ nsProfiler::DumpProfileToFile(const char* aFilename)
}
NS_IMETHODIMP
nsProfiler::GetProfileData(JSContext* aCx,
nsProfiler::GetProfileData(float aSinceTime, JSContext* aCx,
JS::MutableHandle<JS::Value> aResult)
{
JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx));
JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx, aSinceTime));
if (!obj) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -201,7 +201,7 @@ ProfilerMarker::SetGeneration(uint32_t aGenID) {
}
float
ProfilerMarker::GetTime() {
ProfilerMarker::GetTime() const {
return mTime;
}
@ -551,7 +551,7 @@ void mozilla_sampler_save()
t->HandleSaveRequest();
}
char* mozilla_sampler_get_profile()
char* mozilla_sampler_get_profile(float aSinceTime)
{
TableTicker *t = tlsTicker.get();
if (!t) {
@ -559,19 +559,19 @@ char* mozilla_sampler_get_profile()
}
std::stringstream stream;
t->ToStreamAsJSON(stream);
t->ToStreamAsJSON(stream, aSinceTime);
char* profile = strdup(stream.str().c_str());
return profile;
}
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx)
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime)
{
TableTicker *t = tlsTicker.get();
if (!t) {
return nullptr;
}
return t->ToJSObject(aCx);
return t->ToJSObject(aCx, aSinceTime);
}
void mozilla_sampler_save_profile_to_file(const char* aFilename)