Bug 1328365 (part 1) - Replace tlsTicker with gSampler. r=mstange.

There is a single GeckoSampler and it is currently only accessed on the main
thread, so it's silly to use TLS for it; a normal global variable is better.

This patch also adds main thread assertions to a number of the profiler_*()
functions. Even though bug 1330184 may get rid of some of them, right now they
are a useful as both a sanity check and documentation.

--HG--
extra : rebase_source : 7613eb3cc8089b31180365f6463c81f4556c7b66
This commit is contained in:
Nicholas Nethercote 2017-01-25 16:00:47 +11:00
parent 22bea68112
commit fd25b06c81
4 changed files with 89 additions and 62 deletions

View File

@ -2896,6 +2896,9 @@ WorkerThreadPrimaryRunnable::Run()
#ifdef MOZ_GECKO_PROFILER #ifdef MOZ_GECKO_PROFILER
if (stack) { if (stack) {
// XXX: this is currently a no-op because control ends up
// PseudoStack::flushSamplerOnJSShutdown() which is a no-op for any
// thread other than the main thread. See the comment in that function.
stack->sampleContext(nullptr); stack->sampleContext(nullptr);
} }
#endif #endif

View File

@ -605,9 +605,15 @@ void GeckoSampler::FlushOnJSShutdown(JSContext* aContext)
void PseudoStack::flushSamplerOnJSShutdown() void PseudoStack::flushSamplerOnJSShutdown()
{ {
MOZ_ASSERT(mContext); MOZ_ASSERT(mContext);
GeckoSampler* t = tlsTicker.get();
if (t) { // XXX: this function should handle being called by any thread, but it
t->FlushOnJSShutdown(mContext); // currently doesn't because it accesses gSampler, which is main-thread-only.
if (!NS_IsMainThread()) {
return;
}
if (gSampler) {
gSampler->FlushOnJSShutdown(mContext);
} }
} }

View File

@ -65,7 +65,8 @@ public:
#endif #endif
MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack; MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack;
MOZ_THREAD_LOCAL(GeckoSampler *) tlsTicker; GeckoSampler* gSampler;
// We need to track whether we've been initialized otherwise // We need to track whether we've been initialized otherwise
// we end up using tlsStack without initializing it. // we end up using tlsStack without initializing it.
// Because tlsStack is totally opaque to us we can't reuse // Because tlsStack is totally opaque to us we can't reuse
@ -505,6 +506,8 @@ profiler_log(const char* fmt, va_list args)
void void
profiler_init(void* stackTop) profiler_init(void* stackTop)
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
sInitCount++; sInitCount++;
if (stack_key_initialized) if (stack_key_initialized)
@ -515,7 +518,7 @@ profiler_init(void* stackTop)
#endif #endif
LOG("BEGIN profiler_init"); LOG("BEGIN profiler_init");
if (!tlsPseudoStack.init() || !tlsTicker.init()) { if (!tlsPseudoStack.init()) {
LOG("Failed to init."); LOG("Failed to init.");
return; return;
} }
@ -581,20 +584,21 @@ profiler_init(void* stackTop)
void void
profiler_shutdown() profiler_shutdown()
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
sInitCount--; sInitCount--;
if (sInitCount > 0) if (sInitCount > 0)
return; return;
// Save the profile on shutdown if requested. // Save the profile on shutdown if requested.
GeckoSampler *t = tlsTicker.get(); if (gSampler) {
if (t) {
const char *val = getenv("MOZ_PROFILER_SHUTDOWN"); const char *val = getenv("MOZ_PROFILER_SHUTDOWN");
if (val) { if (val) {
std::ofstream stream; std::ofstream stream;
stream.open(val); stream.open(val);
if (stream.is_open()) { if (stream.is_open()) {
t->ToStreamAsJSON(stream); gSampler->ToStreamAsJSON(stream);
stream.close(); stream.close();
} }
} }
@ -618,48 +622,52 @@ profiler_shutdown()
mozilla::UniquePtr<char[]> mozilla::UniquePtr<char[]>
profiler_get_profile(double aSinceTime) profiler_get_profile(double aSinceTime)
{ {
GeckoSampler *t = tlsTicker.get(); MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!t) {
if (!gSampler) {
return nullptr; return nullptr;
} }
return t->ToJSON(aSinceTime); return gSampler->ToJSON(aSinceTime);
} }
JSObject* JSObject*
profiler_get_profile_jsobject(JSContext *aCx, double aSinceTime) profiler_get_profile_jsobject(JSContext *aCx, double aSinceTime)
{ {
GeckoSampler *t = tlsTicker.get(); MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!t) {
if (!gSampler) {
return nullptr; return nullptr;
} }
return t->ToJSObject(aCx, aSinceTime); return gSampler->ToJSObject(aCx, aSinceTime);
} }
void void
profiler_get_profile_jsobject_async(double aSinceTime, profiler_get_profile_jsobject_async(double aSinceTime,
mozilla::dom::Promise* aPromise) mozilla::dom::Promise* aPromise)
{ {
GeckoSampler *t = tlsTicker.get(); MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!t)) {
if (NS_WARN_IF(!gSampler)) {
return; return;
} }
t->ToJSObjectAsync(aSinceTime, aPromise); gSampler->ToJSObjectAsync(aSinceTime, aPromise);
} }
void void
profiler_save_profile_to_file_async(double aSinceTime, const char* aFileName) profiler_save_profile_to_file_async(double aSinceTime, const char* aFileName)
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
nsCString filename(aFileName); nsCString filename(aFileName);
NS_DispatchToMainThread(NS_NewRunnableFunction([=] () { NS_DispatchToMainThread(NS_NewRunnableFunction([=] () {
GeckoSampler *t = tlsTicker.get(); if (NS_WARN_IF(!gSampler)) {
if (NS_WARN_IF(!t)) {
return; return;
} }
t->ToFileAsync(filename, aSinceTime); gSampler->ToFileAsync(filename, aSinceTime);
})); }));
} }
@ -669,26 +677,28 @@ profiler_get_start_params(int* aEntrySize,
mozilla::Vector<const char*>* aFilters, mozilla::Vector<const char*>* aFilters,
mozilla::Vector<const char*>* aFeatures) mozilla::Vector<const char*>* aFeatures)
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!aEntrySize) || NS_WARN_IF(!aInterval) || if (NS_WARN_IF(!aEntrySize) || NS_WARN_IF(!aInterval) ||
NS_WARN_IF(!aFilters) || NS_WARN_IF(!aFeatures)) { NS_WARN_IF(!aFilters) || NS_WARN_IF(!aFeatures)) {
return; return;
} }
GeckoSampler *t = tlsTicker.get(); if (NS_WARN_IF(!gSampler)) {
if (NS_WARN_IF(!t)) {
return; return;
} }
*aEntrySize = t->EntrySize(); *aEntrySize = gSampler->EntrySize();
*aInterval = t->interval(); *aInterval = gSampler->interval();
const ThreadNameFilterList& threadNameFilterList = t->ThreadNameFilters(); const ThreadNameFilterList& threadNameFilterList =
gSampler->ThreadNameFilters();
MOZ_ALWAYS_TRUE(aFilters->resize(threadNameFilterList.length())); MOZ_ALWAYS_TRUE(aFilters->resize(threadNameFilterList.length()));
for (uint32_t i = 0; i < threadNameFilterList.length(); ++i) { for (uint32_t i = 0; i < threadNameFilterList.length(); ++i) {
(*aFilters)[i] = threadNameFilterList[i].c_str(); (*aFilters)[i] = threadNameFilterList[i].c_str();
} }
const FeatureList& featureList = t->Features(); const FeatureList& featureList = gSampler->Features();
MOZ_ALWAYS_TRUE(aFeatures->resize(featureList.length())); MOZ_ALWAYS_TRUE(aFeatures->resize(featureList.length()));
for (size_t i = 0; i < featureList.length(); ++i) { for (size_t i = 0; i < featureList.length(); ++i) {
(*aFeatures)[i] = featureList[i].c_str(); (*aFeatures)[i] = featureList[i].c_str();
@ -698,6 +708,8 @@ profiler_get_start_params(int* aEntrySize,
void void
profiler_get_gatherer(nsISupports** aRetVal) profiler_get_gatherer(nsISupports** aRetVal)
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!aRetVal) { if (!aRetVal) {
return; return;
} }
@ -707,27 +719,27 @@ profiler_get_gatherer(nsISupports** aRetVal)
return; return;
} }
GeckoSampler *t = tlsTicker.get(); if (NS_WARN_IF(!gSampler)) {
if (NS_WARN_IF(!t)) {
*aRetVal = nullptr; *aRetVal = nullptr;
return; return;
} }
t->GetGatherer(aRetVal); gSampler->GetGatherer(aRetVal);
} }
void void
profiler_save_profile_to_file(const char* aFilename) profiler_save_profile_to_file(const char* aFilename)
{ {
GeckoSampler *t = tlsTicker.get(); MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!t) {
if (!gSampler) {
return; return;
} }
std::ofstream stream; std::ofstream stream;
stream.open(aFilename); stream.open(aFilename);
if (stream.is_open()) { if (stream.is_open()) {
t->ToStreamAsJSON(stream); gSampler->ToStreamAsJSON(stream);
stream.close(); stream.close();
LOGF("Saved to %s", aFilename); LOGF("Saved to %s", aFilename);
} else { } else {
@ -790,14 +802,16 @@ profiler_get_buffer_info_helper(uint32_t *aCurrentPosition,
// This function is called by profiler_get_buffer_info(), which has already // This function is called by profiler_get_buffer_info(), which has already
// zeroed the outparams. // zeroed the outparams.
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!stack_key_initialized) if (!stack_key_initialized)
return; return;
GeckoSampler *t = tlsTicker.get(); if (!gSampler) {
if (!t)
return; return;
}
t->GetBufferInfo(aCurrentPosition, aTotalSize, aGeneration); gSampler->GetBufferInfo(aCurrentPosition, aTotalSize, aGeneration);
} }
// Values are only honored on the first start // Values are only honored on the first start
@ -807,6 +821,8 @@ profiler_start(int aProfileEntries, double aInterval,
const char** aThreadNameFilters, uint32_t aFilterCount) const char** aThreadNameFilters, uint32_t aFilterCount)
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
LOG("BEGIN profiler_start"); LOG("BEGIN profiler_start");
if (!stack_key_initialized) if (!stack_key_initialized)
@ -824,17 +840,16 @@ profiler_start(int aProfileEntries, double aInterval,
// Reset the current state if the profiler is running // Reset the current state if the profiler is running
profiler_stop(); profiler_stop();
GeckoSampler* t; gSampler =
t = new GeckoSampler(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL, new GeckoSampler(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY, aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
aFeatures, aFeatureCount, aFeatures, aFeatureCount,
aThreadNameFilters, aFilterCount); aThreadNameFilters, aFilterCount);
tlsTicker.set(t); gSampler->Start();
t->Start(); if (gSampler->ProfileJS() || gSampler->InPrivacyMode()) {
if (t->ProfileJS() || t->InPrivacyMode()) {
MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
const std::vector<ThreadInfo*>& threads = t->GetRegisteredThreads(); const std::vector<ThreadInfo*>& threads = gSampler->GetRegisteredThreads();
for (uint32_t i = 0; i < threads.size(); i++) { for (uint32_t i = 0; i < threads.size(); i++) {
ThreadInfo* info = threads[i]; ThreadInfo* info = threads[i];
@ -846,17 +861,17 @@ profiler_start(int aProfileEntries, double aInterval,
continue; continue;
} }
thread_profile->GetPseudoStack()->reinitializeOnResume(); thread_profile->GetPseudoStack()->reinitializeOnResume();
if (t->ProfileJS()) { if (gSampler->ProfileJS()) {
thread_profile->GetPseudoStack()->enableJSSampling(); thread_profile->GetPseudoStack()->enableJSSampling();
} }
if (t->InPrivacyMode()) { if (gSampler->InPrivacyMode()) {
thread_profile->GetPseudoStack()->mPrivacyMode = true; thread_profile->GetPseudoStack()->mPrivacyMode = true;
} }
} }
} }
#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
if (t->ProfileJava()) { if (gSampler->ProfileJava()) {
int javaInterval = aInterval; int javaInterval = aInterval;
// Java sampling doesn't accuratly keep up with 1ms sampling // Java sampling doesn't accuratly keep up with 1ms sampling
if (javaInterval < 10) { if (javaInterval < 10) {
@ -866,7 +881,7 @@ profiler_start(int aProfileEntries, double aInterval,
} }
#endif #endif
if (t->AddMainThreadIO()) { if (gSampler->AddMainThreadIO()) {
if (!sInterposeObserver) { if (!sInterposeObserver) {
// Lazily create IO interposer observer // Lazily create IO interposer observer
sInterposeObserver = new mozilla::ProfilerIOInterposeObserver(); sInterposeObserver = new mozilla::ProfilerIOInterposeObserver();
@ -876,10 +891,10 @@ profiler_start(int aProfileEntries, double aInterval,
} }
sIsProfiling = true; sIsProfiling = true;
sIsGPUProfiling = t->ProfileGPU(); sIsGPUProfiling = gSampler->ProfileGPU();
sIsLayersDump = t->LayersDump(); sIsLayersDump = gSampler->LayersDump();
sIsDisplayListDump = t->DisplayListDump(); sIsDisplayListDump = gSampler->DisplayListDump();
sIsRestyleProfiling = t->ProfileRestyle(); sIsRestyleProfiling = gSampler->ProfileRestyle();
if (Sampler::CanNotifyObservers()) { if (Sampler::CanNotifyObservers()) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
@ -909,22 +924,23 @@ profiler_start(int aProfileEntries, double aInterval,
void void
profiler_stop() profiler_stop()
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
LOG("BEGIN profiler_stop"); LOG("BEGIN profiler_stop");
if (!stack_key_initialized) if (!stack_key_initialized)
return; return;
GeckoSampler *t = tlsTicker.get(); if (!gSampler) {
if (!t) {
LOG("END profiler_stop-early"); LOG("END profiler_stop-early");
return; return;
} }
bool disableJS = t->ProfileJS(); bool disableJS = gSampler->ProfileJS();
t->Stop(); gSampler->Stop();
delete t; delete gSampler;
tlsTicker.set(nullptr); gSampler = nullptr;
if (disableJS) { if (disableJS) {
PseudoStack *stack = tlsPseudoStack.get(); PseudoStack *stack = tlsPseudoStack.get();
@ -1169,6 +1185,8 @@ profiler_in_privacy_mode()
UniqueProfilerBacktrace UniqueProfilerBacktrace
profiler_get_backtrace() profiler_get_backtrace()
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!stack_key_initialized) if (!stack_key_initialized)
return nullptr; return nullptr;
@ -1182,12 +1200,12 @@ profiler_get_backtrace()
return nullptr; return nullptr;
} }
GeckoSampler* t = tlsTicker.get(); if (!gSampler) {
if (!t) {
return nullptr; return nullptr;
} }
return UniqueProfilerBacktrace(new ProfilerBacktrace(t->GetBacktrace())); return UniqueProfilerBacktrace(
new ProfilerBacktrace(gSampler->GetBacktrace()));
} }
void void

View File

@ -312,7 +312,7 @@ class nsISupports;
class ProfilerMarkerPayload; class ProfilerMarkerPayload;
extern MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack; extern MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack;
extern MOZ_THREAD_LOCAL(GeckoSampler *) tlsTicker; extern GeckoSampler* gSampler;
extern bool stack_key_initialized; extern bool stack_key_initialized;
#ifndef SAMPLE_FUNCTION_NAME #ifndef SAMPLE_FUNCTION_NAME