author | Tom Tromey <tromey@mozilla.com> |
Tue, 16 Jun 2015 22:28:00 -0400 | |
changeset 249359 | 4583dd29ef0eb1c6d90057045c503352ae4dda32 |
parent 249358 | 1da97e961c3d2c9674b4fb621ab7f6b1efe48ee3 |
child 249360 | f5fbae5bbe34a924d3a082efe62edf4503c94fb6 |
push id | 28923 |
push user | ryanvm@gmail.com |
push date | Wed, 17 Jun 2015 18:57:11 +0000 |
treeherder | mozilla-central@099d6cd6725e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | shu, jsantell |
bugs | 1159486 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/devtools/performance/modules/logic/actors.js +++ b/browser/devtools/performance/modules/logic/actors.js @@ -114,20 +114,24 @@ ProfilerFrontFacade.prototype = { // Translate options from the recording model into profiler-specific // options for the nsIProfiler let profilerOptions = { entries: options.bufferSize, interval: options.sampleFrequency ? (1000 / (options.sampleFrequency * 1000)) : void 0 }; - yield this.startProfiler(profilerOptions); + let startInfo = yield this.startProfiler(profilerOptions); + let startTime = 0; + if ('currentTime' in startInfo) { + startTime = startInfo.currentTime; + } this.emit("profiler-activated"); - return { startTime: 0, position, generation, totalSize }; + return { startTime, position, generation, totalSize }; }), /** * Indicates the end of a recording -- does not actually stop the profiler * (stopProfiler does that), but notes that we no longer need to poll * for buffer status. */ stop: Task.async(function *() {
--- a/browser/devtools/performance/modules/logic/recording-model.js +++ b/browser/devtools/performance/modules/logic/recording-model.js @@ -139,17 +139,16 @@ RecordingModel.prototype = { this._duration = profilerEndTime - this._profilerStartTime; this._profile = profile; this._completed = true; // We filter out all samples that fall out of current profile's range // since the profiler is continuously running. Because of this, sample // times are not guaranteed to have a zero epoch, so offset the // timestamps. - // TODO move this into FakeProfilerFront in ./actors.js after bug 1154115 RecordingUtils.offsetSampleTimes(this._profile, this._profilerStartTime); // Markers need to be sorted ascending by time, to be properly displayed // in a waterfall view. this._markers = this._markers.sort((a, b) => (a.start > b.start)); }), /**
--- a/browser/devtools/performance/test/browser_perf-compatibility-05.js +++ b/browser/devtools/performance/test/browser_perf-compatibility-05.js @@ -32,18 +32,16 @@ function* spawnTest() { let firstRecordingStartTime = firstRecording._profilerStartTime; info("Started profiling at: " + firstRecordingStartTime); busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity yield front.stopRecording(firstRecording); info("The first recording is " + firstRecording.getDuration() + "ms long."); - is(firstRecordingStartTime, 0, - "The profiling start time should be 0 for the first recording."); ok(firstRecording.getDuration() >= WAIT_TIME, "The first recording duration is correct."); // Perform the second recording... let secondRecording = yield front.startRecording(); let secondRecordingStartTime = secondRecording._profilerStartTime; info("Started profiling at: " + secondRecordingStartTime);
--- a/browser/devtools/performance/test/browser_perf-data-massaging-01.js +++ b/browser/devtools/performance/test/browser_perf-data-massaging-01.js @@ -17,18 +17,16 @@ function* spawnTest() { let firstRecording = yield front.startRecording(); let firstRecordingStartTime = firstRecording._profilerStartTime; info("Started profiling at: " + firstRecordingStartTime); busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity yield front.stopRecording(firstRecording); - is(firstRecordingStartTime, 0, - "The profiling start time should be 0 for the first recording."); ok(firstRecording.getDuration() >= WAIT_TIME, "The first recording duration is correct."); // Perform the second recording... let secondRecording = yield front.startRecording(); let secondRecordingStartTime = secondRecording._profilerStartTime; info("Started profiling at: " + secondRecordingStartTime);
--- a/toolkit/devtools/server/actors/profiler.js +++ b/toolkit/devtools/server/actors/profiler.js @@ -94,27 +94,31 @@ ProfilerActor.prototype = { onStartProfiler: function(request = {}) { let options = this._profilerStartOptions = { entries: request.entries || DEFAULT_PROFILER_OPTIONS.entries, interval: request.interval || DEFAULT_PROFILER_OPTIONS.interval, features: request.features || DEFAULT_PROFILER_OPTIONS.features, threadFilters: request.threadFilters || DEFAULT_PROFILER_OPTIONS.threadFilters, }; + // The start time should be before any samples we might be + // interested in. + let currentTime = nsIProfilerModule.getElapsedTime(); + nsIProfilerModule.StartProfiler( options.entries, options.interval, options.features, options.features.length, options.threadFilters, options.threadFilters.length ); let { position, totalSize, generation } = this.onGetBufferInfo(); - return { started: true, position, totalSize, generation }; + return { started: true, position, totalSize, generation, currentTime }; }, /** * Stops the nsIProfiler module, if no other client is using it. */ onStopProfiler: function() { // Actually stop the profiler only if the last client has stopped profiling. // Since this is a root actor, and the profiler module interacts with the
--- a/tools/profiler/GeckoProfiler.h +++ b/tools/profiler/GeckoProfiler.h @@ -160,28 +160,28 @@ static inline bool profiler_feature_acti // Internal-only. Used by the event tracer. static inline void profiler_responsiveness(const mozilla::TimeStamp& aTime) {} // Internal-only. static inline void profiler_set_frame_number(int frameNumber) {} // Get the profile encoded as a JSON string. -static inline mozilla::UniquePtr<char[]> profiler_get_profile(float aSinceTime = 0) { +static inline mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0) { return nullptr; } // Get the profile encoded as a JSON object. static inline JSObject* profiler_get_profile_jsobject(JSContext* aCx, - float aSinceTime = 0) { + double aSinceTime = 0) { return nullptr; } // Get the profile encoded as a JSON object. -static inline void profiler_get_profile_jsobject_async(float aSinceTime = 0, +static inline void profiler_get_profile_jsobject_async(double aSinceTime = 0, mozilla::dom::Promise* = 0) {} // Get the profile and write it into a file static inline void profiler_save_profile_to_file(char* aFilename) { } // Get the features supported by the profiler that are accepted by profiler_init. // Returns a null terminated char* array. static inline char** profiler_get_features() { return nullptr; }
--- a/tools/profiler/GeckoProfilerFunc.h +++ b/tools/profiler/GeckoProfilerFunc.h @@ -54,20 +54,20 @@ bool mozilla_sampler_feature_active(cons void mozilla_sampler_responsiveness(const mozilla::TimeStamp& time); void mozilla_sampler_frame_number(int frameNumber); const double* mozilla_sampler_get_responsiveness(); void mozilla_sampler_save(); -mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(float aSinceTime); +mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(double aSinceTime); -JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime); -void mozilla_sampler_get_profile_data_async(float aSinceTime, +JSObject *mozilla_sampler_get_profile_data(JSContext* aCx, double aSinceTime); +void mozilla_sampler_get_profile_data_async(double aSinceTime, mozilla::dom::Promise* aPromise); // 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) extern "C" { void mozilla_sampler_save_profile_to_file(const char* aFilename); }
--- a/tools/profiler/GeckoProfilerImpl.h +++ b/tools/profiler/GeckoProfilerImpl.h @@ -139,29 +139,29 @@ void profiler_responsiveness(const mozil static inline void profiler_set_frame_number(int frameNumber) { return mozilla_sampler_frame_number(frameNumber); } static inline -mozilla::UniquePtr<char[]> profiler_get_profile(float aSinceTime = 0) +mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0) { return mozilla_sampler_get_profile(aSinceTime); } static inline -JSObject* profiler_get_profile_jsobject(JSContext* aCx, float aSinceTime = 0) +JSObject* profiler_get_profile_jsobject(JSContext* aCx, double aSinceTime = 0) { return mozilla_sampler_get_profile_data(aCx, aSinceTime); } static inline -void profiler_get_profile_jsobject_async(float aSinceTime = 0, +void profiler_get_profile_jsobject_async(double aSinceTime = 0, mozilla::dom::Promise* aPromise = 0) { mozilla_sampler_get_profile_data_async(aSinceTime, aPromise); } static inline void profiler_save_profile_to_file(const char* aFilename) {
--- a/tools/profiler/ProfileEntry.cpp +++ b/tools/profiler/ProfileEntry.cpp @@ -48,18 +48,18 @@ ProfileEntry::ProfileEntry(char aTagName , mTagName(aTagName) { } ProfileEntry::ProfileEntry(char aTagName, void *aTagPtr) : mTagPtr(aTagPtr) , mTagName(aTagName) { } -ProfileEntry::ProfileEntry(char aTagName, float aTagFloat) - : mTagFloat(aTagFloat) +ProfileEntry::ProfileEntry(char aTagName, double aTagDouble) + : mTagDouble(aTagDouble) , mTagName(aTagName) { } ProfileEntry::ProfileEntry(char aTagName, uintptr_t aTagOffset) : mTagOffset(aTagOffset) , mTagName(aTagName) { } @@ -558,22 +558,22 @@ void UniqueStacks::StreamFrame(const OnS } } mFrameTableWriter.EndArray(); } struct ProfileSample { uint32_t mStack; - Maybe<float> mTime; - Maybe<float> mResponsiveness; - Maybe<float> mRSS; - Maybe<float> mUSS; + Maybe<double> mTime; + Maybe<double> mResponsiveness; + Maybe<double> mRSS; + Maybe<double> mUSS; Maybe<int> mFrameNumber; - Maybe<float> mPower; + Maybe<double> mPower; }; static void WriteSample(SpliceableJSONWriter& aWriter, ProfileSample& aSample) { // Schema: // [stack, time, responsiveness, rss, uss, frameNumber, power] aWriter.StartArrayElement(); @@ -627,58 +627,58 @@ static void WriteSample(SpliceableJSONWr aWriter.DoubleElement(*aSample.mPower); } index++; } aWriter.EndArray(); } void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, - float aSinceTime, JSRuntime* aRuntime, + double aSinceTime, JSRuntime* aRuntime, UniqueStacks& aUniqueStacks) { Maybe<ProfileSample> sample; int readPos = mReadPos; int currentThreadID = -1; - Maybe<float> currentTime; + Maybe<double> currentTime; UniquePtr<char[]> tagBuff = MakeUnique<char[]>(DYNAMIC_MAX_STRING); while (readPos != mWritePos) { ProfileEntry entry = mEntries[readPos]; if (entry.mTagName == 'T') { currentThreadID = entry.mTagInt; currentTime.reset(); int readAheadPos = (readPos + 1) % mEntrySize; if (readAheadPos != mWritePos) { ProfileEntry readAheadEntry = mEntries[readAheadPos]; if (readAheadEntry.mTagName == 't') { - currentTime = Some(readAheadEntry.mTagFloat); + currentTime = Some(readAheadEntry.mTagDouble); } } } if (currentThreadID == aThreadId && (currentTime.isNothing() || *currentTime >= aSinceTime)) { switch (entry.mTagName) { case 'r': if (sample.isSome()) { - sample->mResponsiveness = Some(entry.mTagFloat); + sample->mResponsiveness = Some(entry.mTagDouble); } break; case 'p': if (sample.isSome()) { - sample->mPower = Some(entry.mTagFloat); + sample->mPower = Some(entry.mTagDouble); } break; case 'R': if (sample.isSome()) { - sample->mRSS = Some(entry.mTagFloat); + sample->mRSS = Some(entry.mTagDouble); } break; case 'U': if (sample.isSome()) { - sample->mUSS = Some(entry.mTagFloat); + sample->mUSS = Some(entry.mTagDouble); } break; case 'f': if (sample.isSome()) { sample->mFrameNumber = Some(entry.mTagInt); } break; case 's': @@ -769,17 +769,17 @@ void ProfileBuffer::StreamSamplesToJSON( readPos = (readPos + 1) % mEntrySize; } if (sample.isSome()) { WriteSample(aWriter, *sample); } } void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThreadId, - float aSinceTime, UniqueStacks& aUniqueStacks) + double aSinceTime, UniqueStacks& aUniqueStacks) { int readPos = mReadPos; int currentThreadID = -1; while (readPos != mWritePos) { ProfileEntry entry = mEntries[readPos]; if (entry.mTagName == 'T') { currentThreadID = entry.mTagInt; } else if (currentThreadID == aThreadId && entry.mTagName == 'm') { @@ -824,17 +824,17 @@ void ProfileBuffer::DuplicateLastSample( readPos != mWritePos; readPos = (readPos + 1) % mEntrySize) { switch (mEntries[readPos].mTagName) { case 'T': // We're done. return; case 't': // Copy with new time - addTag(ProfileEntry('t', static_cast<float>((mozilla::TimeStamp::Now() - sStartTime).ToMilliseconds()))); + addTag(ProfileEntry('t', (mozilla::TimeStamp::Now() - sStartTime).ToMilliseconds())); break; case 'm': // Don't copy markers break; // Copy anything else we don't know about // L, B, S, c, s, d, l, f, h, r, t, p default: addTag(mEntries[readPos]); @@ -882,17 +882,17 @@ void ThreadProfile::addTag(const Profile { mBuffer->addTag(aTag); } void ThreadProfile::addStoredMarker(ProfilerMarker *aStoredMarker) { mBuffer->addStoredMarker(aStoredMarker); } -void ThreadProfile::StreamJSON(SpliceableJSONWriter& aWriter, float aSinceTime) +void ThreadProfile::StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime) { // mUniqueStacks may already be emplaced from FlushSamplesAndMarkers. if (!mUniqueStacks.isSome()) { mUniqueStacks.emplace(mPseudoStack->mRuntime); } aWriter.Start(SpliceableJSONWriter::SingleLineStyle); { @@ -939,17 +939,17 @@ void ThreadProfile::StreamJSON(Spliceabl } aWriter.EndArray(); } aWriter.End(); mUniqueStacks.reset(); } -void ThreadProfile::StreamSamplesAndMarkers(SpliceableJSONWriter& aWriter, float aSinceTime, +void ThreadProfile::StreamSamplesAndMarkers(SpliceableJSONWriter& aWriter, double aSinceTime, UniqueStacks& aUniqueStacks) { // Thread meta data if (XRE_GetProcessType() == GeckoProcessType_Plugin) { // TODO Add the proper plugin name aWriter.StringProperty("name", "Plugin"); } else if (XRE_GetProcessType() == GeckoProcessType_Content) { // This isn't going to really help once we have multiple content
--- a/tools/profiler/ProfileEntry.h +++ b/tools/profiler/ProfileEntry.h @@ -34,17 +34,17 @@ class ProfileEntry { public: ProfileEntry(); // aTagData must not need release (i.e. be a string from the text segment) ProfileEntry(char aTagName, const char *aTagData); ProfileEntry(char aTagName, void *aTagPtr); ProfileEntry(char aTagName, ProfilerMarker *aTagMarker); - ProfileEntry(char aTagName, float aTagFloat); + ProfileEntry(char aTagName, double aTagDouble); ProfileEntry(char aTagName, uintptr_t aTagOffset); ProfileEntry(char aTagName, Address aTagAddress); ProfileEntry(char aTagName, int aTagLine); ProfileEntry(char aTagName, char aTagChar); bool is_ent_hint(char hintChar); bool is_ent_hint(); bool is_ent(char tagName); void* get_tagPtr(); @@ -62,17 +62,17 @@ private: FRIEND_TEST(ThreadProfile, InsertTagsWrap); FRIEND_TEST(ThreadProfile, MemoryMeasure); friend class ProfileBuffer; union { const char* mTagData; char mTagChars[sizeof(void*)]; void* mTagPtr; ProfilerMarker* mTagMarker; - float mTagFloat; + double mTagDouble; Address mTagAddress; uintptr_t mTagOffset; int mTagInt; char mTagChar; }; char mTagName; }; @@ -224,19 +224,19 @@ private: class ProfileBuffer { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProfileBuffer) explicit ProfileBuffer(int aEntrySize); void addTag(const ProfileEntry& aTag); - void StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, float aSinceTime, + void StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, double aSinceTime, JSRuntime* rt, UniqueStacks& aUniqueStacks); - void StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThreadId, float aSinceTime, + void StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThreadId, double aSinceTime, UniqueStacks& aUniqueStacks); void DuplicateLastSample(int aThreadId); void addStoredMarker(ProfilerMarker* aStoredMarker); // The following two methods are not signal safe! They delete markers. void deleteExpiredStoredMarkers(); void reset(); @@ -371,17 +371,17 @@ public: /** * Track a marker which has been inserted into the ThreadProfile. * This marker can safely be deleted once the generation has * expired. */ void addStoredMarker(ProfilerMarker *aStoredMarker); PseudoStack* GetPseudoStack(); mozilla::Mutex* GetMutex(); - void StreamJSON(SpliceableJSONWriter& aWriter, float aSinceTime = 0); + void StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime = 0); /** * Call this method when the JS entries inside the buffer are about to * become invalid, i.e., just before JS shutdown. */ void FlushSamplesAndMarkers(); void BeginUnwind(); @@ -404,17 +404,17 @@ public: mPlatformData = nullptr; } uint32_t bufferGeneration() const { return mBuffer->mGeneration; } protected: - void StreamSamplesAndMarkers(SpliceableJSONWriter& aWriter, float aSinceTime, + void StreamSamplesAndMarkers(SpliceableJSONWriter& aWriter, double aSinceTime, UniqueStacks& aUniqueStacks); private: FRIEND_TEST(ThreadProfile, InsertOneTag); FRIEND_TEST(ThreadProfile, InsertOneTagWithTinyBuffer); FRIEND_TEST(ThreadProfile, InsertTagsNoWrap); FRIEND_TEST(ThreadProfile, InsertTagsWrap); FRIEND_TEST(ThreadProfile, MemoryMeasure);
--- a/tools/profiler/ProfileGatherer.cpp +++ b/tools/profiler/ProfileGatherer.cpp @@ -10,17 +10,17 @@ using mozilla::dom::AutoJSAPI; using mozilla::dom::Promise; namespace mozilla { NS_IMPL_ISUPPORTS0(ProfileGatherer) ProfileGatherer::ProfileGatherer(TableTicker* aTicker, - float aSinceTime, + double aSinceTime, Promise* aPromise) : mPromise(aPromise) , mTicker(aTicker) , mSinceTime(aSinceTime) , mPendingProfiles(0) { }
--- a/tools/profiler/ProfileGatherer.h +++ b/tools/profiler/ProfileGatherer.h @@ -12,27 +12,27 @@ class TableTicker; namespace mozilla { class ProfileGatherer final : public nsISupports { public: NS_DECL_ISUPPORTS ProfileGatherer(TableTicker* aTicker, - float aSinceTime, + double aSinceTime, mozilla::dom::Promise* aPromise); void WillGatherOOPProfile(); void GatheredOOPProfile(); void Start(); private: ~ProfileGatherer() {}; void Finish(); nsRefPtr<mozilla::dom::Promise> mPromise; TableTicker* mTicker; - float mSinceTime; + double mSinceTime; uint32_t mPendingProfiles; }; } // namespace mozilla -#endif \ No newline at end of file +#endif
--- a/tools/profiler/PseudoStack.h +++ b/tools/profiler/PseudoStack.h @@ -77,39 +77,39 @@ class ProfilerLinkedList; class SpliceableJSONWriter; class UniqueStacks; class ProfilerMarker { friend class ProfilerLinkedList<ProfilerMarker>; public: explicit ProfilerMarker(const char* aMarkerName, ProfilerMarkerPayload* aPayload = nullptr, - float aTime = 0); + double aTime = 0); ~ProfilerMarker(); const char* GetMarkerName() const { return mMarkerName; } void StreamJSON(SpliceableJSONWriter& aWriter, UniqueStacks& aUniqueStacks) const; void SetGeneration(uint32_t aGenID); bool HasExpired(uint32_t aGenID) const { return mGenID + 2 <= aGenID; } - float GetTime() const; + double GetTime() const; private: char* mMarkerName; ProfilerMarkerPayload* mPayload; ProfilerMarker* mNext; - float mTime; + double mTime; uint32_t mGenID; }; template<typename T> class ProfilerLinkedList { public: ProfilerLinkedList() : mHead(nullptr) @@ -230,17 +230,17 @@ public: // This is called on every profiler restart. Put things that should happen at that time here. void reinitializeOnResume() { // This is needed to cause an initial sample to be taken from sleeping threads. Otherwise sleeping // threads would not have any samples to copy forward while sleeping. mSleepId++; } - void addMarker(const char *aMarkerStr, ProfilerMarkerPayload *aPayload, float aTime) + void addMarker(const char* aMarkerStr, ProfilerMarkerPayload* aPayload, double aTime) { ProfilerMarker* marker = new ProfilerMarker(aMarkerStr, aPayload, aTime); mPendingMarkers.insert(marker); } // called within signal. Function must be reentrant ProfilerMarkerLinkedList* getPendingMarkers() {
--- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -154,17 +154,18 @@ TableTicker::TableTicker(double aInterva #endif // Deep copy aThreadNameFilters MOZ_ALWAYS_TRUE(mThreadNameFilters.resize(aFilterCount)); for (uint32_t i = 0; i < aFilterCount; ++i) { mThreadNameFilters[i] = aThreadNameFilters[i]; } - sStartTime = mozilla::TimeStamp::Now(); + bool ignore; + sStartTime = mozilla::TimeStamp::ProcessCreation(ignore); { mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex); // Create ThreadProfile for each registered thread for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { ThreadInfo* info = sRegisteredThreads->at(i); @@ -308,23 +309,23 @@ void TableTicker::StreamMetaJSCustomObje nsAutoCString string; res = appInfo->GetName(string); if (!NS_FAILED(res)) aWriter.StringProperty("product", string.Data()); } } -void TableTicker::ToStreamAsJSON(std::ostream& stream, float aSinceTime) +void TableTicker::ToStreamAsJSON(std::ostream& stream, double aSinceTime) { SpliceableJSONWriter b(mozilla::MakeUnique<OStreamJSONWriteFunc>(stream)); StreamJSON(b, aSinceTime); } -JSObject* TableTicker::ToJSObject(JSContext *aCx, float aSinceTime) +JSObject* TableTicker::ToJSObject(JSContext* aCx, double aSinceTime) { JS::RootedValue val(aCx); { UniquePtr<char[]> buf = ToJSON(aSinceTime); NS_ConvertUTF8toUTF16 js_string(nsDependentCString(buf.get())); bool rv = JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()), js_string.Length(), &val); if (!rv) { @@ -351,24 +352,24 @@ JSObject* TableTicker::ToJSObject(JSCont } } #endif } } return &val.toObject(); } -UniquePtr<char[]> TableTicker::ToJSON(float aSinceTime) +UniquePtr<char[]> TableTicker::ToJSON(double aSinceTime) { SpliceableChunkedJSONWriter b; StreamJSON(b, aSinceTime); return b.WriteFunc()->CopyData(); } -void TableTicker::ToJSObjectAsync(float aSinceTime, +void TableTicker::ToJSObjectAsync(double aSinceTime, Promise* aPromise) { if (NS_WARN_IF(mGatherer)) { return; } mGatherer = new ProfileGatherer(this, aSinceTime, aPromise); mGatherer->Start(); @@ -446,17 +447,17 @@ void BuildJavaThreadJSObject(SpliceableJ } } aWriter.EndArray(); aWriter.End(); } #endif -void TableTicker::StreamJSON(SpliceableJSONWriter& aWriter, float aSinceTime) +void TableTicker::StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime) { aWriter.Start(SpliceableJSONWriter::SingleLineStyle); { // Put shared library info aWriter.StringProperty("libs", GetSharedLibraryInfoString().c_str()); // Put meta data aWriter.StartObjectProperty("meta"); @@ -1113,17 +1114,17 @@ void TableTicker::Tick(TickSample* sampl void TableTicker::InplaceTick(TickSample* sample) { ThreadProfile& currThreadProfile = *sample->threadProfile; currThreadProfile.addTag(ProfileEntry('T', currThreadProfile.ThreadId())); if (sample) { mozilla::TimeDuration delta = sample->timestamp - sStartTime; - currThreadProfile.addTag(ProfileEntry('t', static_cast<float>(delta.ToMilliseconds()))); + currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds())); } PseudoStack* stack = currThreadProfile.GetPseudoStack(); #if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK) || \ defined(USE_LUL_STACKWALK) if (mUseStackWalk) { doNativeBacktrace(currThreadProfile, sample); @@ -1142,33 +1143,33 @@ void TableTicker::InplaceTick(TickSample ProfilerMarker* marker = pendingMarkersList->popHead(); currThreadProfile.addStoredMarker(marker); currThreadProfile.addTag(ProfileEntry('m', marker)); } } if (sample && currThreadProfile.GetThreadResponsiveness()->HasData()) { mozilla::TimeDuration delta = currThreadProfile.GetThreadResponsiveness()->GetUnresponsiveDuration(sample->timestamp); - currThreadProfile.addTag(ProfileEntry('r', static_cast<float>(delta.ToMilliseconds()))); + currThreadProfile.addTag(ProfileEntry('r', 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))); + currThreadProfile.addTag(ProfileEntry('R', static_cast<double>(sample->rssMemory))); } // ussMemory is equal to 0 when we are not recording. if (sample && sample->ussMemory != 0) { - currThreadProfile.addTag(ProfileEntry('U', static_cast<float>(sample->ussMemory))); + currThreadProfile.addTag(ProfileEntry('U', static_cast<double>(sample->ussMemory))); } #if defined(XP_WIN) if (mProfilePower) { mIntelPowerGadget->TakeSample(); - currThreadProfile.addTag(ProfileEntry('p', static_cast<float>(mIntelPowerGadget->GetTotalPackagePowerInWatts()))); + currThreadProfile.addTag(ProfileEntry('p', static_cast<double>(mIntelPowerGadget->GetTotalPackagePowerInWatts()))); } #endif if (sLastFrameNumber != sFrameNumber) { currThreadProfile.addTag(ProfileEntry('f', sFrameNumber)); sLastFrameNumber = sFrameNumber; } }
--- a/tools/profiler/TableTicker.h +++ b/tools/profiler/TableTicker.h @@ -92,20 +92,20 @@ class TableTicker: public Sampler { break; } } } return mPrimaryThreadProfile; } - void ToStreamAsJSON(std::ostream& stream, float aSinceTime = 0); - virtual JSObject *ToJSObject(JSContext *aCx, float aSinceTime = 0); - mozilla::UniquePtr<char[]> ToJSON(float aSinceTime = 0); - virtual void ToJSObjectAsync(float aSinceTime = 0, mozilla::dom::Promise* aPromise = 0); + void ToStreamAsJSON(std::ostream& stream, double aSinceTime = 0); + virtual JSObject *ToJSObject(JSContext* aCx, double aSinceTime = 0); + mozilla::UniquePtr<char[]> ToJSON(double aSinceTime = 0); + virtual void ToJSObjectAsync(double aSinceTime = 0, mozilla::dom::Promise* aPromise = 0); void StreamMetaJSCustomObject(SpliceableJSONWriter& aWriter); void StreamTaskTracer(SpliceableJSONWriter& aWriter); void FlushOnJSShutdown(JSRuntime* aRuntime); bool ProfileJS() const { return mProfileJS; } bool ProfileJava() const { return mProfileJava; } bool ProfileGPU() const { return mProfileGPU; } bool ProfilePower() const { return mProfilePower; } bool ProfileThreads() const override { return mProfileThreads; } @@ -123,17 +123,17 @@ class TableTicker: public Sampler { protected: // Called within a signal. This function must be reentrant virtual void InplaceTick(TickSample* sample); // Not implemented on platforms which do not support backtracing void doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample); - void StreamJSON(SpliceableJSONWriter& aWriter, float aSinceTime); + void StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime); // This represent the application's main thread (SAMPLER_INIT) ThreadProfile* mPrimaryThreadProfile; nsRefPtr<ProfileBuffer> mBuffer; bool mSaveRequested; bool mAddLeafAddresses; bool mUseStackWalk; bool mProfileJS;
--- a/tools/profiler/nsIProfiler.idl +++ b/tools/profiler/nsIProfiler.idl @@ -7,56 +7,57 @@ %{C++ template<class T> class nsTArray; class nsCString; %} [ref] native StringArrayRef(const nsTArray<nsCString>); -[scriptable, uuid(0f474ec5-b95c-45d9-a7c8-156da0e3fa25)] +[scriptable, uuid(921e1223-b1ea-4906-bb26-a846e6b6835b)] interface nsIProfiler : nsISupports { void StartProfiler(in uint32_t aEntries, in double aInterval, [array, size_is(aFeatureCount)] in string aFeatures, in uint32_t aFeatureCount, [array, size_is(aFilterCount), optional] in string aThreadNameFilters, [optional] in uint32_t aFilterCount); void StopProfiler(); boolean IsPaused(); void PauseSampling(); void ResumeSampling(); void AddMarker(in string aMarker); /* * Returns the JSON string of the profile. If aSinceTime is passed, only * report samples taken at >= aSinceTime. */ - string GetProfile([optional] in float aSinceTime); + string GetProfile([optional] in double aSinceTime); /* * Returns a JS object of the profile. If aSinceTime is passed, only report * samples taken at >= aSinceTime. */ [implicit_jscontext] - jsval getProfileData([optional] in float aSinceTime); + jsval getProfileData([optional] in double aSinceTime); [implicit_jscontext] - nsISupports getProfileDataAsync([optional] in float aSinceTime); + nsISupports getProfileDataAsync([optional] in double aSinceTime); boolean IsActive(); void GetFeatures(out uint32_t aCount, [retval, array, size_is(aCount)] out string aFeatures); void GetBufferInfo(out uint32_t aCurrentPosition, out uint32_t aTotalSize, out uint32_t aGeneration); /** - * Returns the elapsed time, in milliseconds, since the last StartProfiler call. - * Returns 0 if there is no active sampler. + * Returns the elapsed time, in milliseconds, since the profiler's epoch. + * The epoch is guaranteed to be constant for the duration of the + * process, but is otherwise arbitrary. */ - float getElapsedTime(); + double getElapsedTime(); /** * Returns a JSON string of an array of shared library objects. * Every object has three properties: start, end, and name. * start and end are integers describing the address range that the library * occupies in memory. name is the path of the library as a string. * * On Windows profiling builds, the shared library objects will have
--- a/tools/profiler/nsProfiler.cpp +++ b/tools/profiler/nsProfiler.cpp @@ -116,17 +116,17 @@ nsProfiler::ResumeSampling() NS_IMETHODIMP nsProfiler::AddMarker(const char *aMarker) { PROFILER_MARKER(aMarker); return NS_OK; } NS_IMETHODIMP -nsProfiler::GetProfile(float aSinceTime, char **aProfile) +nsProfiler::GetProfile(double aSinceTime, char** aProfile) { mozilla::UniquePtr<char[]> profile = profiler_get_profile(aSinceTime); if (profile) { size_t len = strlen(profile.get()); char *profileStr = static_cast<char *> (nsMemory::Clone(profile.get(), (len + 1) * sizeof(char))); profileStr[len] = '\0'; *aProfile = profileStr; @@ -200,29 +200,29 @@ nsProfiler::GetSharedLibraryInformation( NS_IMETHODIMP nsProfiler::DumpProfileToFile(const char* aFilename) { profiler_save_profile_to_file(aFilename); return NS_OK; } NS_IMETHODIMP -nsProfiler::GetProfileData(float aSinceTime, JSContext* aCx, +nsProfiler::GetProfileData(double aSinceTime, JSContext* aCx, JS::MutableHandle<JS::Value> aResult) { JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx, aSinceTime)); if (!obj) { return NS_ERROR_FAILURE; } aResult.setObject(*obj); return NS_OK; } NS_IMETHODIMP -nsProfiler::GetProfileDataAsync(float aSinceTime, JSContext* aCx, +nsProfiler::GetProfileDataAsync(double aSinceTime, JSContext* aCx, nsISupports** aPromise) { MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(!aCx)) { return NS_ERROR_FAILURE; } @@ -240,19 +240,19 @@ nsProfiler::GetProfileDataAsync(float aS profiler_get_profile_jsobject_async(aSinceTime, promise); promise.forget(aPromise); return NS_OK; } NS_IMETHODIMP -nsProfiler::GetElapsedTime(float* aElapsedTime) +nsProfiler::GetElapsedTime(double* aElapsedTime) { - *aElapsedTime = static_cast<float>(profiler_time()); + *aElapsedTime = profiler_time(); return NS_OK; } NS_IMETHODIMP nsProfiler::IsActive(bool *aIsActive) { *aIsActive = profiler_is_active(); return NS_OK;
--- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -9,16 +9,17 @@ #include "ProfilerIOInterposeObserver.h" #include "platform.h" #include "PlatformMacros.h" #include "prenv.h" #include "mozilla/ArrayUtils.h" #include "mozilla/StaticPtr.h" #include "mozilla/ThreadLocal.h" +#include "mozilla/TimeStamp.h" #include "PseudoStack.h" #include "TableTicker.h" #include "nsIObserverService.h" #include "nsDirectoryServiceUtils.h" #include "nsDirectoryServiceDefs.h" #include "nsProfilerStartParams.h" #include "mozilla/Services.h" #include "nsThreadUtils.h" @@ -177,35 +178,35 @@ StackOwningThreadInfo::SetPendingDelete( PseudoStack* stack = Stack(); if (stack) { stack->deref(); } ThreadInfo::SetPendingDelete(); } ProfilerMarker::ProfilerMarker(const char* aMarkerName, - ProfilerMarkerPayload* aPayload, - float aTime) + ProfilerMarkerPayload* aPayload, + double aTime) : mMarkerName(strdup(aMarkerName)) , mPayload(aPayload) , mTime(aTime) { } ProfilerMarker::~ProfilerMarker() { free(mMarkerName); delete mPayload; } void ProfilerMarker::SetGeneration(uint32_t aGenID) { mGenID = aGenID; } -float +double ProfilerMarker::GetTime() const { return mTime; } void ProfilerMarker::StreamJSON(SpliceableJSONWriter& aWriter, UniqueStacks& aUniqueStacks) const { // Schema: @@ -461,16 +462,19 @@ void mozilla_sampler_init(void* stackTop if (stack_key_initialized) return; LOG("BEGIN mozilla_sampler_init"); if (!tlsPseudoStack.init() || !tlsTicker.init() || !tlsStackTop.init()) { LOG("Failed to init."); return; } + bool ignore; + sStartTime = mozilla::TimeStamp::ProcessCreation(ignore); + stack_key_initialized = true; Sampler::Startup(); PseudoStack *stack = PseudoStack::create(); tlsPseudoStack.set(stack); bool isMainThread = true; @@ -556,37 +560,37 @@ void mozilla_sampler_save() } t->RequestSave(); // We're on the main thread already so we don't // have to wait to handle the save request. t->HandleSaveRequest(); } -mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(float aSinceTime) +mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(double aSinceTime) { TableTicker *t = tlsTicker.get(); if (!t) { return nullptr; } return t->ToJSON(aSinceTime); } -JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime) +JSObject* mozilla_sampler_get_profile_data(JSContext* aCx, double aSinceTime) { TableTicker *t = tlsTicker.get(); if (!t) { return nullptr; } return t->ToJSObject(aCx, aSinceTime); } -void mozilla_sampler_get_profile_data_async(float aSinceTime, +void mozilla_sampler_get_profile_data_async(double aSinceTime, mozilla::dom::Promise* aPromise) { TableTicker *t = tlsTicker.get(); if (NS_WARN_IF(!t)) { return; } t->ToJSObjectAsync(aSinceTime, aPromise); @@ -963,19 +967,16 @@ void mozilla_sampler_sleep_end() { if (stack == nullptr) { return; } stack->setSleeping(0); } double mozilla_sampler_time(const mozilla::TimeStamp& aTime) { - if (!mozilla_sampler_is_active()) { - return 0.0; - } mozilla::TimeDuration delta = aTime - sStartTime; return delta.ToMilliseconds(); } double mozilla_sampler_time() { return mozilla_sampler_time(mozilla::TimeStamp::Now()); } @@ -1044,15 +1045,15 @@ void mozilla_sampler_add_marker(const ch PseudoStack *stack = tlsPseudoStack.get(); if (!stack) { return; } mozilla::TimeStamp origin = (aPayload && !aPayload->GetStartTime().IsNull()) ? aPayload->GetStartTime() : mozilla::TimeStamp::Now(); mozilla::TimeDuration delta = origin - sStartTime; - stack->addMarker(aMarker, payload.forget(), static_cast<float>(delta.ToMilliseconds())); + stack->addMarker(aMarker, payload.forget(), delta.ToMilliseconds()); } // END externally visible functions ////////////////////////////////////////////////////////////////////////
--- a/tools/profiler/tests/gtest/ThreadProfileTest.cpp +++ b/tools/profiler/tests/gtest/ThreadProfileTest.cpp @@ -17,20 +17,20 @@ TEST(ThreadProfile, Initialization) { } // Make sure we can record one tag and read it TEST(ThreadProfile, InsertOneTag) { PseudoStack* stack = PseudoStack::create(); Thread::tid_t tid = 1000; ThreadInfo info("testThread", tid, true, stack, nullptr); nsRefPtr<ProfileBuffer> pb = new ProfileBuffer(10); - pb->addTag(ProfileEntry('t', 123.1f)); + pb->addTag(ProfileEntry('t', 123.1)); ASSERT_TRUE(pb->mEntries != nullptr); ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagName == 't'); - ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagFloat == 123.1f); + ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagDouble == 123.1); } // See if we can insert some tags TEST(ThreadProfile, InsertTagsNoWrap) { PseudoStack* stack = PseudoStack::create(); Thread::tid_t tid = 1000; ThreadInfo info("testThread", tid, true, stack, nullptr); nsRefPtr<ProfileBuffer> pb = new ProfileBuffer(100);
--- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -871,16 +871,19 @@ NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(JNIEnv* jenv, jclass) { NS_DispatchMemoryPressure(MemPressure_New); } NS_EXPORT jdouble JNICALL Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc) { + if (!profiler_is_active()) { + return 0.0; + } return profiler_time(); } NS_EXPORT void JNICALL Java_org_mozilla_gecko_gfx_NativePanZoomController_abortAnimation(JNIEnv* env, jobject instance) { APZCTreeManager *controller = nsWindow::GetAPZCTreeManager(); if (controller) {