diff options
Diffstat (limited to 'tools/profiler/core/platform.cpp')
-rw-r--r-- | tools/profiler/core/platform.cpp | 1257 |
1 files changed, 0 insertions, 1257 deletions
diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp deleted file mode 100644 index a8a09d66f..000000000 --- a/tools/profiler/core/platform.cpp +++ /dev/null @@ -1,1257 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <ostream> -#include <fstream> -#include <sstream> -#include <errno.h> - -#include "platform.h" -#include "PlatformMacros.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/UniquePtr.h" -#include "GeckoProfiler.h" -#ifndef SPS_STANDALONE -#include "ProfilerIOInterposeObserver.h" -#include "mozilla/StaticPtr.h" -#endif -#include "mozilla/ThreadLocal.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/Sprintf.h" -#include "PseudoStack.h" -#include "GeckoSampler.h" -#ifndef SPS_STANDALONE -#include "nsIObserverService.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "nsXULAppAPI.h" -#include "nsProfilerStartParams.h" -#include "mozilla/Services.h" -#include "nsThreadUtils.h" -#endif -#include "ProfilerMarkers.h" - -#ifdef MOZ_TASK_TRACER -#include "GeckoTaskTracer.h" -#endif - -#if defined(SPS_OS_android) - #include "FennecJNIWrappers.h" -#endif - -#if defined(SPS_OS_android) -#include "FennecJNINatives.h" -#endif - -#ifndef SPS_STANDALONE -#if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_x86_linux) -# define USE_LUL_STACKWALK -# include "lul/LulMain.h" -# include "lul/platform-linux-lul.h" -#endif -#endif - -#if defined(SPS_OS_android) -class GeckoJavaSampler : public java::GeckoJavaSampler::Natives<GeckoJavaSampler> -{ -private: - GeckoJavaSampler(); - -public: - static double GetProfilerTime() { - if (!profiler_is_active()) { - return 0.0; - } - return profiler_time(); - }; -}; -#endif - -MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack; -MOZ_THREAD_LOCAL(GeckoSampler *) tlsTicker; -MOZ_THREAD_LOCAL(void *) tlsStackTop; -// We need to track whether we've been initialized otherwise -// we end up using tlsStack without initializing it. -// Because tlsStack is totally opaque to us we can't reuse -// it as the flag itself. -bool stack_key_initialized; - -mozilla::TimeStamp sLastTracerEvent; // is raced on -mozilla::TimeStamp sStartTime; -int sFrameNumber = 0; -int sLastFrameNumber = 0; -int sInitCount = 0; // Each init must have a matched shutdown. -static bool sIsProfiling = false; // is raced on -static bool sIsGPUProfiling = false; // is raced on -static bool sIsLayersDump = false; // is raced on -static bool sIsDisplayListDump = false; // is raced on -static bool sIsRestyleProfiling = false; // is raced on - -// Environment variables to control the profiler -const char* PROFILER_HELP = "MOZ_PROFILER_HELP"; -const char* PROFILER_INTERVAL = "MOZ_PROFILER_INTERVAL"; -const char* PROFILER_ENTRIES = "MOZ_PROFILER_ENTRIES"; -const char* PROFILER_STACK = "MOZ_PROFILER_STACK_SCAN"; -const char* PROFILER_FEATURES = "MOZ_PROFILING_FEATURES"; - -/* we don't need to worry about overflow because we only treat the - * case of them being the same as special. i.e. we only run into - * a problem if 2^32 events happen between samples that we need - * to know are associated with different events */ - -// Values harvested from env vars, that control the profiler. -static int sUnwindInterval; /* in milliseconds */ -static int sUnwindStackScan; /* max # of dubious frames allowed */ -static int sProfileEntries; /* how many entries do we store? */ - -std::vector<ThreadInfo*>* Sampler::sRegisteredThreads = nullptr; -mozilla::UniquePtr< ::Mutex> Sampler::sRegisteredThreadsMutex; - -GeckoSampler* Sampler::sActiveSampler; - -#ifndef SPS_STANDALONE -static mozilla::StaticAutoPtr<mozilla::ProfilerIOInterposeObserver> - sInterposeObserver; -#endif - -// The name that identifies the gecko thread for calls to -// profiler_register_thread. -static const char * gGeckoThreadName = "GeckoMain"; - -void Sampler::Startup() { - sRegisteredThreads = new std::vector<ThreadInfo*>(); - sRegisteredThreadsMutex = OS::CreateMutex("sRegisteredThreads mutex"); - - // We could create the sLUL object and read unwind info into it at - // this point. That would match the lifetime implied by destruction - // of it in Sampler::Shutdown just below. However, that gives a big - // delay on startup, even if no profiling is actually to be done. - // So, instead, sLUL is created on demand at the first call to - // Sampler::Start. -} - -void Sampler::Shutdown() { - while (sRegisteredThreads->size() > 0) { - delete sRegisteredThreads->back(); - sRegisteredThreads->pop_back(); - } - - sRegisteredThreadsMutex = nullptr; - delete sRegisteredThreads; - - // UnregisterThread can be called after shutdown in XPCShell. Thus - // we need to point to null to ignore such a call after shutdown. - sRegisteredThreadsMutex = nullptr; - sRegisteredThreads = nullptr; - -#if defined(USE_LUL_STACKWALK) - // Delete the sLUL object, if it actually got created. - if (sLUL) { - delete sLUL; - sLUL = nullptr; - } -#endif -} - -StackOwningThreadInfo::StackOwningThreadInfo(const char* aName, int aThreadId, - bool aIsMainThread, - PseudoStack* aPseudoStack, - void* aStackTop) - : ThreadInfo(aName, aThreadId, aIsMainThread, aPseudoStack, aStackTop) -{ - aPseudoStack->ref(); -} - -StackOwningThreadInfo::~StackOwningThreadInfo() -{ - PseudoStack* stack = Stack(); - if (stack) { - stack->deref(); - } -} - -void -StackOwningThreadInfo::SetPendingDelete() -{ - PseudoStack* stack = Stack(); - if (stack) { - stack->deref(); - } - ThreadInfo::SetPendingDelete(); -} - -ProfilerMarker::ProfilerMarker(const char* aMarkerName, - 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; -} - -double -ProfilerMarker::GetTime() const { - return mTime; -} - -void ProfilerMarker::StreamJSON(SpliceableJSONWriter& aWriter, - UniqueStacks& aUniqueStacks) const -{ - // Schema: - // [name, time, data] - - aWriter.StartArrayElement(); - { - aUniqueStacks.mUniqueStrings.WriteElement(aWriter, GetMarkerName()); - aWriter.DoubleElement(mTime); - // TODO: Store the callsite for this marker if available: - // if have location data - // b.NameValue(marker, "location", ...); - if (mPayload) { - aWriter.StartObjectElement(); - { - mPayload->StreamPayload(aWriter, aUniqueStacks); - } - aWriter.EndObject(); - } - } - aWriter.EndArray(); -} - -/* Has MOZ_PROFILER_VERBOSE been set? */ - -// Verbosity control for the profiler. The aim is to check env var -// MOZ_PROFILER_VERBOSE only once. However, we may need to temporarily -// override that so as to print the profiler's help message. That's -// what moz_profiler_set_verbosity is for. - -enum class ProfilerVerbosity : int8_t { UNCHECKED, NOTVERBOSE, VERBOSE }; - -// Raced on, potentially -static ProfilerVerbosity profiler_verbosity = ProfilerVerbosity::UNCHECKED; - -bool moz_profiler_verbose() -{ - if (profiler_verbosity == ProfilerVerbosity::UNCHECKED) { - if (getenv("MOZ_PROFILER_VERBOSE") != nullptr) - profiler_verbosity = ProfilerVerbosity::VERBOSE; - else - profiler_verbosity = ProfilerVerbosity::NOTVERBOSE; - } - - return profiler_verbosity == ProfilerVerbosity::VERBOSE; -} - -void moz_profiler_set_verbosity(ProfilerVerbosity pv) -{ - MOZ_ASSERT(pv == ProfilerVerbosity::UNCHECKED || - pv == ProfilerVerbosity::VERBOSE); - profiler_verbosity = pv; -} - - -bool set_profiler_interval(const char* interval) { - if (interval) { - errno = 0; - long int n = strtol(interval, (char**)nullptr, 10); - if (errno == 0 && n >= 1 && n <= 1000) { - sUnwindInterval = n; - return true; - } - return false; - } - - return true; -} - -bool set_profiler_entries(const char* entries) { - if (entries) { - errno = 0; - long int n = strtol(entries, (char**)nullptr, 10); - if (errno == 0 && n > 0) { - sProfileEntries = n; - return true; - } - return false; - } - - return true; -} - -bool set_profiler_scan(const char* scanCount) { - if (scanCount) { - errno = 0; - long int n = strtol(scanCount, (char**)nullptr, 10); - if (errno == 0 && n >= 0 && n <= 100) { - sUnwindStackScan = n; - return true; - } - return false; - } - - return true; -} - -bool is_native_unwinding_avail() { -# if defined(HAVE_NATIVE_UNWIND) - return true; -#else - return false; -#endif -} - -// Read env vars at startup, so as to set: -// sUnwindInterval, sProfileEntries, sUnwindStackScan. -void read_profiler_env_vars() -{ - /* Set defaults */ - sUnwindInterval = 0; /* We'll have to look elsewhere */ - sProfileEntries = 0; - - const char* interval = getenv(PROFILER_INTERVAL); - const char* entries = getenv(PROFILER_ENTRIES); - const char* scanCount = getenv(PROFILER_STACK); - - if (getenv(PROFILER_HELP)) { - // Enable verbose output - moz_profiler_set_verbosity(ProfilerVerbosity::VERBOSE); - profiler_usage(); - // Now force the next enquiry of moz_profiler_verbose to re-query - // env var MOZ_PROFILER_VERBOSE. - moz_profiler_set_verbosity(ProfilerVerbosity::UNCHECKED); - } - - if (!set_profiler_interval(interval) || - !set_profiler_entries(entries) || - !set_profiler_scan(scanCount)) { - profiler_usage(); - } else { - LOG( "SPS:"); - LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")", - (int)sUnwindInterval); - LOGF("SPS: Entry store size = %d (zero means \"platform default\")", - (int)sProfileEntries); - LOGF("SPS: UnwindStackScan = %d (max dubious frames per unwind).", - (int)sUnwindStackScan); - LOG( "SPS:"); - } -} - -void profiler_usage() { - LOG( "SPS: "); - LOG( "SPS: Environment variable usage:"); - LOG( "SPS: "); - LOG( "SPS: MOZ_PROFILER_HELP"); - LOG( "SPS: If set to any value, prints this message."); - LOG( "SPS: "); - LOG( "SPS: MOZ_PROFILER_INTERVAL=<number> (milliseconds, 1 to 1000)"); - LOG( "SPS: If unset, platform default is used."); - LOG( "SPS: "); - LOG( "SPS: MOZ_PROFILER_ENTRIES=<number> (count, minimum of 1)"); - LOG( "SPS: If unset, platform default is used."); - LOG( "SPS: "); - LOG( "SPS: MOZ_PROFILER_VERBOSE"); - LOG( "SPS: If set to any value, increases verbosity (recommended)."); - LOG( "SPS: "); - LOG( "SPS: MOZ_PROFILER_STACK_SCAN=<number> (default is zero)"); - LOG( "SPS: The number of dubious (stack-scanned) frames allowed"); - LOG( "SPS: "); - LOG( "SPS: MOZ_PROFILER_LUL_TEST"); - LOG( "SPS: If set to any value, runs LUL unit tests at startup of"); - LOG( "SPS: the unwinder thread, and prints a short summary of results."); - LOG( "SPS: "); - LOGF("SPS: This platform %s native unwinding.", - is_native_unwinding_avail() ? "supports" : "does not support"); - LOG( "SPS: "); - - /* Re-set defaults */ - sUnwindInterval = 0; /* We'll have to look elsewhere */ - sProfileEntries = 0; - sUnwindStackScan = 0; - - LOG( "SPS:"); - LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")", - (int)sUnwindInterval); - LOGF("SPS: Entry store size = %d (zero means \"platform default\")", - (int)sProfileEntries); - LOGF("SPS: UnwindStackScan = %d (max dubious frames per unwind).", - (int)sUnwindStackScan); - LOG( "SPS:"); - - return; -} - -void set_tls_stack_top(void* stackTop) -{ - // Round |stackTop| up to the end of the containing page. We may - // as well do this -- there's no danger of a fault, and we might - // get a few more base-of-the-stack frames as a result. This - // assumes that no target has a page size smaller than 4096. - uintptr_t stackTopR = (uintptr_t)stackTop; - if (stackTop) { - stackTopR = (stackTopR & ~(uintptr_t)4095) + (uintptr_t)4095; - } - tlsStackTop.set((void*)stackTopR); -} - -bool is_main_thread_name(const char* aName) { - if (!aName) { - return false; - } - return strcmp(aName, gGeckoThreadName) == 0; -} - -#ifndef SPS_STANDALONE -#ifdef HAVE_VA_COPY -#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) -#elif defined(HAVE_VA_LIST_AS_ARRAY) -#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] -#else -#define VARARGS_ASSIGN(foo, bar) (foo) = (bar) -#endif - -void -mozilla_sampler_log(const char *fmt, va_list args) -{ - if (profiler_is_active()) { - // nsAutoCString AppendPrintf would be nicer but - // this is mozilla external code - char buf[2048]; - va_list argsCpy; - VARARGS_ASSIGN(argsCpy, args); - int required = VsprintfLiteral(buf, fmt, argsCpy); - va_end(argsCpy); - - if (required < 0) { - return; // silently drop for now - } else if (required < 2048) { - profiler_tracing("log", buf, TRACING_EVENT); - } else { - char* heapBuf = new char[required+1]; - va_list argsCpy; - VARARGS_ASSIGN(argsCpy, args); - vsnprintf(heapBuf, required+1, fmt, argsCpy); - va_end(argsCpy); - // EVENT_BACKTRACE could be used to get a source - // for all log events. This could be a runtime - // flag later. - profiler_tracing("log", heapBuf, TRACING_EVENT); - delete[] heapBuf; - } - } -} -#endif - -//////////////////////////////////////////////////////////////////////// -// BEGIN externally visible functions - -void mozilla_sampler_init(void* stackTop) -{ - sInitCount++; - - if (stack_key_initialized) - return; - -#ifdef MOZ_TASK_TRACER - mozilla::tasktracer::InitTaskTracer(); -#endif - -#ifdef SPS_STANDALONE - mozilla::TimeStamp::Startup(); -#endif - - 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; - Sampler::RegisterCurrentThread(isMainThread ? - gGeckoThreadName : "Application Thread", - stack, isMainThread, stackTop); - - // Read interval settings from MOZ_PROFILER_INTERVAL and stack-scan - // threshhold from MOZ_PROFILER_STACK_SCAN. - read_profiler_env_vars(); - - // platform specific initialization - OS::Startup(); - -#ifndef SPS_STANDALONE - set_stderr_callback(mozilla_sampler_log); -#endif - -#if defined(SPS_OS_android) - if (mozilla::jni::IsFennec()) { - GeckoJavaSampler::Init(); - } -#endif - - // We can't open pref so we use an environment variable - // to know if we should trigger the profiler on startup - // NOTE: Default - const char *val = getenv("MOZ_PROFILER_STARTUP"); - if (!val || !*val) { - return; - } - - const char* features[] = {"js" - , "leaf" - , "threads" -#if defined(XP_WIN) || defined(XP_MACOSX) \ - || (defined(SPS_ARCH_arm) && defined(linux)) \ - || defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_x86_linux) - , "stackwalk" -#endif -#if defined(SPS_OS_android) - , "java" -#endif - }; - - const char* threadFilters[] = { "GeckoMain", "Compositor" }; - - profiler_start(PROFILE_DEFAULT_ENTRY, PROFILE_DEFAULT_INTERVAL, - features, MOZ_ARRAY_LENGTH(features), - threadFilters, MOZ_ARRAY_LENGTH(threadFilters)); - LOG("END mozilla_sampler_init"); -} - -void mozilla_sampler_shutdown() -{ - sInitCount--; - - if (sInitCount > 0) - return; - - // Save the profile on shutdown if requested. - GeckoSampler *t = tlsTicker.get(); - if (t) { - const char *val = getenv("MOZ_PROFILER_SHUTDOWN"); - if (val) { - std::ofstream stream; - stream.open(val); - if (stream.is_open()) { - t->ToStreamAsJSON(stream); - stream.close(); - } - } - } - - profiler_stop(); - -#ifndef SPS_STANDALONE - set_stderr_callback(nullptr); -#endif - - Sampler::Shutdown(); - -#ifdef SPS_STANDALONE - mozilla::TimeStamp::Shutdown(); -#endif - - PseudoStack *stack = tlsPseudoStack.get(); - stack->deref(); - tlsPseudoStack.set(nullptr); - -#ifdef MOZ_TASK_TRACER - mozilla::tasktracer::ShutdownTaskTracer(); -#endif -} - -void mozilla_sampler_save() -{ - GeckoSampler *t = tlsTicker.get(); - if (!t) { - return; - } - - 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(double aSinceTime) -{ - GeckoSampler *t = tlsTicker.get(); - if (!t) { - return nullptr; - } - - return t->ToJSON(aSinceTime); -} - -#ifndef SPS_STANDALONE -JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, double aSinceTime) -{ - GeckoSampler *t = tlsTicker.get(); - if (!t) { - return nullptr; - } - - return t->ToJSObject(aCx, aSinceTime); -} - -void mozilla_sampler_get_profile_data_async(double aSinceTime, - mozilla::dom::Promise* aPromise) -{ - GeckoSampler *t = tlsTicker.get(); - if (NS_WARN_IF(!t)) { - return; - } - - t->ToJSObjectAsync(aSinceTime, aPromise); -} - -void mozilla_sampler_get_profiler_start_params(int* aEntrySize, - double* aInterval, - mozilla::Vector<const char*>* aFilters, - mozilla::Vector<const char*>* aFeatures) -{ - if (NS_WARN_IF(!aEntrySize) || NS_WARN_IF(!aInterval) || - NS_WARN_IF(!aFilters) || NS_WARN_IF(!aFeatures)) { - return; - } - - GeckoSampler *t = tlsTicker.get(); - if (NS_WARN_IF(!t)) { - return; - } - - *aEntrySize = t->EntrySize(); - *aInterval = t->interval(); - - const ThreadNameFilterList& threadNameFilterList = t->ThreadNameFilters(); - MOZ_ALWAYS_TRUE(aFilters->resize(threadNameFilterList.length())); - for (uint32_t i = 0; i < threadNameFilterList.length(); ++i) { - (*aFilters)[i] = threadNameFilterList[i].c_str(); - } - - const FeatureList& featureList = t->Features(); - MOZ_ALWAYS_TRUE(aFeatures->resize(featureList.length())); - for (size_t i = 0; i < featureList.length(); ++i) { - (*aFeatures)[i] = featureList[i].c_str(); - } -} - -void mozilla_sampler_get_gatherer(nsISupports** aRetVal) -{ - if (!aRetVal) { - return; - } - - if (NS_WARN_IF(!profiler_is_active())) { - *aRetVal = nullptr; - return; - } - - GeckoSampler *t = tlsTicker.get(); - if (NS_WARN_IF(!t)) { - *aRetVal = nullptr; - return; - } - - t->GetGatherer(aRetVal); -} - -#endif - -void mozilla_sampler_save_profile_to_file(const char* aFilename) -{ - GeckoSampler *t = tlsTicker.get(); - if (!t) { - return; - } - - std::ofstream stream; - stream.open(aFilename); - if (stream.is_open()) { - t->ToStreamAsJSON(stream); - stream.close(); - LOGF("Saved to %s", aFilename); - } else { - LOG("Fail to open profile log file."); - } -} - - -const char** mozilla_sampler_get_features() -{ - static const char* features[] = { -#if defined(MOZ_PROFILING) && defined(HAVE_NATIVE_UNWIND) - // Walk the C++ stack. - "stackwalk", -#endif -#if defined(ENABLE_SPS_LEAF_DATA) - // Include the C++ leaf node if not stackwalking. DevTools - // profiler doesn't want the native addresses. - "leaf", -#endif -#if !defined(SPS_OS_windows) - // Use a seperate thread of walking the stack. - "unwinder", -#endif - "java", - // Only record samples during periods of bad responsiveness - "jank", - // Tell the JS engine to emmit pseudostack entries in the - // pro/epilogue. - "js", - // GPU Profiling (may not be supported by the GL) - "gpu", - // Profile the registered secondary threads. - "threads", - // Do not include user-identifiable information - "privacy", - // Dump the layer tree with the textures. - "layersdump", - // Dump the display list with the textures. - "displaylistdump", - // Add main thread I/O to the profile - "mainthreadio", - // Add RSS collection - "memory", -#ifdef MOZ_TASK_TRACER - // Start profiling with feature TaskTracer. - "tasktracer", -#endif -#if defined(XP_WIN) - // Add power collection - "power", -#endif - nullptr - }; - - return features; -} - -void mozilla_sampler_get_buffer_info(uint32_t *aCurrentPosition, uint32_t *aTotalSize, - uint32_t *aGeneration) -{ - *aCurrentPosition = 0; - *aTotalSize = 0; - *aGeneration = 0; - - if (!stack_key_initialized) - return; - - GeckoSampler *t = tlsTicker.get(); - if (!t) - return; - - t->GetBufferInfo(aCurrentPosition, aTotalSize, aGeneration); -} - -// Values are only honored on the first start -void mozilla_sampler_start(int aProfileEntries, double aInterval, - const char** aFeatures, uint32_t aFeatureCount, - const char** aThreadNameFilters, uint32_t aFilterCount) - -{ - LOG("BEGIN mozilla_sampler_start"); - - if (!stack_key_initialized) - profiler_init(nullptr); - - /* If the sampling interval was set using env vars, use that - in preference to anything else. */ - if (sUnwindInterval > 0) - aInterval = sUnwindInterval; - - /* If the entry count was set using env vars, use that, too: */ - if (sProfileEntries > 0) - aProfileEntries = sProfileEntries; - - // Reset the current state if the profiler is running - profiler_stop(); - - GeckoSampler* t; - t = new GeckoSampler(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL, - aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY, - aFeatures, aFeatureCount, - aThreadNameFilters, aFilterCount); - - tlsTicker.set(t); - t->Start(); - if (t->ProfileJS() || t->InPrivacyMode()) { - ::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); - std::vector<ThreadInfo*> threads = t->GetRegisteredThreads(); - - for (uint32_t i = 0; i < threads.size(); i++) { - ThreadInfo* info = threads[i]; - if (info->IsPendingDelete()) { - continue; - } - ThreadProfile* thread_profile = info->Profile(); - if (!thread_profile) { - continue; - } - thread_profile->GetPseudoStack()->reinitializeOnResume(); -#ifndef SPS_STANDALONE - if (t->ProfileJS()) { - thread_profile->GetPseudoStack()->enableJSSampling(); - } - if (t->InPrivacyMode()) { - thread_profile->GetPseudoStack()->mPrivacyMode = true; - } -#endif - } - } - -#if defined(SPS_OS_android) - if (t->ProfileJava()) { - int javaInterval = aInterval; - // Java sampling doesn't accuratly keep up with 1ms sampling - if (javaInterval < 10) { - aInterval = 10; - } - java::GeckoJavaSampler::Start(javaInterval, 1000); - } -#endif - -#ifndef SPS_STANDALONE - if (t->AddMainThreadIO()) { - if (!sInterposeObserver) { - // Lazily create IO interposer observer - sInterposeObserver = new mozilla::ProfilerIOInterposeObserver(); - } - mozilla::IOInterposer::Register(mozilla::IOInterposeObserver::OpAll, - sInterposeObserver); - } -#endif - - sIsProfiling = true; -#ifndef SPS_STANDALONE - sIsGPUProfiling = t->ProfileGPU(); - sIsLayersDump = t->LayersDump(); - sIsDisplayListDump = t->DisplayListDump(); - sIsRestyleProfiling = t->ProfileRestyle(); - - if (Sampler::CanNotifyObservers()) { - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) { - nsTArray<nsCString> featuresArray; - nsTArray<nsCString> threadNameFiltersArray; - - for (size_t i = 0; i < aFeatureCount; ++i) { - featuresArray.AppendElement(aFeatures[i]); - } - - for (size_t i = 0; i < aFilterCount; ++i) { - threadNameFiltersArray.AppendElement(aThreadNameFilters[i]); - } - - nsCOMPtr<nsIProfilerStartParams> params = - new nsProfilerStartParams(aProfileEntries, aInterval, featuresArray, - threadNameFiltersArray); - - os->NotifyObservers(params, "profiler-started", nullptr); - } - } -#endif - - LOG("END mozilla_sampler_start"); -} - -void mozilla_sampler_stop() -{ - LOG("BEGIN mozilla_sampler_stop"); - - if (!stack_key_initialized) - return; - - GeckoSampler *t = tlsTicker.get(); - if (!t) { - LOG("END mozilla_sampler_stop-early"); - return; - } - - bool disableJS = t->ProfileJS(); - - t->Stop(); - delete t; - tlsTicker.set(nullptr); - -#ifndef SPS_STANDALONE - if (disableJS) { - PseudoStack *stack = tlsPseudoStack.get(); - ASSERT(stack != nullptr); - stack->disableJSSampling(); - } - - mozilla::IOInterposer::Unregister(mozilla::IOInterposeObserver::OpAll, - sInterposeObserver); - sInterposeObserver = nullptr; -#endif - - sIsProfiling = false; -#ifndef SPS_STANDALONE - sIsGPUProfiling = false; - sIsLayersDump = false; - sIsDisplayListDump = false; - sIsRestyleProfiling = false; - - if (Sampler::CanNotifyObservers()) { - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) - os->NotifyObservers(nullptr, "profiler-stopped", nullptr); - } -#endif - - LOG("END mozilla_sampler_stop"); -} - -bool mozilla_sampler_is_paused() { - if (Sampler::GetActiveSampler()) { - return Sampler::GetActiveSampler()->IsPaused(); - } else { - return false; - } -} - -void mozilla_sampler_pause() { - if (Sampler::GetActiveSampler()) { - Sampler::GetActiveSampler()->SetPaused(true); -#ifndef SPS_STANDALONE - if (Sampler::CanNotifyObservers()) { - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) - os->NotifyObservers(nullptr, "profiler-paused", nullptr); - } -#endif - } -} - -void mozilla_sampler_resume() { - if (Sampler::GetActiveSampler()) { - Sampler::GetActiveSampler()->SetPaused(false); -#ifndef SPS_STANDALONE - if (Sampler::CanNotifyObservers()) { - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) - os->NotifyObservers(nullptr, "profiler-resumed", nullptr); - } -#endif - } -} - -bool mozilla_sampler_feature_active(const char* aName) -{ - if (!profiler_is_active()) { - return false; - } - - if (strcmp(aName, "gpu") == 0) { - return sIsGPUProfiling; - } - - if (strcmp(aName, "layersdump") == 0) { - return sIsLayersDump; - } - - if (strcmp(aName, "displaylistdump") == 0) { - return sIsDisplayListDump; - } - - if (strcmp(aName, "restyle") == 0) { - return sIsRestyleProfiling; - } - - return false; -} - -bool mozilla_sampler_is_active() -{ - return sIsProfiling; -} - -void mozilla_sampler_responsiveness(const mozilla::TimeStamp& aTime) -{ - sLastTracerEvent = aTime; -} - -void mozilla_sampler_frame_number(int frameNumber) -{ - sFrameNumber = frameNumber; -} - -void mozilla_sampler_lock() -{ - profiler_stop(); -#ifndef SPS_STANDALONE - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) - os->NotifyObservers(nullptr, "profiler-locked", nullptr); -#endif -} - -void mozilla_sampler_unlock() -{ -#ifndef SPS_STANDALONE - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) - os->NotifyObservers(nullptr, "profiler-unlocked", nullptr); -#endif -} - -bool mozilla_sampler_register_thread(const char* aName, void* aGuessStackTop) -{ - if (sInitCount == 0) { - return false; - } - - MOZ_ASSERT(tlsPseudoStack.get() == nullptr); - PseudoStack* stack = PseudoStack::create(); - tlsPseudoStack.set(stack); - bool isMainThread = is_main_thread_name(aName); - void* stackTop = GetStackTop(aGuessStackTop); - return Sampler::RegisterCurrentThread(aName, stack, isMainThread, stackTop); -} - -void mozilla_sampler_unregister_thread() -{ - // Don't check sInitCount count here -- we may be unregistering the - // thread after the sampler was shut down. - if (!stack_key_initialized) { - return; - } - - PseudoStack *stack = tlsPseudoStack.get(); - if (!stack) { - return; - } - stack->deref(); - tlsPseudoStack.set(nullptr); - - Sampler::UnregisterCurrentThread(); -} - -void mozilla_sampler_sleep_start() { - if (sInitCount == 0) { - return; - } - - PseudoStack *stack = tlsPseudoStack.get(); - if (stack == nullptr) { - return; - } - stack->setSleeping(1); -} - -void mozilla_sampler_sleep_end() { - if (sInitCount == 0) { - return; - } - - PseudoStack *stack = tlsPseudoStack.get(); - if (stack == nullptr) { - return; - } - stack->setSleeping(0); -} - -bool mozilla_sampler_is_sleeping() { - if (sInitCount == 0) { - return false; - } - PseudoStack *stack = tlsPseudoStack.get(); - if (stack == nullptr) { - return false; - } - return stack->isSleeping(); -} - -double mozilla_sampler_time(const mozilla::TimeStamp& aTime) -{ - mozilla::TimeDuration delta = aTime - sStartTime; - return delta.ToMilliseconds(); -} - -double mozilla_sampler_time() -{ - return mozilla_sampler_time(mozilla::TimeStamp::Now()); -} - -ProfilerBacktrace* mozilla_sampler_get_backtrace() -{ - if (!stack_key_initialized) - return nullptr; - - // Don't capture a stack if we're not profiling - if (!profiler_is_active()) { - return nullptr; - } - - // Don't capture a stack if we don't want to include personal information - if (profiler_in_privacy_mode()) { - return nullptr; - } - - GeckoSampler* t = tlsTicker.get(); - if (!t) { - return nullptr; - } - - return new ProfilerBacktrace(t->GetBacktrace()); -} - -void mozilla_sampler_free_backtrace(ProfilerBacktrace* aBacktrace) -{ - delete aBacktrace; -} - -// Fill the output buffer with the following pattern: -// "Lable 1" "\0" "Label 2" "\0" ... "Label N" "\0" "\0" -// TODO: use the unwinder instead of pseudo stack. -void mozilla_sampler_get_backtrace_noalloc(char *output, size_t outputSize) -{ - MOZ_ASSERT(outputSize >= 2); - char *bound = output + outputSize - 2; - output[0] = output[1] = '\0'; - PseudoStack *pseudoStack = tlsPseudoStack.get(); - if (!pseudoStack) { - return; - } - - volatile StackEntry *pseudoFrames = pseudoStack->mStack; - uint32_t pseudoCount = pseudoStack->stackSize(); - - for (uint32_t i = 0; i < pseudoCount; i++) { - size_t len = strlen(pseudoFrames[i].label()); - if (output + len >= bound) - break; - strcpy(output, pseudoFrames[i].label()); - output += len; - *output++ = '\0'; - *output = '\0'; - } -} - -void mozilla_sampler_tracing(const char* aCategory, const char* aInfo, - TracingMetadata aMetaData) -{ - mozilla_sampler_add_marker(aInfo, new ProfilerMarkerTracing(aCategory, aMetaData)); -} - -void mozilla_sampler_tracing(const char* aCategory, const char* aInfo, - ProfilerBacktrace* aCause, - TracingMetadata aMetaData) -{ - mozilla_sampler_add_marker(aInfo, new ProfilerMarkerTracing(aCategory, aMetaData, aCause)); -} - -void mozilla_sampler_add_marker(const char *aMarker, ProfilerMarkerPayload *aPayload) -{ - // Note that aPayload may be allocated by the caller, so we need to make sure - // that we free it at some point. - mozilla::UniquePtr<ProfilerMarkerPayload> payload(aPayload); - - if (!stack_key_initialized) - return; - - // Don't insert a marker if we're not profiling to avoid - // the heap copy (malloc). - if (!profiler_is_active()) { - return; - } - - // Don't add a marker if we don't want to include personal information - if (profiler_in_privacy_mode()) { - return; - } - - 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.release(), delta.ToMilliseconds()); -} - -#ifndef SPS_STANDALONE -#include "mozilla/Mutex.h" - -class GeckoMutex : public ::Mutex { - public: - explicit GeckoMutex(const char* aDesc) : - mMutex(aDesc) - {} - - virtual ~GeckoMutex() {} - - virtual int Lock() { - mMutex.Lock(); - return 0; - } - - virtual int Unlock() { - mMutex.Unlock(); - return 0; - } - - private: - mozilla::Mutex mMutex; -}; - -mozilla::UniquePtr< ::Mutex> OS::CreateMutex(const char* aDesc) { - return mozilla::MakeUnique<GeckoMutex>(aDesc); -} - -#else -// Otherwise use c++11 Mutex -#include <mutex> - -class OSXMutex : public ::Mutex { - public: - OSXMutex(const char* aDesc) : - mMutex() - {} - - virtual ~OSXMutex() {} - - virtual int Lock() { - mMutex.lock(); - return 0; - } - - virtual int Unlock() { - mMutex.unlock(); - return 0; - } - - private: - std::mutex mMutex; -}; - -mozilla::UniquePtr< ::Mutex> OS::CreateMutex(const char* aDesc) { - return mozilla::MakeUnique<GeckoMutex>(aDesc); -} - -#endif - -// END externally visible functions -//////////////////////////////////////////////////////////////////////// |