зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1145824 - In nsProfiler, allow GetProfile and getProfileData to filter by a start time. (r=mstange)
This commit is contained in:
Родитель
a145bf447c
Коммит
0fafc89798
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче