diff --git a/tools/profiler/core/ThreadInfo.h b/tools/profiler/core/ThreadInfo.h index bdf243e92b3c..989ee98ba30f 100644 --- a/tools/profiler/core/ThreadInfo.h +++ b/tools/profiler/core/ThreadInfo.h @@ -90,8 +90,8 @@ private: // This is only used for the main thread. mozilla::Maybe mResponsiveness; - // When sampling, this holds the generation number and offset in PS::mBuffer - // of the most recent sample for this thread. + // When sampling, this holds the generation number and offset in + // ProfilerState::mBuffer of the most recent sample for this thread. ProfileBuffer::LastSample mLastSample; }; diff --git a/tools/profiler/core/platform-linux-android.cpp b/tools/profiler/core/platform-linux-android.cpp index 5c2296a220cf..19913d589924 100644 --- a/tools/profiler/core/platform-linux-android.cpp +++ b/tools/profiler/core/platform-linux-android.cpp @@ -279,7 +279,7 @@ ThreadEntry(void* aArg) return nullptr; } -SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration, +SamplerThread::SamplerThread(PS::LockRef aLock, uint32_t aActivityGeneration, double aIntervalMilliseconds) : mActivityGeneration(aActivityGeneration) , mIntervalMicroseconds( @@ -343,7 +343,7 @@ SamplerThread::~SamplerThread() } void -SamplerThread::Stop(PSLockRef aLock) +SamplerThread::Stop(PS::LockRef aLock) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); @@ -356,7 +356,7 @@ SamplerThread::Stop(PSLockRef aLock) } void -SamplerThread::SuspendAndSampleAndResumeThread(PSLockRef aLock, +SamplerThread::SuspendAndSampleAndResumeThread(PS::LockRef aLock, TickSample& aSample) { // Only one sampler thread can be sampling at once. So we expect to have @@ -466,7 +466,7 @@ paf_prepare() MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); gPS->SetWasPaused(lock, gPS->IsPaused(lock)); gPS->SetIsPaused(lock, true); @@ -480,14 +480,14 @@ paf_parent() MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); gPS->SetIsPaused(lock, gPS->WasPaused(lock)); gPS->SetWasPaused(lock, false); } static void -PlatformInit(PSLockRef aLock) +PlatformInit(PS::LockRef aLock) { // Set up the fork handlers. pthread_atfork(paf_prepare, paf_parent, nullptr); @@ -496,7 +496,7 @@ PlatformInit(PSLockRef aLock) #else static void -PlatformInit(PSLockRef aLock) +PlatformInit(PS::LockRef aLock) { } diff --git a/tools/profiler/core/platform-macos.cpp b/tools/profiler/core/platform-macos.cpp index 6cfe210d87c2..715226f36f6f 100644 --- a/tools/profiler/core/platform-macos.cpp +++ b/tools/profiler/core/platform-macos.cpp @@ -101,7 +101,7 @@ ThreadEntry(void* aArg) return nullptr; } -SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration, +SamplerThread::SamplerThread(PS::LockRef aLock, uint32_t aActivityGeneration, double aIntervalMilliseconds) : mActivityGeneration(aActivityGeneration) , mIntervalMicroseconds( @@ -121,13 +121,13 @@ SamplerThread::~SamplerThread() } void -SamplerThread::Stop(PSLockRef aLock) +SamplerThread::Stop(PS::LockRef aLock) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); } void -SamplerThread::SuspendAndSampleAndResumeThread(PSLockRef aLock, +SamplerThread::SuspendAndSampleAndResumeThread(PS::LockRef aLock, TickSample& aSample) { thread_act_t samplee_thread = aSample.mPlatformData->ProfiledThread(); @@ -204,7 +204,7 @@ SamplerThread::SuspendAndSampleAndResumeThread(PSLockRef aLock, //////////////////////////////////////////////////////////////////////// static void -PlatformInit(PSLockRef aLock) +PlatformInit(PS::LockRef aLock) { } diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index 918c2c2ee73d..6c4f41cb7de7 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -98,7 +98,7 @@ ThreadEntry(void* aArg) return 0; } -SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration, +SamplerThread::SamplerThread(PS::LockRef aLock, uint32_t aActivityGeneration, double aIntervalMilliseconds) : mActivityGeneration(aActivityGeneration) , mIntervalMicroseconds( @@ -139,7 +139,7 @@ SamplerThread::~SamplerThread() } void -SamplerThread::Stop(PSLockRef aLock) +SamplerThread::Stop(PS::LockRef aLock) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); @@ -157,7 +157,7 @@ SamplerThread::Stop(PSLockRef aLock) } void -SamplerThread::SuspendAndSampleAndResumeThread(PSLockRef aLock, +SamplerThread::SuspendAndSampleAndResumeThread(PS::LockRef aLock, TickSample& aSample) { HANDLE profiled_thread = aSample.mPlatformData->ProfiledThread(); @@ -229,7 +229,7 @@ SamplerThread::SuspendAndSampleAndResumeThread(PSLockRef aLock, //////////////////////////////////////////////////////////////////////// static void -PlatformInit(PSLockRef aLock) +PlatformInit(PS::LockRef aLock) { } diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index fddcabcf4ac5..55c66d689ed1 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -110,33 +110,34 @@ class SamplerThread; // Per-thread state. MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack; -class PSMutex : public mozilla::StaticMutex {}; - -typedef mozilla::BaseAutoLock PSAutoLock; - -// Only functions that take a PSLockRef arg can modify this class's fields. -typedef const PSAutoLock& PSLockRef; - // This class contains most of the profiler's global state. gPS is the single // instance. Most profile operations can't do anything useful when gPS is not // instantiated, so we release-assert its non-nullness in all such operations. // // Accesses to gPS are guarded by gPSMutex. Every getter and setter takes a -// PSAutoLock reference as an argument as proof that the gPSMutex is currently -// locked. This makes it clear when gPSMutex is locked and helps avoid -// accidental unlocked accesses to global state. There are ways to circumvent -// this mechanism, but please don't do so without *very* good reason and a -// detailed explanation. +// PS::AutoLock reference as an argument as proof that the gPSMutex is +// currently locked. This makes it clear when gPSMutex is locked and helps +// avoid accidental unlocked accesses to global state. There are ways to +// circumvent this mechanism, but please don't do so without *very* good reason +// and a detailed explanation. // // Other from the lock protection, this class is essentially a thin wrapper and // contains very little "smarts" itself. // -class PS +class ProfilerState { public: + // Shorter names for local use. + class Mutex : public mozilla::StaticMutex {}; + + typedef mozilla::BaseAutoLock AutoLock; + + // Only functions that take a LockRef arg can modify this class's fields. + typedef const AutoLock& LockRef; + typedef std::vector ThreadVector; - PS() + ProfilerState() : mEntries(0) , mInterval(0) , mFeatureDisplayListDump(false) @@ -154,7 +155,7 @@ public: , mFeatureThreads(false) , mBuffer(nullptr) , mIsPaused(false) -#if defined(GP_OS_linux) +#if defined(GP_OS_linux) || defined(GP_OS_android) , mWasPaused(false) #endif , mSamplerThread(nullptr) @@ -167,18 +168,18 @@ public: {} #define GET_AND_SET(type_, name_) \ - type_ name_(PSLockRef) const { return m##name_; } \ - void Set##name_(PSLockRef, type_ a##name_) { m##name_ = a##name_; } + type_ name_(LockRef) const { return m##name_; } \ + void Set##name_(LockRef, type_ a##name_) { m##name_ = a##name_; } - GET_AND_SET(TimeStamp, ProcessStartTime) + GET_AND_SET(TimeStamp, StartTime) GET_AND_SET(int, Entries) GET_AND_SET(double, Interval) - Vector& Features(PSLockRef) { return mFeatures; } + Vector& Features(LockRef) { return mFeatures; } - Vector& Filters(PSLockRef) { return mFilters; } + Vector& ThreadNameFilters(LockRef) { return mThreadNameFilters; } GET_AND_SET(bool, FeatureDisplayListDump) GET_AND_SET(bool, FeatureGPU) @@ -196,13 +197,13 @@ public: GET_AND_SET(ProfileBuffer*, Buffer) - ThreadVector& LiveThreads(PSLockRef) { return mLiveThreads; } - ThreadVector& DeadThreads(PSLockRef) { return mDeadThreads; } + ThreadVector& LiveThreads(LockRef) { return mLiveThreads; } + ThreadVector& DeadThreads(LockRef) { return mDeadThreads; } - static bool IsActive(PSLockRef) { return sActivityGeneration > 0; } - static uint32_t ActivityGeneration(PSLockRef) { return sActivityGeneration; } - static void SetInactive(PSLockRef) { sActivityGeneration = 0; } - static void SetActive(PSLockRef) + static bool IsActive(LockRef) { return sActivityGeneration > 0; } + static uint32_t ActivityGeneration(LockRef) { return sActivityGeneration; } + static void SetInactive(LockRef) { sActivityGeneration = 0; } + static void SetActive(LockRef) { sActivityGeneration = sNextActivityGeneration; // On overflow, reset to 1 instead of 0, because 0 means inactive. @@ -213,7 +214,7 @@ public: GET_AND_SET(bool, IsPaused) -#if defined(GP_OS_linux) +#if defined(GP_OS_linux) || defined(GP_OS_android) GET_AND_SET(bool, WasPaused) #endif @@ -231,8 +232,8 @@ public: #undef GET_AND_SET private: - // The time that the process started. - mozilla::TimeStamp mProcessStartTime; + // When profiler_init() or profiler_start() was most recently called. + mozilla::TimeStamp mStartTime; // The number of entries in mBuffer. Zeroed when the profiler is inactive. int mEntries; @@ -247,7 +248,7 @@ private: // Substrings of names of threads we want to profile. Cleared when the // profiler is inactive - Vector mFilters; + Vector mThreadNameFilters; // Configuration flags derived from mFeatures. Cleared when the profiler is // inactive. @@ -305,7 +306,7 @@ private: // Is the profiler paused? False when the profiler is inactive. bool mIsPaused; -#if defined(GP_OS_linux) +#if defined(GP_OS_linux) || defined(GP_OS_android) // Used to record whether the profiler was paused just before forking. False // at all times except just before/after forking. bool mWasPaused; @@ -329,17 +330,17 @@ private: int mLatestRecordedFrameNumber; }; +// A shorter name for use within this compilation unit. +typedef ProfilerState PS; + uint32_t PS::sActivityGeneration = 0; uint32_t PS::sNextActivityGeneration = 1; -// The core profiler state. Null at process startup, it is set to a non-null -// value in profiler_init() and stays that way until profiler_shutdown() is -// called. Therefore it can be checked to determine if the profiler has been -// initialized but not yet shut down. -static PS* gPS = nullptr; +// The profiler state. Set by profiler_init(), cleared by profiler_shutdown(). +PS* gPS = nullptr; // The mutex that guards accesses to gPS. -static PSMutex gPSMutex; +static PS::Mutex gPSMutex; // The name of the main thread. static const char* const kMainThreadName = "GeckoMain"; @@ -472,7 +473,7 @@ AddDynamicCodeLocationTag(ProfileBuffer* aBuffer, const char* aStr) static const int SAMPLER_MAX_STRING_LENGTH = 128; static void -AddPseudoEntry(PSLockRef aLock, ProfileBuffer* aBuffer, +AddPseudoEntry(PS::LockRef aLock, ProfileBuffer* aBuffer, volatile js::ProfileEntry& entry, PseudoStack* stack, void* lastpc) { @@ -574,7 +575,7 @@ struct AutoWalkJSStack }; static void -MergeStacksIntoProfile(PSLockRef aLock, ProfileBuffer* aBuffer, +MergeStacksIntoProfile(PS::LockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample, NativeStack& aNativeStack) { NotNull pseudoStack = aSample.mPseudoStack; @@ -758,7 +759,7 @@ MergeStacksIntoProfile(PSLockRef aLock, ProfileBuffer* aBuffer, // Update the JS context with the current profile sample buffer generation. // // Do not do this for synchronous samples, which use their own - // ProfileBuffers instead of the global one in PS. + // ProfileBuffers instead of the global one in ProfilerState. if (!aSample.mIsSynchronous && pseudoStack->mContext) { MOZ_ASSERT(aBuffer->mGeneration >= startBufferGen); uint32_t lapCount = aBuffer->mGeneration - startBufferGen; @@ -784,7 +785,7 @@ StackWalkCallback(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure) } static void -DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer, +DoNativeBacktrace(PS::LockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample) { void* pc_array[1000]; @@ -826,7 +827,7 @@ DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer, #ifdef USE_EHABI_STACKWALK static void -DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer, +DoNativeBacktrace(PS::LockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample) { void* pc_array[1000]; @@ -915,7 +916,7 @@ ASAN_memcpy(void* aDst, const void* aSrc, size_t aLen) #endif static void -DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer, +DoNativeBacktrace(PS::LockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample) { const mcontext_t* mc = @@ -1058,7 +1059,7 @@ DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer, #endif static void -DoSampleStackTrace(PSLockRef aLock, ProfileBuffer* aBuffer, +DoSampleStackTrace(PS::LockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample) { NativeStack nativeStack = { nullptr, nullptr, 0, 0 }; @@ -1072,12 +1073,11 @@ DoSampleStackTrace(PSLockRef aLock, ProfileBuffer* aBuffer, // This function is called for each sampling period with the current program // counter. It is called within a signal and so must be re-entrant. static void -Tick(PSLockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample) +Tick(PS::LockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample) { aBuffer->addTagThreadId(aSample.mThreadId, aSample.mLastSample); - mozilla::TimeDuration delta = - aSample.mTimeStamp - gPS->ProcessStartTime(aLock); + mozilla::TimeDuration delta = aSample.mTimeStamp - gPS->StartTime(aLock); aBuffer->addTag(ProfileBufferEntry::Time(delta.ToMilliseconds())); NotNull pseudoStack = aSample.mPseudoStack; @@ -1186,13 +1186,13 @@ StreamNameAndThreadId(JSONWriter& aWriter, const char* aName, int aThreadId) #endif static void -StreamTaskTracer(PSLockRef aLock, SpliceableJSONWriter& aWriter) +StreamTaskTracer(PS::LockRef aLock, SpliceableJSONWriter& aWriter) { #ifdef MOZ_TASK_TRACER aWriter.StartArrayProperty("data"); { UniquePtr> data = - mozilla::tasktracer::GetLoggedData(gPS->ProcessStartTime(aLock)); + mozilla::tasktracer::GetLoggedData(gPS->StartTime(aLock)); for (uint32_t i = 0; i < data->Length(); ++i) { aWriter.StringElement((data->ElementAt(i)).get()); } @@ -1221,7 +1221,7 @@ StreamTaskTracer(PSLockRef aLock, SpliceableJSONWriter& aWriter) } static void -StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter) +StreamMetaJSCustomObject(PS::LockRef aLock, SpliceableJSONWriter& aWriter) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); @@ -1241,10 +1241,10 @@ StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter) aWriter.IntProperty("asyncstack", asyncStacks); // The "startTime" field holds the number of milliseconds since midnight - // January 1, 1970 GMT. This grotty code computes (Now - (Now - - // ProcessStartTime)) to convert gPS->ProcessStartTime() into that form. + // January 1, 1970 GMT. This grotty code computes (Now - (Now - StartTime)) + // to convert gPS->StartTime() into that form. mozilla::TimeDuration delta = - mozilla::TimeStamp::Now() - gPS->ProcessStartTime(aLock); + mozilla::TimeStamp::Now() - gPS->StartTime(aLock); aWriter.DoubleProperty( "startTime", static_cast(PR_Now()/1000.0 - delta.ToMilliseconds())); @@ -1353,9 +1353,7 @@ BuildJavaThreadJSObject(SpliceableJSONWriter& aWriter) #endif static void -locked_profiler_stream_json_for_this_process(PSLockRef aLock, - SpliceableJSONWriter& aWriter, - double aSinceTime) +locked_profiler_stream_json_for_this_process(PS::LockRef aLock, SpliceableJSONWriter& aWriter, double aSinceTime) { LOG("locked_profiler_stream_json_for_this_process"); @@ -1386,23 +1384,23 @@ locked_profiler_stream_json_for_this_process(PSLockRef aLock, { gPS->SetIsPaused(aLock, true); - const PS::ThreadVector& liveThreads = gPS->LiveThreads(aLock); - for (size_t i = 0; i < liveThreads.size(); i++) { - ThreadInfo* info = liveThreads.at(i); - if (!info->IsBeingProfiled()) { - continue; + const PS::ThreadVector& liveThreads = gPS->LiveThreads(aLock); + for (size_t i = 0; i < liveThreads.size(); i++) { + ThreadInfo* info = liveThreads.at(i); + if (!info->IsBeingProfiled()) { + continue; + } + info->StreamJSON(gPS->Buffer(aLock), aWriter, gPS->StartTime(aLock), + aSinceTime); } - info->StreamJSON(gPS->Buffer(aLock), aWriter, - gPS->ProcessStartTime(aLock), aSinceTime); - } - const PS::ThreadVector& deadThreads = gPS->DeadThreads(aLock); - for (size_t i = 0; i < deadThreads.size(); i++) { - ThreadInfo* info = deadThreads.at(i); - MOZ_ASSERT(info->IsBeingProfiled()); - info->StreamJSON(gPS->Buffer(aLock), aWriter, - gPS->ProcessStartTime(aLock), aSinceTime); - } + const PS::ThreadVector& deadThreads = gPS->DeadThreads(aLock); + for (size_t i = 0; i < deadThreads.size(); i++) { + ThreadInfo* info = deadThreads.at(i); + MOZ_ASSERT(info->IsBeingProfiled()); + info->StreamJSON(gPS->Buffer(aLock), aWriter, gPS->StartTime(aLock), + aSinceTime); + } #if defined(PROFILE_JAVA) if (gPS->FeatureJava(aLock)) { @@ -1431,7 +1429,7 @@ profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter, double aSin MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return false; @@ -1469,7 +1467,7 @@ ProfilerMarker::GetTime() const { } void ProfilerMarker::StreamJSON(SpliceableJSONWriter& aWriter, - const TimeStamp& aProcessStartTime, + const TimeStamp& aStartTime, UniqueStacks& aUniqueStacks) const { // Schema: @@ -1485,7 +1483,7 @@ void ProfilerMarker::StreamJSON(SpliceableJSONWriter& aWriter, if (mPayload) { aWriter.StartObjectElement(); { - mPayload->StreamPayload(aWriter, aProcessStartTime, aUniqueStacks); + mPayload->StreamPayload(aWriter, aStartTime, aUniqueStacks); } aWriter.EndObject(); } @@ -1560,19 +1558,19 @@ class SamplerThread { public: // Creates a sampler thread, but doesn't start it. - SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration, + SamplerThread(PS::LockRef aLock, uint32_t aActivityGeneration, double aIntervalMilliseconds); ~SamplerThread(); // This runs on the sampler thread. It suspends and resumes the samplee // threads. - void SuspendAndSampleAndResumeThread(PSLockRef aLock, TickSample& aSample); + void SuspendAndSampleAndResumeThread(PS::LockRef aLock, TickSample& aSample); // This runs on (is!) the sampler thread. void Run(); // This runs on the main thread. - void Stop(PSLockRef aLock); + void Stop(PS::LockRef aLock); private: // The activity generation, for detecting when the sampler thread must stop. @@ -1626,7 +1624,7 @@ SamplerThread::Run() while (true) { // This scope is for |lock|. It ends before we sleep below. { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); // At this point profiler_stop() might have been called, and // profiler_start() might have been called on another thread. @@ -1656,9 +1654,9 @@ SamplerThread::Run() // cheaper than taking a new sample. if (info->Stack()->CanDuplicateLastSampleDueToSleep()) { bool dup_ok = - gPS->Buffer(lock)->DuplicateLastSample( - info->ThreadId(), gPS->ProcessStartTime(lock), - info->LastSample()); + gPS->Buffer(lock)->DuplicateLastSample(info->ThreadId(), + gPS->StartTime(lock), + info->LastSample()); if (dup_ok) { continue; } @@ -1759,7 +1757,7 @@ GeckoProfilerReporter::CollectReports(nsIHandleReportCallback* aHandleReport, #endif { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (gPS) { profSize = GeckoProfilerMallocSizeOf(gPS); @@ -1784,7 +1782,7 @@ GeckoProfilerReporter::CollectReports(nsIHandleReportCallback* aHandleReport, // Measurement of the following things may be added later if DMD finds it // is worthwhile: // - gPS->mFeatures - // - gPS->mFilters + // - gPS->mThreadNameFilters // - gPS->mLiveThreads itself (its elements' children are measured above) // - gPS->mDeadThreads itself (ditto) // - gPS->mInterposeObserver @@ -1798,8 +1796,8 @@ GeckoProfilerReporter::CollectReports(nsIHandleReportCallback* aHandleReport, MOZ_COLLECT_REPORT( "explicit/profiler/profiler-state", KIND_HEAP, UNITS_BYTES, profSize, - "Memory used by the Gecko Profiler's global state (excluding memory used " - "by LUL)."); + "Memory used by the Gecko Profiler's ProfilerState object (excluding " + "memory used by LUL)."); #if defined(USE_LUL_STACKWALK) MOZ_COLLECT_REPORT( @@ -1813,23 +1811,23 @@ GeckoProfilerReporter::CollectReports(nsIHandleReportCallback* aHandleReport, NS_IMPL_ISUPPORTS(GeckoProfilerReporter, nsIMemoryReporter) static bool -ThreadSelected(PSLockRef aLock, const char* aThreadName) +ThreadSelected(PS::LockRef aLock, const char* aThreadName) { // This function runs both on and off the main thread. MOZ_RELEASE_ASSERT(gPS); - const Vector& filters = gPS->Filters(aLock); + const Vector& threadNameFilters = gPS->ThreadNameFilters(aLock); - if (filters.empty()) { + if (threadNameFilters.empty()) { return true; } std::string name = aThreadName; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - for (uint32_t i = 0; i < filters.length(); ++i) { - std::string filter = filters[i]; + for (uint32_t i = 0; i < threadNameFilters.length(); ++i) { + std::string filter = threadNameFilters[i]; std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); // Crude, non UTF-8 compatible, case insensitive substring search @@ -1842,7 +1840,7 @@ ThreadSelected(PSLockRef aLock, const char* aThreadName) } static bool -ShouldProfileThread(PSLockRef aLock, ThreadInfo* aInfo) +ShouldProfileThread(PS::LockRef aLock, ThreadInfo* aInfo) { // This function runs both on and off the main thread. @@ -1855,7 +1853,7 @@ ShouldProfileThread(PSLockRef aLock, ThreadInfo* aInfo) // Find the ThreadInfo for the current thread. On success, *aIndexOut is set to // the index if it is non-null. static ThreadInfo* -FindLiveThreadInfo(PSLockRef aLock, int* aIndexOut = nullptr) +FindLiveThreadInfo(PS::LockRef aLock, int* aIndexOut = nullptr) { // This function runs both on and off the main thread. @@ -1874,7 +1872,7 @@ FindLiveThreadInfo(PSLockRef aLock, int* aIndexOut = nullptr) } static void -locked_register_thread(PSLockRef aLock, const char* aName, void* stackTop) +locked_register_thread(PS::LockRef aLock, const char* aName, void* stackTop) { // This function runs both on and off the main thread. @@ -1908,7 +1906,7 @@ locked_register_thread(PSLockRef aLock, const char* aName, void* stackTop) static void NotifyProfilerStarted(const int aEntries, double aInterval, const char** aFeatures, uint32_t aFeatureCount, - const char** aFilters, uint32_t aFilterCount) + const char** aThreadNameFilters, uint32_t aFilterCount) { if (!CanNotifyObservers()) { return; @@ -1924,13 +1922,14 @@ NotifyProfilerStarted(const int aEntries, double aInterval, featuresArray.AppendElement(aFeatures[i]); } - nsTArray filtersArray; + nsTArray threadNameFiltersArray; for (size_t i = 0; i < aFilterCount; ++i) { - filtersArray.AppendElement(aFilters[i]); + threadNameFiltersArray.AppendElement(aThreadNameFilters[i]); } nsCOMPtr params = - new nsProfilerStartParams(aEntries, aInterval, featuresArray, filtersArray); + new nsProfilerStartParams(aEntries, aInterval, featuresArray, + threadNameFiltersArray); os->NotifyObservers(params, "profiler-started", nullptr); } @@ -1951,9 +1950,9 @@ NotifyObservers(const char* aTopic) } static void -locked_profiler_start(PSLockRef aLock, const int aEntries, double aInterval, +locked_profiler_start(PS::LockRef aLock, const int aEntries, double aInterval, const char** aFeatures, uint32_t aFeatureCount, - const char** aFilters, uint32_t aFilterCount); + const char** aThreadNameFilters, uint32_t aFilterCount); void profiler_init(void* aStackTop) @@ -1980,14 +1979,14 @@ profiler_init(void* aStackTop) } { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); // We've passed the possible failure point. Instantiate gPS, which // indicates that the profiler has initialized successfully. gPS = new PS(); bool ignore; - gPS->SetProcessStartTime(lock, mozilla::TimeStamp::ProcessCreation(ignore)); + gPS->SetStartTime(lock, mozilla::TimeStamp::ProcessCreation(ignore)); locked_register_thread(lock, kMainThreadName, aStackTop); @@ -2053,10 +2052,10 @@ profiler_init(void* aStackTop) } static void -locked_profiler_save_profile_to_file(PSLockRef aLock, const char* aFilename); +locked_profiler_save_profile_to_file(PS::LockRef aLock, const char* aFilename); static SamplerThread* -locked_profiler_stop(PSLockRef aLock); +locked_profiler_stop(PS::LockRef aLock); void profiler_shutdown() @@ -2070,7 +2069,7 @@ profiler_shutdown() // gPS is destroyed, in order to delete it. SamplerThread* samplerThread = nullptr; { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); // Save the profile on shutdown if requested. if (gPS->IsActive(lock)) { @@ -2161,7 +2160,7 @@ profiler_get_start_params(int* aEntries, double* aInterval, return; } - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); *aEntries = gPS->Entries(lock); *aInterval = gPS->Interval(lock); @@ -2172,15 +2171,15 @@ profiler_get_start_params(int* aEntries, double* aInterval, (*aFeatures)[i] = features[i].c_str(); } - const Vector& filters = gPS->Filters(lock); - MOZ_ALWAYS_TRUE(aFilters->resize(filters.length())); - for (uint32_t i = 0; i < filters.length(); ++i) { - (*aFilters)[i] = filters[i].c_str(); + const Vector& threadNameFilters = gPS->ThreadNameFilters(lock); + MOZ_ALWAYS_TRUE(aFilters->resize(threadNameFilters.length())); + for (uint32_t i = 0; i < threadNameFilters.length(); ++i) { + (*aFilters)[i] = threadNameFilters[i].c_str(); } } static void -locked_profiler_save_profile_to_file(PSLockRef aLock, const char* aFilename) +locked_profiler_save_profile_to_file(PS::LockRef aLock, const char* aFilename) { LOG("locked_profiler_save_profile_to_file(%s)", aFilename); @@ -2214,7 +2213,7 @@ profiler_save_profile_to_file(const char* aFilename) MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return; @@ -2278,7 +2277,7 @@ profiler_get_buffer_info_helper(uint32_t* aCurrentPosition, MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return; @@ -2301,9 +2300,9 @@ hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature) } static void -locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval, +locked_profiler_start(PS::LockRef aLock, int aEntries, double aInterval, const char** aFeatures, uint32_t aFeatureCount, - const char** aFilters, uint32_t aFilterCount) + const char** aThreadNameFilters, uint32_t aFilterCount) { if (LOG_TEST) { LOG("locked_profiler_start"); @@ -2313,13 +2312,16 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval, LOG("- feature = %s", aFeatures[i]); } for (uint32_t i = 0; i < aFilterCount; i++) { - LOG("- threads = %s", aFilters[i]); + LOG("- threads = %s", aThreadNameFilters[i]); } } MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS && !gPS->IsActive(aLock)); + bool ignore; + gPS->SetStartTime(aLock, mozilla::TimeStamp::ProcessCreation(ignore)); + // Fall back to the default value if the passed-in value is unreasonable. int entries = aEntries > 0 ? aEntries : PROFILE_DEFAULT_ENTRIES; gPS->SetEntries(aLock, entries); @@ -2335,11 +2337,12 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval, features[i] = aFeatures[i]; } - // Deep copy aFilters. Must precede the ShouldProfileThread() call below. - Vector& filters = gPS->Filters(aLock); - MOZ_ALWAYS_TRUE(filters.resize(aFilterCount)); + // Deep copy aThreadNameFilters. Must precede the ShouldProfileThread() call + // below. + Vector& threadNameFilters = gPS->ThreadNameFilters(aLock); + MOZ_ALWAYS_TRUE(threadNameFilters.resize(aFilterCount)); for (uint32_t i = 0; i < aFilterCount; ++i) { - filters[i] = aFilters[i]; + threadNameFilters[i] = aThreadNameFilters[i]; } #define HAS_FEATURE(feature) hasFeature(aFeatures, aFeatureCount, feature) @@ -2438,7 +2441,7 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval, void profiler_start(int aEntries, double aInterval, const char** aFeatures, uint32_t aFeatureCount, - const char** aFilters, uint32_t aFilterCount) + const char** aThreadNameFilters, uint32_t aFilterCount) { LOG("profiler_start"); @@ -2446,7 +2449,7 @@ profiler_start(int aEntries, double aInterval, SamplerThread* samplerThread = nullptr; { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); // Initialize if necessary. if (!gPS) { @@ -2459,7 +2462,7 @@ profiler_start(int aEntries, double aInterval, } locked_profiler_start(lock, aEntries, aInterval, aFeatures, aFeatureCount, - aFilters, aFilterCount); + aThreadNameFilters, aFilterCount); } // We do these operations with gPSMutex unlocked. The comments in @@ -2469,11 +2472,11 @@ profiler_start(int aEntries, double aInterval, delete samplerThread; } NotifyProfilerStarted(aEntries, aInterval, aFeatures, aFeatureCount, - aFilters, aFilterCount); + aThreadNameFilters, aFilterCount); } static MOZ_MUST_USE SamplerThread* -locked_profiler_stop(PSLockRef aLock) +locked_profiler_stop(PS::LockRef aLock) { LOG("locked_profiler_stop"); @@ -2551,7 +2554,7 @@ locked_profiler_stop(PSLockRef aLock) gPS->SetFeatureTaskTracer(aLock, false); gPS->SetFeatureThreads(aLock, false); - gPS->Filters(aLock).clear(); + gPS->ThreadNameFilters(aLock).clear(); gPS->Features(aLock).clear(); @@ -2572,7 +2575,7 @@ profiler_stop() SamplerThread* samplerThread; { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return; @@ -2604,7 +2607,7 @@ profiler_is_paused() MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return false; @@ -2622,7 +2625,7 @@ profiler_pause() MOZ_RELEASE_ASSERT(gPS); { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return; @@ -2643,7 +2646,7 @@ profiler_resume() MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); { if (!gPS->IsActive(lock)) { @@ -2664,7 +2667,7 @@ profiler_feature_active(const char* aName) MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock)) { return false; @@ -2696,7 +2699,7 @@ profiler_is_active() MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); return gPS->IsActive(lock); } @@ -2708,7 +2711,7 @@ profiler_set_frame_number(int aFrameNumber) MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); gPS->SetFrameNumber(lock, aFrameNumber); } @@ -2721,7 +2724,7 @@ profiler_register_thread(const char* aName, void* aGuessStackTop) MOZ_RELEASE_ASSERT(!NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); void* stackTop = GetStackTop(aGuessStackTop); locked_register_thread(lock, aName, stackTop); @@ -2733,7 +2736,7 @@ profiler_unregister_thread() MOZ_RELEASE_ASSERT(!NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); // We don't call PseudoStack::stopJSSampling() here; there's no point doing // that for a JS thread that is in the process of disappearing. @@ -2831,10 +2834,10 @@ profiler_time() MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); mozilla::TimeDuration delta = - mozilla::TimeStamp::Now() - gPS->ProcessStartTime(lock); + mozilla::TimeStamp::Now() - gPS->StartTime(lock); return delta.ToMilliseconds(); } @@ -2844,7 +2847,7 @@ profiler_get_backtrace() MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock) || gPS->FeaturePrivacy(lock)) { return nullptr; @@ -2907,7 +2910,7 @@ profiler_get_backtrace_noalloc(char *output, size_t outputSize) bool includeDynamicString = true; { - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); includeDynamicString = !gPS->FeaturePrivacy(lock); } @@ -2944,7 +2947,7 @@ profiler_get_backtrace_noalloc(char *output, size_t outputSize) } static void -locked_profiler_add_marker(PSLockRef aLock, const char* aMarker, +locked_profiler_add_marker(PS::LockRef aLock, const char* aMarker, ProfilerMarkerPayload* aPayload) { // This function runs both on and off the main thread. @@ -2963,7 +2966,7 @@ locked_profiler_add_marker(PSLockRef aLock, const char* aMarker, mozilla::TimeStamp origin = (payload && !payload->GetStartTime().IsNull()) ? payload->GetStartTime() : mozilla::TimeStamp::Now(); - mozilla::TimeDuration delta = origin - gPS->ProcessStartTime(aLock); + mozilla::TimeDuration delta = origin - gPS->StartTime(aLock); stack->addMarker(aMarker, payload.release(), delta.ToMilliseconds()); } @@ -2974,7 +2977,7 @@ profiler_add_marker(const char* aMarker, ProfilerMarkerPayload* aPayload) MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); // aPayload must be freed if we return early. mozilla::UniquePtr payload(aPayload); @@ -2994,7 +2997,7 @@ profiler_tracing(const char* aCategory, const char* aInfo, MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock) || gPS->FeaturePrivacy(lock)) { return; @@ -3012,7 +3015,7 @@ profiler_tracing(const char* aCategory, const char* aInfo, MOZ_RELEASE_ASSERT(gPS); - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (!gPS->IsActive(lock) || gPS->FeaturePrivacy(lock)) { return; @@ -3065,7 +3068,7 @@ profiler_clear_js_context() // On JS shut down, flush the current buffer as stringifying JIT samples // requires a live JSContext. - PSAutoLock lock(gPSMutex); + PS::AutoLock lock(gPSMutex); if (gPS->IsActive(lock)) { gPS->SetIsPaused(lock, true); @@ -3074,8 +3077,7 @@ profiler_clear_js_context() ThreadInfo* info = FindLiveThreadInfo(lock); MOZ_RELEASE_ASSERT(info); if (info->IsBeingProfiled()) { - info->FlushSamplesAndMarkers(gPS->Buffer(lock), - gPS->ProcessStartTime(lock)); + info->FlushSamplesAndMarkers(gPS->Buffer(lock), gPS->StartTime(lock)); } gPS->SetIsPaused(lock, false); diff --git a/tools/profiler/public/GeckoProfiler.h b/tools/profiler/public/GeckoProfiler.h index 264fdaaf8201..94c2d98b0d1f 100644 --- a/tools/profiler/public/GeckoProfiler.h +++ b/tools/profiler/public/GeckoProfiler.h @@ -289,8 +289,8 @@ PROFILER_FUNC(bool profiler_thread_is_sleeping(), false) // not. PROFILER_FUNC_VOID(profiler_js_interrupt_callback()) -// The number of milliseconds since the process started. Operates the same -// whether the profiler is active or inactive. +// Gets the time since the last profiler_init() or profiler_start() call. +// Operates the same whether the profiler is active or inactive. PROFILER_FUNC(double profiler_time(), 0) PROFILER_FUNC_VOID(profiler_log(const char *str)) @@ -329,6 +329,14 @@ class ProfilerMarkerPayload; // extern MOZ_THREAD_LOCAL(PseudoStack*) tlsPseudoStack; +class ProfilerState; + +// The core profiler state. Null at process startup, it is set to a non-null +// value in profiler_init() and stays that way until profiler_shutdown() is +// called. Therefore it can be checked to determine if the profiler has been +// initialized but not yet shut down. +extern ProfilerState* gPS; + #ifndef SAMPLE_FUNCTION_NAME # if defined(__GNUC__) || defined(_MSC_VER) # define SAMPLE_FUNCTION_NAME __FUNCTION__ @@ -347,6 +355,8 @@ profiler_call_enter(const char* aInfo, { // This function runs both on and off the main thread. + MOZ_RELEASE_ASSERT(gPS); + PseudoStack* stack = tlsPseudoStack.get(); if (!stack) { return stack; @@ -363,6 +373,8 @@ profiler_call_exit(void* aHandle) { // This function runs both on and off the main thread. + MOZ_RELEASE_ASSERT(gPS); + if (!aHandle) { return; } @@ -486,6 +498,8 @@ profiler_get_pseudo_stack(void) { // This function runs both on and off the main thread. + MOZ_RELEASE_ASSERT(gPS); + return tlsPseudoStack.get(); }